How can I use #around spring aop annotation on method declaration? - java

How can I use #around spring AOP annotation on method declaration? actually there are lots of duplicate code in the java class so I am thinking to optimize it.Only the #around execution values are getting changed every time and method definition is same for 3-4 methods.Can you please suggest what I can do in this case for code optimization?Here in the given example you can see nicdStatus and nicdPortStatus are only getting changed and rest all the method definition is same.
Please provide some suggestion for code optimization because I have duplicate code in my java class.
#Around("execution(* dcp.casa.services.nicd.NicdController.**nicdStatus**(..)) && args(*, relationId,..)")
Object handleRunTest(final ProceedingJoinPoint joinPoint, final String relationId) {
log.info("xyz");
callAbc();
return joinPoint.proceed();
}
#Around("execution(* dcp.casa.services.nicd.NicdController.nicdPortStatus(..)) && args(*, relationId,..)")
Object handleRunTest(final ProceedingJoinPoint joinPoint, final String relationId) {
log.info("xyz");
callAbc();
return joinPoint.proceed();
}

AOP means you want to intercept some logic. While with #around , you are ready to put the some logic before and after some your method. That's good way to remove duplicate code.
What you need to do:
1) find all the methods with duplicate code.
2) abstract those duplicate code into some methods.
3) config with right pointcut.
here have more example. Hope can help.

Your question is a bit unclear. Am I guessing right that you have multiple #Around advice methods with identical method bodies and you want to factor out those method bodies into a helper method in order to avoid code duplication within your aspect(s)?
yes you are correct #kriegaex. you understood my question.
Well, then the answer is simple: Just refactor like you would refactor any other Java class:
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Aspect
public class LoggingAspect {
private static final Logger log = LoggerFactory.getLogger(LoggingAspect.class);
private void callAbc() {}
#Around("execution(* dcp.casa.services.nicd.NicdController.**nicdStatus**(..)) && args(*, relationId, ..)")
public Object handleRunTestA(ProceedingJoinPoint joinPoint, String relationId) throws Throwable {
return handleRunHelper(joinPoint);
}
#Around("execution(* dcp.casa.services.nicd.NicdController.nicdPortStatus(..)) && args(*, relationId, ..)")
public Object handleRunTestB(ProceedingJoinPoint joinPoint, String relationId) throws Throwable {
return handleRunHelper(joinPoint);
}
private Object handleRunHelper(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("xyz");
callAbc();
return joinPoint.proceed();
}
}
If the helper method also needs access to String relationId, just add another parameter to it and call it correspondingly.

Related

Adding AOP to Spring Boot process changes object returned by method to null

I want to add AOP for logging purposes to my Spring Boot application. But it seems to change my application's behavior in unexpected ways.
For example, my application has a method, doThis(), which creates a MyObject instance:
MyObject myObect = doThis(); // a non-null myObject is returned from doThis()
That works great and myObject is populated as expected with an instance returned from doThis(). But I want the doThis() method to also log some messages via AOP.
So then I add the following aspect class:
#Aspect
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
#Around("execution(* my.service.package.*.*(..))")
public void log(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("before");
joinPoint.proceed();
logger.info("after");
}
}
And I also add this configuration class:
#Configuration
#ComponentScan(basePackages = "my.service.package")
#EnableAspectJAutoProxy
public class AppConfig {
#Bean
public LoggingAspect aspect() {
return new LoggingAspect();
}
}
However, now when I run my app, the logging statements do appear, as expected - but now that same exact doThis() method apparently returns a null object:
MyObject myObect = doThis(); // myObject is now unexplainedly null
But that's not true! What I mean by that is when I set a breakpoint on the last line of doThis(), the MyObject instance it is just about to return is very clearly not null. It has been created and populated within the doThis() method. So where did it go? Why did myObject not get populated when doThis() clearly returned a non-null MyObject instance?
It seems like the aspect is somehow nullifying the object returned from doThis(). Has anyone seen this before? Is there any way around it?
I believe the first * in my execution statement is supposed to indicate that the intercepted method can have any return type. But yet the returned value from my intercepted method seems to get somehow changed to null.
I'm working on how I can create a "minimal reproducible example", per the comment, which I'll add here, but this seems like perhaps a fairly standard AOP use case, so throwing it out there in the meantime in case someone may have some insight.
You made a simple beginner's AOP mistake: Your #Around advice proceeds, but does not return the result of the proceed() call. Your advice method has a void return type, your intercepted target method has not. So the advice implicitly returns null. By the way, for primitive types like int this would not even work and throw exceptions because of incompatible return types. I was actually surprised that Spring AOP, weirdly enough, even intercepts non-void methods if the around-advice returns void, because AFAIR native AspectJ would not match non-void methods in this case.
So what can you do?
Either keep the #Around advice, if you really think you need it. Usually, this is only the case if you want to do more than log things, e.g. modify method parameters or return values, handle exceptions or other things potentially changing the control flow:
#Around("execution(* my.service.package.*.*(..))")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("[BEFORE] " + joinPoint);
try {
return joinPoint.proceed();
}
finally {
logger.info("[AFTER] " + joinPoint);
}
}
Or keep it simple and just use a pair of #Before and #After advice methods, if there is no need to transfer data from one advice to the other. This is much simpler, because you do not need to proceed, use try-finally or return anything:
#Before("execution(* my.service.package.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
logger.info("[BEFORE] " + joinPoint);
}
#After("execution(* my.service.package.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
logger.info("[AFTER] " + joinPoint);
}
Here, you could also factor out the duplicate pointcut expression into its own #Pointcut and simply refer to it from both advice methods.

