2013-10-04 3 views
2

Я совмещаю API компилятора Java (JSR199) с пользовательским обработчиком аннотаций (JSR269). Некоторые ошибки синтаксиса в исходном коде Java, предоставленные компилятору, приводят к появлению дважды диагностических сообщений. Многие синтаксические ошибки по-прежнему вызывают только одно диагностическое сообщение. Например, отмена фигурных скобок приведет только к одному сообщению, но импорт с недопустимым квалифицированным идентификатором приведет к двум диагностическим сообщениям, но только при использовании обработчика аннотаций.Компилятор API + Обработка аннотаций == Двойные диагностические сообщения?

Вот некоторые примеры ввода, который вызывает проблему:

import javax.xml.bind.annotation; // missing ".*" 

public class Test { } 

Для процессора аннотаций я следующее. (Я пытался возвращение фальши процесса, и я также пытался реализацией процессора вручную вместо расширения AbstractProcessor.)

@SupportedSourceVersion(SourceVersion.RELEASE_7) 
@SupportedAnnotationTypes("*") 
public class AnnotationProcessor extends AbstractProcessor { 
    @Override 
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 
     return true; 
    } 
} 

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

javax.tools.DiagnosticCollector<javax.tools.JavaFileObject> diagnostics = 
     new javax.tools.DiagnosticCollector<>(); 

javax.tools.StandardJavaFileManager fileManager = 
     javac.getStandardFileManager(diagnostics, null, null); 

fileManager.setLocation(javax.tools.StandardLocation.CLASS_OUTPUT, Arrays.asList(tempDir.toFile())); 

javax.tools.JavaCompiler.CompilationTask task = 
     javac.getTask(out, fileManager, diagnostics, null, null, compilationUnits); 

List<Processor> processors = new ArrayList<>(); 
AnnotationProcessor ap = new AnnotationProcessor(); 
processors.add(ap); 
task.setProcessors(processors); 

Boolean compiled = task.call(); 

for (Diagnostic<? extends JavaFileObject> diag : diagnostics.getDiagnostics()) { 
    out.println(diag.toString()); 
} 

Мой выход выглядит следующим образом:

/Test.java:1: error: cannot find symbol 
import javax.xml.bind.annotation; 
        ^
    symbol: class annotation 
    location: package javax.xml.bind 
/Test.java:1: error: cannot find symbol 
import javax.xml.bind.annotation; 
        ^
    symbol: class annotation 
    location: package javax.xml.bind 

Если я вынуть processors.add(ap); линии, то сообщение об ошибке дубликата исчезает. Добавление нескольких процессоров не оказывает дополнительного эффекта.

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

ответ

3

В соответствии с specification обработка аннотаций происходит в последовательности rounds, и всегда есть как минимум два раунда обработки. Таким образом, Test.java из вашего примера скомпилирован дважды, а метод процесса процессора вызывается дважды. Вот самодостаточный пример:

public class AnnotationProcessor { 
    public static final String JAVA_SOURCE = "import javax.xml.bind.annotation; // missing \".*\"\n" + 
      "\n" + 
      "public class Test { }"; 

    @SupportedSourceVersion(SourceVersion.RELEASE_7) 
    @SupportedAnnotationTypes("*") 
    public static class MyProcessor extends AbstractProcessor { 

     @Override 
     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 
      System.out.println("Process : " + roundEnv); 
      return true; 
     } 
    } 

    public static void main(String[] args) throws IOException { 
     JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); 
     StandardJavaFileManager fileManager = javac.getStandardFileManager(null, null, null); 
     Path source = Files.createTempDirectory("stackoverflow").resolve("Test.java"); 
     Files.write(source, JAVA_SOURCE.getBytes()); 
     Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(source.toFile()); 
     JavaCompiler.CompilationTask task = javac.getTask(null, null, null, null, null, compilationUnits); 
     task.setProcessors(Collections.singleton(new MyProcessor())); 
     task.call(); 
    } 
} 

Выход:

Process : [errorRaised=false, rootElements=[Test], processingOver=false] 
Process : [errorRaised=false, rootElements=[], processingOver=true] 
C:\Users\Alexey_2\AppData\Local\Temp\stackoverflow4274340620494105881\Test.java:1: error: cannot find symbol 
import javax.xml.bind.annotation; // missing ".*" 
        ^
    symbol: class annotation 
    location: package javax.xml.bind 
C:\Users\Alexey_2\AppData\Local\Temp\stackoverflow4274340620494105881\Test.java:1: error: cannot find symbol 
import javax.xml.bind.annotation; // missing ".*" 
        ^
    symbol: class annotation 
    location: package javax.xml.bind 
1 error