2016-02-22 3 views
3

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

Есть ли какие-либо механизмы, которые я мог бы использовать, чтобы помочь мне с этой задачей? Или я должен реализовать это сам с нуля?

Если бы мне пришлось это сделать сам, есть несколько подходов, о которых я могу думать.

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

  2. Используйте javap для проверки классов. Поскольку я не знаю программного интерфейса с javap (вы?), Это, вероятно, означает итерацию по файлам и запуск нового процесса для каждого из них, а затем массирование созданного вывода подходящим способом. Возможно, для этого может быть использована задача <scriptdef>. Это будет работать с сохранением аннотаций классов и не требует инициализации.

  3. Используйте обработчик аннотации для сбора информации во время компиляции. Это должно иметь возможность работать с сохранением исходного кода. Но у меня нет опыта написания или использования компиляторов аннотаций, поэтому я не уверен, что это сработает и потребует много исследований, чтобы выяснить некоторые детали. В частности, как активировать задачу для использования ant (Java 6 annotation processing configuration with Ant дает некоторые указатели на это, как и What is the default annotation processors discovery process?), и когда создавать выходной файл (в каждом раунде или только в последнем раунде).

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

+0

Я бы, вероятно, использовал вариант 3, т. Е. Препроцессор аннотации, но я не могу предоставить какой-либо код или пример. Однако, может быть, есть другой способ, для чего нужны эти службы? Может ли поиск по времени выполнения работать на вас? – Thomas

+0

@Thomas: У нас в настоящее время есть поиск во время выполнения, и, к моему удивлению, он недавно сломался, когда я представил индексацию файлов jar. Среда выполнения также означала, что файлы jar должны были загружаться дважды, один раз для загрузчика классов и один раз для перечисления элементов. – MvG

+0

Хм, это кажется довольно странным, но я мало знаю о вашем коде :). Вы могли бы попробовать что-то вроде отражений google (которые подключались бы к иерархии загрузчика классов IIRC), или если вы можете использовать использование CDI для поиска сервисов/beans после их загрузки. Нет необходимости загружать банку дважды. – Thomas

ответ

0

Воодушевленные комментарием Томаса, я дал подход 3 попытку и получил следующую аннотацию процессор работает достаточно хорошо:

import java.io.IOException; 
import java.io.Writer; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.Set; 
import javax.annotation.processing.AbstractProcessor; 
import javax.annotation.processing.ProcessingEnvironment; 
import javax.annotation.processing.RoundEnvironment; 
import javax.annotation.processing.SupportedSourceVersion; 
import javax.lang.model.SourceVersion; 
import javax.lang.model.element.Element; 
import javax.lang.model.element.QualifiedNameable; 
import javax.lang.model.element.TypeElement; 
import javax.tools.StandardLocation; 

@SupportedSourceVersion(SourceVersion.RELEASE_7) 
public class AnnotationServiceProcessor extends AbstractProcessor { 

    // Map name of the annotation to name of the corresponding service interface 
    private static Map<String, String> annotationToServiceMap = new HashMap<>(); 

    static { 
     // Adapt this to your use, or make it configurable somehow 
     annotationToServiceMap.put("Annotation1", "Service1"); 
     annotationToServiceMap.put("Annotation2", "Service2"); 
    } 

    @Override public Set<String> getSupportedAnnotationTypes() { 
     return annotationToServiceMap.keySet(); 
    } 

    // Map name of the annotation to list of names 
    // of the classes which carry that annotation 
    private Map<String, List<String>> classLists; 

    @Override public void init(ProcessingEnvironment env) { 
     super.init(env); 
     classLists = new HashMap<>(); 
     for (String ann: getSupportedAnnotationTypes()) 
      classLists.put(ann, new ArrayList<String>()); 
    } 

    public boolean process(Set<? extends TypeElement> annotations, 
          RoundEnvironment env) { 
     for (TypeElement ann: annotations) { 
      List<String> classes = 
       classLists.get(ann.getQualifiedName().toString()); 
      for (Element elt: env.getElementsAnnotatedWith(ann)) { 
       QualifiedNameable qn = (QualifiedNameable)elt; 
       classes.add(qn.getQualifiedName().toString()); 
      } 
     } 
     if (env.processingOver()) { // Only write results at the end 
      for (String ann: getSupportedAnnotationTypes()) { 
       try { 
        write(ann, classLists.get(ann)); 
       } catch (IOException e) { 
        throw new RuntimeException(e); // UGLY! 
       } 
      } 
     } 
     return true; 
    } 

    // Write the service file for each annotation we found 
    private void write(String ann, List<String> classes) throws IOException { 
     if (classes.isEmpty()) 
      return; 
     String service = annotationToServiceMap.get(ann); 
     Writer w = processingEnv.getFiler() 
      .createResource(StandardLocation.CLASS_OUTPUT, 
          "", "META-INF/services/" + service) 
      .openWriter(); 
     classes.sort(null); // Make the processing order irrelevant 
     for (String cls: classes) { 
      w.write(cls); 
      w.write('\n'); 
     } 
     w.close(); 
    } 

} 

До сих пор я замкнув это до муравья, используя <compilerarg> с от https://stackoverflow.com/a/3644624/1468366. Я попробую что-то получше, и если мне удастся, отредактируйте это сообщение, чтобы включить фрагмент муравейника.

Смежные вопросы