Как создать экземпляр аннотации
Я пытаюсь сделать некоторую магию аннотации Java. Должен сказать, что я все еще догоняю аннотационные трюки и что некоторые вещи мне все еще не совсем понятны.
Итак... У меня есть некоторые аннотированные классы, методы и поля. У меня есть метод, который использует отражение для выполнения некоторых проверок классов и ввода некоторых значений в класс. Все это прекрасно работает.
Однако теперь я столкнулся с случаем, когда мне нужен экземпляр (так сказать) аннотации. Итак... аннотации не похожи на обычные интерфейсы, и вы не можете выполнять анонимную реализацию класса. Я понял. Я просмотрел некоторые сообщения о подобных проблемах, но я не могу найти ответ на то, что я ищу.
Мне бы хотелось получить экземпляр аннотации и указать некоторые из его полей, используя отражение (я полагаю). Есть ли вообще способ сделать это?
Ответы
Ответ 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.