Java 如何从 ProceedingJoinPoint 获取方法的注释值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21275819/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:49:18  来源:igfitidea点击:

How to get a method's annotation value from a ProceedingJoinPoint?

javaspringspring-aopspring-3java-ee-7

提问by user755806

I have below annotation.

我有以下注释。

MyAnnotation.java

我的注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

}

SomeAspect.java

一些方面.java

public class SomeAspect{

 @Around("execution(public * *(..)) && @annotation(com.mycompany.MyAnnotation)")
    public Object procede(ProceedingJoinPoint call) throws Throwable {

  //Some logic

}

}

SomeOther.java

SomeOther.java

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 procedemethod of SomeAspect.javaclass?

在上面的课程中,我在@MyAnnotation 中传递了“ ABC” 。现在如何在SomeAspect.java类的procede方法中访问“ ABC”值?

Thanks!

谢谢!

采纳答案by René Link

You can get the Signaturefrom a ProceedingJoinPointand in case of a method invocation just cast it to a MethodSignature.

您可以从ProceedingJoinPoint获取签名,并且在方法调用的情况下只需将其转换为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 ?

如果我在类级别有 @MyAnnotation("ABC") ,如何获得价值?

A Classis 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

AClass也是 an AnnotatedElement,因此您可以通过与从 a 相同的方式获取它Method。例如,可以使用以下方法获得方法声明类的注释

 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.

由于您使用的是 spring,您可能还想使用 spring 的AnnotationUtils.findAnnotation(..). 它像 spring 一样搜索注释。例如,还要查看超类和接口方法等。

 MyAnnotation foundAnnotation = AnnotationUtils.findAnnotation(method, MyAnnotation.class);

EDIT

编辑

You might also be interessted in the capabilities of spring's MergedAnnotationswhich was introduced in 5.2.

您可能还MergedAnnotations对 5.2 中引入的 spring 的功能感兴趣。

回答by Martin Frey

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)

回答by Hearen

Actually I think we can get the valuein another way round instead of just from ProceedingJoinPoint, which will definitely require us to make use of reflection.

实际上,我认为我们可以通过value另一种方式获得 ,而不仅仅是从ProceedingJoinPoint 获得,这肯定需要我们使用reflection.

Have a try as follows using annotation directly: add com.mycompany.MyAnnotation yourAnnotationin your advice paramsand @annotation(yourAnnotation)in @Around.

直接使用注解试试如下:com.mycompany.MyAnnotation yourAnnotation在你的advice params@annotation(yourAnnotation)@Around.

@Around("execution(public * *(..)) && @annotation(yourAnnotation)")
public Object procede(ProceedingJoinPoint pjp, com.mycompany.MyAnnotation yourAnnotation) {
    ...
    yourAnnotation.value(); // get your annotation value directly;
    ...
}

com.mycompany.MyAnnotationin advice params just work as that in

com.mycompany.MyAnnotation在建议参数中就像在

@Around("execution(public * *(..)) && @annotation(com.mycompany.MyAnnotation)")

yourAnnotationcan be valid variable name since MyAnnotationin params already points out which annotation it should be. Here yourAnnotationis used to retrieve the annotation instance only.

yourAnnotation可以是有效的变量名,因为MyAnnotation在 params 中已经指出它应该是哪个注释。这里yourAnnotation仅用于检索注释实例。

If you want to pass more params you can try args().

如果你想传递更多参数,你可以尝试args().

For more details, do please check its official doc. For Annotation value, you can just search @Auditable.

有关更多详细信息,请查看其官方文档。对于 Annotation 值,您只需搜索@Auditable.

回答by Tom K.

René'sexample is taking me a long way. Also the explanation how I get ClassLevel Annotations.

René 的例子让我受益匪浅。还解释了我如何获得 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)")""

但后来我只能读ClassLevel标注值,如果我以前使用的方法与标注“* @大约(”执行(公* (..))&& @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?

我怎样才能解决这个问题?如果在不通过方法执行的情况下设置了 ClassLevel 注释,如何触发方面?

I want to write a ClassLevel Annotation like

我想写一个 ClassLevel Annotation 像

@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"

它正在导入有关“SwaggerConfiguration”的配置,我想在其中接收“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.classis not known to SwaggerConfiguration(Swagger Stuff it's in a separate lib) I can't use simple reflection like

我怎样才能摆脱initSwagger()上的注释?由于Application.class不为SwaggerConfiguration 所知(Swagger Stuff 它在一个单独的库中)我不能使用简单的反射

Application.class.getAnnotation(EnableSwaggerApi.class)

回答by Rajeev Rathor

Find working code for Method Annotation and class level annotation using AspectJ/AOP

使用 AspectJ/AOP 查找方法注释和类级别注释的工作代码

   @Around("execution(* com.first.test.controller..*(..)))")
    public Object profileAllMethods(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();

        java.lang.reflect.Method method = methodSignature.getMethod();

  Annotation []methodAnnotations =  method.getDeclaredAnnotations();
        System.out.println("==============="+methodAnnotations[0].toString());

        Annotation []classAnnotations = proceedingJoinPoint.getTarget().getClass().getAnnotations();

        System.out.println("===Class Annotation : "+classAnnotations[1].toString());
       Object result = proceedingJoinPoint.proceed();
        return result;
    }