I have methods annotated as follows:
#Action(actionType=<..>)
public void doSomeAction() {
...
}
Now, I would like to invoke one of such annotated methods with given actionType from another flow in another class.
In order to do this, I found the approaches as mentioned in the following SO posts:
How to run all methods with a given annotation?
Java seek a method with specific annotation and its annotation element
But in some cases, such methods may accept arguments as follows:
#Action(actionType='SEND_NOTIFICATION')
public void sendReport(String email) {
...
}
In this regard, I am not able to understand, how to check if the annotated method has any params and invoke such methods with required params.
Related
On the first screenshot you can see my test class. This class is annotated with #ExtendWith({MockitoExtension.class}) and also the tested service is annotated with #InjectMocks. On the second screenshot you can see the tested service.
Why does Mockito uses the long supplier in both cases?
Mockito uses different strategies when injecting mocks in this order:
Constructor injection
Property setter injection
Field injection
Field injection will not work in your example, since the service's fields are declared final.
Since the fields are declared final and the code snippet you showed does not have a field initializer, I assume that you have a constructor with the Supplier args. E.g.
public SomeService(Supplier<String> stringSupplier, Supplier<Long> longTimeSupplier) {
this.stringSupplier = stringSupplier;
this.longTimeSupplier = longTimeSupplier;
}
Thus Mockito will try the constructor injection, find the constructor with the two Supplier parameters and tries to resolve the arguments.
Mockito then finds the two Supplier mocks in the test, but it can not see the generic type due to type erasure. Thus Mockito sees the constructor like this:
public SomeService(Supplier stringSupplier, Supplier longTimeSupplier)
Mockito can also not decide which Supplier to use based on the parameter name, because the normal Java reflection API does not provide that information. So the name of the mocks, will not be taken into account.
There are libraries like paranamer that read the bytecode and extract the debug information to read the parameter names, but Mockito doesn't use that libs.
Thus Mockito just injects the first matching mock which is Supplier<String> stringSupplier in your case. Even your issues is related to generics, Mockito would also act the same way when you have two parameters of the same type that are not generic.
I assumed that you have a constructor that takes the two Supplier. So you can just invoke it in your test's before.
#BeforeEach
public void setup() {
service = new SomeService(stringSupplier, longSupplier);
}
If you can not access the constructor, e.g. it has package scope, you need to invoke it using reflection and set the accessible property to true
#BeforeEach
public void setup() throws Exception {
Constructor<SomeService> constructor = SomeService.class.getConstructor(Supplier.class, Supplier.class);
constructor.setAccessible(true);
service = constructor.newInstance(stringSupplier, longSupplier);
}
PS If you want to remove the final, make sure that the mocks are either named after the fields in the service longTimeSupplier vs. longSupplier or you use #Mock(name = "longTimeSupplier").
I have my authentication class where i want to fetch something which require EntityManager which is present in a class. That class only works after authentication is done.
I have tried importing bean of that class in authentication class. Then i tried initializing EntityManager in Authentication class. But i didn't the things i wanted from that class. I looked over AOP and come to know about #Around annotation, which require to have "ProceedingJoinPoint joinPoint" in method argument. But as i have implemented Filter class in Authentication class, i can't override my filter class. Can we have some work around for that?
In AOP, The method you need to annotate with #Around is not the method you want to wrap, but the method you want to be called 'around' it (the aspect method). The joinPoint parameter in the method is there to represent your 'wrapped' method, and there to tell it when to execute it.
I think an example will be best to understand.
Consider this simple AOP method that prints 'before' and 'after' the execution:
This is the aspect class
#Around("execution(* testWrappedMethod(..))")
public void aopSample(ProceedingJoinPoint joinPoint) {
System.out.println("before");
joinPoint.proceed();// this will make the wrapped method execute
System.out.println("after");
}
and this is the 'wrapped' method:
public void testWrappedMethod(String whatever) {
System.out.println("inside");
}
The output of the execution of testWrappedMethod will be:
before
inside
after
In the Spring Statemachine reference doc is this sample code:
#WithStateMachine
static class Bean1 {
#OnTransition(source = "S1", target = "S2")
public void fromS1ToS2() {
}
}
Is it possible to access the StateContext object from a method annotated with #OnTransition? Perhaps I don't understand the correct use of the annotation...I thought it could be used in a similar manner as an Action, where I could access data stored in the ExtendedState.
It seems that I've totally forget to add this specific information on our docs. We can't access StateContext but event headers and ExtendedState are available.
There's a unit test for this in MethodAnnotationTests.
Short story is that processor handling method calling detects argument types ExtendedState and Map if it's annotated with #EventHeaders. I've also been thinking to support StateContext in a same way via method arguments but haven't yet got that far.
#WithStateMachine
public class Bean2 {
#OnTransition(source = "S1", target = "S2")
public void method1(#EventHeaders Map<String, Object> headers, ExtendedState extendedState) {
}
}
I'll also get docs sorted out for this, thx for pointing this out!
Their documentation says:
A method annotated with #OnTransition may accept a parameter of type
ExtendedState, Map if map argument itself is annotated with
EventHeaders, StateMachine, Message or Exception.
https://docs.spring.io/spring-statemachine/docs/current/api/org/springframework/statemachine/annotation/OnTransition.html
I have several APIs which retain a parameter "feature" from the url (path param). To avoid retrieving it in each method endpoint (eg.)
#GET
public void findAll(#PathParam("feature") String feature);
am trying to implement AOP using AspectJ.
Following is the implementation of the Aspect
#Aspect
public class FeatureAOP {
#Pointcut("execution(* x.y.z.rest.ModifiersFacadeWrapper.*(..)) && args(feature)")
public void pointCut(String feature) {
}
#Before("x.y.z.rest.aop.FeatureAOP.pointCut(feature)")
public void parseParams(JoinPoint jp, String feature) {
Object[] x = jp.getArgs();
System.out.println("Feature: " + feature);
}
}
The above method gives me the value of "feature" in the Aspect class but if I change the method findAll to following signature, it doesn't works.
#GET
public void findAll();
What I understand is the control is transferred to the Aspect after the parameters are resolved and removing it from the method definition is failing it.
Doing so, thus takes me to the same point where I have to define all method endpoints with the parameter in its signature. I would like to know if there is a way I can get the PathParams in the Aspect class without having to define my methods with the designated parameters.
I think you could probably do it by putting the resolved params in a globally accessible data structure (e.g. a Singleton having some sort of Map or Set), but
I wouldn't recommend that kind of approach. I don't know why you don't like having all the params in your method signatures, but that is the intended way of declaring rest services, e.g.
#GET
#Path("{feature}")
#Produces("text/plain")
public String getFeature(#PathParam("feature") String feature) {
return feature;
}
This way you don't have to write any code for retrieving the params, the rest library you are using (be it Jersey or a different one) will just do everything for you.
I'd like to implement declarative security with Spring/AOP and annotations.
As you see in the next code sample I have the Restricted Annotations with the paramter "allowedRoles" for defining who is allowed to execute an adviced method.
#Restricted(allowedRoles="jira-administrators")
public void setPassword(...) throws UserMgmtException {
// set password code
...
}
Now, the problem is that in my Advice I have no access to the defined Annotations:
public Object checkPermission(ProceedingJoinPoint pjp) throws Throwable {
Signature signature = pjp.getSignature();
System.out.println("Allowed:" + rolesAllowedForJoinPoint(pjp));
...
}
private Restricted rolesAllowedForJoinPoint(ProceedingJoinPoint thisJoinPoint)
{
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
Method targetMethod = methodSignature.getMethod();
return targetMethod.getAnnotation(Restricted.class);
}
The method above always returns null (there are no annotations found at all).
Is there a simple solution to this?
I read something about using the AspectJ agent but I would prefer not to use this agent.
To whoever is still having problem after changing annotation retention to Runtime, you might be having the same problem I had: getMethod() returns interface method instead of the implementing class. So, if you have your annotations in the class then naturally getAnnotations() on the interface method returns null.
The following solution solved this problem:
final String methodName = pjp.getSignature().getName();
final MethodSignature methodSignature = (MethodSignature)pjp.getSignature();
Method method = methodSignature.getMethod();
if (method.getDeclaringClass().isInterface()) {
method = pjp.getTarget().getClass().getDeclaredMethod(methodName, method.getParameterTypes());
}
and if you like, you have the option of handling interface annotations here too.
Some more comments available here:
getting template method instance from ProceedingJoinPoint
Oleg
I assume #Restricted is your annotation. If that is the case, make sure you have:
#Retention(RetentionPolicy.RUNTIME)
in your annotation definition. This means that the annotation is retained at runtime.
Even after changing the retention policy like Bozho mentioned this call to get annotation returns null:
targetMethod.getAnnotation(Restricted.class);
What I found is you have to bind the annotation. Given the interface is declared like this:
#Retention(RetentionPolicy.RUNTIME)
public #interface Restricted {
String[] allowedRoles();
}
The advice would need to be declared like this:
#Before("#annotation( restrictedAnnotation )")
public Object processRequest(final ProceedingJoinPoint pjp, Restricted restrictedAnnotation) throws Throwable {
String[] roles = restrictedAnnotation.allowedRoles();
System.out.println("Allowed:" + roles);
}
What this does is bind the annotation to the parameter in the method signature, restrictedAnnotation. The part I am not sure about is how it gets the annotation type, it seems to be based on the parameter. And once you have the annotation you can get the values.
Why don't you just use Spring Security ? It's a brief to implement and use, I don't really see the point in wasting time reinventing the wheel.
Whith Spring AOP if you have a situation like MyManagerImpl implements MyManager the pointcut is applied to the interface method so MethodSignature describes the method defined on MyManager that doesn't have any annotation. the only way I've found to fix this is to inspect the class of the jp.getTarget() object and retrieve the corresponding method.