8

I am trying to use the HttpClient from incubator in Java 9 maven project. I am not getting any Compilation issue. The project builds successfully. But when I try to run the Main class, it gives me the following exception:

Exception in thread "main" java.lang.NoClassDefFoundError: jdk/incubator/http/HttpClient
at java9.http_client.Main.main(Main.java:18)
Caused by: java.lang.ClassNotFoundException: jdk.incubator.http.HttpClient
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)....

My code is just a module-info file and a Main class that just calls google.com and tries to read the response:

module-info.java

module java9.http_client {   
    requires jdk.incubator.httpclient;
}

Main.java

public final class Main {

public static void main(String[] args) {
 try {
        HttpClient client = HttpClient.newHttpClient();
        URI httpURI = new URI("http://www.google.com/");
        HttpRequest request = HttpRequest.newBuilder(httpURI).GET().build();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandler.asString());

        String responseBody = response.body();
        int responseStatusCode = response.statusCode();
        System.out.println(responseBody + "\n" + responseStatusCode);

    } catch (URISyntaxException | IOException | InterruptedException e) {
        throw new RuntimeException("Unable to run Java 9 Http Client examples", e);
    }
}
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javacodegeeks.java9</groupId>
<artifactId>http_client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Java9HttpClient</name>
<description>Java Http Client example</description>
<properties>
    <java-version>1.9</java-version>

    <maven-compiler-plugin-version>3.6.1</maven-compiler-plugin-version>
    <maven-shade-plugin-version>3.0.0</maven-shade-plugin-version>
</properties>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-compiler-plugin-version}</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>${maven-shade-plugin-version}</version>
            </plugin>
        </plugins>
    </pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>${java-version}</source>
                <target>${java-version}</target>
                <verbose>true</verbose>

            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <transformers>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <mainClass>com.javacodegeeks.java9.http_client.Main</mainClass>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

What am I missing? I found various articles about this but they are all doing it in this way.

Any help is appreicated. Thanks!

Command executed when using --add-modules

cd /home/mansi/NetBeansProjects/java9-http-client; JAVA_HOME=/home/mansi/jdk-9 /home/mansi/netbeans-dev-201709070001/java/maven/bin/mvn "-Dexec.args=--add-modules=jdk.incubator.httpclient -classpath %classpath java9.http_client.Main" -Dexec.executable=/home/mansi/jdk-9/bin/java -Dexec.classpathScope=runtime org.codehaus.mojo:exec-maven-plugin:1.5.0:exec

When not using --add-modules

cd /home/mansi/NetBeansProjects/java9-http-client; JAVA_HOME=/home/mansi/jdk-9 /home/mansi/netbeans-dev-201709070001/java/maven/bin/mvn "-Dexec.args=-classpath %classpath java9.http_client.Main" -Dexec.executable=/home/mansi/jdk-9/bin/java -Dexec.classpathScope=runtime org.codehaus.mojo:exec-maven-plugin:1.5.0:exec
Mani
  • 1,068
  • 3
  • 13
  • 27
parth karia
  • 230
  • 2
  • 7
  • Yes, the one linked above has the solution for Compilation Error, but I am not getting any Compilation issue. The project builds successfully. But when I try to run the `Main` class, it gives me the mentioned exception – parth karia Nov 24 '17 at 06:47
  • I run the `Main` class, just right click and run file. And yes I saw the answer in another link you mentioned, as per your answer, using `--add-modules` is an alternative to using `module-info.java` isn't it? – parth karia Nov 24 '17 at 06:51
  • While you run the Main class, make sure to add VM arguments `--add-modules jdk.incubator.httpclient`. – Naman Nov 24 '17 at 06:52
  • That works! Thanks a lot. Is it mandatory to use this VM options? Is there a way without using it? – parth karia Nov 24 '17 at 06:58
  • 1
    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. from http://openjdk.java.net/jeps/11 – Naman Nov 24 '17 at 07:00
  • I actually thought it was possible without using --add-modules, looking at this answer https://stackoverflow.com/a/44049826/4894142 – parth karia Nov 24 '17 at 07:02
  • If you are using an IDE like IntelliJ to Run the main class. It generally prints the java command used to execute to the console. Could you share the complete command executed in the edit to the question? – Naman Nov 24 '17 at 07:07
  • Added the commands – parth karia Nov 24 '17 at 07:14
  • Have moved the explanation to [an answer](https://stackoverflow.com/a/47468106/1746118), just notice the difference in using the classpath vs modulepath during execution. Retracted the vote, since the previous answers I made didn't specify the different ways of executing(cp vs mp) and maybe the question could be worded specifically in terms of runtime failure as well. (or precisely [this being the question](https://stackoverflow.com/questions/47467663/java-9-httpclient-java-lang-noclassdeffounderror-jdk-incubator-http-httpclient#comment81890148_47467663)) – Naman Nov 24 '17 at 07:31

2 Answers2

12

The difference during the execution is using the classpath vs the modulepath. The statement in the JEP11#Incubator Modules to notice is as

... incubator modules are not resolved by default for applications on the class path.

so in order to execute the code using the classpath

Applications on the class path must use the --add-modules command-line option to request that an incubator module be resolved.


If you want to execute without using the --add-modules option, while creating a new module and trying to execute the Main class make sure the java command executed using the module path using the arguments :

-p or --module-path <module path>

Searches for directories from a semicolon-separated (;) list of directories. Each directory is a directory of modules.

-m or --module <module>/<mainclass

Specifies the name of the initial module to resolve and, if it isn’t specified by the module, then specifies the name of the mainclass to execute.

The complete command would be something (e.g.) like :

.../jdk-9.0.1.jdk/Contents/Home/bin/java 
       -p .../jdk9-httpincubate-maven/target/classes 
       -m jdk.httpincubate.maven/http2.Main

Note:

  • The above directory structure is followed in the sample project that I have created on GitHub to replicate the same as well.

  • Just to add to it and without any publicisizing I am using 2017.3 EAP of intelliJ and it lets me Run the Main class without the VM arguments as well (using the command including the arguments as shared above.)

user1803551
  • 12,965
  • 5
  • 47
  • 74
Naman
  • 27,789
  • 26
  • 218
  • 353
  • Question: if I demand Incubator module resolution at compilation time via the `--add-modules` argument, why are these modules not included in a WAR/JAR that results from the compilation/packaging? I would think that the compiled code has the modules resolved, so their classes are included, and I don't need to hack my appserver to add the same argument as well... – Zalán Meggyesi Jul 20 '18 at 19:22
  • 1
    @ZalánMeggyesi *why are these modules not included in a WAR/JAR that results from the compilation/packaging?* ... to answer that, none of the modules from the JDK would be included in the JAR that you create... the execution would rely on the JDK/JRE you would use to launch the application and hence the resolution of the modules as per that specifically.. for what I can suggest about using the HTTP module, you can wait and migrate to JDK11(also an LTS release) and then make use of [the standardized HTTP module](https://stackoverflow.com/questions/50122696) itself. – Naman Jul 20 '18 at 20:31
  • Thanks for clearing that up for me! Honestly, I just found it strange that even a shaded JAR is lacking these modules, but since the appserver in this specific case is a standalone Jetty under my control, hacking it is an absolutely viable possibility, though a bit of a stretch. The application is pretty much a testbed for me, so I _will_ jump to JDK11 as well. – Zalán Meggyesi Jul 20 '18 at 20:54
0

If the accepted answer still did not work for you then..

The missing secret is to also include the maven-surefire-plugin with the same compiler arg.

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>10</source>
                    <target>10</target>
                    <compilerArgument>--add-modules=jdk.incubator.httpclient</compilerArgument>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.21.0</version>
                <configuration>
                    <argLine>--add-modules=jdk.incubator.httpclient</argLine>
                </configuration>
            </plugin>
        </plugins>
    </build>
reversebind
  • 1,216
  • 1
  • 14
  • 18