Java 9 no class definition exception - java

So i want to try the http client
package com.company;
import jdk.incubator.http.HttpClient;
public class Main {
public static void main(String[] args) {
HttpClient client = HttpClient.newHttpClient();
}
}
And my module info looks like this
module com.company {
requires jdk.incubator.httpclient;
}
But i get java.lang.NoClassDefFoundError: jdk/incubator/http/HttpClient
And I don't really understand why. My java version is "build 9-ea+ 169" and I use the latest version of IntelliJ idea (2017.1.3). I looked into this answer and it looks like I have to just add requirement into a file, but it doesn't work for some reason.

works fine for me if I use --add-modules jdk.incubator.httpclient as the start-up parameter.
HttpClient client = HttpClient.newHttpClient();
client.executor().execute(() -> System.out.println("Here")); // prints Here
If you say that your module requires it, does not mean it will be included; at it is not included by default.

Either you or IntelliJ must have made a mistake. You are using an incubator module, about which the documentation says:
Incubator modules are part of the JDK run-time image produced by the standard JDK build. However, incubator modules are not resolved by default for applications on the class path. Applications on the class path must use the --add-modules command-line option to request that an incubator module be resolved. Applications developed as modules can specify requires or requires transitive dependences upon an incubator module directly.
I just confirmed that behavior on java-9-ea+169, i.e. I can compile and launch such a module (from the command line) without additional flags.
The fact that you do not get a compile error seems to indicate that IntelliJ correctly includes the module declaration in the compilation. The fact that you get a run-time error and that this answer helped indicates that the JVM does not see the code you launch as a module.

