Skip to content

Refactoring and support of <release> and <module> elements #320

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

desruisseaux
Copy link
Contributor

This is a refactoring of the compiler plugin which separates the MOJO, which contains the configuration, from the code that configures and executes the javax.tools.JavaCompiler. This refactoring splits one big class in two smaller classes for the compilation of main, and similarly for the compilation of test. This refactoring facilitates the development described in the next paragraph.

This pull request implements the support of the <include>, <exclude>, <release> and <module> elements of <source>. For now, the release and module elements can be used separately but not yet together.

This pull request also contains opportunistic bug fixes in the incremental compilation. There is one change visible to users compared to 4.0.0-beta-2: in the incrementalCompilation option, the additions enumeration value has been renamed rebuild-on-add for clarity and consistency with rebuild-on-change. These options did not existed in Maven 3.

…as testing another plugin than this project.

It was testing `pw.krejci:multi-release-jar-maven-plugin`, which fails with `NoSuchMethodError` with Maven 4-RC3.
That external project may need to be updated for Maven 4.
Update for changes in the `Project` interface.
The fix leverages the new `SourceRoot` element.
…of the `pom.xml` file.

With this commit, the include/exclude filters declared in `<source>` are combined with the
include/exclude filters declared in the puglin configuration. The module name and release
information are also stored, but only partially supported yet.
…d body in a separated class.

The intend is to reduce the complexity by splitting one big method into smaller methods.
It may also help external applications (e.g. IDE) to use `ToolExecutor` in their environment.
…ment.

Initial support of modular project (JPMS) by using the `<module>` element.
Currently support only one or the other, not yet both in same time.

Contains fixes for incremental build:
* The `package-info.java` source files may produce no output.
* Provide an option to rebuild everything as soon as one file changed.

The `additions` aspect has been renamed `rebuild-on-add` for clarity and
for consistency with `rebuild-on-change` added in the last above point.
…c link.

This hack is needed only when we want to simulate the Maven 3 behaviour for compatibility reasons.

This hack is fragile to the case where a module name is a single name (without dot)
and that name is the same as the package name. This ambiguity breaks two tests.
For allowing the tests to pass, this commit renames "foo" module as "foo.bar".
- Multi-release project defined with the new `<source>` element.
- Modular project defined with the new `<source>` element.
@desruisseaux
Copy link
Contributor Author

Hello @gnodet. I'm not sure how to proceed with this pull request, because it is massive and would require a lot of work for reviewers. This PR is hard to split in smaller pull requests focussing on different features. The best I could do is to try to organize the commits.

…r and more readable output.

Give a hint when a change of directory is needed for using the relative paths.
@desruisseaux
Copy link
Contributor Author

desruisseaux commented Apr 14, 2025

Fixes #326, #160 and (under some conditions) #27.

@desruisseaux
Copy link
Contributor Author

Note that this pull request does not contain the module-info-patch debated on the mailing list, so it should be less controversial. Thos module-info-pach proposal is in a separated branch.

@rmannibucau
Copy link

@desruisseaux is it worth adding an integration test with an annotation processor to ensure that if any file changed the module is totally cleaned as before and rebuilt? (ie there is no "diff" logic in the compilation pipeline). Similarly the template plugin (https://www.mojohaus.org/templating-maven-plugin/) can need something similar so it impacts the templated files if any other changed (case a date is in the template).

@desruisseaux
Copy link
Contributor Author

Sure, thanks for pointing a hole. Just to clarify, there is already an integration test that compiles the project, change a file, then recompiles the project, but not using an annotation processor (it uses Groovy if I remember right). Is it the kind of test you had in mind?

@rmannibucau
Copy link

@desruisseaux yes, the main diff is that without annotation processors (or alike) you can just rerun javac and it does a kind of incremental compilation (idea uses it a lot) whereas with an annotation processor if you do it you break the compilation unit and some annotation processor needs the global unit view (to generate an index for ex). So current (maven 3) behavior was clean then recompile if there is any diff. I'm just trying to ensure we do not loose that behavior for annot procs.

@desruisseaux
Copy link
Contributor Author

In the new compiler plugin, the incremental compilation is controlled by an incrementalCompilation parameter which is a comma-separated string of values. The default values are options,dependencies,sources, meaning to recompile everything if the compiler options or the dependencies changed, or otherwise recompile only the sources that changed. So the proposal would be to add rebuild-on-add and rebuild-on-change to the default values if an annotation processor is present? (those values already exist, the only change would be their automatic addition to the default values).

@rmannibucau
Copy link

@desruisseaux I guess so (but have to admit I have no idea yet why it is made so complex for something so simple, either a change invalidates the compilation or it doesn't, no?)

@desruisseaux
Copy link
Contributor Author

The problem is that neither the old or the new implementation can determine reliably what needs to be recompiled as a result of a change. For a true determination, we would need to build a graph of relationships between all *.class files. Since we don't do that (yet), we provide options for different approximations. Which approximation is the best compromise between speed and safety depends on the developer's habits (e.g., do they run mvn clean themselves when they know that it will be necessary?). Hence the choice left to the developers.

Another reason is historical: the old implementation already provided a configuration option in the form of a simple boolean value. But neither the behaviour of the true or false value was really satisfying, which caused the complains that we received from users against incremental compilation. Therefore, we needed a mechanism capable to reproduce both the behaviour of the old boolean flag and a more satisfying behaviour.

@rmannibucau
Copy link

Which approximation is the best compromise between speed and safety depends on the developer's habits (e.g., do they run mvn clean themselves when they know that it will be necessary?). Hence the choice left to the developers.

Hmm no, on that part the only valuable default is the safe one, heuristics (for speed) are ok but not as defaults and ultimately shouldn't be used in the xml (except in a profile) as a good practise IMHO.

we would need to build a graph of relationships between all *.class files

technically this wouldn't work since you would need to know an annotation processor needs all classes (this is even outside the .class of the project even the .class of the processor doesn't even have a ref on others so the graph doesn't work). Several build systems did enable incremental annotation processors and/or toggles to configure that - looks like your new option at some extent.

That said it doesn't change that the default should clear by default if any doubt and never assume it can do an incremental compilation, as a record idea just fixed it partially in a very recent release and it was really blocking the development and a hidden gem so hope maven doesnt reach that state for end users and keeps a safe default which is optimizable with your option explicitly if desired but not the opposite probably.

So a good default would more look like: options,dependencies,sources,any-processor with any-processor being a simple "if there is an annotation processor then clean and recompile without doing a diff nor managing incremental state" (this last part got proven slower than the recompilation on some project when the option got introduced so let's skip it when we know we do not need it)

hope it makes sense

@desruisseaux
Copy link
Contributor Author

Applied the above-proposed default (rebuild everything when an annotation processor is present) in commit c7535b5.

@desruisseaux
Copy link
Contributor Author

This pull request now fixes #308, #319, #326, #327, #193 (in different places), #160 and (under some conditions) #27.

…ess (forked compiler).

Avoid too verbatim verifications of locale-sensitive compiler messages.
apache#327
…ameter if an annotation processor is present.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants