On Fri Feb 20 2015 at 21:11:14 Sébastien Lesaint <
sebastien.lesa...@gmail.com> wrote:

> Hello,
>
> I have been into annotation processing a lot for the past year and a half
> and I am now going back to the basics so that I can share knowledge I
> gathered.
>
> Doing so, I stumbled upon, again, a problem I had meet very early, for
> which I had googled the solution, but this time I went deeper to figure out
> what was really wrong.
>
> # the symptoms
>
> When writing an annotation processor and creating the associated
> service-discovery file
> "`META-INF/services/javax.annotation.processing.Processor" in a Maven
> module, one needs to disable annotation processing completely (using
> the <proc>none</proc> configuration option of the maven-compiler-plugin)
> otherwise the module compilation succeeds but not a single .class file is
> created.
>
> # how I investigated
>
> I compiled the module with the -X option, extracted the javac command line
> and ran it by hand. I got the following compilation error:
> error: Bad service configuration file, or exception thrown while
> constructing Processor object: javax.annotation.processing.Processor:
> Provider com.foo.BarProcessor not found
>
> The thing is, the com.foo.BarProcessor is the very processor I am compiling
> (and the single .java file of the module).
>
> # what I found
>
> I went through the maven logs, spent some time thinking about it and
> believe that we are facing one, maybe two bugs in the
> maven-compiler-plugin:
>
> 1. Maven copies resources from the "src/main/resources" directory to the
> "target/classes" directory
> 2. the maven-compiler-plugin builds up a javac command line that specifies
> the "target/classes" directory as a member on the classpath with the
> argument "-classpath" (is that a bug ? there may be a good reason to do so
> but in a basic jar module setup I can see any)
>

This is because of m-compiler-p's attempt at incremental compilation. It
looks at all source files and if one doesn't have a corresponding *.class
file or is newer then it adds it to the list of source files to recompile.
Because those will likely reference other classes that might not have
changed, target/classes is included in the classpath so that the
already-compiled classes can be found.

That said, incremental compilation is (was) kind-of broken, as it doesn't
track class dependencies and won't recompile those classes that reference
the classes that have changed. See
https://cwiki.apache.org/confluence/display/MAVEN/Incremental+Builds for an
example.
If you ask me, m-compiler-p should just check whether "something" needs to
be recompiled (which in itself is already error-prone, for many reasons
[1]) and recompile everything.
Actually, m-compiler-p 3.1+ should apparently behave that way by deleting
all *.class files it had created in a previous run (unless you set
useIncrementalCompilation=false [2]), so it shouldn't need target/classes
to be part of the classpath, at least for this use-case of incremental
compilation, but still includes it anyway.
Takari has a new plugin (and lifecycle) that apparently does truly
incremental compilation [3], by tracking class dependencies (when using JDT
rather than javac). It'd still fail your use-case though IIUC, if it
supported annotation processing through JDT (I haven't looked at how it
handles incremental builds with javac).

The other reason for target/classes to be in the classpath is so that
annotation processors could find resources (let's not debate here whether
it's a good idea or not). m-compiler-p developers can't seem to agree on
what should be done: should m-compiler-p use -sourcepath sometimes [4] or
always [5] ? Should target/classes be included in the sourcepath [6] ?

[1] http://blog.ltgt.net/maven-is-broken-by-design/ (note: things have
changed a bit since I wrote this; e.g. incremental build in m-compiler-p
3.1+, the Takari lifecycle, etc.)
[2]
https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#useIncrementalCompilation
[3] http://takari.io/2014/10/16/incremental-compilation.html
[4] https://jira.codehaus.org/browse/MCOMPILER-26,
https://jira.codehaus.org/browse/MCOMPILER-174
[5] https://jira.codehaus.org/browse/MCOMPILER-98
[6] https://jira.codehaus.org/browse/MCOMPILER-122

3. when run, javac finds a
> "META-INF/services/javax.annotation.processing.Processor" file in the
> classpath and looks for the specified processor "com.foo.BarProcessor "
> 4. obviously, this processor can not be found, javac reports an error and
> stops the compilation before it even started compiling anything (ence not a
> single .class file in the target directory)
> 5. the error ("error: Bad service configuration file, or exception thrown
> while constructing Processor object: javax.annotation.processing.
> Processor:
> Provider com.foo.BarProcessorr not found") is ignored by the
> maven-compiler-plugin that considers the compilation successful and the
> maven build goes on (this is our big bug)
>
> # bonus
>
> Please note that this has pernicious side effects.
>
> Since the build is successful, the jar which is supposed to contain the
> processor is created but only with the resources which means that it
> contains the "META-INF/services/javax.annotation.processing.Processor"
> file.
>
> Now, any module or project which has this jar file as a dependency will
> produce 0 .class file. Their compilation classpath is "contaminated" with a
> "META-INF/services/javax.annotation.processing.Processor which references
> an non existent processor. Javac will therefor fail with the "Bad service
> configuration file" and produces no .class file.
>
> # affected versions
>
> I tested this with Maven 3.1.1 & 3.2.5, maven-compiler-plugin 2.5, 3.1 and
> 3.2 and Oracle JDK 6, 7 & 8 on a ubuntu 64 bits machine. But, according to
> the various posts, stackoverflow entries, etc. all around the web which
> provide the <proc>none</proc> solution, it occurs on other setups.
>
> # conclusion
>
> I initially though I would file a bug in the maven-compiler-plugin JIRA but
> it is unclear how I can create an account.
>

It's a known bug, opened for YEARS:
https://jira.codehaus.org/browse/MCOMPILER-97

Note that a workaround might be to generate the
META-INF/services/javax.annotation.processor.Processor file using
annotation processing ;-) using either
com.google.auto.service:auto-service,
org.kohsuke.metainf-services:metainf-services, or org.immutables:metainf
(or anything similar)

Reply via email to