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

Как создать экземпляр аннотации

Я пытаюсь сделать некоторую магию аннотации Java. Должен сказать, что я все еще догоняю аннотационные трюки и что некоторые вещи мне все еще не совсем понятны.

Итак... У меня есть некоторые аннотированные классы, методы и поля. У меня есть метод, который использует отражение для выполнения некоторых проверок классов и ввода некоторых значений в класс. Все это прекрасно работает.

Однако теперь я столкнулся с случаем, когда мне нужен экземпляр (так сказать) аннотации. Итак... аннотации не похожи на обычные интерфейсы, и вы не можете выполнять анонимную реализацию класса. Я понял. Я просмотрел некоторые сообщения о подобных проблемах, но я не могу найти ответ на то, что я ищу.

Мне бы хотелось получить экземпляр аннотации и указать некоторые из его полей, используя отражение (я полагаю). Есть ли вообще способ сделать это?

4b9b3361

Ответ 1

Ну, это, очевидно, ничего сложного. Действительно!

Как отметил коллега, вы можете просто создать анонимный экземпляр аннотации (например, любой интерфейс) следующим образом:

MyAnnotation:

public @interface MyAnnotation
{

    String foo();

}

Вызывающий код:

class MyApp
{
    MyAnnotation getInstanceOfAnnotation(final String foo)
    {
        MyAnnotation annotation = new MyAnnotation()
        {
            @Override
            public String foo()
            {
                return foo;
            }

            @Override
            public Class<? extends Annotation> annotationType()
            {
                return MyAnnotation.class;
            }
        };

        return annotation;
    }
}

Кредиты Мартин Григоров.

Ответ 2

Вы можете использовать прокси-аннотацию, например этот, или this один из проекта Hibernate Validator (отказ от ответственности: я коммиттер последнего).

Ответ 3

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

Даунсайд: классы из sun.* могут быть изменены в более поздних версиях (хотя этот метод существует с Java 5 с той же сигнатурой) и недоступны для всех реализаций Java, см. это обсуждение.

Если это проблема: вы можете создать общий прокси с вашим собственным InvocationHandler - это именно то, что AnnotationParser делает для вас внутренне. Или вы используете свою собственную реализацию MyAnnotation как определено здесь. В обоих случаях вам следует запомнить annotationType(), equals() и hashCode(), поскольку результат документально определен для java.lang.Annotation.

Ответ 4

Прокси-подход, как предлагается в Gunnar answer, уже реализован в GeAnTyRef:

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

Это приведет к аннотации, эквивалентной тому, что вы получите:

@MyAnnotation(name = "someName")

Созданные таким образом экземпляры аннотаций будут действовать идентично тем, которые были созданы Java, и их hashCode и equals были правильно реализованы для обеспечения совместимости.

Сама библиотека является крошечной и не имеет зависимостей.

Раскрытие информации: Я разработчик GeAnTyRef.