I have a question about junit.jupiter. Is it useful to compile the test as module? Something like that?
module usecases {
requires org.junit.jupiter.api;
}
When I try to compile with ant, I get the following error message:
[javac] error: module not found: org.opentest4j
[javac] error: module not found: org.apiguardian.api
I don't understand it because inside the classpath it would compile without problems but in the module-path not?
Both modules and also org.junit.platform.commons are required to satisfy the declarations of org.junit.jupiter.api. See this snippet of the module descriptor:
/**
* Defines JUnit Jupiter API for writing tests.
*/
module org.junit.jupiter.api {
requires transitive org.apiguardian.api;
requires transitive org.junit.platform.commons;
requires transitive org.opentest4j;
exports org.junit.jupiter.api;
...
}
That's why you have to configure your build tool to also provide at least those three modules.
IIRC, the default "JUnit 5" integration of Ant makes use the non-modular junit-platform-console-standalone artifact. Its JAR does contain all required normal classes but no module-info.class files. Therefore, compiling and running on the classpath works out-of-the-box.
More and recent details for using the "JUnitLauncher Task" can be found here: https://ant.apache.org/manual/Tasks/junitlauncher.html
Related
I created a Java 13 project that uses the modular system, and want to use LITIEngine, a game library made with java 8.
After adding the dependency in Maven using :
<dependency>
<groupId>de.gurkenlabs</groupId>
<artifactId>litiengine</artifactId>
<version>0.4.18</version>
</dependency>
I was expecting to use it as an automatic module, in my module-info.java:
module com.myproject {
require litiengine; // Error: Module litiengine not found.
}
Surprisingly enough, it doesn't seem to be an automatic module, so I grabbed the jar and ran the command jar --file=litiengine-0.4.18.jar --describe-module, and got this weird result:
java.xml.bind jar:file:///D:/WhereverMyJarIs/litiengine-0.4.18.jar/!module-info.class
exports javax.xml.bind
exports javax.xml.bind.annotation
exports javax.xml.bind.annotation.adapters
exports javax.xml.bind.attachment
exports javax.xml.bind.helpers
exports javax.xml.bind.util
requires java.activation transitive
requires java.base mandated
requires java.desktop
requires java.logging
requires java.xml transitive
uses javax.xml.bind.JAXBContextFactory
So, I am supposed to use LITIEngine as java.xml.bind? It doesn't have anything to do with the library I want to use. This makes no sense!
I still tried to require it:
module com.myproject {
requires java.xml.bind; // IntelliJ gives an error: Ambiguous module reference: java.xml.bind
}
Despite the error IntelliJ gives me, i tried to compile my project with Maven, containing a simple HelloWorld.java file:
package com.myproject;
import de.gurkenlabs.litiengine.Game;
public class HelloWorld {
public static void main(String[] args) {
Game.init(args);
Game.start();
}
}
When running mvn compile, the compilation fails (I set maven.compiler.target and maven.compiler.source to 13):
Error:(3,21) java: package de.gurkenlabs.litiengine is not visible
At this point, I just tried to use my project as a nonmodular one, but still use Java 13, so i just deleted the module-info.java, and like that, it works. Great, but I lose the ability to use the module system, which i need to use in my project.
I tried one last thing, I used the LITIEngine jar i grabbed earlier, and removed the module-info.class file in it, by opening the jar file as an archive in 7-zip and deleting that file. Then I added it as a local dependency in maven with:
mvn install:install-file -Dfile=./whereverItIs/litiengine-0.4.18.jar \
-DgroupId=com.myproject.jars -DartifactId=litiengine -Dversion=1 -Dpackaging=jar
And I added it as a dependency:
<dependency>
<groupId>com.myproject.jars</groupId>
<artifactId>litiengine</artifactId>
<version>1</version>
</dependency>
I could then use the library in my module-info.java
module com.myproject {
require litiengine; // No errors this time!
}
And then successfully build it and run it!
So, this proves that this library can work with when imported as an automatic module, but this requires me to edit the jar file and remove the module-info.class in order to make it work, which is very undesirable, because this requires manual action everytime the library receives an update.
The perfect solution would be to be able to ignore the module-info.class file contained inside the jar and make the module system threat it as an automatic module, is there a way to do that?
I would like to use ResponseSubscribers.ByteArraySubscriber that is in jdk.internal.net.http. I use openjdk11.
I tried 2 things :
1/
I added to maven compiler plugin exports module
<compilerArgs>
<arg>--add-exports</arg><arg>java.net.http/jdk.internal.net.http=fr.app</arg>
</compilerArgs>
-> it compile !
2/
I created module-info.java
module fr.app {
requires java.net.http;
requires com.fasterxml.jackson.core;
requires com.fasterxml.jackson.databind;
requires com.fasterxml.jackson.datatype.jsr310;
exports fr.app;
exports fr.app.parser;
}
There is an error when running a junit test that use the class importing jdk.internal.net.http
fr.app.AppException: java.io.IOException: class fr.app.MyClass$BodySubscribers (in unnamed module #0x6537cf78) cannot access class jdk.internal.net.http.ResponseSubscribers$ByteArraySubscriber (in module java.net.http) because module java.net.http does not export jdk.internal.net.http to unnamed module #0x6537cf78
I understand BodySubscribers must be exported only in named module. But my module is name fr.app right ?
But my module is name fr.app right ?
Not really, while you've created the module-info.java in your project, during the execution of your application your actual code seems to be found on the classpath eventually.
Hence your MyClass is residing in the unnamed module and the error reads as follows
class fr.app.MyClass$BodySubscribers (in unnamed module.....
On another note, the class you've mentioned seems to be packaged internal to the java.net.http module and should not be relied upon from your code. You must implement your own subscriber even if you desire a similar functionality as the code you're looking at. Since the module wouldn't be exporting it for a public use anyway.
You shouldn't use directly any class from any jdk.internal.* package. Have you tried using the public API HttpResponse.BodySubscribers.ofByteArray() instead?
After upgrading a Maven project to Java 9 and adding a module descriptor, javac complains about a transitive dependency for an automatic module:
[WARNING] /.../src/main/java/module-info.java:[3,35] requires transitive directive for an automatic module
An example module-info.java to reproduce the problem:
module com.example.mymodule {
exports com.example.mymodule.myexportedpackage;
requires transitive com.google.common;
}
The meaning of this warning is completely clear, here are some related links:
What's the difference between requires and requires transitive statements in Java 9?
Why does javac complain about named automatic-modules?
Related OpenJDK issue
The question is — how to suppress this warning, without fixing the actual issue, and without disabling all the other javac warnings?
I've tried the following options, but none of them worked:
#SuppressWarnings("module") in module-info.java
#SuppressWarnings("all") in module-info.java
-Xlint:all,-module command line option
Unfortunately, I cannot fix the actual issue (for now) because "my" module has return types and annotations from third-party (automatic) modules (e.g. Guava). Thus, if I'd use "requires com.google.common" (without transitive), then there would be a different warning, e.g.:
[WARNING] .../MyClass.java:[25,20] class com.google.common.collect.Table in module com.google.common is not indirectly exported using requires transitive
And of course I cannot define module descriptors for the third-party libraries (which are automatic modules right now).
I'm using -Werror which I'd prefer to keep, so the warning isn't merely annoying...
P.S. I do not intend to publish my artifacts to any public repositories.
You could try out the option of switching off the warning using
-Xlint:-requires-transitive-automatic
The changes for which were merged with JDK-8178011 stating:-
There should be two new warnings:
when a named module "requires transitive" an automatic module (default on)
when a named module "requires" an automatic module (default off)
Inferring this from the changes made here and also from the edit to the JEP 261: Module System which confirms that(emphasis mine):-
In both of the modular modes the compiler will, by default, generate
various warnings related to the module system; these may be disabled
via the option -Xlint:-module.
More precise control of these warnings
is available via the exports, opens, requires-automatic, and
requires-transitive-automatic keys for the -Xlint option.
You can also just use #SuppressWarnings like so:
#SuppressWarnings({ "requires-automatic", "requires-transitive-automatic" })
module foo {
// ...
}
The JDK itself uses this technique.
Sadly, the accepted answer didn't help me.
BTW, I am using Java 14 with a bunch of module system hacks for JUnit.
I had to add another flag, so the complete list looks as following:
-Xlint:-exports -Xlint:-requires-transitive-automatic -Xlint:-requires-automatic
I have searched for the error message and found the source code. There, one can see that the corresponding compiler key is called compiler.warn.leaks.not.accessible.not.required.transitive, with the command line arg -Xlint:exports.
I have an "executable" Java 9 module (meaning it won't expose any packages, it just contains a main function) which I need to test.
I am using Gradle's java-library and org.gradle.java.experimental-jigsaw plugins.
I have some package-private methods I need to test, and when I run in IntelliJ the tests work, but when running with Gradle, I get many errors like this:
abc.MyClassTest > myTestMethod FAILED
java.lang.IllegalAccessException
In the Gradle report, I see the root of the error:
class org.junit.runners.BlockJUnit4ClassRunner (in module junit)
cannot access class abc.MyClassTest (in module com.my.mod)
because module com.my.mod does not export abc to module junit
If I add this to my module-info.java file, it works with a warning:
exports abc to junit; // I don't really want to export this
Warning (when compiling):
warning: [module] module not found: junit
This looks pretty horrible even without the warning, in my opinion.
My question: how to "open" this package for tests only to avoid warnings and errors?
As the Gradle Plugin is still experimental (6 months after the release of Java 9), it seems it still has some bugs and missing features.
But here's how to work around the issue while the Gradle devs don't improve the situation.
Add this to your build file:
test {
doFirst {
jvmArgs += [
'--add-exports', "module/package=junit",
]
}
}
Where module/package is the name of the module and package you need to make visible to JUnit.
This is basically equivalent to the exports package to junit clause in module-info.java, but without having the clause make into the compiled jar!
This option is not documented in javac -help, but you can at least find it mentioned in the Oracle JDK Docs and, more thoroughly, in JEP-261... see the Breaking encapsulation section.
I have a Gradle project using the Kotlin Gradle plugin. I want to build a Java 9 module, so my directory structure looks like this:
src/main/java/
- module-info.java
src/main/kotlin/
- Foo.kt
- Bar.kt
build.gradle
...
My build.gradle declares the following dependencies:
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.10"
compile "org.jetbrains.kotlin:kotlin-reflect:1.2.10"
compile "org.junit.jupiter:junit-jupiter-api:5.0.2"
}
and I use all of these dependencies in my Kotlin source (Foo.kt, Bar.kt, ...).
Everything works hunky-dory if I write my module-info.java like so:
module my.module {
requires kotlin.stdlib;
exports my.module.pkg;
}
and if I supply all my compile-time dependencies to javac during the compileJava task using this technique.
However if I turn on -Xlint:all for the Java compiler during the compileJava task (to compile module-info.java), I get the following warnings:
/path/to/my.module/src/main/java/module-info.java:26: warning: requires directive for an automatic module
requires kotlin.stdlib;
^
So here we have the Java compiler, javac complaining that kotlin.stdlib is an automatic module so I shouldn't have a requires clause for it.
But if I delete the requires clause to make javac happy, it makes kotlinc even angrier than javac was (I get an error not a warning):
e: /path/to/my.module/src/main/java/module-info.java: The Kotlin standard library is not found in the module graph. Please ensure you have the 'requires kotlin.stdlib' clause in your module definition
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':my.module:compileKotlin'.
Now I can fix that, too, by editing my compileKotlin task thus:
compileKotlin {
doFirst {
kotlinOptions.freeCompilerArgs = ['-Xallow-kotlin-package']
}
}
But this only leads to MORE errors during the compileKotlin task, all looking like this one:
e: /path/to/my.module/src/main/kotlin/Foo.kt: (27, 30): Symbol is declared in module 'org.junit.jupiter.api' which current module does not depend on
And then if I try to force compileKotlin to take a module path rather than a classpath by adding "-Xmodule-path=${classpath.asPath}" to freeCompilerArgs and setting classpath to be empty, the Kotlin compiler can't find anything at all, and I end up with zillions of unresolved reference errors!
Why is the Kotlin compiler telling me I have to have requires kotlin.stdlib; when the Java compiler says the opposite? How can I get Kotlin and Java to work together to produce a Java 9 module?
If you're authoring Java 9 module in Kotlin, you have to declare requires kotlin.stdlib in your module-info.java in order to satisfy runtime dependencies of the compiled Kotlin code in addition to the explicit dependencies on the standard library API.
javac warns you about requiring an automatic module when lint is enabled, because automatic modules have some potential drawbacks compared to normal modules. Until the standard library is compiled as a normal module, you have to deal with this warning.
-Xallow-kotlin-package compiler flag allows you to omit require kotlin.stdlib, because it is intended to be used only when the standard library itself is compiled. Obviously, if you specify this flag and omit that requirement, you won't be able to use any API from the standard library, so this is not really an option for you.
I find it easiest to simply suppress the warnings for use of an automatic module. (In my case I have to use some automatic modules whether I want to or not, so these warnings are just distracting noise.) I have the following in my build.gradle.kts:
val compilerArgs = listOf(
"-Xlint:all", // Enable all warnings except...
"-Xlint:-requires-automatic", // Suppress "requires directive for an automatic module" warnings from module-info.java
"-Xlint:-requires-transitive-automatic" // Suppress "requires transitive directive for an automatic module" warnings from module-info.java
)
// This task will compile all Java code in the target module except for test code.
tasks.compileJava {
doFirst {
options.compilerArgs.addAll(compilerArgs)
}
}
// This task will compile all Java test code in the target module.
tasks.compileTestJava {
doFirst {
options.compilerArgs.addAll(compilerArgs)
}
}