I have a jersey resource method annotated with custom annotation #InBound(responseLog = true, requestLog = true). The annotation basically logs request and response for each incoming request into a db table, so that these can be looked later for debugging.
Definition of the annotation is as below:
#NameBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface InBound {
boolean requestLog() default false;
boolean responseLog() default false;
}
I want to accept one more argument in annotation which will be basically an object of Type java.util.function.Function to do an awesome task(find a unique key from the request).
Can annotations accept Function in parameters? If yes, Can you please help with an example?
Related
The idea is to create annotations hierarchy (similar to #Service, #Component etc) using #AliasFor annotation. This should give me the possibility to define aspect, that would execute on parent annotation, and every alias of it. But somehow it doesn't work for me.
#ComponentScan is fine, #EnableAspectJAutoProxy is set.
Example:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface ParentAnnotation {
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#ParentAnnotation
public #interface ChildAnnotation {
#AliasFor(annotation = ParentAnnotation.class)
String value() default "";
}
#Aspect
#Component
public class EventRecorderAspect {
#Around("#annotation(com.example.ParentAnnotation)")
public void exampleMethod(ProceedingJoinPoint joinPoint) throws Throwable {
// This should be executed for both #ParentAnnotation and #ChildAnnotation
}
}
#RestController
public class ExampleController {
#ChildAnnotation // This should result in executing aspect for every implementation
String controllerMethod();
}
UPDATE:
I've updated code, as #M.Deinum suggested in a comment below. But it still doesnt work.
AspectJ pointcut matching syntax, a subset of which is used by Spring AOP, is ignorant of meta annotations, even though withing the Spring framework as such there is support for it in other places. I think the closest you can get to specifying meta annotations in your pointcut is to do it explicitly up to the nesting level you require. See this answer for examples showing the syntax variants for both
class-level, e.g. within(#(#com.example.ParentAnnotation *) *),
method-level, e.g. execution(#(#com.example.ParentAnnotation *) * *(..))
annotations.
Update: #Ariel Grabijas asked in a follow-up comment:
So is there a way to somehow inherit annotations from interface method to class method?
Not in Java and also not by means of Spring AOP. But there is a workaround using native AspectJ inter-type definitions (ITD).
I created a Spring Boot 2.3 application. I securited my REST endpoint and my services.
I created some meta annotations because I have many role. For example:
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasAnyRole('ROLE_CUSTOMER')")
public #interface IsCustomerUser {
}
and
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasAnyRole('ROLE_API')")
public #interface IsApiUser {
}
I've several of this meta annotations with many other roles. I thought I could add multiple meta annotations on my endpoints like this:
#IsCustomerUser
#IsApiUser
#GetMapping(path = "/tenants/current/avatar/{version}")
public ResponseEntity<?> getAvatar(#PathVariable("version") long version) {
//TODO some stuff
}
but it seems only one annotation is evalued. I see there is a feature request here. I'd like to know if you have some workaround in order to add multiple meta annotations.
It is very annoying be forced to create all permutations of my basic security annotation.
In fact I should create something like #IsAdminOrCustomerOrApiOrManagerOr.... and it's not really convenient.
I want to implement an Aspect so that Kafka read message from the latest offset.
I want to create and annotation like below:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
}
So if I use this annotation with any of the #KafkaListener method then this listener should read message from the latest one only.
I don't know how to write the AOP for this scenario.
Seems there are two ways to binding interceptor to target class/method:
#Interceptors on target class/method
Declare a interceptor binding type(aka, a custom annotation annotated with #InterceptorBinding itself, for example #Logged), and using it on target class/method
I am using interceptor in CDI environment. My question is, does it is completely unnecessary to declare a extra interceptor binding type if I using #Interceptors to binding interceptor to my target methods?
If answer is yes, then why IntelliJ IDEA constantly complaint me a error
#Interceptor must specify at least one interceptor binding
when I am not annotating interceptor binding type on my interceptor?
If answer is no, I already binding my interceptor to target class/method with #Interceptors(arrayOfMyInceptor) directly, why declare a extra interceptor binding type and using it on my interceptor?
I search the web but cannt found anything about difference of this two approaches, hope SO can solve my problem.
Thank you for your patience.
The annotations #Interceptor and other costum annotations like #Logged are supposed to be invoked on a interceptor class, e.g.
#Logged
#Interceptor
#Priority(Interceptor.Priority.APPLICATION)
public class LoggedInterceptor implements Serializable { ... }
The annotation #InterceptorBinding has to be invoked on the annotation you want to create to make clear it's somewhat of a "interceptor qualifier".
#Inherited
#InterceptorBinding
#Retention(RUNTIME)
#Target({METHOD, TYPE})
public #interface Logged {
}
Then you can invoke the interceptor-binding annotation on a (managed) bean or its methods.
#Logged
public String pay() {...}
#Logged
public void reset() {...}
See the java tutorial for more help https://docs.oracle.com/javaee/7/tutorial/cdi-adv006.htm
EDIT
Because I misread your question, here's my edit:
The annotation #Interceptors is like a collection of interceptors.
By passing several interceptor classes (e.g. LoggedInterceptor from #Logged) to the value variable of the applied #Interceptors annotation all those inteceptor bindings are invoked:
#Interceptors({LoggedInterceptor.class,
OtherInterceptor.class,.....})
Thus you need at least one interceptor binding for #Interceptors
So you need an interceptor binding for the interceptor class itself but not for the target class since it's already mentioned in the #Interceptors annotation.
See the API documentation https://docs.oracle.com/javaee/7/api/javax/interceptor/Interceptors.html
PostProcessInterceptor will intercept all types of response. But in my case I have two categories of response. I have to intercept one kind and let go the other kind untouched (as a plain json string result).
Is there a way by which I skip the interception of the other response kind. May be some kind of marking? Or is there a way of doing this thing differently?
With JAX-RS 2 you could use a name binding for a ContainerResponseFilter. Define an annotation:
#NameBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface Special {}
And mark the filter:
#Provider
#Special
public class SpecialFilter implements ContainerResponseFilter {}
The filter will only be executed if the resource class or method is also annotated #Special.
If you need to use the deprecated PostProcessInterceptor you can't use name binding. But a simple if in the postProcess method will do the same.