I have my old codebase which currently uses java8.
I am migrating my codebase to use jdk9-ea. But it looks like all the sun.font classes are now not available like the way they used to be earlier
error: package sun.font does not exist
More specifically i am using
CompositeFont
Font2D
FontDesignMetrics
FontManager
FontManagerFactory
SunFontManager
and more..
A feature of the module system is that it allows library developers to strongly encapsulate implementation details due to the new accessibility rules. In a nutshell, most types in sun.* and com.sun.* packages will no longer be accessible. This is in line with Sun and later Oracle stating that these packages are not meant for public consumption.
A workaround is to export these packages at compile and launch time with a command line flag:
--add-exports java.desktop/sun.font=ALL-UNNAMED
This exports the package sun.font from the module java.desktop to all modules including the unnamed module, which is the one that collects all classes on the class path.
Related
I have a large multi module (100s) Java project and have been experimenting with adopting java module support. This is using Java 17 (temurin), gradle 7.6, and IntelliJ 2022.3.
I have hit a couple of stubborn errors with java modules where the module cannot be found.
I have one project which has some java code that uses plexus ie:
import org.codehaus.plexus.util.Base64;
...
byte[] encodedAuthorizationString = Base64.encodeBase64(authorizationString.getBytes(StandardCharsets.US_ASCII));
It has a gradle dependency
implementation 'org.codehaus.plexus:plexus-utils'
This has a version constraint in our main build.gradle (just salient lines included):
plexusVersion = '3.5.0'
implementation("org.codehaus.plexus:plexus-utils:${plexusVersion}")
Prior to adding module support this is working fine.
Now, with a module-info.java:
module egeria.open.metadata.implementation.adapters.open.connectors.rest.client.connectors.spring.rest.client.connector.main {
requires egeria.open.metadata.implementation.adapters.authentication.plugins.http.helper.main;
requires egeria.open.metadata.implementation.adapters.open.connectors.rest.client.connectors.rest.client.connectors.api.main;
//requires egeria.open.metadata.implementation.adapters.open.connectors.rest.client.connectors.rest.client.factory.main;
requires egeria.open.metadata.implementation.frameworks.open.connector.framework.main;
requires plexus.utils;
requires org.slf4j;
requires spring.core;
requires spring.web;
exports org.odpi.openmetadata.adapters.connectors.restclients.spring;
}
I am getting a compile error
Task ':open-metadata-implementation:adapters:open-connectors:rest-client-connectors:spring-rest-client-connector:compileJava' is not up-to-date because:
Task has failed previously.
The input changes require a full rebuild for incremental task ':open-metadata-implementation:adapters:open-connectors:rest-client-connectors:spring-rest-client-connector:compileJava'.
Full recompilation is required because no incremental change information is available. This is usually caused by clean builds or changing compiler arguments.
Compiling with toolchain '/Library/Java/JavaVirtualMachines/temurin-19.jdk/Contents/Home'.
Compiling with JDK Java compiler API.
/Users/jonesn/IdeaProjects/egeria/v4/open-metadata-implementation/adapters/open-connectors/rest-client-connectors/spring-rest-client-connector/src/main/java/module-info.java:6: error: module not found: plexus.utils
requires plexus.utils;
^
1 error
This is despite the fact, that having downloaded the jar file, the automatic module name looks to be what I am using ie:
jar --file=/Users/jonesn/Downloads/plexus-utils-3.5.0.jar --describe-module
No module descriptor found. Derived automatic module.
plexus.utils#3.5.0 automatic
requires java.base mandated
contains org.codehaus.plexus.util
contains org.codehaus.plexus.util.cli
contains org.codehaus.plexus.util.cli.shell
contains org.codehaus.plexus.util.dag
contains org.codehaus.plexus.util.introspection
contains org.codehaus.plexus.util.io
contains org.codehaus.plexus.util.reflection
contains org.codehaus.plexus.util.xml
contains org.codehaus.plexus.util.xml.pull
I am seeing the same error with kafka-clients
For most other code, including those libraries without full module support, all is good....
tried various compilers, such as openjdk 17 & temurin 19
built at cli & within IntelliJ
I was expecting this module to resolve ok
I have also reviewed Java 9 automatic modules not found but note that other automatic modules (including org.slf4j) are working just fine
I should add that I could refactor this code to use java.util.Base64 (probably makes sense)... but I'm still confused as to why the module error, which I also see in another project with 'kafka.clients'
In JDKs 9 and 10, there used to be a few modules such as java.xml.bind, containing Java EE classes. They were marked as deprecated and to be removed with the advent of JDK 9 and finally removed in 11 (see JEP 320). In a product I am contributing to, there used to be tests for the javac compiler option --add-modules, adding those modules as root modules. Those tests have been deactivated for JDK 11+. Instead of removing them, I would like to reactivate them, if there are any other JDK modules which are also non-root by default. The tests could then just use those modules instead.
I know I can just test --add-modules with my own modules, but then I have to specify them on the module path. The test case that an extra module path is not necessary for JDK modules added via --add-modules is also interesting, if any JDK 11+ modules still exist to be tested against. I am not talking about non-exported packages, but really about non-root JDK modules.
So, according to the information in this answer, I am actually looking for non-java.* modules among the system modules which do not export at least one package without qualification. In that case, those modules should not be root, and they would be eligible for my test case.
Update: What I am looking for is an equivalent for this in JDK 9:
import javax.xml.bind.JAXBContext;
public class UsesJAXB {
JAXBContext context;
}
xx> "C:\Program Files\Java\jdk-9.0.4\bin"\javac UsesJAXB.java
UsesJAXB.java:1: error: package javax.xml.bind is not visible
import javax.xml.bind.JAXBContext;
^
(package javax.xml.bind is declared in module java.xml.bind, which is not in the module graph)
1 error
xx> "C:\Program Files\Java\jdk-9.0.4\bin"\javac --add-modules java.xml.bind UsesJAXB.java
See? With --add-modules it builds, without it does not.
I am looking for modules (if any) in JDK 11-18, which would yield the same result when importing their classes in a simple program, i.e. require them to be explicitly added via --add-modules for compilation (not talking about runtime).
You can list all modules of the jdk with:
java --list-modules
Then you can print the module descriptors with:
java --describe-module a.module.name
After filterting these outputs in a little script, here are the modules of my JDK 17 than could qualify:
jdk.charsets
jdk.crypto.cryptoki
jdk.crypto.ec
jdk.editpad
jdk.internal.vm.compiler
jdk.internal.vm.compiler.management
jdk.jcmd
jdk.jdwp.agent
jdk.jlink
jdk.jpackage
jdk.localedata
jdk.zipfs
jdk.charsets, for instance, is a module providing a service.
Update after question update
So you are looking for a module that exports a package but is not in the default module graph when compiling a class in the unnamed module. According to the JEP, only java.* modules can qualify.
When I'm looking for modules required, either directly or indirectly, by java.se (which is a root module when it exists), I see all java.* modules of the JDK, but java.smartcardio. And due to some unknown magic, java.smartcardio is also in the default graph : I tried to compile a class importing one of its class and it works without --add-modules.
So I think you are down to using a non-java module exporting no package (like jdk.charsets), importing one of its class (like sun.nio.cs.ext.ExtendedCharsets) and either:
add --add-exports in addition to --add-modules when compiling your test class so that javac succeeds.
or parse the error message of javac and distinguish between "not in the module graph" and "not exported".
I am not sure if I got it right: java.base is the underlying base module from all other modules and contains all the base stuff from them, like a superclass from a class. And java.se is the module which contains the whole JDK, like a subclass (which contains the basic functionality and more specific stuff)
java.base is the base module; every other module implicitly or explicitly depends on it:
If the declaration of a module does not express a dependence on the java.base module [...] then the module has an implicitly declared dependence on the java.base module.
(Java Language Specification 17 ยง7.7.1)
java.se "defines the API of the Java SE Platform" (per documentation). It roughly (?) comprises all the classes which were present in Java SE before modularization, except being separated now in different modules, e.g. java.desktop or java.sql. It does not include JDK specific modules (such as jdk.javadoc). A Java runtime might not necessarily provide all of these modules; for example you could use jlink to create a Java runtime which only contains the modules you need (at the minimum java.base).
The Java API specification can also be helpful for understanding the content of modules and their relations:
java.base
java.se
Your comparison with a class (module java.base) and its subclass (module java.se) works in this case because java.se acts kind of like an 'aggregator' module which itself does not contain or export any packages but only has indirect exports through requires transitive. See this question for why the java.se module exists. Although normally you would not declare a dependency on java.se because that defeats the purpose of making custom small runtime images; instead you would only declare dependencies on the specific modules you really need, e.g. java.logging.
Such aggregator modules are rather uncommon though. In most cases modules will rather be used for grouping related packages, and restricting access to internal implementations. However, in these cases services defined by one module and the corresponding service provider being implemented and declared by another module are similar to your analogy.
I am getting an error as "The package java.util is accessible from more than one module: error" while importing file in java.
It seems like you messed things up in your module path. The error message indicates that you depend on multiple java modules that all export the java package java.util.
This is also called split package, as some classes in this package might be loaded from one module the others from another module.
With the new Java module system introduced with Java 9 this is strictly forbidden.
java.util should only be present in java.base module and nowhere else.
If you need further information, please tell us how you built and try to run your application.
I have a question concerning default packages in Java.
It is written in Java SE 8 specification:
An implementation of the Java SE platform must support at least one
unnamed package. An implementation may support more than one unnamed
package, but is not required to do so. Which compilation units are in
each unnamed package is determined by the host system.
see section 7.4.2 in the JLS.
I.e. it is possible to have more than one unnamed package.
As I understand Oracle implementation of Java 8 SE has only one unnamed package.
Do you know, is this feature is implemented somewhere?
Or do you have any idea how it could be implemented?
It looks like they leave the details of implementing the feature up to Java implementors.
But there is no any of such implementation yet.
Note:
Of cource we can have several source folders: src1, src2, ..., srcN but all of them share the same default package.
See, for example, https://docs.oracle.com/javase/tutorial/java/package/createpkgs.html