I ran into the same problems
java.lang.NoClassDefFoundError: jdk/incubator/http/HttpClient
with java-9-ea+173 and IntelliJ. I followed Eugenes and Nicolais advice to add jdk.incubator.httpclient explicitly to the module path via --add-modules jdk.incubator.httpclient in Run/Debug Configurations (on macOS: Menu Bar -> Run -> Edit Configurations -> Configuration Tab -> VM Options -> --add-modules jdk.incubator.httpclient
After that everything worked fine. Of course you have to add the dependency into the module-info.java like this as said before:
module network {
requires jdk.incubator.httpclient;
}
UPDATE:
With the latest IntelliJ IDEA 2017.2 EAP 172.2953.9 , I don't need to put the --add-modules to the VM Options. It just works out of the box.

Related

JavaFX with Gradle error module not found

I'm creating a sample demo application with JavaFX in IntelliJ, but I need to use a library called the JavaFaker library. I'm using Gradle as the build system, but every time I try to add the library, either as the implementation in the build.gradle file, or via IntelliJ project structure options, the module.java file says error: module not found. I've already tried adding it to modules but nothing changes.
module-info.java
module com.example.demo1 {
requires javafx.controls;
requires javafx.fxml;
requires javafaker;
opens com.example.demo1 to javafx.fxml;
exports com.example.demo1;
}
build.gradle
plugins {
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.10'
id 'org.beryx.jlink' version '2.24.1'
}
group 'com.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
ext {
junitVersion = '5.8.2'
javaFakerVersion = '1.0.2'
}
sourceCompatibility = '17'
targetCompatibility = '17'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
application {
mainModule = 'com.example.demo1'
mainClass = 'com.example.demo1.HelloApplication'
}
javafx {
version = '17.0.1'
modules = ['javafx.controls', 'javafx.fxml']
}
dependencies {
implementation("com.github.javafaker:javafaker:${javaFakerVersion}")
testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
}
test {
useJUnitPlatform()
}
jlink {
imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip") as RegularFile
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
launcher {
name = 'app'
}
}
jlinkZip {
group = 'distribution'
}
error message
> Task :HelloApplication.main() FAILED
Error occurred during initialization of boot layer
java.lang.module.FindException: Module javafaker not found, required by com.example.demo1
I tried for a while to get this to work with Gradle but was unable to. I don't know Gradle well, but unless you do, I don't advise trying it.
Alternate option: use a static import
I didn't try this, but this is suggested in another answer.
Before you try this, see:
What's the difference between requires and requires static in module declaration
It is IMO, a bit of a hack in this usage case. This makes the module optional at runtime. But, if the module is on the classpath instead of the module path its code can still be used. More information quoted from the linked answer:
A requires static clause expresses a dependency that is optional at
run time. That means at compile time the module system behaves exactly
as described above.
At run time, on the other hand, it mostly ignores requires static
clauses. If it encounters one, it does not resolve it. That means, if
an observable module is only referenced with requires static, it does
not make it into the module graph!
Alternate option: Non-modular project
You can fix this issue by making your project non-modular:
Delete your module-info.java file.
Run your application with JavaFX modules on the module-path.
The org.openjfx.javafxplugin you are already doing will help achieve this by specifying the modules to be used.
To execute the application directly in the IDE rather than through Gradle, you will need to specify the module options to the VM for the IDE execution configuration (information on that is in the getting started documentation at openjfx.io).
For packaging, switch to using the badass-runtime-plugin rather than the badass-jlink-plugin. This will package the application via jpackage rather than jlink (which cannot package non-modular applications or applications with automatic modules).
In the application block of your build file, you no longer need to specify the module for your application as you no longer have one.
While that means that your application is no longer modular, in this case, in my opinion, this is not such a big loss. The dependencies you are using are not well-defined modules, so you can't use jlink to create a package for your application, and you don't have the level of modular encapsulation and definition you would normally receive for fully modular projects.
For more information, see the Getting started instructions at:
https://openjfx.io/openjfx-docs/
Under the sections "Non-Modular with Gradle" for your selected IDE.
Alternate option: Using Maven
It is easy to get this to work with Maven.
Create a new JavaFX project
Choose Maven as your build system instead of Gradle.
Add the javafaker dependency to your pom.xml.
<dependency>
<groupId>com.github.javafaker</groupId>
<artifactId>javafaker</artifactId>
<version>1.0.2</version>
</dependency>
Press the refresh icon in the Maven window to reimport the Maven project into the IDE.
Add the requires clause for the javafaker module into your module-info.java
requires javafaker;
Add the code to use javafaker to your app.
I don't have code to use javafaker, so I could not verify that the last step would work, but, give it a try . . .
Why you can receive this issue when using Gradle, but not Maven
Looking at the Gradle Documentation section "Using libraries that are not modules":
A third case are traditional libraries that provide no module information at all — for example commons-cli:commons-cli:1.4. Gradle puts such libraries on the classpath instead of the module path. The classpath is then treated as one module (the so called unnamed module) by Java.
This is the case with the javafaker dependency that you are using. It has no module-info.java and does not define the property Automatic-Module-Name in its manifest file (which are the other two cases in the section). Both the other cases result in Gradle putting the library on the module path, but the case you have means that it is on the class path.
This is a problem when you want to access the code from a named module that you define, which you have because you created a module-info.java.
Your module can only find code and resources of modules it requires (which need to be on the module path), so you add requires javafaker to the module-info.java, and get the following when you try to run through the IDE:
java.lang.module.FindException: Module javafaker not found, required by com.example.demo1
So you remove the requires javafaker from the module-info.java as advised by the Gradle documentation I linked and you get the following when you try to compile:
Package 'com.github.javafaker' is declared in module 'javafaker', but module 'com.example.demo1' does not read it
So you must place the library in the module-info to use it, but you can't place the library in module-info because Gradle puts in on the classpath -> catch-22.
There are workarounds to this such as providing VM arguments to allow access to the unnamed module (which is the classpath), or maybe modifying the module path handling of the Gradle build and/or IDE somehow (I don't know how), but they are pretty ugly.
On the other hand, for this case, Maven acts differently from Gradle, it places the dependent library on the module path, even if it does not have a module-info.java or Automatic-Module-Name defined. This means that it was (for me) much easier to set up and use.
Incidental advice on module naming
This is not an error, but note: Although module names with numbers in them are now allowed due to a change in the module system specification, it is probably best not to put numbers in module names to prevent the module name and version info being confused.
I've had a similar issue recently. Adding static to the requires statement helped however. Maybe this will fix your issue without having to switch to maven.
So you'd need to add: requires static javafaker;

Changed jdeps behavior in OpenJDK 11.0.11 (JDK-8214213)

Summary
Our build pipeline has been broken after some machines have updated from JDK 11.0.10- to JDK 11.0.11+. This happens due to changed jdeps behavior. After some research it became evident, this is likely due to changes introduced with JDK-8214213:
https://mail.openjdk.java.net/pipermail/jdk-updates-dev/2021-April/005860.html
Assuming we were retrieving dependencies for sentry-1.7.25.jar, then our usage of jdeps via CLI is as follows:
jdeps --list-deps -filter:module --multi-release=11 "..\somePath\sentry-1.7.25.jar
The resulting dependency lists look like this:
11.0.10 and below
java.base
java.logging
java.naming
11.0.11 and above
Error: Missing dependencies: classes not found from the module path and classpath.
To suppress this error, use --ignore-missing-deps to continue.
sentry-1.7.25.jar
io.sentry.event.helper.BasicRemoteAddressResolver -> javax.servlet.http.HttpServletRequest not found
io.sentry.event.helper.ForwardedAddressResolver -> javax.servlet.http.HttpServletRequest not found
io.sentry.event.helper.HttpEventBuilderHelper -> javax.servlet.http.HttpServletRequest not found
io.sentry.event.helper.RemoteAddressResolver -> javax.servlet.http.HttpServletRequest not found
io.sentry.event.interfaces.HttpInterface -> javax.servlet.http.Cookie not found
io.sentry.event.interfaces.HttpInterface -> javax.servlet.http.HttpServletRequest not found
io.sentry.servlet.SentryServletContainerInitializer -> javax.servlet.ServletContainerInitializer not found
io.sentry.servlet.SentryServletContainerInitializer -> javax.servlet.ServletContext not found
io.sentry.servlet.SentryServletContainerInitializer -> javax.servlet.ServletException not found
io.sentry.servlet.SentryServletRequestListener -> javax.servlet.ServletRequest not found
io.sentry.servlet.SentryServletRequestListener -> javax.servlet.ServletRequestEvent not found
io.sentry.servlet.SentryServletRequestListener -> javax.servlet.ServletRequestListener not found
io.sentry.servlet.SentryServletRequestListener -> javax.servlet.http.HttpServletRequest not found
In order to fix this on OpenJDK 11.0.11+ it's necessary to set --ignore-missing-deps when calling jdeps. If done, then the output again looks correct again:
java.base
java.logging
java.naming
Question
So I am able to produce the same output with jdeps using JDK 11.0.11+ as I was able to do with JDK 11.0.10-. That being said, this output is used to create a custom runtime and in the description of JDK-8214213 is explicitely stated:
Note that a
custom image is created with the list of modules output by jdeps when
using the --ignore-missing-deps option for a non-modular
application. Such an application, running on the custom image, might
fail at runtime when missing dependence errors are suppressed.
From my understanding this means that if there is a transitive dependency involved, where the dependency of a dependency requires a runtime module that is not required by any of the top level dependencies, then this can lead to a custom runtime uncapable of running the application, since the transitive dependency cannot be resolved. In other words, if my application requires dependency A, which requires dependency B and module C, but dependency B also requires module D, then my application is at risk of encountering runtime errors, since my custom runtime is not being provided with module D.
My question now is this, since I am unable to derive it from documentation:
With JDK 11.0.11+ I can only get the same dependency list output, if --ignore-missing-deps is used. Does that mean that...
...jdeps was able to resolve transitive dependencies prior to 11.0.11, but cannot do so anylonger above said version, e.g. because dependency analysis is done differently internally in jdeps?
...jdeps acted as if it was using --ignore-missing-deps prior to 11.0.11 by default, hence if the default changed, jdeps is now throwing an error on 11.0.11+?
...something else is going on?
The resulting dependency list might be the same, simply because there are a lot of libraries, so most modules are used either way. However I am trying to determine, whether
jdeps --list-deps -filter:module --multi-release=11 "..\somePath\sentry-1.7.25.jar (11.0.10)
and
jdeps --list-deps --ignore-missing-deps -filter:module --multi-release=11 "..\somePath\sentry-1.7.25.jar (11.0.11)
behave exactly the same, or whether using --ignore-missing-deps introduces a new risk when adding new libraries to our project, as they may at some point require a module that is not part of the current jdeps-list.
Bear in mind, to me this is rather a deep-dive into OpenJDK specifics, so if there is faulty terminoogy or problems with my understanding of these scenarios, then feel free to point out and correct them.

Error: JavaFX runtime components are missing, and are required to run this application - Analysis

Starting with badass-runtime-example-javafx which works for me, I copied this project and extended it with my own code. I created an image with gradlew runtime. When executing the generated .bat file on Windows, I get "Error: JavaFX runtime components are missing, and are required to run this application".
In build.gradle, I added an additional module javafx.fxml:
javafx {
modules = ['javafx.controls', 'javafx.fxml' ]
}
I also ran the suggestModules task and added the suggested modules to
runtime {
modules = ['java.naming', 'java.xml ...']
}
My question is how I can analyze which modules are missing from the Java runtime. I see that java.exe is executed only with -classpath (which includes the application jar) and the main class parameter.
Is java --list-modules the answer? I see there is a large file "modules" in build\image\lib which looks important to me.
I am looking for an analytical method of discovery to solve the problem.

No class def found for SOAPConnectionFactory

I am re-building an application from Java 8 in Java 9 (jdk 9.0.4), using modules. One of these modules requires making SOAP calls to our server to check if various services are running, and then reports back the status of those services via email.
I understand that the SOAP libraries have been deprecated in Java 9 but not removed yet. I have the java.xml.ws module declared as a requirement in the appropriate module-info:
module services {
exports com.nams.hyperion.services;
requires configurations;
requires java.xml.ws;
}
It compiles, but I get an error when I try running the project: java.lang.NoClassDefFoundError: javax/xml/soap/SOAPConnectionFactory
scf = SOAPConnectionFactory.newInstance(); <-- error here
conn = scf.createConnection();
mf = MessageFactory.newInstance();
msg = mf.createMessage();
I tried using the --add-modules java.xml.ws compiler option, but that doesn't resolve the problem; does my Java installation not have this module? What are my options? I've mucked around maven a bit looking for a separate distribution but haven't found anything yet.
I found a Maven distribution that I could use: https://search.maven.org/artifact/com.sun.xml.ws/rt-jdk9/2.3.0/jar
However, the module-info file gives me a warning that my module reads java.xml.ws from 2 identically named sources; but the project runs, which is all that matters to me at the moment. I'll work out how to deal with the ambiguity later and update this answer if I manage to do it.
Update:
I solved the ambiguity by removing the jar file from the module's dependencies, but retaining it in Maven's dependencies list.

Running a Gradle compiled Java application with dependencies via the java command

I’m trying to compile the Code Example 3 from this article explaining the Swing Application Framework (JSR 296) with Gradle and to run it from the command line with the java command.
My directory layout looks like this:
├── build.gradle
└── src/
└── main/
└── java/
└── demo/
└── BasicSingleFrameApp.java
The build.gradle file defines a dependency to the appframework:
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile 'org.jdesktop:appframework:1.0.3'
}
And this is the BasicSingleFrameApp.java file, a copy of the example of the article mentioned above, enhanced by a package declaration:
package demo;
import org.jdesktop.application.*;
import javax.swing.*;
import java.awt.*;
public class BasicSingleFrameApp extends SingleFrameApplication {
JLabel label;
#Override
protected void startup() {
getMainFrame().setTitle("BasicSingleFrameApp");
label = new JLabel("Hello, world!");
label.setFont(new Font("SansSerif", Font.PLAIN, 22));
show(label);
}
public static void main(String[] args) {
Application.launch(BasicSingleFrameApp.class, args);
}
}
Compiling with gradle build works fine and without errors.
But when I then try to run the BasicSingleFrameApp with
$ java -cp build/classes/main/ demo.BasicSingleFrameApp
I get the error message:
Error: Could not find or load main class demo.BasicSingleFrameApp
When I replace the BasicSingleFrameApp class with a simple “Hello, world!” printing class without dependencies, everything works fine.
I’m confused, because in my understanding I correctly set up the classpath and I don’t understand why the main method (which has the right signature) cannot be found.
This is my Java version:
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
which I am running an Mac OS X Yosemite 10.10.2.
OK, so #chuchikaeschtli helped me to get to the core of the problem, namely that Gradle manages dependencies for compiling and reports to do so for runtime, but more manual tasks are required to make these dependencies available during runtime.
What still confuses me is the unintuitive error message I got:
Error: Could not find or load main class demo.BasicSingleFrameApp
I would have expected a problem that has to do with missing dependencies at runtime to report an error like
error: package org.jdesktop.application does not exist
which is the kind of error I get when these dependencies are missing at compile time.
And as Gradle gave me the following report about runtime dependencies (by running gradle dependencies) I thought that Gradle somehow manages these:
compile - Compile classpath for source set 'main'.
\--- org.jdesktop:appframework:1.0.3
\--- org.jdesktop:swing-worker:1.1
…
runtime - Runtime classpath for source set 'main'.
\--- org.jdesktop:appframework:1.0.3
\--- org.jdesktop:swing-worker:1.1
…
In the end, after knowing that it is a problem of missing runtime dependencies I found several ways to provide them, which I will share.
First solution: Linking to the cache
As stated in this Stackoverflow answer Gradle caches dependencies in $HOME/.gradle, but the actual path to them is tricky. The answer describes a small Gradle task that outputs the full path of each dependency in the cache (in this example for the compile configuration, which is what I need):
task showMeCache << {
configurations.compile.each { println it }
}
In my case gradle showMeCache reports:
$HOME/.gradle/caches/modules-2/files-2.1/org.jdesktop/appframework/1.0.3/338045feff6e61df237aafd11b6f3fe1a3b4e60e/appframework-1.0.3.jar
$HOME/.gradle/caches/modules-2/files-2.1/org.jdesktop/swing-worker/1.1/dc9f8d6f7236087924aad28fbec794a087dd1b3d/swing-worker-1.1.jar
These are long and nasty file paths, but I’m able to construct a java command that works in the style #chuchikaeschtli suggested:
java \
-cp build/classes/main/\
:$HOME/.gradle/caches/modules-2/files-2.1/org.jdesktop/appframework/1.0.3/338045feff6e61df237aafd11b6f3fe1a3b4e60e/appframework-1.0.3.jar\
:$HOME/.gradle/caches/modules-2/files-2.1/org.jdesktop/swing-worker/1.1/dc9f8d6f7236087924aad28fbec794a087dd1b3d/swing-worker-1.1.jar \
demo.BasicSingleFrameApp
This works, but of course this does not feel very “right”. But it helps to understand the problem: it was really a matter of missing dependency jars.
Second solution: Syncing dependencies to the build directory
In the section Using the Sync task of the Gradle User Guide it explicitly uses an example that describes a better solution to the problem at hand:
Here is an example which maintains a copy of the project's runtime dependencies in the build/libs directory.
task libs(type: Sync) {
from configurations.runtime
into "$buildDir/libs"
}
After running this task with gradle libs I’m able to construct a much simpler working java command:
java -cp build/classes/main/:build/libs/appframework-1.0.3.jar:build/libs/swing-worker-1.1.jar demo.BasicSingleFrameApp
Remember: these dependencies haven’t been synced into the build directory by default!
Third solution: Using Gradle to run the application
With the Application Plugin Gradle itself provides a convenient solution to running an application. After adding these two lines to my build.gradle
apply plugin:'application'
mainClassName = 'demo.BasicSingleFrameApp'
I was able to succesfully start the application with just gradle run. Simplest solution so far!
Note that the application plugin also delivers a task named installDist that within build/install creates a runnable distribution of the app and all its dependencies, complete with start scripts for UNIX and Windows systems. This has the advantage that Gradle is not needed for execution of the application.
Also, if you like the gradle run task of the Application Plugin but are concerned about whether Gradle is available at the target system, have a look at the Gradle Wrapper.
Fourth solution: Creating a One-JAR, Fat Jar, or Uber Jar
There seem to exist Gradle-only ways and Gradle plugins that help with the creation of these jars that include all of the required dependencies for the application.
In the case of the gradle-one-jar-Plugin the application can then be started with a java command like:
java -jar build/libs/YOUR_APP_NAME-standalone.jar
from what I get is that you are starting the app just using java so you have to tell java where to find the swing application framework jar you downloaded. so the command should look something like
java -cp pathtojdektopjar/jdesktopjar.jar;build/classes/main/ demo.BasicSingleFrameApp

Categories

Resources