jsoup icon indicating copy to clipboard operation
jsoup copied to clipboard

Provide module-info.java for Java9+ users

Open cowwoc opened this issue 3 years ago • 13 comments

I know you already provide an Automatic-Module-Name for Java9+ users but we would be better off with a multi-release JAR that exports a full-fledged module-info.java because when using requires transitive org.jsoup the compiler complains (warns) against exporting automatic modules.

Publishing a MultiRelease JAR using Maven should be relatively easy. See multiReleaseOutput at https://www.baeldung.com/maven-multi-release-jars

Hit me up if you run into any problems and I'll take a look.

cowwoc avatar Dec 19 '20 18:12 cowwoc

Hi @cowwoc - I gave this a try, but can't get it to work. Animal Sniffer is failing when it tests (either for Java 1.8 or for Android 10 signature -- the exception doesn't specify which signature is failing on which class.

Have pushed a PR - #1470. If you have any ideas I'd love to hear them. I flailed around in Maven trying to upgrade dependencies and trying to find similar issues but could not. I can't find any projects that have a multi release jar and are using Animal Sniffer, if we could find a reference I think that would probably solve the issue.

[ERROR] Failed to execute goal org.codehaus.mojo:animal-sniffer-maven-plugin:1.19:check (compile-java-8) on project jsoup: Execution compile-java-8 of goal org.codehaus.mojo:animal-sniffer-maven-plugin:1.19:check failed: This feature
requires ASM6 -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.codehaus.mojo:animal-sniffer-maven-plugin:1.19:check (compile-java-8) on project jsoup: Execution compile-java-8 of goal org.codehaus.mojo:animal-sniff
er-maven-plugin:1.19:check failed: This feature requires ASM6
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:215)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:567)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
Caused by: org.apache.maven.plugin.PluginExecutionException: Execution compile-java-8 of goal org.codehaus.mojo:animal-sniffer-maven-plugin:1.19:check failed: This feature requires ASM6
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:148)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:567)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
Caused by: java.lang.UnsupportedOperationException: This feature requires ASM6
    at org.objectweb.asm.ClassVisitor.visitModule (ClassVisitor.java:137)
    at org.objectweb.asm.ClassReader.readModuleAttributes (ClassReader.java:754)
    at org.objectweb.asm.ClassReader.accept (ClassReader.java:553)
    at org.objectweb.asm.ClassReader.accept (ClassReader.java:401)
    at org.codehaus.mojo.animal_sniffer.ClassListBuilder.process (ClassListBuilder.java:70)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.processClassFile (ClassFileVisitor.java:197)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.process (ClassFileVisitor.java:116)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.process (ClassFileVisitor.java:96)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.processDirectory (ClassFileVisitor.java:134)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.process (ClassFileVisitor.java:112)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.process (ClassFileVisitor.java:96)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.processDirectory (ClassFileVisitor.java:134)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.process (ClassFileVisitor.java:112)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.process (ClassFileVisitor.java:96)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.processDirectory (ClassFileVisitor.java:134)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.process (ClassFileVisitor.java:112)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.process (ClassFileVisitor.java:96)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.processDirectory (ClassFileVisitor.java:134)
    at org.codehaus.mojo.animal_sniffer.ClassFileVisitor.process (ClassFileVisitor.java:112)
    at org.codehaus.mojo.animal_sniffer.maven.CheckSignatureMojo.apply (CheckSignatureMojo.java:366)
    at org.codehaus.mojo.animal_sniffer.maven.CheckSignatureMojo.buildPackageList (CheckSignatureMojo.java:359)
    at org.codehaus.mojo.animal_sniffer.maven.CheckSignatureMojo.execute (CheckSignatureMojo.java:251)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:567)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
[ERROR]
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException

jhy avatar Dec 31 '20 07:12 jhy

This issue is fixed by https://github.com/mojohaus/animal-sniffer/pull/91 which is in master but has not yet been released.

cowwoc avatar Dec 31 '20 17:12 cowwoc

Is there a way to get a version of Jsoup that works with java 9+?

I have been searching but have not found any instructions.

jjanderson5 avatar Jan 23 '21 22:01 jjanderson5

@jjanderson5 this packaging fix doesn't impact jsoup's compatibility with Java 9+ (which it does support). Please follow up on #1477.

