Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
3.8.1
-
None
Description
When one invokes mvn clean compile test, the default-compile execution runs twice.
This is because org.apache.maven.lifecycle.internal.DefaultLifecycleExecutionPlanCalculator#calculateMojoExecutions() (which hasn't changed in 6 years) collects the list of mojo executions in a list, and for each phase on the command-line it adds the mojo executions for that phase and its dependencies, even if some executions already exist in the list. E.g.
mojoExecutions = {java.util.ArrayList} size = 8 0 = {org.apache.maven.plugin.MojoExecution} "org.apache.maven.plugins:maven-clean-plugin:2.5:clean {execution: default-clean}" 1 = {org.apache.maven.plugin.MojoExecution} "org.apache.maven.plugins:maven-resources-plugin:2.6:resources {execution: default-resources}" 2 = {org.apache.maven.plugin.MojoExecution} "org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile {execution: default-compile}" 3 = {org.apache.maven.plugin.MojoExecution} "org.apache.maven.plugins:maven-resources-plugin:2.6:resources {execution: default-resources}" 4 = {org.apache.maven.plugin.MojoExecution} "org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile {execution: default-compile}" 5 = {org.apache.maven.plugin.MojoExecution} "org.apache.maven.plugins:maven-resources-plugin:2.6:testResources {execution: default-testResources}" 6 = {org.apache.maven.plugin.MojoExecution} "org.apache.maven.plugins:maven-compiler-plugin:3.8.1:testCompile {execution: default-testCompile}" 7 = {org.apache.maven.plugin.MojoExecution} "org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test {execution: default-test}"
The second execution of maven-compiler-plugin version 3.8.0 used to check that the sources haven't changed and do nothing. But that check was wrong, because it didn't check any class files, and MCOMPILER-349 replaced it with another check that is also wrong, because it (org.apache.maven.plugin.compiler.AbstractCompilerMojo#isDependencyChanged()) checks for changes since the start of the build in all the classes on the module's classpath, including target/classes.
This means the second execution of maven-compiler-plugin verison 3.8.1 deletes all the .class files from target/classes. It does not delete the files generated by annotation processors in target/generated-sources/annotations, but it also doesn't add them to the Javac sources parameter because org.apache.maven.plugin.compiler.AbstractCompilerMojo#getCompileSources() ignores the generated sources directory:
compileSourceRoots = {java.util.ArrayList} size = 3 0 = "/home/dan/Work/maven-compiler-test/src/main/java" 1 = "/home/dan/Work/maven-compiler-test/target/generated-sources/annotations" 2 = "/home/dan/Work/maven-compiler-test/target/generated-sources/annotations"
sources = {java.util.HashSet} size = 2 0 = {java.io.File} "/home/dan/Work/maven-compiler-test/src/main/java/ProtoStreamContextInitializer.java" 1 = {java.io.File} "/home/dan/Work/maven-compiler-test/src/main/java/A.java"
We have an annotation processor that tries to be smart and doesn't overwrite its generated Java source files if they already exists and they have the correct checksum. But because the generated file isn't written, it is not added to Javac's sources, and Javac does not compile it to a .class file. I haven't tested it, but I believe the same problem appears if the source files were generated e.g. by another Maven plugin or by an Ant script in the generate-sources phase.
I believe the maven-core behaviour won't change any time soon (and in fact some users may depend on the duplicate executions). Instead org.apache.maven.plugin.compiler.AbstractCompilerMojo#isDependencyChanged() needs to be fixed to avoid recompilation when runs the second time.
Attachments
Issue Links
- is broken by
-
MCOMPILER-349 maven-compiler-plugin does not recompile a module if a dependency module has been updated & recompiled
- Closed
- is fixed by
-
MCOMPILER-525 Incremental recompile incorrect detection of dependency change
- Closed
- is related to
-
MCOMPILER-502 checking dependency time from reactor lead to re compiling while it's not needed
- Open