-
Notifications
You must be signed in to change notification settings - Fork 0
Implementation changes
This page lists some noticeable implementation changes.
The major change is the replacement of Plexus compiler API by the standard javax.tools.JavaCompiler API introduced in Java 6.
This changes required an almost full rewrite of the compiler plugin.
Other Plexus dependencies such as StringUtils could also be removed because they now have replacements in the standard Java API.
Dependencies to org.objectweb.asm have been removed.
Those dependencies were used for rewriting some class files in two circumstances:
- For generating
package-info.classfiles that were omitted by the Java compiler because empty. - For patching
module-info.classfile for the MCOMPILER-542 issue.
The first case was moot because the package-info.class files were generated
as a workaround for the way that Maven incremental compilation worked.
The new plugin no longer generate those classes by default
(i.e., the <createMissingPackageInfoClass> default value has been changed to false).
If empty package-info.class files are nevertheless desired,
they are generated by the Java compiler itself with the -Xpkginfo:always option.
If that extra option is not supported, then a warning is logged and no option is added.
The second case is for erasing an information which was not always the same between different builds. That patch was needed only when all the following conditions were true:
- The project is built with a Java compiler older than Java 22.
- The project has
module-info.javafiles. - Reproducible build is desired.
For reproducible builds of modular projects, the recommended fix is to compile with Java 22 or later.
Note that it does not means that the project needs Java 22 at runtime.
Use the <release> option for targeting an older release if desired.
If class modifications are needed in future versions of the Maven compiler plugin, the plan is to use the standard Class-File API.
The previous plugin tried to be clever by intercepting and modifying the values of user-supplied --patch-module compiler arguments,
by adding --path-module and --add-reads <module>=ALL-UNNAMED arguments on its own initiative, etc.
The result was saved in a META-INF/jpms.args file added to the JAR file.
Above-cited heuristics have been removed from the Maven 4 plugin,
as Maven 4 aims to give more configuration control to the users.
For example, developers are encouraged to set a dependency type to modular-jar or classpath-jar instead of jar.
Some heuristics have been kept for compatibility with current widespread practice,
in particular when the dependency type is only jar.
But most heuristics should not be applied when developers use the most explicit ways to configure Maven.
The Plexus scranners used for include/exclude filters have been replaced by java.nio.file.PathMatcher.
The set of allowed syntax contains at least "glob" and "regex".
See FileSystem.getPathMatcher(String) Javadoc for a description of the "glob" syntax.
If no syntax is specified, then the default syntax is "glob" with the following modification:
- Unless escaped by
\, all occurrences of the/character are replaced by the platform-specific separator.
The list of files to process is built by applying the path matcher on each regular (non directory) files. The walk in file trees has the following characteristics:
- Symbolic links are followed.
- Hidden files and hidden directories are ignored.
The code for detecting which files to recompile has been rewritten. The previous code had an issue with list of files generated and compared in one case as absolute files, and in other case as relative files. Consequently, the plugin always considered that all files changed, which may explain the performance issue reported in MCOMPILER-209.
The new implementation saves the list of source files, together with their last modification times, in a binary file with the {@code .cache} extension instead of a text file with the {@code .lst} extension. This custom binary encoding is more compact than the previous text files (because of less redundancies) and has more information. The incremental compilation behavior is modified as below:
- Changes in compiler options cause a recompilation of all files. Those changes are detected on a "best effort" basis only.
- By default, addition of new source files does not cause the recompilation of all files, because this is usually not necessary.
- The modification times of source files are compared with the modification times of the same source files during the previous build (saved in above-cited binary file), instead of compared with the modification times of the class files.
The last point avoids the problem that the <createMissingPackageInfoClass> parameter tried to solve.
Because the new algorithm does not depend on .class timestamps, there is no need to force their creation.
If the <useIncrementalCompilation> parameter is set to false, the plugin does not use the binary cache file
and compare modification times of source files with modification times of class files.
This approach reproduces the previous behavior.
When checking if a dependency changed, the new implementation compares the JAR timestamps against the start time of
the previous build saved in the binary file instead of comparing against the value given by session.getStartTime().
The reason for this change is as below:
- Consider a project with 3 modules named A, B and C where modules B and C depend on module A.
- Module A is modified and
mvn installis executed on the command-line. -
A.jarget a modification time which is after the build start time. Module B and C detect that fact and perform a "clean and build all". This is the current behavior of Maven 3 incremental compilation.
But let assume that the compilation failed in module B because of the change in A.
The developer fixes the compilarion error in B, then executes mvn install a second time:
- Compilation of A is skipped because nothing changed. Consequently, the timestamp of
A.jaris unchanged. - With the Maven 3 implementation, module C will not detect that module A changed because the modification time
of
A.jaris before the second build start time.
By using the timestamp saved in the binary file instead, the new algorithm will detect that A.jar has been
updated since the last build of C.
The way to handle compiler options has been modified.
Previously, the Maven plugin validated some options before to pass them to the compiler.
For example, if the <debuglevel> value contains anything else than lines, vars or source, the plugin raised an error.
The intend was to provide more informative message.
But in the javax.tools.JavaCompiler interface, there is an API telling us whether an option is supported.
Therefor, the new plugin version first asks to the compiler whether the option is supported,
and only if the compiler said "no", the validation is performed for producing the error message.
Consequently, if the compiler claims to support the -g:foo option,
then the plugin will no longer block the use of the foo value in <debuglevel> even if the plugin does not know that value.
The plugin prints a replacement proposal when a deprecated option is used and a replacement exists.
The proposal is shown as an XML snippet for POM configuration.
The Maven compiler plugin version shown in the snippet is fetched from META-INF/MANIFEST.MF
instead of META-INF/maven/org.apache.maven.plugins/maven-compiler-plugin/pom.properties.