jira.codehaus.org

  • Log In Access more options
    • Online Help
    • Keyboard Shortcuts
    • About JIRA
    • JIRA Credits
    • What?s New
  • Dashboards Access more options (Alt+d)
  • Projects Access more options (Alt+p)
  • Issues Access more options (Alt+i)
  • Maven 2.x Compiler Plugin
  • MCOMPILER-97

META-INF/services/javax.annotation.processing.Processor copied before compilation and causes error

  • Log In
  • Views
    • XML
    • Word
    • Printable

Details

  • Type: Bug Bug
  • Status: Open Open
  • Priority: Major Major
  • Resolution: Unresolved
  • Affects Version/s: 2.0.2
  • Fix Version/s: None
  • Labels:
    None
  • Environment:
    Ubuntu 8.10, JDK 6.
  • Testcase included:
    yes

Description

It is tricky to compile a Maven module which defines a (269-compliant) annotation processor. If you write the code for the processor in src/main/java and register it in src/main/resources, META-INF/services/javax.annotation.processing.Processor is copied to target/classes first, and then javac is run. But javac is given target/classes in -classpath, so it tries to load the processor, which of course has not been compiled yet - a chicken-and-egg problem.

The most straightforward workaround is to specify <compilerArgument>-proc:none</compilerArgument> in your POM. This will only work, however, if the module does not use any annotation processors defined in dependencies. If it does, there may be some other trick involving -processorpath and Maven variable substitution to insert the dependency classpath.

Switching the order of resources:resources and compiler:compile would help - at least a clean build would work - though it could still cause problems in incremental builds. Better would be for the compiler plugin to pass -processorpath based on the dependency classpath (i.e. -classpath minus target/classes) when using -source 1.6 or higher.

  • Options
    • Sort By Name
    • Sort By Date
    • Ascending
    • Descending
    • Download All

Attachments

  1. Hide
    Zip Archive
    maven-6647998-test.zip
    13/Apr/09 9:42 PM
    8 kB
    Jesse Glick
    1. XML File
      maven-6647998-test/.../pom.xml 0.9 kB
    2. Java Source File
      maven-6647998-test/.../Proc.java 1 kB
    3. File
      maven-6647998-test/.../javax.annotation.processing.Processor 0.0 kB
    4. XML File
      maven-6647998-test/.../pom.xml 0.8 kB
    5. Java Source File
      maven-6647998-test/.../X.java 0.1 kB
    6. File
      maven-6647998-test/.../info 0.0 kB
    7. XML File
      maven-6647998-test/pom.xml 0.9 kB
    Download Zip
    Show
    Zip Archive
    maven-6647998-test.zip
    13/Apr/09 9:42 PM
    8 kB
    Jesse Glick
  2. Hide
    Zip Archive
    MCOMPILER-97-workaround.zip
    07/Jul/11 11:07 AM
    6 kB
    Jesse Glick
    1. XML File
      MCOMPILER-97/nb-configuration.xml 0.3 kB
    2. File
      MCOMPILER-97/.../javax.annotation.processing.Processor 0.0 kB
    3. Java Source File
      MCOMPILER-97/src/.../mcompiler97/Proc.java 1 kB
    4. Java Source File
      MCOMPILER-97/src/.../Unrelated.java 0.2 kB
    5. Java Source File
      MCOMPILER-97/src/.../mcompiler97/Ann.java 0.3 kB
    6. Java Source File
      MCOMPILER-97/src/.../UnrelatedTest.java 0.2 kB
    7. Java Source File
      MCOMPILER-97/src/.../ProcTest.java 0.2 kB
    8. XML File
      MCOMPILER-97/pom.xml 4 kB
    Download Zip
    Show
    Zip Archive
    MCOMPILER-97-workaround.zip
    07/Jul/11 11:07 AM
    6 kB
    Jesse Glick

Issue Links

is depended upon by

Bug - A problem which impairs or prevents the functions of the product. MCOMPILER-98 -sourcepath not passed to javac

  • Critical - Crashes, loss of data, severe memory leak.
  • Closed - The issue is considered finished, the resolution is correct. Issues which are not closed can be reopened.
is related to

New Feature - A new feature of the product, which has yet to be developed. MCOMPILER-134 add support for jdk 6 javac -processorpath parameter

  • Minor - Minor loss of function, or other problem where easy workaround is present.
  • Open - The issue is open and ready for the assignee to start work on it.

