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

Introduce Java module descriptors #243

Closed
sormuras opened this issue Oct 12, 2021 · 18 comments
Closed

Introduce Java module descriptors #243

sormuras opened this issue Oct 12, 2021 · 18 comments

Comments

@sormuras
Copy link
Contributor

Automatic Modules

Here's a listing of modules used by project that runs on Java 17 and uses jqwik via JUnit Platform's Launcher module.

java.base@17
...
jdk.xml.dom@17
jdk.zipfs@17
net.jqwik@1.5.6 file:///.../jqwik-1.5.6.jar automatic
net.jqwik.api@1.5.6 file:///.../jqwik-api-1.5.6.jar automatic
net.jqwik.engine@1.5.6 file:///.../jqwik-engine-1.5.6.jar automatic
net.jqwik.time@1.5.6 file:///.../jqwik-time-1.5.6.jar automatic
net.jqwik.web@1.5.6 file:///.../jqwik-web-1.5.6.jar automatic
org.apiguardian.api@1.1.2 file:///.../apiguardian-api-1.1.2.jar
org.junit.platform.commons@1.8.1 file:///.../junit-platform-commons-1.8.1.jar
org.junit.platform.engine@1.8.1 file:///.../junit-platform-engine-1.8.1.jar
org.junit.platform.launcher@1.8.1 file:///.../junit-platform-launcher-1.8.1.jar
org.opentest4j@1.2.0 file:///.../opentest4j-1.2.0.jar

Suggested Solution

Define and compile a module-info.java for each jqwik module. Package the generated module-info.class files to eliminate the automatic tag and ...

Discussion

... commit to jqwik's modular API: namely, its exported packages and possibly provided and/or used services.

Notable benefit: get jqwik's version rendered into stacktraces.

@jlink
Copy link
Collaborator

jlink commented Oct 12, 2021

@sormuras Thank for the suggestion.

Do you have by any chance an example handy how to do that in Gradle. Mind that Java 1.8 is still jqwik's main platform and I'd very much prefer to stick with a single artefact per module.

@sormuras
Copy link
Contributor Author

sormuras commented Oct 12, 2021

Sure. This is all about adding a module-info.class into each existing JAR file published by jqwik.

Would you mind requiring JDK 17 at build time? With --release 8 for jqwik's production code, with --release 9 for module descriptors and (with implicite --release 17) for test code?

