Skip to content
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

[MJAVADOC-620] Do not ignore JARs w/o module info when building classpath #35

Merged
merged 3 commits into from Nov 29, 2019

Conversation

fwienber
Copy link
Contributor

@fwienber fwienber commented Nov 19, 2019

When locationManager.resolvePaths() processes JARs that do not define a module name, module-name-guessing is triggered. The last resort is to use the JAR's file name to derive a module name. The heuristic is to determine where a version number starts, for which the regex is used: "-(\\d+(\\.|$))"
See JavaDoc of ModuleFinder.of().

For the remaining prefix, all non-alphanumeric characters (this includes dashes) are replaced by dots. When splitting at the dots, every part must be a legal Java identifier.

Now, when a Maven JAR uses the version 1-SNAPSHOT, the JAR is named <artifactId>-1-SNAPSHOT.jar, so the version suffix is not recognized by the heuristic (the number is neither followed by a dot, nor is this the end of the file name without extension), so trying to guess the module name eventually fails with an error (FindException, "1" is not a valid Java identifier).

There are other situations in which trying to derive module information from a JAR leads to errors, e.g. when the top-level package is used ("unnamed package not allowed in module").

The code in maven-javadoc-plugin checks all returned classpath elements whether they contain module information. Now, in the result returned by locationManager.resolvePaths(), all JARs for that no module information could be derived are not contained in getClasspathElements(), but only in getPathExceptions(). When a JAR path is mapped to a FindException, it does not make sense to look for module information, but it does make sense to still add these JARs to the classpath.
Ignoring them, as before, is what breaks backwards-compatibility with non-module JARs and causes bug MJAVADOC-620.

The fix is to add all such JARs without module information to the JavaDoc classpath.

Filled-in Template:

Following this checklist to help us incorporate your
contribution quickly and easily:

  • Make sure there is a JIRA issue filed
    for the change (usually before you start working on it). Trivial changes like typos do not
    require a JIRA issue. Your pull request should address just this issue, without
    pulling in other changes. --> MJAVADOC-620
  • Each commit in the pull request should have a meaningful subject line and body.
  • Format the pull request title like [MJAVADOC-XXX] - Fixes bug in ApproximateQuantiles,
    where you replace MJAVADOC-XXX with the appropriate JIRA issue. Best practice
    is to use the JIRA issue title in the pull request title and in the first line of the
    commit message.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Run mvn clean verify to make sure basic checks pass. A more thorough check will
    be performed on your pull request automatically.

If your pull request is about ~20 lines of code you don't need to sign an
Individual Contributor License Agreement if you are unsure
please ask on the developers list.

To make clear that you license your contribution under
the Apache License Version 2.0, January 2004
you have to acknowledge this by using the following check-box.

…path

When locationManager.resolvePaths() processes JARs that do not define a
module name, module-name-guessing is triggered. The last resort is to
use the JAR's file name to derive a module name. The heuristic is to
determine where a version number starts, for which the regex
is used: "-(\\d+(\\.|$))"
See https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/module/ModuleFinder.html#of(java.nio.file.Path...)

For the remaining prefix, all non-alphanumeric characters (this
includes dashes) are replaced by dots. When splitting at the dots,
every part must be a legal Java identifier.

Now, when a Maven JAR uses the version "1-SNAPSHOT", the JAR is named
<artifactId>-1-SNAPSHOT.jar, so the version suffix is not recognized by
the heuristic (the number is neither followed by a dot, nor is this the
end of the file name without extension), so trying to guess the module
name eventually fails with an error (FindException, "1" is not a valid
Java identifier).

There are other situations in which trying to derive module information
from a JAR leads to errors, e.g. when the top-level package is
used ("unnamed package not allowed in module").

The code in maven-javadoc-plugin checks all returned classpath elements
whether they contain module information. Now, in the result returned by
locationManager.resolvePaths(), all JARs for that no module information
could be derived are not contained in getClasspathElements(), but only
in getPathExceptions(). When a JAR path is mapped to a FindException,
it does not make sense to look for module information, but it *does*
make sense to still add these JARs to the classpath.
Ignoring them, as before, is what breaks backwards-compatibility with
non-module JARs and causes bug MJAVADOC-620.
The fix is to add all such JARs without module information to the
JavaDoc classpath.
@rfscholte
Copy link
Contributor