Activity

Ascending order - Click to sort in descending order
  • All
  • Comments
  • Work Log
  • History
  • Activity
Hide
Permalink
Petr Jiricka added a comment - 08/Jan/10 3:34 PM

I also hit this issue. My scenario is that the my Maven project provides an annotation processor, and tests for this project use this processor. So when compiling sources, I do not need to run annotation processors; when compiling tests, they need to be compiled. The workaround I found (based on Jesse's straightforward workaround above) is to configure maven-compiler-plugin as follows:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<compilerArgument>-proc:none</compilerArgument>
<source>1.6</source>
<target>1.6</target>
</configuration>
</execution>
<execution>
<id>default-testCompile</id>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</execution>
</executions>
</plugin>

Show
Petr Jiricka added a comment - 08/Jan/10 3:34 PM I also hit this issue. My scenario is that the my Maven project provides an annotation processor, and tests for this project use this processor. So when compiling sources, I do not need to run annotation processors; when compiling tests, they need to be compiled. The workaround I found (based on Jesse's straightforward workaround above) is to configure maven-compiler-plugin as follows: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <executions> <execution> <id>default-compile</id> <configuration> <compilerArgument>-proc:none</compilerArgument> <source>1.6</source> <target>1.6</target> </configuration> </execution> <execution> <id>default-testCompile</id> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </execution> </executions> </plugin>
Hide
Permalink
Petr Jiricka added a comment - 08/Jan/10 3:37 PM

Sorry, what I meant is "when compiling tests, processors need to be run".

See: http://maven.apache.org/guides/mini/guide-default-execution-ids.html

Show
Petr Jiricka added a comment - 08/Jan/10 3:37 PM Sorry, what I meant is "when compiling tests, processors need to be run". See: http://maven.apache.org/guides/mini/guide-default-execution-ids.html
Hide
Permalink
C Divilly added a comment - 16/Mar/10 10:27 AM

I used a variation of the above workaround, in my case I needed the outputs from the annotation processing to be packaged in the final jar not just generated for the testing phase. I added the following to my pom:

 
<plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-compiler-plugin</artifactId>
 <version>2.1</version>
 <configuration>
  <source>1.6</source>
  <target>1.6</target>
 </configuration>
 <executions>
  <execution>
   <id>default-compile</id>
   <configuration>
    <compilerArgument>-proc:none</compilerArgument>
    <includes>
     <include>path/to/annotation/processor/**</include>
     <include>path/to/annotation/processor/dependencies/**</include>
    </includes>
   </configuration>
  </execution>
  <execution>
   <id>compile-everything-else</id>
   <phase>compile</phase>
   <goals>
    <goal>compile</goal>
   </goals>
  </execution>
 </executions>
</plugin>

more detail on this approach here

Show
C Divilly added a comment - 16/Mar/10 10:27 AM I used a variation of the above workaround, in my case I needed the outputs from the annotation processing to be packaged in the final jar not just generated for the testing phase. I added the following to my pom:
 
<plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-compiler-plugin</artifactId>
 <version>2.1</version>
 <configuration>
  <source>1.6</source>
  <target>1.6</target>
 </configuration>
 <executions>
  <execution>
   <id>default-compile</id>
   <configuration>
    <compilerArgument>-proc:none</compilerArgument>
    <includes>
     <include>path/to/annotation/processor/**</include>
     <include>path/to/annotation/processor/dependencies/**</include>
    </includes>
   </configuration>
  </execution>
  <execution>
   <id>compile-everything-else</id>
   <phase>compile</phase>
   <goals>
    <goal>compile</goal>
   </goals>
  </execution>
 </executions>
</plugin>
more detail on this approach here
Hide
Permalink
Ramon Buckland added a comment - 17/Mar/11 11:30 AM - edited

I needed to do something similar.

I have a Unit Test which actually runs my Processor by calling the JavaCompiler.

@Test
    public void fullComprehensiveTest() {


       ...
        
        // Get an instance of java compiler
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        // Get a new instance of the standard file manager implementation
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        List<String> options = new ArrayList<String>();
        options.add("-d");
        File outputDir = new File("target", "processor-test");
        outputDir.mkdirs();
        options.add(outputDir.getAbsolutePath());

        options.add("-s");
        options.add(outputDir.getAbsolutePath());

        // Get the list of java file objects
        SrcFilesTestClass srcFiles = new SrcFilesTestClass();

        System.out.println(">> testing: files to run annotation test on (only some have annotations): ");
        for (String f : srcFiles.srcFiles()) {
            System.out.println(f);
        }

        Iterable<? extends JavaFileObject> compilationUnits1 = fileManager.getJavaFileObjects(srcFiles.srcFiles());

        StringWriter output = new StringWriter();
        CompilationTask task = compiler.getTask(output, fileManager, null, options, null, compilationUnits1);

        // Create a list to hold annotation processors
        LinkedList<AbstractProcessor> processors = new LinkedList<AbstractProcessor>();

        // Add an annotation processor to the list
        processors.add(new VannitationOneToOneProcessor());
        processors.add(new VannitationManyToOneProcessor());

        // Set the annotation processor to the compiler task
        task.setProcessors(processors);

        // Perform the compilation task.
        // the compiler will return false for us because the files we are
        // creating won't compile as
        // we don't have the required fields.
        task.call();

        // now some tests .. we will just validate that
        ...

     }

So .. to ensure that the processor does not run in my package from maven, and that I control it (maven via surefire runs it), I -proc:none on the compile test also.

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <executions>
          <execution>
            <id>default-compile</id>
            <configuration>
              <compilerArgument>-proc:none</compilerArgument>
              <source>1.6</source>
              <target>1.6</target>
            </configuration>
          </execution>
          <execution>
            <id>default-testCompile</id>
            <configuration>
              <compilerArgument>-proc:none</compilerArgument>
              <source>1.6</source>
              <target>1.6</target>
            </configuration>
          </execution>
        </executions>
      </plugin>
Show
Ramon Buckland added a comment - 17/Mar/11 11:30 AM - edited I needed to do something similar. I have a Unit Test which actually runs my Processor by calling the JavaCompiler.
@Test
    public void fullComprehensiveTest() {


       ...
        
        // Get an instance of java compiler
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        // Get a new instance of the standard file manager implementation
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        List<String> options = new ArrayList<String>();
        options.add("-d");
        File outputDir = new File("target", "processor-test");
        outputDir.mkdirs();
        options.add(outputDir.getAbsolutePath());

        options.add("-s");
        options.add(outputDir.getAbsolutePath());

        // Get the list of java file objects
        SrcFilesTestClass srcFiles = new SrcFilesTestClass();

        System.out.println(">> testing: files to run annotation test on (only some have annotations): ");
        for (String f : srcFiles.srcFiles()) {
            System.out.println(f);
        }

        Iterable<? extends JavaFileObject> compilationUnits1 = fileManager.getJavaFileObjects(srcFiles.srcFiles());

        StringWriter output = new StringWriter();
        CompilationTask task = compiler.getTask(output, fileManager, null, options, null, compilationUnits1);

        // Create a list to hold annotation processors
        LinkedList<AbstractProcessor> processors = new LinkedList<AbstractProcessor>();

        // Add an annotation processor to the list
        processors.add(new VannitationOneToOneProcessor());
        processors.add(new VannitationManyToOneProcessor());

        // Set the annotation processor to the compiler task
        task.setProcessors(processors);

        // Perform the compilation task.
        // the compiler will return false for us because the files we are
        // creating won't compile as
        // we don't have the required fields.
        task.call();

        // now some tests .. we will just validate that
        ...

     }
So .. to ensure that the processor does not run in my package from maven, and that I control it (maven via surefire runs it), I -proc:none on the compile test also.
<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <executions>
          <execution>
            <id>default-compile</id>
            <configuration>
              <compilerArgument>-proc:none</compilerArgument>
              <source>1.6</source>
              <target>1.6</target>
            </configuration>
          </execution>
          <execution>
            <id>default-testCompile</id>
            <configuration>
              <compilerArgument>-proc:none</compilerArgument>
              <source>1.6</source>
              <target>1.6</target>
            </configuration>
          </execution>
        </executions>
      </plugin>
Hide
Permalink
Kohsuke Kawaguchi added a comment - 06/Jul/11 9:01 PM

The original description of the issue says "when using -source 1.6 or higher" in the end, but that doesn't make sense. The question is if the build is using JDK6 or above to compile, not whether it's producing 1.6 compatible files or 1.5 compatible files. JSR-269 still kicks in with -source 1.5.

Note that the problem is beyond just the maven-compiler-plugin. IDEs are also affected by this — for example when IntelliJ IDEA compiles a subset of source files that are updated, it automatically adds the class file folder to classpath, and you get the same problem.

I wonder if this calls for a change in javac — perhaps it shouldn't look for its own output directory to look for annotation processors. I can't think of a valid use case for doing that.

Show
Kohsuke Kawaguchi added a comment - 06/Jul/11 9:01 PM The original description of the issue says "when using -source 1.6 or higher" in the end, but that doesn't make sense. The question is if the build is using JDK6 or above to compile, not whether it's producing 1.6 compatible files or 1.5 compatible files. JSR-269 still kicks in with -source 1.5. Note that the problem is beyond just the maven-compiler-plugin. IDEs are also affected by this — for example when IntelliJ IDEA compiles a subset of source files that are updated, it automatically adds the class file folder to classpath, and you get the same problem. I wonder if this calls for a change in javac — perhaps it shouldn't look for its own output directory to look for annotation processors. I can't think of a valid use case for doing that.
Hide
Permalink
Jesse Glick added a comment - 07/Jul/11 9:51 AM

Regarding -source 1.5: it is unsafe to pass -processorpath in this case, since the target javac might in fact be from JDK 5 and not recognize this option. (If the compiler plugin went through JSR 199, with javac on the plugin classpath, this would not be an issue.)

Regarding a change in javac's behavior: I would not hold my breath. After all, you passed -classpath target/classes:... so that is where it is looking. It is really the responsibility of the invoker to make sure the processor path is correct.

Show
Jesse Glick added a comment - 07/Jul/11 9:51 AM Regarding -source 1.5: it is unsafe to pass -processorpath in this case, since the target javac might in fact be from JDK 5 and not recognize this option. (If the compiler plugin went through JSR 199, with javac on the plugin classpath, this would not be an issue.) Regarding a change in javac's behavior: I would not hold my breath. After all, you passed -classpath target/classes:... so that is where it is looking. It is really the responsibility of the invoker to make sure the processor path is correct.
Hide
Permalink
Jesse Glick added a comment - 07/Jul/11 11:07 AM

Complete example project working around this problem; for the main sources the processorpath is set to the Maven classpath, so that processors in dependencies can still be used.

For test sources, the default behavior is left alone, which is usually OK since tests would not likely define their own processors; processors from dependencies and main sources are still run over test sources.

Show
Jesse Glick added a comment - 07/Jul/11 11:07 AM Complete example project working around this problem; for the main sources the processorpath is set to the Maven classpath, so that processors in dependencies can still be used. For test sources, the default behavior is left alone, which is usually OK since tests would not likely define their own processors; processors from dependencies and main sources are still run over test sources.
Hide
Permalink
Kohsuke Kawaguchi added a comment - 07/Jul/11 12:41 PM

My workaround is to define a separate Maven module (D) and defines a dummy do-nothing processor of the same fully-qualifled class name. This D module is then added as an optional dependency to my real project (R), so that D won't pollute other projects depending on R.

This has the added benefit of making IDEs happy, but the downside is that the test code won't be subject to the annotation processing (which is OK in my case, but may not be OK for others.)

Show
Kohsuke Kawaguchi added a comment - 07/Jul/11 12:41 PM My workaround is to define a separate Maven module (D) and defines a dummy do-nothing processor of the same fully-qualifled class name. This D module is then added as an optional dependency to my real project (R), so that D won't pollute other projects depending on R. This has the added benefit of making IDEs happy, but the downside is that the test code won't be subject to the annotation processing (which is OK in my case, but may not be OK for others.)

People

  • Assignee:
    Unassigned
    Reporter:
    Jesse Glick
Vote (11)
Watch (14)

Dates

  • Created:
    13/Apr/09 9:42 PM
    Updated:
    Yesterday 2:56 PM
  • Atlassian JIRA (v5.0.4#731-sha1:3aa7374)
  • Report a problem
  • Powered by a free Atlassian JIRA open source license for Codehaus. Try JIRA - bug tracking software for your team.