Поиск всех экземпляров определенного типа аннотации - PullRequest
0 голосов
/ 01 апреля 2012

Предположим, у меня есть эта аннотация

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface  Name 
{
    String value();
}

Это будет использоваться следующим образом

@Name("name1")
public static Foo foo = new Foo();

У меня есть несколько таких в исходных файлах моего проекта. Есть ли достаточно простой способ поиска и сбора всех тех «foo», которым предшествует @Name? Другими словами, я хотел бы написать метод, который бы возвращал Set<Foo>, содержащий их.

Спасибо !!!

Ответы [ 4 ]

2 голосов
/ 01 апреля 2012

Я не очень знаком со сканерами пути к классам, которые предлагают другие.Они кажутся надежным - если не идеальным - решением.

Если у вас есть контроль над источником, вы можете использовать обработку аннотаций.

Создать процессор аннотаций, который создаст класс - MapClass со статическим элементом Map<String,Foo>.Каждый раз, когда обработчик аннотаций встречает аннотацию @Name, он добавляет это к исходному коду MapClass.Когда он завершит обработку аннотаций, он будет иметь такой же эффект, как если бы вы жестко закодировали карту.

Обработка аннотаций происходит во время компиляции.Если некоторые классы в вашем проекте не скомпилированы вами.Например, если кто-то еще скомпилирует некоторые классы и даст вам банку, тогда это не будет работать так же легко.Но если все классы скомпилированы вами, это не должно быть проблемой.

Чтобы создать процессор аннотаций, добавьте AbstractProcessor.Вы можете аннотировать свой класс с помощью аннотации @ SupportedAnnotationTypes ( "Name" ) (убедитесь, что name - это полное имя вашей аннотации.

Переопределите метод process. process имеет два параметра: annotations и roundEnv. annotations - это просто набор аннотаций, которые поддерживает данный конкретный процессор - в вашем случае это должно быть (Name). roundEnv - полезный служебный класс.

Выполните итерацию по одной аннотации в annotations. Используйте от roundEnv до getElementsAnnotatedWith. Это должно дать вам набор всех элементов, которые содержат аннотацию @Name.

AbstractProcessor имеет еще один служебный элемент - processingEnv. Используйте его getFiler метод для createSourceFile.

Затем вы должны немного изменить свою компиляцию. Вы должны скомпилировать ваш процессор отдельно и до других классов. После того, как процессор скомпилирован и вы компилируете другие классы, вы должны сообщить компилятору о вашем процессоре. Если вы используетеКомандная строка вы бы добавили -processorpath /path/to/processor/class[es] и-processor qualified.name.of.processor.

Преимущества этого подхода перед сканером путей к классам в том, что все происходит во время компиляции.Например, если вы случайно добавили аннотацию @Name к элементу Bar, процессор может выдать ошибку времени компиляции (если вы хотите, чтобы процессор мог ее игнорировать).Затем вы можете исправить это, прежде чем продукт будет отправлен.В сканере путей к классам любая выброшенная ошибка является ошибкой во время выполнения, которую увидит пользователь.

Недостатком этого подхода также является то, что все происходит во время компиляции.Это усложняет динамическое добавление классов в проект.

1 голос
/ 01 апреля 2012

Вам нужен сканер Classpath. Я использовал Metapossum Scanner (он выиграл, потому что он находится в репозитории mvn) для сканирования аннотированных классов, но я не думаю, что он будет сканировать аннотированные поля.

Другой вариант, который я изучал, был Reflections . Reflections я не использовал, только исследовал. В документации есть запрос getFieldsAnnotatedWith, который выглядит так, как вам нужно.

Будьте предупреждены, сканеры Classpath становятся все медленнее и получают меньше, чем больше у вас в Classpath.

0 голосов
/ 01 апреля 2012

Возможно, вы захотите взглянуть на Scannotation ! Это может решить вашу проблему !!!

Scannotation - это библиотека Java, которая создает базу данных аннотаций из набора файлов .class. Эта база данных на самом деле представляет собой просто набор карт, которые указывают, какие аннотации используются и какие классы их используют.

PS .: Каркас VRaptor использует его внутри!

0 голосов
/ 01 апреля 2012

Нет, не совсем (не из кода).Решением было бы поместить их всех в класс, а затем выполнить итерации по Field s (getFields()) класса и проверить наличие Annotation s (getAnnotation())

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...