I have below annotation.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}
public class SomeAspect{
@Around("execution(public * *(..)) && @annotation(com.mycompany.MyAnnotation)")
public Object procede(ProceedingJoinPoint call) throws Throwable {
//Some logic
}
}
public class SomeOther{
@MyAnnotation("ABC")
public String someMethod(String name){
}
}
In above class am passing "ABC" with in @MyAnnotation. Now how can i access "ABC" value in procede method of SomeAspect.java class?
Thanks!
First, you can use the JoinPoint#getArgs() method which returns an Object[] containing all the arguments of the advised method. You might have to do some casting depending on what you want to do with them.
The ProceedingJoinPoint. getSignature() method returns everything you need to get the actual class name, method name, return type and parameters for the joinpoint.
Spring has something called a AnnotatedTypeScanner class. This class has the code for actual scanning of the classpath resources. It does this by using the class metadata available at runtime.
Use @Field to define a structured data type's field name for an object mapped to NoSql data. Annotation Elements. Table 2-24 describes this annotation's elements.
You can get the Signature from a ProceedingJoinPoint and in case of a method invocation just cast it to a MethodSignature.
@Around("execution(public * *(..)) && @annotation(com.mycompany.MyAnnotation)")
public Object procede(ProceedingJoinPoint call) throws Throwable {
MethodSignature signature = (MethodSignature) call.getSignature();
Method method = signature.getMethod();
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
}
But you should first add an annotation attribute. Your example code doesn't have one, e.g.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
}
Then you can access it
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
String value = myAnnotation.value();
EDIT
How to get value if I have @MyAnnotation("ABC") at class level ?
A Class
is also an AnnotatedElement
, so you can get it the same way as from a Method
. E.g. An annotation of the method's declaring class can be obtained using
Method method = ...;
Class<?> declaringClass = method.getDeclaringClass();
MyAnnotation myAnnotation = declaringClass.getAnnotation(MyAnnotation.class)
Since you are using spring you might also want to use spring's AnnotationUtils.findAnnotation(..)
. It searches for an annotation as spring does. E.g. also looking at superclass and interface methods, etc.
MyAnnotation foundAnnotation = AnnotationUtils.findAnnotation(method, MyAnnotation.class);
EDIT
You might also be interessted in the capabilities of spring's MergedAnnotations
which was introduced in 5.2.
Actually I think we can get the value
in another way round instead of just from ProceedingJoinPoint, which will definitely require us to make use of reflection
.
Have a try as follows using annotation directly: add com.mycompany.MyAnnotation yourAnnotation
in your advice params
and @annotation(yourAnnotation)
in @Around
.
@Around("execution(public * *(..)) && @annotation(yourAnnotation)")
public Object procede(ProceedingJoinPoint pjp, com.mycompany.MyAnnotation yourAnnotation) {
...
yourAnnotation.value(); // get your annotation value directly;
...
}
com.mycompany.MyAnnotation
in advice params just work as that in
@Around("execution(public * *(..)) && @annotation(com.mycompany.MyAnnotation)")
yourAnnotation
can be valid variable name since MyAnnotation
in params already points out which annotation it should be. Here yourAnnotation
is used to retrieve the annotation instance only.
If you want to pass more params you can try args()
.
For more details, do please check its official doc. For Annotation value, you can just search @Auditable
.
This works as well - You can fetch annotation information using reflection on the class.
Annotation anno = MyClass.class.getAnnotation(MyAnnotation.class);
Or
Annotation anno = MyClass.class.getDeclaredMethod("somethod").getAnnotation(MyAnnotation.class);
This works only if your annotation is available at runtime, which you have declared correctly.
@Retention(RetentionPolicy.RUNTIME)
René's example is taking me a long way. Also the explanation how I get ClassLevel Annotations.
But then I can only read ClassLevel Annotations Values if I have previously used a method annotation with "*@Around("execution(public * (..)) && @annotation(com.mycompany.MyAnnotation)")""
How can I get around this? How can I trigger an Aspect if a ClassLevel Annotation is set without going through a Method Execution?
I want to write a ClassLevel Annotation like
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.METHOD, ElementType.TYPE })
@EnableSwagger2
@Import(SwaggerConfiguration.class)
public @interface EnableSwaggerApi {
String controllerPackage() default "foo.bar.ctrl";
}
It's importing the Configuration about "SwaggerConfiguration" where I want to receive the value of "controllerPackage"
@Aspect
public class SwaggerConfiguration {
@Value("${tom.swagger.controller.package:foo.bar.notset}")
private String controllerPackage;
@Value("${tom.swagger.api.version:1.0.0}")
private String apiVersion;
@Value("${spring.application.name:MyApplication}")
private String applicationName;
@Around("execution(public * *(..)) && @annotation(EnableSwaggerApi)")
public void procede(ProceedingJoinPoint call) throws Throwable {
MethodSignature signature = (MethodSignature) call.getSignature();
Method method = signature.getMethod();
Class<?> declaringClass = method.getDeclaringClass();
EnableSwaggerApi myAnnotation = declaringClass.getAnnotation(EnableSwaggerApi.class);
System.err.println("1 -> " + myAnnotation.controllerPackage()); // -> tko.backend.spring.ctrl
myAnnotation = method.getAnnotation(EnableSwaggerApi.class);
System.err.println("2 -> " + myAnnotation.controllerPackage()); // -> tko.backend.spring.SOMEOTHERSTUFF
// THIS WORKS, BUT JUST IF I USE THE @EnableSwaggerApi ON SOME METHOD!
// NOT ON CLASS
}
@Bean
public Docket swaggerApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("controllerPackage"))
.paths(PathSelectors.any())
.build()
.apiInfo(new ApiInfoBuilder().version(apiVersion).title(applicationName).description("Documentation " + applicationName + " API v" + apiVersion)
.build());
}
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/v2/api-docs", config);
return new CorsFilter(source);
}
}
@EnableSwaggerApi(controllerPackage="tko.backend.spring.ctrl")
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class, Initializer.class);
}
@Bean
@EnableSwaggerApi(controllerPackage="tko.backend.spring.SOMEOTHERSTUFF")
public String initSwagger() {
return "some dummy";
}
}
How can I can rid of the annotation on initSwagger()? Since the Application.class is not known to SwaggerConfiguration (Swagger Stuff it's in a separate lib) I can't use simple reflection like
Application.class.getAnnotation(EnableSwaggerApi.class)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With