jhy avatar Jan 27 '21 09:01 jhy

This might be a good use case for using moditect to generate the module-info.java.

rgoers avatar Jul 26 '21 23:07 rgoers

@jhy FYI, the latest version of animal-sniffer now contains the required Java 9 fix. Can you please retry with this version?

cowwoc avatar Aug 08 '21 15:08 cowwoc

Thanks, yes I will have another go

jhy avatar Aug 11 '21 12:08 jhy

I took another pass at this and got stuck with all the Surefire integration tests failing, despite adding a module-info.java for the tests. (And despite that it doesn't seem required, given that the regular Junit tests still pass).

Does anyone have an example existing library I can use as a reference that uses Maven and Surefire / Integration tests?

jhy avatar Sep 13 '21 06:09 jhy

I've done extensive work on this with Log4j 2. You don't say what the problem is but in general:

  1. The unit tests must be in the same package space as the main source. The module-info.java more or less extends the base module-info.
  2. If you create test helper classes that are used by other modules then they must not overlap the package space of the main module and will need their own module-info.java.
  3. In the case Log4j 2 has where it creates a test jar the Maven team recommends that the test jar be created in a separate Maven module which will cause it to be named something like log4j-core-tests-2.xx.0.jar instead of log4j-core-2.xx.0-tests.jar,
  4. Doing item 3 implies that the log4j core unit tests would have to be test classes in the log4j-core-tests module.
  5. As you might imagine from the above, it would be recommended that integration tests be in their own Maven module such as log4j-core-its. Needless to say, this requires the packages in this module do not overlap with the log4j-core packages.

As you can tell, JPMS has seriously complicated builds.Right now the master branch of Log4j 2 is not yet following the advice above and has the test jar and unit tests all in the same module as the main source. Needless to say this causes quite a mess that an IDE won't understand as it requires the compiler plugin be invoked several times using odd lifecycle phases.

I should also point out that there is a bug in the compiler where if you are compiling with JPMS and you have a package like com.acme.book and you have a class named com.acme.Book the compile will fail on MacOS. This bug is fixed in a later version of Java - off the top of my head I can't recall if it is 15 or 16.

rgoers avatar Sep 13 '21 07:09 rgoers

@rgoers thank you, that's very helpful!

jhy avatar Sep 13 '21 10:09 jhy

@jhy My understanding is that you need to decide whether your tests are doing blackbox or whitebox testing. Once you figured that out, you have 3 options:

  1. Whitebox testing: Place tests and production code in the same package and run tests on the classpath (no module-info.java).
  2. Blackbox testing: Place tests in a different package than production code and run tests on the modulepath.
  3. Whitebox testing on the modulepath: Place tests in a different package than production code and use the SharedSecrets mechanism (https://stackoverflow.com/q/46722452/14731) to access production code.

Reference: discussion with Surefire authors at https://issues.apache.org/jira/browse/SUREFIRE-1733?focusedCommentId=17127382&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-17127382

cowwoc avatar Sep 13 '21 13:09 cowwoc

It's about a half year passed, any progress?

Meodinger avatar Apr 01 '22 11:04 Meodinger

I've created a pull request (#1744) to make Jsoup a multi-release module.

Meodinger avatar Apr 19 '22 08:04 Meodinger

any chance of getting that PR rebased and merged in?

SingingBush avatar Oct 17 '23 18:10 SingingBush

Thanks all - I have implemented this in #2025.

It would be great if folks could test this out and report back with confirmation of success or any issues. Please report back on the PR #2025 (or a new issue if any problems) as there are a few duplicate issues for this. To use a snapshot, git pull && mvn install, and use version 1.17.1-SNAPSHOT in your project.

jhy avatar Nov 01 '23 05:11 jhy

I installed 1.17.1-SNAPSHOT and added requires org.jsoup; to a module-info in a project. Added some code to parse html of a page and extract elements.

final org.jsoup.nodes.Document doc = Jsoup.parse(someHtmlString, someUrl);
doc.select("a[href]")
    .stream()
    .collect(Collectors.toSet());

Can confirm it worked as expected.

SingingBush avatar Nov 03 '23 15:11 SingingBush

Thanks!

bmarwell avatar Nov 03 '23 20:11 bmarwell