How to create an instance of an annotation

前端 未结 8 1189
无人及你
无人及你 2021-01-30 12:47

I am trying to do some Java annotation magic. I must say I am still catching up on annotation tricks and that certain things are still not quite clear to me.

So... I hav

相关标签:
8条回答
  • 2021-01-30 12:58

    You can also absolutely stupidly (but simply) create a dummy annotation target and get it from there

    @MyAnnotation(foo="bar", baz=Blah.class)
    private static class Dummy {}
    

    And

    final MyAnnotation annotation = Dummy.class.getAnnotation(MyAnnotation.class)
    

    Creating method/parameter targeted annotation instances may be a little more elaborate, but this approach has the benefit of getting the annotation instance as the JVM would normally do. Needless to say it is as simple as it can get.

    0 讨论(0)
  • 2021-01-30 13:01

    You could use an annotation proxy such as this one from the Hibernate Validator project (disclaimer: I'm a committer of this project).

    0 讨论(0)
  • 2021-01-30 13:04

    I did this for adding annotation reference on my weld unit test:

    @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ METHOD, FIELD, PARAMETER })
    public @interface AuthenticatedUser {
    
        String value() default "foo";
    
        @SuppressWarnings("all")
        static class Literal extends AnnotationLiteral<AuthenticatedUser> implements AuthenticatedUser {
    
            private static final long serialVersionUID = 1L;
    
            public static final AuthenticatedUser INSTANCE = new Literal();
    
            private Literal() {
            }
    
            @Override
            public String value() {
                return "foo";
            }
        }
    }
    

    usage:

    Bean<?> createUserInfo() {
        return MockBean.builder()
                .types(UserInfo.class)
                .qualifiers(AuthenticatedUser.Literal.INSTANCE)
                .create((o) -> new UserInfo())
                .build();
    }
    
    0 讨论(0)
  • 2021-01-30 13:09

    The proxy approach, as suggested in Gunnar's answer is already implemented in GeAnTyRef:

    Map<String, Object> annotationParameters = new HashMap<>();
    annotationParameters.put("name", "someName");
    MyAnnotation myAnnotation = TypeFactory.annotation(MyAnnotation.class, annotationParameters);
    

    This will produce an annotation equivalent to what you'd get from:

    @MyAnnotation(name = "someName")
    

    Annotation instances produced this way will act identical to the ones produced by Java normally, and their hashCode and equals have been implemented properly for compatibility, so no bizarre caveats like with directly instantiating the annotation as in the accepted answer. In fact, JDK internally uses this same approach: sun.reflect.annotation.AnnotationParser#annotationForMap.

    The library itself is tiny and has no dependencies.

    Disclosure: I'm the developer behind GeAnTyRef.

    0 讨论(0)
  • 2021-01-30 13:09

    You can use sun.reflect.annotation.AnnotationParser.annotationForMap(Class, Map):

    public @interface MyAnnotation {
        String foo();
    }
    
    public class MyApp {
        public MyAnnotation getInstanceOfAnnotation(final String foo) {
            MyAnnotation annotation = AnnotationParser.annotationForMap(
                MyAnnotation.class, Collections.singletonMap("foo", "myFooResult"));
        }
    }
    

    Downside: Classes from sun.* are subject to change in later versions (allthough this method exists since Java 5 with the same signature) and are not available for all Java implementations, see this discussion.

    If that is a problem: you could create a generic proxy with your own InvocationHandler - this is exactly what AnnotationParser is doing for you internally. Or you use your own implementation of MyAnnotation as defined here. In both cases you should remember to implement annotationType(), equals() and hashCode() as the result is documented specifically for java.lang.Annotation.

    0 讨论(0)
  • 2021-01-30 13:13

    @Gunnar's answer is the simplest way for most webservice as we already got hibernate, for example KafkaListener kafkaListener = new org.hibernate.validator.internal.util.annotation.AnnotationDescriptor.Builder<>(KafkaListener.class, ImmutableMap.of("topics", new String[]{"my-topic"})).build().getAnnotation(); and all other properties will stay default.

    0 讨论(0)
提交回复
热议问题