[ByteBuddy] NoClassDefFoundError: java.lang.instrument.Instrumentation
Running tests included in JUnit 5's documentation project (backing the User Guide) on the class-path works fine. Converting those tests and demos into a Java module and running it on the module-path fails with several errors. One of the error is related to AssertJ/ByteBuddy.
Found this issue while working on https://github.com/junit-team/junit5/issues/1877
/cc @raphw
JUnit Jupiter:EngineTestKitAllEventsDemo:verifyAllJupiterEvents()
MethodSource [className = 'example.testkit.EngineTestKitAllEventsDemo', methodName = 'verifyAllJupiterEvents', methodParameterTypes = '']
=> java.lang.IllegalArgumentException: Could not create type
[email protected]/org.assertj.core.internal.bytebuddy.TypeCache.findOrInsert(TypeCache.java:154)
[email protected]/org.assertj.core.internal.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:365)
[email protected]/org.assertj.core.api.SoftProxies.createSoftAssertionProxyClass(SoftProxies.java:118)
[email protected]/org.assertj.core.api.SoftProxies.createSoftAssertionProxy(SoftProxies.java:104)
[email protected]/org.assertj.core.api.AbstractSoftAssertions.proxy(AbstractSoftAssertions.java:31)
[...]
Caused by: java.lang.NoClassDefFoundError: java/lang/instrument/Instrumentation
[email protected]/org.assertj.core.internal.bytebuddy.utility.JavaModule$Dispatcher$CreationAction.run(JavaModule.java:270)
[email protected]/org.assertj.core.internal.bytebuddy.utility.JavaModule$Dispatcher$CreationAction.run(JavaModule.java:251)
java.base/java.security.AccessController.doPrivileged(Native Method)
[email protected]/org.assertj.core.internal.bytebuddy.utility.JavaModule.<clinit>(JavaModule.java:45)
[email protected]/org.assertj.core.internal.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$CreationAction.run(ClassInjector.java:454)
[...]
Caused by: java.lang.ClassNotFoundException: java.lang.instrument.Instrumentation
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
[...]
_Side note: Nice to see the AssertJ's version 3.12.2 compiled into its module! :+1:_
I think AssertJ shades Byte Buddy, I assume this is related to the shading? Byte Buddy's module-info has a static requirement onto both the jdk.unsupported and the java.instrument modules.
So, adding those modules at test runtime via java's --add-modules option should work around the issue. I'll fine-tune generated module descriptor https://github.com/junit-team/junit5/compare/issues/1877-fix-module-descriptors#diff-2ede7e4068c8ae230cc4a350bb825229R40 and report back.
A better solution, working for all users of module org.assertj.core, would be if AssertJ re-declared those static requirements in its module descriptor, correct?
But https://github.com/joel-costigliola/assertj-core/blob/master/pom.xml#L140 looks like AssertJ is "only" an automatic module. Hm...
...so I need to add --add-reads options, methinks.
I confirm AssertJ shades BB.
We haven't really tested AssertJ with modules, I'm open to any suggestions to improve that aspect.
I could work around the error in two ways:
requires java.instrument; to documentation's module descriptor.requires java.instrument; to org.junit.platform.testkit, the module that also requires transitive org.assertj.core;.Soo... users of org.junit.platform.testkit will get org.assertj.core and java.instrument for granted.
Ideally, org.assertj.core would provide a compiled module descriptor that requires java.instrument;.
We'll add requires java.instrument; in the module descriptor for the next release.
I guess we should also add jdk.unsupported right ?
This is way more complicated than I expected as we build assertj with java 8.
I have tried using moditect plugin as:
<plugin>
<groupId>org.moditect</groupId>
<artifactId>moditect-maven-plugin</artifactId>
<version>1.0.0.Beta2</version>
<executions>
<execution>
<id>add-module-infos</id>
<phase>package</phase>
<goals>
<goal>add-module-info</goal>
</goals>
<configuration>
<jvmVersion>9</jvmVersion>
<module>
<moduleInfo>
<name>org.assertj.core</name>
<exports>
org.assertj.core*;
</exports>
</moduleInfo>
</module>
</configuration>
</execution>
</executions>
</plugin>
but it fails when executing jdeps with this error:
Error: Modules java.xml.ws.annotation and jsr305 export package javax.annotation to module junit
I could not find a fix for this error, googling seemed to suggest it is related to the JSR 305 and as these two modules contain types in the same package.
At this point I'm not sure what to do as I'm no java 9 module expert.
Maybe the way to go is to build AssertJ with java 9 targeted to java 8 and add manually a module-info.java but it is quite a big change.
@sormuras any idea how to fix this issue without moving to a java 9 build ?
I'll have a look, soon.
@sormuras gentle reminder, if you don't have the time to look at it, that's alright ;-)
@sormuras any idea how to fix this issue without moving to a java 9 build ?
Mh, I don't have a good solution that works using Java 8 only.
We actually lifted recently all of "our" builds to use Java 11 as minimum for compiling them. This includes:
Feel free to find inspiration from the build scripts.
Here is the maven-compiler-plugin user guide describing "Multi Release JAR" support.
https://maven.apache.org/plugins/maven-compiler-plugin/multirelease.html
I'd go with the "Single project (runtime)" approach.
Shall I try to compose a PR ... today?
PR #1525 created -- the module-info.java file needs more love, especially the exports <package name>; section is far from complete.
I will complete it, thanks @sormuras !
Awesome.
Happy to provide an integration test, as I encounter a warning with the current AssertJ at the moment:
src/test/integration/module-info.java:5: warning: requires directive for an automatic module
requires org.assertj.core;
^
1 warning
https://travis-ci.com/sormuras/mainrunner/jobs/207327458#L469-L472
That one should vanish with AssertJ being an explicit Java module, soon.
@sormuras I have added the missing export to module-info.java and pushed the commit to master.
https://travis-ci.org/joel-costigliola/assertj-core/builds/545177956
Can you test it ?
_in progress..._
Do you upload snapshot artifacts?
Unfortunately nope, simply build it with mvn clean install -Dmaven.test.skip=true
Running on Java 11 and using the --module-path yields:
assertj-core-3.13.0-SNAPSHOT.jar locally, skipping tests, some fail on Windowsmodule org.assertj.core, location=file:///R:/dev/github/sormuras/mainrunner/lib/test/assertj-core-3.13.0-SNAPSHOT.jarrequires transitive org.assertj.core;) and test runtime.So far, so good.
What about other modules AssertJ Core reads? Is requires java.instrumentation; all you need?
mvn clean install -Dmaven.test.skip=true
Fixed mvn clean verify -Dmaven.test.skip=true -- no need to deploy it locally, @rfscholte keeps saying. ;-)
exports org.assertj.core.internal 🤔
I know about the internal stuff, dates back from Fest Assert the project AssertJ comes from.
Is there an easy way to know the other java modules a lib depends on ? AssertJ Core does not depend on any third party lib (except BBuddy).
The only one that I think of is jdk.unsupported as mentioned in this previous comment.
Is there an easy way to know the other java modules a lib depends on?
jdeps https://docs.oracle.com/en/java/javase/11/tools/jdeps.html
AssertJ Core does not depend on any third party lib (except BBuddy).
Which is a good sign, that no other 3rd-party module is required.
The only one that I think of is jdk.unsupported [...]
Well, there're two options: either add it and remove it later, if it's not required -- or don't add it now, and if it is missing, add it later. ;-)
Best would be to execute all "black-box" unit test from within a (temporary) module. This way AssertJ could assert that the module descriptor is correct or at least provides a broad happy path for consuming modules.
This is how I ensure all "JUnit 5" modules are usable:
https://github.com/junit-team/junit5/blob/23ee6b3dc9cb6b4b9efbfe0994bfcc697f28d863/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ModularUserGuideTests.java#L38
jdeps --multi-release 9 -summary target\assertj-core-3.13.0-SNAPSHOT.jar
org.assertj.core -> java.base
org.assertj.core -> java.instrument
org.assertj.core -> not found
not found is due to those package references:
jdeps --multi-release 9 target\assertj-core-3.13.0-SNAPSHOT.jar
...
org.assertj.core.annotations -> javax.annotation not found
org.assertj.core.annotations -> javax.annotation.meta not found
...
org.assertj.core.internal -> java.lang.management not found
...
org.assertj.core.api -> org.hamcrest not found
org.assertj.core.api -> org.junit.jupiter.api.extension not found
org.assertj.core.api -> org.junit.rules not found
org.assertj.core.api -> org.junit.runner not found
org.assertj.core.api -> org.junit.runners.model not found
...
org.assertj.core.util -> java.util.logging not found
...
org.assertj.core.util.xml -> javax.xml.parsers not found
org.assertj.core.util.xml -> org.w3c.dom not found
org.assertj.core.util.xml -> org.w3c.dom.bootstrap not found
org.assertj.core.util.xml -> org.w3c.dom.ls not found
org.assertj.core.util.xml -> org.xml.sax not found
Some of them are "static" in nature, methinks, that is only required "sometimes" at runtime.
Adding some (Java SE-provided) module yields:
jdeps --multi-release 9 -summary --add-modules java.logging,java.management,java.xml target\assertj-core-3.13.0-SNAPSHOT.jar
java.logging -> java.base
java.management -> java.base
java.xml -> java.base
org.assertj.core -> java.base
org.assertj.core -> java.instrument
org.assertj.core -> java.logging
org.assertj.core -> java.management
org.assertj.core -> java.xml
org.assertj.core -> not found
Mh, just discovered the --check <module, ...> option of jdeps!
jdeps --multi-release 9 --module-path target\assertj-core-3.13.0-SNAPSHOT.jar --check org.assertj.core
org.assertj.core (.../assertj-core/target/assertj-core-3.13.0-SNAPSHOT.jar)
[Module descriptor]
requires mandated java.base;
requires java.instrument;
[Suggested module descriptor for org.assertj.core]
requires mandated java.base;
requires java.instrument;
requires java.logging;
requires java.management;
requires java.xml;
requires transitive unnamed;
Exception in thread "main" java.lang.NullPointerException
at jdk.jdeps/com.sun.tools.jdeps.ModuleGraphBuilder.requiresTransitive(ModuleGraphBuilder.java:124)
at jdk.jdeps/com.sun.tools.jdeps.ModuleGraphBuilder.buildGraph(ModuleGraphBuilder.java:110)
at jdk.jdeps/com.sun.tools.jdeps.ModuleGraphBuilder.buildGraph(ModuleGraphBuilder.java:80)
at jdk.jdeps/com.sun.tools.jdeps.ModuleAnalyzer$ModuleDeps.buildReducedGraph(ModuleAnalyzer.java:182)
at jdk.jdeps/com.sun.tools.jdeps.ModuleAnalyzer$ModuleDeps.reduced(ModuleAnalyzer.java:195)
at jdk.jdeps/com.sun.tools.jdeps.ModuleAnalyzer$ModuleDeps.analyzeDeps(ModuleAnalyzer.java:215)
at jdk.jdeps/com.sun.tools.jdeps.ModuleAnalyzer.lambda$run$3(ModuleAnalyzer.java:92)
at java.base/java.util.HashMap$Values.forEach(HashMap.java:976)
at jdk.jdeps/com.sun.tools.jdeps.ModuleAnalyzer.run(ModuleAnalyzer.java:88)
at jdk.jdeps/com.sun.tools.jdeps.JdepsTask$CheckModuleDeps.run(JdepsTask.java:968)
at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:560)
at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:519)
at jdk.jdeps/com.sun.tools.jdeps.Main.main(Main.java:49)
...and will filed a :bug: report: https://bugs.openjdk.java.net/browse/JDK-8225773
Some of the modules are only needed if a specific feature is used, for example org.junit.jupiter.api.extension is only used for soft assertions on Junit 5. I guess in that case module-info should contain requires static org.junit.jupiter.api.extension.
I have played with jdeps and the output is a bit scary, is the goal not having any org.assertj.core -> not found output ?
TBH, it looks awfully complicated to get things right especially since I believe most of the people don't use AssertJ as a module, I think I'll start small and wait for users to report issues.
Writing a test is definitely the best way to ensure the module is correctly defined.
[...] I guess in that case module-info should contain
requires static org.junit.jupiter.api;.
Exactly. Except for requiring a module via its name, not a package from within a module.
[...] is the goal not having any
org.assertj.core -> not foundoutput?
Guess so, yes.
TBH, it looks awfully complicated to get things right ...
But "right" is also "correct". Know your dependencies "as good as" your own code.
... especially since I believe most of the people don't use AssertJ as a module,
Granted, that is totally true. But modular testing is taking off ... _soon_, especially for libraries.
I think I'll start small and wait for users to report issues.
That's a fair start. The modular test I performed against the JUnit 5 code base reported "green". That's a solid basis.
I have the report with the missing modules thanks to jdeps --multi-release 9 target/assertj-core-3.13.0-SNAPSHOT.jar:
org.assertj.core.annotations -> javax.annotation not found
org.assertj.core.annotations -> javax.annotation.meta not found
org.assertj.core.api -> org.hamcrest not found
org.assertj.core.api -> org.junit.jupiter.api.extension not found
org.assertj.core.api -> org.junit.rules not found
org.assertj.core.api -> org.junit.runner not found
org.assertj.core.api -> org.junit.runners.model not found
org.assertj.core.internal -> java.lang.management not found
org.assertj.core.matcher -> org.hamcrest not found
org.assertj.core.util -> java.util.logging not found
org.assertj.core.util.xml -> javax.xml.parsers not found
org.assertj.core.util.xml -> org.w3c.dom not found
org.assertj.core.util.xml -> org.w3c.dom.bootstrap not found
org.assertj.core.util.xml -> org.w3c.dom.ls not found
org.assertj.core.util.xml -> org.xml.sax not found
Most of them are optional dependencies, so requires static should be good for them but now the question is: _how do you find the module containing a given package ?_
I have found java.lang.management was in java.management by exploring the Java 9 api but I'm not sure what's the best way for the other ones ? (org.junit.runner for example)
I also have added requires static javax.xml; for the xml dependencies but mvn package fails with
[ERROR] /home/joel/prog/assertj/assertj-core-3.x/src/main/java9/module-info.java:[42,24] module not found: javax.xml
I guess I need to use --add-modules to fix this, right ?
edit: ^^ that did not work, :thinking: the maven args looks fine to me:
d /home/joel/prog/assertj/assertj-core-3.x/target/classes/META-INF/versions/9 -classpath /home/joel/prog/assertj/assertj-core-3.x/target/classes:/home/joel/.m2/repository/junit/junit/4.12/junit-4.12.jar:/home/joel/.m2/repository/org/junit/jupiter/junit-jupiter-api/5.4.2/junit-jupiter-api-5.4.2.jar:/home/joel/.m2/repository/org/apiguardian/apiguardian-api/1.0.0/apiguardian-api-1.0.0.jar:/home/joel/.m2/repository/org/junit/platform/junit-platform-commons/1.4.2/junit-platform-commons-1.4.2.jar:/home/joel/.m2/repository/org/opentest4j/opentest4j/1.1.1/opentest4j-1.1.1.jar:/home/joel/.m2/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar:/home/joel/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/home/joel/.m2/repository/net/bytebuddy/byte-buddy/1.9.12/byte-buddy-1.9.12.jar: -sourcepath /home/joel/prog/assertj/assertj-core-3.x/src/main/java9:/home/joel/prog/assertj/assertj-core-3.x/target/generated-sources/annotations: -s /home/joel/prog/assertj/assertj-core-3.x/target/generated-sources/annotations -g -nowarn --release 9 -encoding UTF-8 --patch-module org.assertj.core=/home/joel/prog/assertj/assertj-core-3.x/target/classes --add-modules java.xml
BTW, thanks for the help @sormuras !
BTW, thanks for the help @sormuras !
You're welcome.
The XML module name is java.xml. Only one x. :-)
https://docs.oracle.com/en/java/javase/11/docs/api/java.xml/module-summary.html
Taking jdeps hint from above, the module-info.java should read like:
[Suggested module descriptor for org.assertj.core]
requires mandated java.base;
requires java.instrument;
requires static java.logging;
requires static java.management;
requires static java.xml;
requires static junit; // JUnit 3/4
requires static org.junit.jupiter.api; // JUnit Jupiter API
// ...
Making progress, after modifying the module-info with this :
// required when printThreadDump is true
requires static java.management;
// used for pretty print XML
requires static javax.xml;
// JUnit/Hamcrest specific features
requires static hamcrest.core;
requires static org.junit.platform.commons;
requires static jsr305;
requires static junit;
requires static org.junit.jupiter.api;
requires static org.apiguardian.api;
requires static org.opentest4j;
I only have the java.xml error:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (jdk9) on project assertj-core: Compilation failure
[ERROR] /home/joel/prog/assertj/assertj-core-3.x/src/main/java9/module-info.java:[42,24] module not found: javax.xml
Not javax.xml, but java.xml.
No error but I still have the same not found ! :cry:
org.assertj.core -> not found
org.assertj.core.annotations -> javax.annotation not found
org.assertj.core.annotations -> javax.annotation.meta not found
org.assertj.core.api -> org.hamcrest not found
org.assertj.core.api -> org.junit.jupiter.api.extension not found
org.assertj.core.api -> org.junit.rules not found
org.assertj.core.api -> org.junit.runner not found
org.assertj.core.api -> org.junit.runners.model not found
org.assertj.core.internal -> java.lang.management not found
org.assertj.core.matcher -> org.hamcrest not found
org.assertj.core.util -> java.util.logging not found
org.assertj.core.util.xml -> javax.xml.parsers not found
org.assertj.core.util.xml -> org.w3c.dom not found
org.assertj.core.util.xml -> org.w3c.dom.bootstrap not found
org.assertj.core.util.xml -> org.w3c.dom.ls not found
org.assertj.core.util.xml -> org.xml.sax not found
Turning one of the requires static to a requires (ex org.junit.jupiter.api) fails the jdeps command below even when the classpath contains all assertj non test dependencies.
~/prog/assertj/assertj-core-3.x ∙ jdeps --multi-release 9 --class-path 'target/dependency/*' -recursive target/assertj-core-3.13.0-SNAPSHOT.jar | grep "not found"
Exception in thread "main" java.lang.module.FindException: Module org.junit.jupiter.api not found, required by org.assertj.core
at java.base/java.lang.module.Resolver.findFail(Resolver.java:889)
...
target/dependency content:
~/prog/assertj/assertj-core-3.x ∙ ll target/dependency/*
-rw-rw-r-- 1 joel joel 2164 Jun 16 21:33 target/dependency/apiguardian-api-1.0.0.jar
-rw-rw-r-- 1 joel joel 45024 Jun 16 21:33 target/dependency/hamcrest-core-1.3.jar
-rw-rw-r-- 1 joel joel 19936 Jun 16 21:33 target/dependency/jsr305-3.0.2.jar
-rw-rw-r-- 1 joel joel 314932 Jun 16 21:33 target/dependency/junit-4.12.jar
-rw-rw-r-- 1 joel joel 134167 Jun 16 21:33 target/dependency/junit-jupiter-api-5.4.2.jar
-rw-rw-r-- 1 joel joel 89363 Jun 16 21:33 target/dependency/junit-platform-commons-1.4.2.jar
-rw-rw-r-- 1 joel joel 7121 Jun 16 21:33 target/dependency/opentest4j-1.1.1.jar
Any idea, what to do next ?
Use --module-path target/dependency instead of --class-path ... ... maybe. Will take a look later.
Running mvn compile org.apache.maven.plugins:maven-dependency-plugin:3.1.1:resolve -DexcludeTransitive yields:
[INFO] The following files have been resolved:
[INFO] com.google.code.findbugs:jsr305:jar:3.0.2:provided (optional) -- module jsr305 (auto)
[INFO] net.bytebuddy:byte-buddy:jar:1.9.12:compile -- module net.bytebuddy
[INFO] com.github.marschall:memoryfilesystem:jar:2.1.0:test -- module com.github.marschall.memoryfilesystem
[INFO] org.junit.jupiter:junit-jupiter-api:jar:5.4.2:provided (optional) -- module org.junit.jupiter.api [auto]
[INFO] org.apache.commons:commons-lang3:jar:3.9:test -- module org.apache.commons.lang3 [auto]
[INFO] org.hamcrest:hamcrest-core:jar:1.3:provided (optional) -- module hamcrest.core (auto)
[INFO] junit:junit:jar:4.12:provided (optional) -- module junit (auto)
[INFO] org.mockito:mockito-junit-jupiter:jar:2.23.0:test -- module mockito.junit.jupiter (auto)
[INFO] org.junit.vintage:junit-vintage-engine:jar:5.4.2:test -- module org.junit.vintage.engine [auto]
[INFO] org.opentest4j:opentest4j:jar:1.1.1:provided (optional) -- module org.opentest4j [auto]
[INFO] org.mockito:mockito-core:jar:2.23.0:test -- module org.mockito [auto]
[INFO] org.junit.jupiter:junit-jupiter:jar:5.4.2:test -- module org.junit.jupiter [auto]
[INFO] com.google.guava:guava:jar:27.1-jre:test -- module com.google.common [auto]
Running
jdeps --multi-release 9 --module-path 'target/dependency/' -recursive target/assertj-core-3.13.0-SNAPSHOT.jar | grep 'not found'
gives:
org.assertj.core -> not found
org.assertj.core.annotations -> javax.annotation not found
org.assertj.core.annotations -> javax.annotation.meta not found
org.assertj.core.api -> org.hamcrest not found
org.assertj.core.api -> org.junit.jupiter.api.extension not found
org.assertj.core.api -> org.junit.rules not found
org.assertj.core.api -> org.junit.runner not found
org.assertj.core.api -> org.junit.runners.model not found
org.assertj.core.internal -> java.lang.management not found
org.assertj.core.matcher -> org.hamcrest not found
org.assertj.core.util -> java.util.logging not found
org.assertj.core.util.xml -> javax.xml.parsers not found
org.assertj.core.util.xml -> org.w3c.dom not found
org.assertj.core.util.xml -> org.w3c.dom.bootstrap not found
org.assertj.core.util.xml -> org.w3c.dom.ls not found
org.assertj.core.util.xml -> org.xml.sax not found
where target/dependency/ contains:
target/dependency/animal-sniffer-annotations-1.17.jar
target/dependency/apiguardian-api-1.0.0.jar
target/dependency/byte-buddy-1.9.12.jar
target/dependency/byte-buddy-agent-1.9.0.jar
target/dependency/checker-qual-2.5.2.jar
target/dependency/commons-lang3-3.9.jar
target/dependency/error_prone_annotations-2.2.0.jar
target/dependency/failureaccess-1.0.1.jar
target/dependency/guava-27.1-jre.jar
target/dependency/hamcrest-core-1.3.jar
target/dependency/j2objc-annotations-1.1.jar
target/dependency/jsr305-3.0.2.jar
target/dependency/junit-4.12.jar
target/dependency/junit-jupiter-5.4.2.jar
target/dependency/junit-jupiter-api-5.4.2.jar
target/dependency/junit-jupiter-engine-5.4.2.jar
target/dependency/junit-jupiter-params-5.4.2.jar
target/dependency/junit-platform-commons-1.4.2.jar
target/dependency/junit-platform-engine-1.4.2.jar
target/dependency/junit-vintage-engine-5.4.2.jar
target/dependency/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar
target/dependency/memoryfilesystem-2.1.0.jar
target/dependency/mockito-core-2.23.0.jar
target/dependency/mockito-junit-jupiter-2.23.0.jar
target/dependency/objenesis-2.6.jar
target/dependency/opentest4j-1.1.1.jar
I have the same result as your when running
mvn compile org.apache.maven.plugins:maven-dependency-plugin:3.1.1:resolve -DexcludeTransitive
I quite don't get why with all the libs in target/dependency, jdeps does not seem to find any module ???
We might just be hitting https://bugs.openjdk.java.net/browse/JDK-8210502 ?
edit: nope, same result with java 12
Got it (almost) working. Found the solution here: https://stackoverflow.com/a/47512109/1431016
Add --add-modules=ALL-MODULE-PATH to the jdeps command line. And replace -recursive with -summary.
_It is also a convenient means to add automatic modules to the root set._
jdeps --multi-release 9 --module-path target/dependency --add-modules=ALL-MODULE-PATH -summary target/assertj-core-3.13.0-SNAPSHOT.jar
yields
animal.sniffer.annotations -> java.base
checker.qual -> java.base
com.github.marschall.memoryfilesystem -> java.base
com.github.marschall.memoryfilesystem -> not found
com.google.common -> JDK removed internal API
com.google.common -> error.prone.annotations
com.google.common -> failureaccess
com.google.common -> j2objc.annotations
com.google.common -> java.base
com.google.common -> java.logging
com.google.common -> jsr305
error.prone.annotations -> java.base
error.prone.annotations -> java.compiler
failureaccess -> java.base
hamcrest.core -> java.base
j2objc.annotations -> java.base
jsr305 -> java.base
junit -> hamcrest.core
junit -> java.base
junit -> not found
mockito.junit.jupiter -> java.base
mockito.junit.jupiter -> org.junit.jupiter.api
mockito.junit.jupiter -> org.junit.platform.commons
mockito.junit.jupiter -> org.mockito
net.bytebuddy -> java.base
net.bytebuddy -> java.instrument
net.bytebuddy.agent -> java.base
net.bytebuddy.agent -> java.instrument
net.bytebuddy.agent -> not found
objenesis -> JDK removed internal API
objenesis -> java.base
org.apache.commons.lang3 -> java.base
org.apache.commons.lang3 -> not found
org.apiguardian.api -> java.base
org.assertj.core -> hamcrest.core
org.assertj.core -> java.base
org.assertj.core -> java.instrument
org.assertj.core -> java.logging
org.assertj.core -> jsr305
org.assertj.core -> junit
org.assertj.core -> not found
org.assertj.core -> org.junit.jupiter.api
org.junit.jupiter.api -> java.base
org.junit.jupiter.api -> not found
org.junit.jupiter.api -> org.apiguardian.api
org.junit.jupiter.api -> org.junit.platform.commons
org.junit.jupiter.api -> org.opentest4j
org.junit.jupiter.engine -> java.base
org.junit.jupiter.engine -> not found
org.junit.jupiter.engine -> org.apiguardian.api
org.junit.jupiter.engine -> org.junit.jupiter.api
org.junit.jupiter.engine -> org.junit.platform.commons
org.junit.jupiter.engine -> org.junit.platform.engine
org.junit.jupiter.engine -> org.opentest4j
org.junit.jupiter.params -> java.base
org.junit.jupiter.params -> not found
org.junit.jupiter.params -> org.apiguardian.api
org.junit.jupiter.params -> org.junit.jupiter.api
org.junit.jupiter.params -> org.junit.platform.commons
org.junit.platform.commons -> java.base
org.junit.platform.commons -> java.compiler
org.junit.platform.commons -> java.logging
org.junit.platform.commons -> org.apiguardian.api
org.junit.platform.engine -> java.base
org.junit.platform.engine -> org.apiguardian.api
org.junit.platform.engine -> org.junit.platform.commons
org.junit.platform.engine -> org.opentest4j
org.junit.vintage.engine -> java.base
org.junit.vintage.engine -> junit
org.junit.vintage.engine -> org.apiguardian.api
org.junit.vintage.engine -> org.junit.platform.commons
org.junit.vintage.engine -> org.junit.platform.engine
org.junit.vintage.engine -> org.opentest4j
org.mockito -> hamcrest.core
org.mockito -> java.base
org.mockito -> java.instrument
org.mockito -> junit
org.mockito -> net.bytebuddy
org.mockito -> net.bytebuddy.agent
org.mockito -> objenesis
org.opentest4j -> java.base
Only some not found instances are left...
In summary, the goal to resolve all not found instance is ... a no-goal. At least when it comes to verify that AssertJ's module descriptor is valid. Methinks.
I ran jdpes [...] --check org.assertj.core again. Here's the result.
All required modules are listed. Now, throw in some static modifiers as needed. ;-)
jdeps --multi-release 9 --module-path target\assertj-core-3.13.0-SNAPSHOT.jar;target\dependency --add-modules=ALL-MODULE-PATH --check org.assertj.core
org.assertj.core (file:///R:/dev/github/sormuras/assertj-core/target/assertj-core-3.13.0-SNAPSHOT.jar)
[Module descriptor]
requires mandated java.base;
requires java.instrument;
[Suggested module descriptor for org.assertj.core]
requires transitive hamcrest.core;
requires mandated java.base;
requires java.instrument;
requires java.logging;
requires java.management;
requires java.xml;
requires jsr305;
requires transitive junit;
requires transitive org.junit.jupiter.api;
[Transitive reduced graph for org.assertj.core]
requires transitive hamcrest.core;
requires mandated java.base;
requires java.instrument;
requires java.logging;
requires java.management;
requires java.xml;
requires jsr305;
requires transitive junit;
requires transitive org.junit.jupiter.api;
That's cool @sormuras :smiley:
Here's my results
~/prog/assertj/assertj-core-3.x ∙ jdeps --multi-release 9 --module-path target/dependency --add-modules=ALL-MODULE-PATH -summary check org.assertj.core | grep 'not found'
junit -> not found
org.junit.jupiter.api -> not found
org.junit.platform.commons -> not found
with these requires
requires java.instrument;
// required when printThreadDump is true
requires static java.management;
// used for pretty print XML
requires static java.xml;
// For annotations: Beta and NonNull ones for Kotlin
requires static jsr305;
// JUnit/Hamcrest specific features
requires static hamcrest.core;
requires static junit;
requires static org.junit.jupiter.api;
// To throw AssertionFailedError which is IDE friendly
requires static org.opentest4j;
and these dependencies:
~/prog/assertj/assertj-core-3.x ∙ ll target/dependency
total 612
drwxrwxr-x 2 joel joel 4096 Jun 18 23:20 .
drwxrwxr-x 13 joel joel 4096 Jun 18 22:05 ..
-rw-rw-r-- 1 joel joel 45024 Jun 17 22:38 hamcrest-core-1.3.jar
-rw-rw-r-- 1 joel joel 19936 Jun 17 22:38 jsr305-3.0.2.jar
-rw-rw-r-- 1 joel joel 314932 Jun 17 22:38 junit-4.12.jar
-rw-rw-r-- 1 joel joel 134167 Jun 17 22:38 junit-jupiter-api-5.4.2.jar
-rw-rw-r-- 1 joel joel 7121 Jun 17 22:38 opentest4j-1.1.1.jar
Running this leads to the same not found but I'm not sure how relevant that is.
~/prog/assertj/assertj-core-3.x ∙ jdeps --multi-release 9 --module-path target/dependency --add-modules=ALL-MODULE-PATH -summary target/assertj-core-3.13.0-SNAPSHOT.jar
hamcrest.core -> java.base
jsr305 -> java.base
junit -> hamcrest.core
junit -> java.base
junit -> not found
org.assertj.core -> hamcrest.core
org.assertj.core -> java.base
org.assertj.core -> java.instrument
org.assertj.core -> jsr305
org.assertj.core -> junit
org.assertj.core -> not found
org.assertj.core -> org.junit.jupiter.api
org.junit.jupiter.api -> java.base
org.junit.jupiter.api -> not found
org.junit.jupiter.api -> org.opentest4j
org.opentest4j -> java.base
I think I'm reasonably happy to ship the above module-info and wait for the community feedback.
Looking forward to test-drive the new AssertJ module as soon as you push it to master.
You can now, it's in master ;-)
Thanks again for your help.
You're welcome.
That's how and why open source works.
Did you see this warning from the compile task?
********************************************************************************************************************
* Required filename-based automodules detected. Please don't publish this project to a public artifact repository! *
********************************************************************************************************************
There are some issues with the latest module descriptor:
[X] org.assertj.core.presentation.Representation: module org.assertj.core does not declare "uses"[X] Could not initialize class org.assertj.core.configuration.ConfigurationProviderTrying to find the underlying reason...
Looking at the (auto) and [auto] line endings from Maven's output:
[INFO] The following files have been resolved:
[INFO] com.google.code.findbugs:jsr305:jar:3.0.2:provided (optional) -- module jsr305 (auto)
[INFO] net.bytebuddy:byte-buddy:jar:1.9.12:compile -- module net.bytebuddy
[INFO] com.github.marschall:memoryfilesystem:jar:2.1.0:test -- module com.github.marschall.memoryfilesystem
[INFO] org.junit.jupiter:junit-jupiter-api:jar:5.4.2:provided (optional) -- module org.junit.jupiter.api [auto]
[INFO] org.apache.commons:commons-lang3:jar:3.9:test -- module org.apache.commons.lang3 [auto]
[INFO] org.hamcrest:hamcrest-core:jar:1.3:provided (optional) -- module hamcrest.core (auto)
[INFO] junit:junit:jar:4.12:provided (optional) -- module junit (auto)
[INFO] org.mockito:mockito-junit-jupiter:jar:2.23.0:test -- module mockito.junit.jupiter (auto)
[INFO] org.junit.vintage:junit-vintage-engine:jar:5.4.2:test -- module org.junit.vintage.engine [auto]
[INFO] org.opentest4j:opentest4j:jar:1.1.1:provided (optional) -- module org.opentest4j [auto]
[INFO] org.mockito:mockito-core:jar:2.23.0:test -- module org.mockito [auto]
[INFO] org.junit.jupiter:junit-jupiter:jar:5.4.2:test -- module org.junit.jupiter [auto]
[INFO] com.google.guava:guava:jar:27.1-jre:test -- module com.google.common [auto]
...it appears to me that iff it reads only module x.y.z (without auto) it is an explicit module, it contains a stable name and API exposed via a compiled module descriptor. Examples:
module net.bytebuddymodule com.github.marschall.memoryfilesystemAutomatic modules with a stable module name defined via their manifests end with [auto]:
module org.apache.commons.lang3 [auto]module org.junit.jupiter [auto]Automatic modules with their names derived from their JAR file names end with (auto):
module jsr305 (auto)module junit (auto)module hamcrest.core (auto)module mockito.junit.jupiter (auto)Is that observation correct, @rfscholte?
Robert said: "the code is the truth"
https://github.com/apache/maven-dependency-plugin/blob/master/src/main/java/org/apache/maven/plugins/dependency/resolvers/ResolveDependenciesMojo.java#L233-L243
In case of module org.junit.jupiter.api I can guarantee that this is a stable name. Will be an explicit stable name with the upcoming 5.5.0 GA release.
In case of module junit I can assure that the upcoming (and last?) version of JUnit 4.13 will set its module name to junit via a manifest entry. Thus, this name is safe to use.
Removing...
requires static jsr305;
requires static hamcrest.core;
requires static junit;
...from src/main/java9/module-info.java makes the maven-compiler-plugin happy and allows end-users to put those JARs on the --class-path.
I did miss the warning, so the right way is to remove these entries to avoid this potential issue ?
If I understand correctly, users will have to add these modules to the classpath for the features relying on them to work, correct ?
I did miss the warning, so the right way is to remove these entries to avoid this potential issue ?
I'm not 100% about the "right way" here. But yes, removing them avoids the valid warning when compiling. Even javac warns about requires directives that refer to automatic modules. At runtime users may put those libraries on the class- or module-path allowing dependent AssertJ features to work.
There are some issues with the latest module descriptor:
[X] org.assertj.core.presentation.Representation: module org.assertj.core does not declare "uses"[X] Could not initialize class org.assertj.core.configuration.ConfigurationProviderTrying to find the underlying reason...
Found it. To help the module system wire up services, modules have to declare which services the will load at runtime. PR incoming...
FYI: detected and fixed a similar issue in org.junit.jupiter.engine via https://github.com/junit-team/junit5/commit/c281338c049ab455b198887d48b54ab0ce01b6c6
@sormuras I have pushed a commit removing the requires clause on the filename-based automodules (this indeed fixes the warning you mentioned).
Is there anything that should be done on this issue ?
No, I think this issue is solved as good as possible for the time being.
Sweet, thanks again for the help :)
Guess, we need to reopen this issue, as 3.15.0 introduced a regression. Will a create a PR showing the underlying issue in Byte Buddy (possible already solved by https://github.com/raphw/byte-buddy/commit/d9a5b3af63d12730c39d15ea6830933383c648d4) ... soon.
Upgrading to AssertJ 3.16.0 worked out as expected. This issue may rest in peace.
I'm afraid rumours of this issue's death were greatly exaggerated. With the current AssertJ 3.18.1, I am getting IllegalAccessErrors, caused by the shaded bytebuddy still trying to use java.instrument, whenever I use an assumption -- unless I hack in the --add-reads option documented above.
This occurs consistently if I run the tests in JDK 13, 14, or 15. JDK 11 does not seem to have the same problem for some reason but our code needs JDK 14 to function fully (the assumption that triggered this was the one that disables some tests in earlier versions!)
In short, please consider restoring the requires java.instrument to module-info.java, because AssertJ does still seem to require it 🙂
Do you have a stack? This path should never be entered but there is of course a chance something is overlooked.
Most helpful comment
You're welcome.
That's how and why open source works.