Подтвердить что ты не робот

Как получить значение аннотации метода из ProceedingJoinPoint?

У меня ниже аннотации.

MyAnnotation.java

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

}

SomeAspect.java

public class SomeAspect{

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

  //Some logic

}

}

SomeOther.java

public class SomeOther{

@MyAnnotation("ABC") 
public String someMethod(String name){


}


}

В вышеприведенном классе пропуская " ABC" с помощью @MyAnnotation. Теперь, как я могу получить доступ к значению ABC процедуре метода класса SomeAspect.java?

Спасибо!

4b9b3361

Ответ 1

Вы можете получить подпись из 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);
}

Но сначала вы должны добавить атрибут аннотации. В вашем примере кода его нет, например

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

    String value();
}

Тогда вы можете получить к нему доступ

MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
String value = myAnnotation.value();

EDIT

Как получить значение, если у меня есть @MyAnnotation ("ABC") на уровне класса?

Class также является AnnotatedElement, поэтому вы можете получить его так же, как и из Method. Например. Аннотация к классу объявления метода может быть получена с помощью

 Method method = ...;
 Class<?> declaringClass = method.getDeclaringClass();
 MyAnnotation myAnnotation = declaringClass.getAnnotation(MyAnnotation.class)

Поскольку вы используете пружину, вы также можете использовать пружину AnnotationUtils.findAnnotation(..). Он ищет аннотацию, как spring. Например. также изучаем методы суперкласса и интерфейса и т.д.

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

Ответ 2

На самом деле я думаю, что мы можем получить value по-другому, а не только из ProceedingJoinPoint, что, безусловно, потребует от нас использования reflection.

Попробуйте сделать следующее, используя непосредственную аннотацию: добавьте 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.MyAnnotation в параметрах совета просто работает как в

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

yourAnnotation может быть допустимым именем переменной, поскольку MyAnnotation в параметрах уже указывает, какой аннотацией она должна быть. Здесь yourAnnotation используется только для извлечения экземпляра аннотации.

Если вы хотите передать больше параметров, попробуйте args().

Для получения более подробной информации, пожалуйста, проверьте его официальный документ. По значению аннотации вы можете просто выполнить поиск @Auditable.

Ответ 3

Это также работает. Вы можете получить информацию об аннотации, используя отражение в классе.

Annotation anno = MyClass.class.getAnnotation(MyAnnotation.class);

или

Annotation anno = MyClass.class.getDeclaredMethod("somethod").getAnnotation(MyAnnotation.class);

Это работает, только если ваша аннотация доступна во время выполнения, которую вы заявили правильно.

@Retention(RetentionPolicy.RUNTIME)

Ответ 4

Пример Рене уводит меня далеко. Также объяснение, как я получаю аннотации ClassLevel.

Но тогда я могу читать только значения аннотаций ClassLevel, если я ранее использовал аннотацию метода с "* @Around (" выполнение (public * (..)) && @annotation (com.mycompany.MyAnnotation) ")" "

Как я могу обойти это? Как я могу активировать аспект, если аннотация ClassLevel установлена без выполнения метода?

Я хочу написать аннотацию ClassLevel вроде

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.METHOD, ElementType.TYPE })
@EnableSwagger2
@Import(SwaggerConfiguration.class)
public @interface EnableSwaggerApi {
    String controllerPackage() default "foo.bar.ctrl";
}

Это импортирование Конфигурации о "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";
    }

}

Как я могу избавиться от аннотации на initSwagger()? Поскольку класс Application.class не известен SwaggerConfiguration (Swagger поместите его в отдельную библиотеку), я не могу использовать простые отражения, такие как

Application.class.getAnnotation(EnableSwaggerApi.class)

Ответ 5

Найдите рабочий код для аннотации метода и аннотации на уровне класса, используя 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;
    }