web-dev-qa-db-fra.com

Comment obtenir la valeur d'annotation d'une méthode à partir d'un ProceedingJoinPoint?

J'ai ci-dessous l'annotation.

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){


}


}

Dans la classe ci-dessus, je passe "ABC" avec dans @MyAnnotation . Maintenant, comment puis-je accéder à la valeur "ABC" dans procede méthode de SomeAspect.Java class?

Merci!

37
user755806

Vous pouvez obtenir le Signature à partir d'un ProceedingJoinPoint et, dans le cas d'une invocation de méthode, il suffit de le convertir en un 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);
}

Mais vous devez d'abord ajouter un attribut d'annotation. Votre exemple de code n'en a pas, par exemple.

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

    String value();
}

Ensuite, vous pouvez y accéder

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

MODIFIER

Comment obtenir de la valeur si j'ai @MyAnnotation ("ABC") au niveau de la classe?

Une Class est aussi un AnnotatedElement , vous pouvez donc l'obtenir de la même manière que pour une Method. Par exemple. Une annotation de la classe déclarante de la méthode peut être obtenue en utilisant

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

Si vous utilisez le printemps, vous pouvez aussi utiliser le AnnotationUtils.findAnnotation(..) du printemps. Il recherche une annotation comme le fait le printemps. Par exemple. également à la recherche d'une classe supérieure et de méthodes d'interface, etc.

 MyAnnotation foundAnnotation = AnnotationUtils.findAnnotation(method, MyAnnotation.class);
85
René Link

En fait, je pense que nous pouvons obtenir la value d'une autre manière au lieu de simplement ProceedingJoinPoint, ce qui nous obligera certainement à utiliser reflection.

Essayez d’utiliser les annotations directement comme suit: ajoutez com.mycompany.MyAnnotation yourAnnotation dans votre advice params et @annotation(yourAnnotation) dans @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 dans les paramètres de conseil fonctionnent comme cela dans 

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

yourAnnotation peut être un nom de variable valide car MyAnnotation dans params indique déjà quelle annotation elle devrait être. Ici, yourAnnotation est utilisé pour extraire l'instance d'annotation uniquement.

Si vous voulez passer plus de paramètres, vous pouvez essayer args().

Pour plus de détails, s'il vous plaît vérifier son officiel doc . Pour la valeur d'annotation, vous pouvez simplement rechercher @Auditable

8
Hearen

Cela fonctionne aussi. Vous pouvez récupérer les informations sur les annotations en utilisant la réflexion sur la classe.

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

Ou

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

Cela ne fonctionne que si votre annotation est disponible au moment de l'exécution, ce que vous avez déclaré correctement.

@Retention(RetentionPolicy.RUNTIME)
3
Martin Frey

_ {René} _ l'exemple me prend beaucoup de temps. Aussi l'explication de la façon dont j'obtiens ClassLevel Annotations.

Mais alors, je ne peux lire les valeurs des annotations ClassLevel que si j'ai déjà utilisé une annotation de méthode avec "* @ Around (" execution (public * (..)) &&annotation (com.mycompany.MyAnnotation) ")" "

Comment puis-je contourner cela? Comment puis-je déclencher un Aspect si une annotation ClassLevel est définie sans passer par une exécution de méthode?

Je veux écrire une annotation ClassLevel comme

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

Il importe la configuration sur "SwaggerConfiguration" où je veux recevoir la valeur de "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";
    }

}

Comment puis-je supprimer les annotations sur initSwagger ()? Puisque Application.class n'est pas connu de SwaggerConfiguration (Swagger Stuff c'est dans une bibliothèque séparée), je ne peux pas utiliser une réflexion simple comme 

Application.class.getAnnotation(EnableSwaggerApi.class)
0
Tom K.