How do I access private fields with AspectJ?

I am investigating AspectJ and its many uses and have discovered mixins.
I can find many examples employing pure AspectJ .aj aspects however I need to use only #AspectJ annotations.
What I am trying to achieve is the following:-
I have a class that I cannot amend, it has a private class variable that I need to interrogate after a particular class method has completed execution. This class does not have getter or setter methods associated with this private class variable.
public final class CannotAmend {
private Uri privateUri;
public final void methodOne(){}
public final void methodTwo(){}
public final void methodThree(){
privateUri = "something";
}
}
I require an aspect/mixin that can capture #After methodThree() and allow me to see the value set in privateUri.
Is this possible to achieve?
With #AspectJ annotations?
Where can I discover documentation/tutorial/examples of how to achieve this?
Within an aspect you can access the private field using the reflection API.
In the aspect you need two things:
A pointcut to define methods on which the aspect matches.
And a method annotated with #After containing logic that's executed after a method matched by the pointcut returns.
#Aspect
public class MyAspect {
#Pointcut("execution(* CannotAmend.methodThree(..))")
public void methodThreePointcut(){
}
#After("methodThreePointcut()")
public void afterMethod(JoinPoint joinPoint) throws NoSuchFieldException, IllegalAccessException {
Object instance = joinPoint.getThis();
Field privateUriField = instance.getClass().getDeclaredField("privateUri");
privateUriField.setAccessible(true);
String privateUri = (String) privateUriField.get(instance);
System.out.println(privateUri); // prints "something"
}
}
On a side note, using String constants to access a private field is not a clean solution. If sometime in the future the name of the variable changes or if it's removed, the aspect will break.
Not with mixins, but you can use #Around advice to get JoinPoint and get field through reflection.
For example:
#Around("execution(* *.methodThree())")
public Object getValue(ProceedingJoinPoint pjp) throws Throwable {
try {
return pjp.proceed();
} finally {
System.out.println(pjp.getThis().getClass().getDeclaredField("privateUri").get(pjp.getThis()));
}
}

For what reason should I mock?

I am new to Mockito and PowerMockito as well. I found out that I can not test static methods with pure Mockito so I need to user PowerMockito (right?).
I have very simple class called Validate with this very easy method
public class Validate {
public final static void stateNotNull(
final Object object,
final String message) {
if (message == null) {
throw new IllegalArgumentException("Exception message is a null object!");
}
if (object == null) {
throw new IllegalStateException(message);
}
}
So I need to verify that:
1) When I call that static method on null message argument, IllegalArgumentException is called
2) When I call that static method on null object argument, IllegalStateException is called
From what I got so far, I wrote this test:
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.isNull;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.testng.annotations.Test;
#RunWith(PowerMockRunner.class)
#PrepareForTest(Validate.class)
public class ValidateTestCase {
#Test(expectedExceptions = { IllegalStateException.class })
public void stateNotNullTest() throws Exception {
PowerMockito.mockStatic(Validate.class);
Validate mock = PowerMockito.mock(Validate.class);
PowerMockito.doThrow(new IllegalStateException())
.when(mock)
.stateNotNull(isNull(), anyString());
Validate.stateNotNull(null, null);
}
}
So this says that I mock Validate class and I am checking that when mock is called on that method with null argument as an object and any string as a message, an IllegalStateException is thrown.
Now, I really don't get it. Why I just can't call that method directly, dropping the whole voodoo magic around mocking that static class? It seems to me that unless I call Validate.stateNotNull that test passes anyway ... For what reason should I mock it?
You should not mock the classes and methods you are testing. You should only mock methods that are needed to perform the test itself.
For example, if you need some objects from a web service to perform a test, you could mock the web service calls, so you don't need to actually call the web service.
First, decide what your objective is and what you want to test. Your test isn't testing your Validate class method, it's creating a mock that behaves like that method, as Fortega points out. Identify what it is you are testing (the object under test) and what it is you need in order to perform the test (the collaborators), then look at the collaborators and decide whether they are things that are easy to create or if you need to mock them.
For something like this class which has no dependencies on anything, I would recommend doing without mocks entirely. There is nothing here that needs mocking, the test can be written like this:
import static org.junit.Assert.*;
public class ValidateTestCase {
#Test
public void testHappyPath() throws Exception {
Validate.stateNotNull("", "");
}
#Test
public void testNullMessage() throws Exception {
try {
Validate.stateNotNull(null, null);
fail();
}
catch (IllegalStateException e) {
String expected = "Exception message is a null object!"
assertEquals(expected, e.getMessage());
}
}
#Test(expected=IllegalStateException.class)
public void testNullObject() throws Exception {
Validate.stateNotNull(null, "test");
}
}
and that tells you whether the code does what you want it to.
Don't mock unless there is some dependency that you want to avoid introducing to the test due to it being either an external resource (like a filesystem or database) or some complex subsystem. The mock frameworks can be very useful but they add complexity, they can over-specify the behavior of the things they are testing, making the tests brittle, and they can make tests hard to read. Do without them if you can.

