Use jdk.internal.net.http - java

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?

Related

Are non-exported packages still accessible from the unnamed module?

I am trying to restrict access to a package in my Java application using module-info.java.
For the sake of simplicity, lets say I have the packages org.test.a, org.test.b and this module-info.class:
module test {
exports org.test.a;
}
I then compile that, install the artifact to my local repository and import it in a second project.
There, I am still able to access classes of both packages org.test.a and org.test.b, even though only org.test.a should be accessible.
Only when I modularize that project (by adding a module-info.java that requires the test module), I can no longer compile it:
java: package org.test.b is not visible
(package org.test.b is declared in module test, which does not export it)
Is it not possible to restrict package access to applications that are part of the "unnamed module", or am I just doing something wrong?
I am a bit confused, because even as part of the unnamed module, I am not able to access classes of unexported packages from the jdk (such as jdk.internal.misc.Unsafe).

How to force using a jar as an automatic module, without editing it?

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?

Package is accessible from more than one module in JDK 11 Module system

We are making use of Zulu JDK 11 and we are facing issue The package com.sample.test is accessible from more than one module: test1.module, test2.sample.
Below is the git url for sample project and screenshot for your reference.
https://github.com/kkvaranasi88/test1.git
A simple solution is to rename the package in your second module tes-2 to say com.sample.another.test and then update your module description to
module test2.sample {
exports com.sample.another.test;
requires transitive test1.module;
}
and things shall work fine.
Having said that, the cause for failure is that no two modules should export the same package such that they are both resolved in the module layer as s conflict.

java jigsaw extend jar library

I am trying to separate a project of mine into Jigsaw Modules. One pain point has been to use .jar libraries in multiple modules and extend their functionality in some of them.
To be more concrete, I am using minimal-json-0.9.1.jar via "requires transitive minimal.json" in a module-info.java file and I set the module to be on the modulepath in eclipse.
I then created this interface:
import com.eclipsesource.json.JsonObject;
public interface JsonSerializable {
JsonObject toJson();
}
Note that JsonObject comes from the minimal.json library.
Now I get a warning message in eclipse: "The type JsonObject is not exported from this module". How can I get rid of it?
Suggestion: Do not transitively rely on an automatic-module and change your module-descriptor to make use of
requires minimal.json;
Explanation: While including the transitive modifier, an implied readability is expressed by the requires clause. This means that any module that depends upon your module [requires your.module] will also be able to read the minimal.json module.
The warning from eclipse seems to be highlighting the same point that the use of JsonObject in any further module that requires your module would not be because your module have explicitly exported [exports some.package;] the package including the class, rather because of the transitive dependency.

Why Java 9 does not simply turn all JARs on the class path into automatic modules?

In order to understand the categories we have:
platform explicit modules
application explicit modules
open modules
automatic modules
unnamed module
All classes and jars within the classpath will be part of the unnamed module. But why is that what we need? Where is the advantage over automatic modules? I could "require" those damn legacy jars to make them to an automatic module. Do I not have included everything with it?
There are at least two reasons:
Just as regular modules, automatic ones are suspect to certain examinations by the module system, e.g. not splitting packages. Since JARs on the class path can (and occasionally do) split packages, imposing that check on them would be backwards-incompatible and break a number of applications.
The unnamed module can read all platform modules, whereas automatic modules can only read those that made it into the module graph. That means a JAR needing the java.desktop module (for example) will work from the class path but not from the module graph unless java.desktop also makes it into the graph (via a dependency or --add-modules).
I have no time right now to check the second but that's what the State of the Module system says:
After a module graph is resolved, therefore, an automatic module is made to read every other named module, whether automatic or explicit
Resolution works on the declared dependencies and an automatic modules declares none.
Apart from the items listed in the accepted answer, there is one more difference: unnamed modules can access all packages of modules that come with Java, even is they are not exported.
As long the class is public, access will work - the same as before Java 9. But as soon as a jar is run from module path, it will be able to access only exported packages.
For example if some .jar has this code:
com.sun.jmx.remote.internal.ArrayQueue c = new com.sun.jmx.remote.internal.ArrayQueue(10);
it will run normally without any warnings when placed on class path, but when run from module path (as automatic module) it will fail at runtime:
Exception in thread "main" java.lang.IllegalAccessError: class test1.C
(in module test1) cannot access class com.sun.jmx.remote.internal.ArrayQueue
(in module java.management) because module java.management does not export
com.sun.jmx.remote.internal to module test1
Note that this is different from the well known illegal reflective access warning, which is about using reflection to access private fields or methods. Here we are statically (non-reflectively) accessing public class (but from non-exported package).

Categories