If you want to stay on 8 ... there are ways to compile modules here, too. (For example, let Gradle toolchain provide a recent JDK and use it to compile module descriptors, or also make use of https://github.com/moditect/moditect or https://github.com/beryx/badass-jar-plugin#module-infojava-location).

@sormuras
Copy link
Contributor Author

I guess @marcphilipp could apply some of his Great Gradle-Fu to help us here. 🤓

@marcphilipp
Copy link

This will require a separate source set or an additional compile task in Gradle. Alternatively, Moditect als has a Gradle plugin.

@sormuras
Copy link
Contributor Author

(FYI: here's a similar feature request at micronaut-projects/micronaut-core#6395)

@jlink
Copy link
Collaborator

jlink commented Oct 26, 2021

I had a look at the moditect Gradle plugin. 1.0.0 is still a RC and I didn't succeed in making it work for one single module :-(

Guess it's too much hassle for me to tackle it in 1.6.0.

Looks like a perfect task for the community to pick up. If there only was any ;-)

@jlink
Copy link
Collaborator

jlink commented Oct 26, 2021

@sormuras You probably know if Kotlin modules come with additional challenges?

@sormuras
Copy link
Contributor Author

I don't know - but if you have drafted some module-info.java files, I can try to make them compile and added to the generated JAR files.

@sormuras
Copy link
Contributor Author

Work in progress...


@sormuras ➜ $ jar --describe-module --file api/build/libs/jqwik-api-1.6.0-SNAPSHOT.jar
net.jqwik.api jar:file:///workspaces/jqwik/api/build/libs/jqwik-api-1.6.0-SNAPSHOT.jar/!module-info.class
requires java.base mandated

@sormuras ➜ $ jar --describe-module --file base/build/libs/jqwik-1.6.0-SNAPSHOT.jar 
net.jqwik jar:file:///workspaces/jqwik/base/build/libs/jqwik-1.6.0-SNAPSHOT.jar/!module-info.class
requires java.base mandated
requires net.jqwik.api

Using @beryx's https://github.com/beryx/badass-jar-plugin and some module-info.java skeletons: #244

@jlink
Copy link
Collaborator

jlink commented Oct 27, 2021

Ready for testing with commit 9c2be82.

Released in 1.6.0-SNAPSHOT

@sormuras
Copy link
Contributor Author

sormuras commented Oct 27, 2021

Preparing an integration test module in parallel...

java.lang.module.ResolutionException: Module net.jqwik.engine does not read a module that exports net.jqwik.api.facades

Fixing those exception on-the-fly.

@sormuras
Copy link
Contributor Author

sormuras commented Oct 27, 2021

This is one strange. Any clue?

Could not initialize class net.jqwik.api.domains.DomainContext$DomainContextFacade
java.lang.NoClassDefFoundError: Could not initialize class net.jqwik.api.domains.DomainContext$DomainContextFacade
	at net.jqwik.engine/net.jqwik.engine.execution.PropertyMethodExecutor.execute(PropertyMethodExecutor.java:47)
	at net.jqwik.engine/net.jqwik.engine.execution.PropertyTaskCreator.executeTestMethod(PropertyTaskCreator.java:129)
	at net.jqwik.engine/net.jqwik.engine.execution.PropertyTaskCreator.lambda$createTask$1(PropertyTaskCreator.java:55)
	at net.jqwik.engine/net.jqwik.engine.execution.pipeline.ExecutionTask$1.lambda$execute$0(ExecutionTask.java:31)
	at net.jqwik.engine/net.jqwik.engine.execution.lifecycle.CurrentTestDescriptor.runWithDescriptor(CurrentTestDescriptor.java:17)
	at net.jqwik.engine/net.jqwik.engine.execution.pipeline.ExecutionTask$1.execute(ExecutionTask.java:31)
	at net.jqwik.engine/net.jqwik.engine.execution.pipeline.ExecutionPipeline.runToTermination(ExecutionPipeline.java:82)
	at net.jqwik.engine/net.jqwik.engine.execution.JqwikExecutor.execute(JqwikExecutor.java:46)
	at net.jqwik.engine/net.jqwik.engine.JqwikTestEngine.executeTests(JqwikTestEngine.java:70)
	at net.jqwik.engine/net.jqwik.engine.JqwikTestEngine.execute(JqwikTestEngine.java:53)

Never mind. Build was out of sync...

sormuras added a commit to sormuras/jqwik that referenced this issue Oct 27, 2021
jlink pushed a commit that referenced this issue Oct 27, 2021
@jlink
Copy link
Collaborator

jlink commented Oct 27, 2021

gradle test-modular-api:test fails locally with:
java.lang.IllegalAccessError: class net.jqwik.engine.JqwikTestEngine (in module net.jqwik.engine) cannot access class java.util.logging.Logger (in module java.logging) because module net.jqwik.engine does not read module java.logging

Any idea?

Gradle version 7.2. IntelliJ also complains.

@sormuras
Copy link
Contributor Author

Works on my machine and GH Actions was also fine.

https://github.com/jlink/jqwik/blob/4418ccf9ef65b0ff218f8453a9b9d21b7f86adf2/engine/src/main/module/module-info.java#L1-L3

According to that requires java.logging; line, it smells like an outdated JAR and/or classes folder on your machine.

@jlink
Copy link
Collaborator

jlink commented Oct 27, 2021

Integration test works. Done!

@jlink jlink closed this as completed Oct 27, 2021
@sormuras
Copy link
Contributor Author

Cheers! Modules, modules, every where!

@sormuras
Copy link
Contributor Author

sormuras commented Nov 7, 2021

Running some smoke-test commands in a workspace of https://github.com/sormuras/jqwik-samples/tree/main/jqwik-starter-bach yields:

@sormuras ➜ /workspaces/jqwik-samples/jqwik-starter-bach $ java --module-path .bach/external-modules --list-modules

java.base@17.0.1
...
jdk.zipfs@17.0.1
net.jqwik.api file:///.../net.jqwik.api.jar
net.jqwik.engine file:///.../net.jqwik.engine.jar
org.apiguardian.api@1.1.2 ...
...

@sormuras ➜ /workspaces/jqwik-samples/jqwik-starter-bach $ java --module-path .bach/external-modules --describe-module net.jqwik.api

net.jqwik.api file:///workspaces/jqwik-samples/jqwik-starter-bach/.bach/external-modules/net.jqwik.api.jar
exports net.jqwik.api
exports net.jqwik.api.arbitraries
exports net.jqwik.api.configurators
exports net.jqwik.api.constraints
exports net.jqwik.api.domains
exports net.jqwik.api.facades
exports net.jqwik.api.footnotes
exports net.jqwik.api.lifecycle
exports net.jqwik.api.providers
exports net.jqwik.api.sessions
exports net.jqwik.api.stateful
exports net.jqwik.api.statistics
requires org.opentest4j
requires java.logging
requires java.base mandated
requires org.junit.platform.commons
uses net.jqwik.api.facades.ShrinkingSupportFacade

...
uses net.jqwik.api.ExhaustiveGenerator$ExhaustiveGeneratorFacade

@sormuras ➜ /workspaces/jqwik-samples/jqwik-starter-bach $ java --module-path .bach/external-modules --describe-module net.jqwik.engine

net.jqwik.engine file:///workspaces/jqwik-samples/jqwik-starter-bach/.bach/external-modules/net.jqwik.engine.jar
requires org.junit.platform.engine
requires java.logging
requires net.jqwik.api
requires java.base mandated
uses net.jqwik.api.providers.TypeUsage$Enhancer
uses net.jqwik.api.SampleReportingFormat
uses net.jqwik.api.providers.ArbitraryProvider
uses net.jqwik.api.lifecycle.LifecycleHook
uses net.jqwik.api.configurators.ArbitraryConfigurator
provides net.jqwik.api.Functions$FunctionsFacade with 
    net.jqwik.engine.facades.FunctionsFacadeImpl
...
provides net.jqwik.api.providers.ArbitraryProvider with
    net.jqwik.engine.providers.BigDecimalArbitraryProvider
    ...
    net.jqwik.engine.providers.StringArbitraryProvider
qualified opens net.jqwik.engine.properties.configurators to
    org.junit.platform.commons
contains net.jqwik.engine
...
contains net.jqwik.engine.support.types

Looks good to me.

@jlink
Copy link
Collaborator

jlink commented Nov 13, 2021

Feature has been released in 1.6.0

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

No branches or pull requests

3 participants