While moving a project to Gradle, I stopped using my custom build of org.json which had a module-info.java fitted to it to comply to the module system. Now, I am using it via Maven normally, and as org.json is not a module by default, it gets put into the unnamed module.
My module-info looks like this:
open module mymodule {
requires java.desktop;
requires java.logging;
}
I am getting the error:
SomeSourceFile.java: error: package org.json is not visible
import org.json.*;
^
(package org.json is declared in the unnamed module, but module mymodule does not read it)
This is logical, except I don't know why my module doesn't read the unnamed module (the purpose of the unnamed module is full backwards compatibility with non-modular software so all packages are exported etc.), and how I could make my module read the unnamed module. As you can see, I have already tried making my module open to no avail.
Probably updating the Maven Compiler Plugin (to 3.8.1, for instance) will do the trick.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins>
</build>
The other thing will be to require the JSON module. From their pom.xml, I can see that they declare the Automatic-Module-Name as org.json (https://github.com/stleary/JSON-java/blob/master/pom.xml#L186)
So your module-info.java will become like this:
open module mymodule {
requires java.desktop;
requires java.logging;
requires org.json;
}
Related
I am trying to create a modular Spring Boot sample using JMPS which introduced in Java 9.
Currently, I created a standalone Maven module for the testing work.
module greeting.webapp.test {
requires greeting.webapp;
requires spring.test;
requires spring.boot;
requires spring.web;
requires spring.boot.starter.webflux;
requires spring.boot.starter.test;
requires spring.boot.test;
requires spring.boot.test.autoconfigure;
requires org.junit.jupiter;
requires org.junit.jupiter.api;
requires org.junit.jupiter.params;
requires org.junit.jupiter.engine;
requires org.junit.platform.commons;
requires org.assertj.core;
requires mockito.junit.jupiter;
}
And when run the sample test, I got the following errors.
Exception in thread "main" java.lang.IllegalAccessError: class org.junit.platform.launcher.TestIdentifier (in unnamed module #0x6325a3ee) cannot access class org.junit.platform.commons.util.Preconditions (in module org.junit.platform.commons) because module org.junit.platform.commons does not export org.junit.platform.commons.util to unnamed module #0x6325a3ee
at org.junit.platform.launcher.TestIdentifier.from(TestIdentifier.java:56)
at com.intellij.junit5.JUnit5IdeaTestRunner.<clinit>(JUnit5IdeaTestRunner.java:86)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:377)
at com.intellij.rt.junit.JUnitStarter.getAgentClass(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:210)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
And in the test module, I have to move the test scoped deps to compile time to make it work in jmps, how to resolve this issue?
There is no easy way, or no good way at all, imho.
The problem you are having is that you have not configured maven surefire correctly. You can try that - I did and somehow was unlucky, but I did not invest too much time in making it work (neither do I think that will work, but that is a different problem). Instead I configured surefire plugin manually, via:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<argLine>
--add-exports org.junit.platform.commons/org.junit.platform.commons.util=ALL-UNNAMED
--add-exports org.junit.platform.commons/org.junit.platform.commons.logging=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
Overall, I like gradle approach more. You can read on my experience with it here. I also don't think that IDEs (Intellij in my case) have yet proper support to run a single (maven based project) test, unlike gradle. But, to be fair, I only tried that against your repo, so far...
You can also read about a rather neat approach that gradle has taken when you need to declare modules here, with their dedicated plugin.
I've got a class that uses jdk.internal.misc.Signal.
In module-info.java there is requires jdk.unsupported.
If I try to compile this I get:
[ERROR] MyClass.java:[28,20] package jdk.internal.misc is not visible
[ERROR] (package jdk.internal.misc is declared in module java.base, which does not export it to module MyModule)
Then if I add <arg>--add-exports</arg><arg>java.base/jdk.internal.misc=MyModule</arg>
to maven-compiler-plugin:3.8.1 I get:
[ERROR] exporting a package from system module java.base is not allowed with --release
Then if I remove <release>11</release> I get:
Fatal error compiling: warning: source release 11 requires target release 11
I've the feeling that I'm missing something important or maybe it is just a bug?
I'm using maven 3.6.3 and openjdk 11.0.2.
jdk.internal.misc.Signal is in java.base module. If you take a look inside its module-info.java file you will notice this:
exports jdk.internal.misc to
(...)
jdk.unsupported;
However jdk.unsupported contains sun.misc.Signal which is the original pre-Java 9 class for handling signals.
In general usage of classes in .internal. packages is a bad practice because they are not part of public API.
Instead I would suggest to use sun.misc.Signal with requires jdk.unsupported module clause until there is a #Deprecated annotation with information which API should be used instead.
BTW. This is a great example how JPMS helps with hiding internal implementation details of a library (in this case JDK) from un/intended usage.
fixed by changing <release>11</release> into <target>11</target> in my pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
When I compile my Spring Boot application in Java 9, it fails after a couple of messages such as this one:
package com.fasterxml.jackson.annotation is not visible
(package com.fasterxml.jackson.annotation is declared in the unnamed module, but module com.fasterxml.jackson.annotation does not read it)
Can someone tell me what is going on here? As I understand it, any pre-Java 9 code not in a Java-9 module will be part of the unnamed module where anything is exposed.
I'm using this as an annotation like this in my module:
#JsonIgnore
public Week getNextWeek()
{
Calendar instance = this.getFirstDay();
instance.set(Calendar.WEEK_OF_YEAR, this.week + 1);
return new Week(instance);
}
So if this is the case with the com.fasterxml.jackson.annotation package, why is the error referring to a module with that name, and why is it a problem that it does not read it?
Quoting from the JigSaw Spec:
The unnamed module exports all of its packages. This enables flexible migration, as we shall see below. It does not, however, mean that code in a named module can access types in the unnamed module. A named module cannot, in fact, even declare a dependence upon the unnamed module.
What you're looking for are Automatic Modules. In automatic modules, a jar can be placed on the module path and will automatically derive the module name from the jar itself. In case you're using Maven, that should be the artifactId.
As such, if you are using jackson-annotations in maven as following:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.0.0</version>
</dependency>
You'd still require to define it inside your module-info.java:
module example {
requires jackson.annotations;
}
After that, you're free to use the annotations within your module.
I've tried to "upgrade" a project using Hibernate to Java 9, but I am having problems getting the module to function properly.
The relevant part of my module-info.java looks like this:
module test {
...
requires java.base;
requires hibernate.core;
requires javax.transaction;
requires java.sql;
}
and the relevant dependencies in my POM are
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec, 2.0.0.Alpha1
org.hibernate:hibernate-core, 5.2.12.Final
javax.transaction:javax.transaction-api, 1.2
The problem is, if I run the program, I get a NoClassDefFoundError for javax.transaction.SystemException. I looked into this, and quite obviously, my module is missing a requires on javax.transaction.
So I add a module dependency on javax.transaction-api. I then go on and attempt to run the program again - now I'm missing java.sql.SQLException.
Here is what I am having a problem with: if I add a dependency on the module java.sql, which contains this class, I end up with a conflict:
module reads package javax.transaction.xa from both java.sql and javax.transaction.api
java.sql and javax.transaction.api contain different packages, and have one in common (javax.transaction.xa), but I require all of them.
How do I deal with this? Is there something simple I am missing?
Use version 1.3 instead of 1.2 of javax.transaction-api, in this version javax.transaction.xa has been removed.
Maven dependency:
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<version>1.3</version>
</dependency>
I have a multi-module maven project with three modules core, utils and test-utils
Core has the following dependencies definition
<dependency>
<groupId>my.project</groupId>
<artifactId>utils</artifactId>
</dependency>
<dependency>
<groupId>my.project</groupId>
<artifactId>test-utils</artifactId>
<scope>test</scope>
</dependency>
I have added Java 9 module-info.java definitions for all three modules and core's looks like this:
module my.project.core {
requires my.project.utils;
}
However I cannot figure out how to get core's test classes to be able to see the test-utils classes during test execution. When maven-surefire-plugin attempts the test run I get class not found.
If I add a requires my.project.testutils; to core's module-info.java:
module my.project.core {
requires my.project.utils;
requires my.project.testutils; //test dependency
}
Then at compile time I get an error that the my.project.testutils module can't be found (presumably because it's only brought in as a test dependency).
How does one work with test dependencies in a Java 9 modular world? For obvious reason's I don't want my main code to pull in test dependencies. Am I missing something?
With maven and java9, if your my.project.testutils is a test scope dependency, you don't need to explicitly include(requires) it in the module descriptor.
The test dependencies are taken care via the classpath itself. So you can simply remove the testutils and it would be patched by maven while executing tests.
module my.project.core {
requires my.project.utils;
}
Refer to the slide 30 pertaining to maven-compiler-plugin.
I would also suggest you take a look at Where should I put unit tests when migrating a Java 8 project to Jigsaw and this comment by Robert confirming on the implementation that maven follows.
Edit: Created a sample project drawing an analogy that the main module is same as your core, the dependency on guava is same as your utils and the junit dependency is same as your testutils.