Match argument with custom annotation on class - detect in runtime

I have annotation like #SecureObject, which might be applied to some classes. Additionally there is the ORM, which provides method like
public ObjectID get(Class paramClass, Object object);
Now I need to create aspect, which will be triggered only in case if paramClass is annotated with #SecureObject.
Straightforward solution like:
#Before("call(public * some.orm.Datastore.get(..,#SecureObject *,..))"
void runBefore() {
// method code
}
does not work - method is never invoked. but wired (checked with aspectj -debug).
Is it possible to achieve such behavior with AspectJ, and if so - how?
The problem is that the first parameter of your get() method is of type Class.
Given that, you can't use an annotation-based method signature pattern. One possible solution is to use an if() pointcut expressions:
package aspects;
#Aspect
public class MyAspect {
#Pointcut("if() && call(public * some.orm.Datastore.get(..)) && args(paramClass,..)")
public static boolean runBefore(JoinPoint jp, Class paramClass) {
return paramClass.isAnnotationPresent(annotation.SecureObject.class);
}
#Before("runBefore(jp, paramClass)")
public void runBeforeAdvice(JoinPoint jp, Class paramClass) {
System.out.println("annotated!");
}
}
Note: This pointcut also triggers if no #SecureObject annotation is present but the if() condition gets evaluated at runtime.

How to mock object with constructor that takes a Class?

This is the test:
import static junit.framework.Assert.assertTrue;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.whenNew;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest( {ClassUnderTesting.class} )
public class ClassUnderTestingTest {
#Test
public void shouldInitializeMocks() throws Exception {
CollaboratorToBeMocked mockedCollaborator = mock(CollaboratorToBeMocked.class);
suppress(constructor(CollaboratorToBeMocked.class, InjectedIntoCollaborator.class));
whenNew(CollaboratorToBeMocked.class)
.withArguments(InjectedAsTypeIntoCollaborator.class)
.thenReturn(mockedCollaborator);
new ClassUnderTesting().methodUnderTesting();
assertTrue(true);
}
}
These are the classes :
public class ClassUnderTesting {
public void methodUnderTesting() {
new CollaboratorToBeMocked(InjectedAsTypeIntoCollaborator.class);
}
}
public class CollaboratorToBeMocked {
public CollaboratorToBeMocked(Class<InjectedAsTypeIntoCollaborator> clazz) {
}
public CollaboratorToBeMocked(InjectedIntoCollaborator someCollaborator) {
}
public CollaboratorToBeMocked() {
}
}
public class InjectedAsTypeIntoCollaborator {
}
public class InjectedIntoCollaborator {
}
This is the error :
org.powermock.reflect.exceptions.TooManyConstructorsFoundException: Several matching constructors found, please specify the argument parameter types so that PowerMock can determine which method you're refering to.
Matching constructors in class CollaboratorToBeMocked were:
CollaboratorToBeMocked( InjectedIntoCollaborator.class )
CollaboratorToBeMocked( java.lang.Class.class )
Here comes the question: how can I make PowerMock figure out what constructor to look for?
The problematic line is the suppress. That is where the error comes from.
Perhaps it is too late for your question. I met it today and found the solution at the following url. Basically, you need to specify your argument type like.
whenNew(MimeMessage.class).**withParameterTypes(MyParameterType.class)**.withArguments(isA(MyParameter.class)).thenReturn(mimeMessageMock);
http://groups.google.com/group/powermock/msg/347f6ef1fb34d946?pli=1
Hope it can help you. :)
I didn't know of PowerMock until you wrote your question, but did some reading and found this in their documentation. Still I am not really sure if that helps you:
If the super class have several
constructors it's possible to tell
PowerMock to only suppress a specific
one. Let's say you have a class called
ClassWithSeveralConstructors that has
one constructor that takes a String
and another constructor that takes an
int as an argument and you only want
to suppress the String constructor.
You can do this using the
suppress(constructor(ClassWithSeveralConstructors.class, String.class));
method.
found at http://code.google.com/p/powermock/wiki/SuppressUnwantedBehavior
Isn't it the thing you wanted?
EDIT: Now I see, you've already tried suppressing. But are you sure you got the suppress call right? Isn't the first argument of constructor() supposed to be the class you would like to surpress the constructor in?
If using PowerMock for EasyMock you can do PowerMock.expectNew(CollaboratorToBeMocked.class, new Class[]{InjectedIntoCollaborator.class}, ...) where the Class[] is the parameter types of the constructor you're expecting to be called. This will resolve the ambiguity between the constructors.

Categories