Looks like you removed the PR-template, please restore. And this issue probably deserves an integration test, the template has the instructions for it.

@fwienber
Copy link
Contributor Author

Sorry, it did not occur to me the template was meant to keep. I followed the instructions step by step and only kept the license declaration. If you really think it makes sense that every single PR contains the instructions how to author PRs, I can restore the template text.
Granted, I didn't write an integration test. The problem is that, as in the "minimal example" in the ticket, you need two independent Maven projects, so that the first project is referenced by the second one as an external JAR, not as part of the Reactor. I'll try to come up with something.

The first case in which the module info retrieval fails is a JAR
containing a class in the top-level package. This is the originally
reported case in the JIRA ticket MJAVADOC-620.
The FindException has a root cause that says that the usage of
top-level packages is not allowed in modules.

For the test, it is important to build the JAR in a Maven module that
is *not* part of the Reactor. Otherwise, javadoc:aggregate would use
the sources of class Test directly and the bug would not occur.
This has been achieved by *not* adding the test project
maven-MJAVADOC620-jar as a <module> to the main project. Instead,
in invoker.properties, the first project is built using option -f.

Note: The artifactId may not be maven-MJAVADOC-620-jar (with a dash
before the issue number), because then, the module info retrieval
fails for another reason, namely not being able to derive a module
name. This is tested by an upcoming second integration test.

Without the fix, maven-MJAVADOC620-jar-1.0-SNAPSHOT.jar is not added
to the classpath and building the JavaDoc fails, because class Test
is not found.
With the fix, maven-MJAVADOC620-jar-1.0-SNAPSHOT.jar is added
to the classpath and building the JavaDoc succeeds.
The second case in which the module info retrieval fails is a JAR
with a file name that contains a number *not* followed by a dot.
This is the case we experienced, because we often use 1-SNAPSHOT as
the working version, resulting in a JAR file name like
"foo-1-SNAPSHOT.jar".
The FindException has a root cause that says that the module name
derived from the file name, "foo.1.SNAPSHOT", is invalid because "1"
is not a valid Java identifier.

Compared to the first integration test, the version number of the
test project has been changed from "1.0" to just "1".
To test one failure cause at a time, the test class Test has been
moved from the top-level package into package "somepackage".

Without the fix, maven-MJAVADOC620-jar-1-SNAPSHOT.jar is not added
to the classpath and building the JavaDoc fails, because class Test
is not found.
With the fix, maven-MJAVADOC620-jar-1-SNAPSHOT.jar is added
to the classpath and building the JavaDoc succeeds.
@fwienber
Copy link
Contributor Author

Here you go: Not one, but two integration tests that test both scenarios described in the JIRA ticket, with extensive commit messages.
Feedback welcome!

@fwienber
Copy link
Contributor Author

Anything more you need? Any questions?

@rfscholte
Copy link
Contributor

I just need time to review

@olamy
Copy link
Member

olamy commented Nov 25, 2019

Sounds good. I need to test this but I did something similar in a branch see 15419fd

Copy link
Member

@ctubbsii ctubbsii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what's going on with the integration test stuff, but the actual code change is what I would have come up with to fix MJAVADOC-609, which might be the same issue as MJAVADOC-620. So, I think this looks good and should be merged (assuming tests pass).

@fwienber
Copy link
Contributor Author

Thanks everybody!
I tried to explain the two integration test scenarios as good as I could in the commit messages of 769b73f5 and efd0e478.
Concerning "assuming tests pass": I ran all tests (unit tests and integration tests) locally, and they all passed (and do not pass if without the fix). Not sure if there is automated QA that runs all tests, but the PR description template sound like that.

@olamy olamy merged commit 2649d40 into apache:master Nov 29, 2019
@ctubbsii
Copy link
Member

ctubbsii commented Mar 6, 2020

Which version of maven-javadoc-plugin contains this fix?

@olamy
Copy link
Member

olamy commented Mar 7, 2020

@ctubbsii no release yet I hope soon in the coming weeks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants