NoClassDefFoundError at Runtime with Gradle
Asked Answered
K

3

25

I'm using gradle as the JavaFX plugin. Everything works perfectly even after building and runnig the excecutable at distribution/, except with one class: CloseableHttpClient

For several purposes I create the following object like this:

CloseableHttpClient client = HttpClients.createDefault();

Running the program in the IDE is no problem, everything works fine. But if I build and try to run the .exe-File I get the following Throwable-StackTrace:

java.lang.NoClassDefFoundError: Could not initialize class org.apache.http.conn.ssl.SSLConnectionSocketFactory
    at org.apache.http.impl.client.HttpClientBuilder.build(HttpClientBuilder.java:955)
    at org.apache.http.impl.client.HttpClients.createDefault(HttpClients.java:58)
    at ch.itcb.tools.lom.util.JsonSimpleUtil.http(JsonSimpleUtil.java:29)...

I really don't understand that. How can it be that just this class doesn't get found, but all my other classes do?

My build.gradle file:

apply plugin: 'java'
apply plugin: 'eclipse'
apply from: 'javafx.plugin'

sourceCompatibility = 1.8
version = '0.1'

jar {
    manifest {
        attributes 'Implementation-Title': 'LogoffManager',
                   'Implementation-Version': version
    }
}

repositories {
    mavenCentral()
}

dependencies {
    compile fileTree(dir: 'lib', include: ['*.jar'])

    compile 'ch.qos.logback:logback-classic:1.1.3'

    compile 'org.apache.httpcomponents:httpclient:4.5.1'

    compile 'com.googlecode.json-simple:json-simple:1.1'



    compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
    testCompile group: 'junit', name: 'junit', version: '4.+'
}

test {
    systemProperties 'property': 'value'
}

uploadArchives {
    repositories {
       flatDir {
           dirs 'repos'
       }
    }
}

Please write a comment if you need more information. Thx.

Kaitlinkaitlyn answered 13/10, 2015 at 15:21 Comment(6)
Please share your build.gradle file.Tabitha
@Tabitha done. still found no solution :/Kaitlinkaitlyn
Is the apache jar in the distribution? Does it contain the missing class?Doughnut
@JensSchauder yes it does. can't believe it by myself.Kaitlinkaitlyn
No further help? Struggling still with the same problem..Kaitlinkaitlyn
Did you find a solution? would you share it? tnksCauseuse
Q
32

it's a good question, which I came across just now while researching examples of the many ways Java developers can end up with class path fun :-)

I started with a minimal version of your build.gradle (including only what's directly relevant), specifically:

plugins {
    id 'java'
}
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

jar {
    manifest {
        attributes 'Main-Class': 'com.oliverlockwood.Main'
    }
}

dependencies {
    compile 'org.apache.httpcomponents:httpclient:4.5.1'
}

My 'Main' class, in this context, uses your code example, i.e.:

package com.oliverlockwood;

import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

public class Main {
    public static void main(String[] args) {
        CloseableHttpClient client = HttpClients.createDefault();
    }
}

At this stage, I can run gradle clean build followed by java -jar build/libs/33106520.jar (my project was named after this StackOverflow question) and I see this:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/impl/client/HttpClients
    at com.oliverlockwood.Main.main(Main.java:8)
Caused by: java.lang.ClassNotFoundException: org.apache.http.impl.client.HttpClients
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

This is subtly different from your error, but before we dig and reproduce that, let me emphasise something: both this error and the one you're seeing are caused at runtime when the classloader is unable to find a class that it needs. There's quite a good blog post here with some more details about the difference between compile-time classpath and runtime classpaths.

If I run gradle dependencies I can see the runtime dependencies for my project:

runtime - Runtime classpath for source set 'main'.
\--- org.apache.httpcomponents:httpclient:4.5.1
     +--- org.apache.httpcomponents:httpcore:4.4.3
     +--- commons-logging:commons-logging:1.2
     \--- commons-codec:commons-codec:1.9

I added these manually one-by-one to my runtime classpath. (For the record, this isn't generally considered good practice; but for the sake of the experiment, I copied these jars to my build/libs folder and ran with java -cp build/libs/33106520.jar:build/libs/* com.oliverlockwood.Main. Interestingly enough, this wasn't able to reproduce your exact problem. To recap:

  • Without org.apache.httpcomponents:httpclient available at runtime, then we fail because the HttpClients jar is not found.
  • With org.apache.httpcomponents:httpclient:4.5.1 available at runtime, then your problem does not manifest - and I note that the class your build fails to find (org.apache.http.conn.ssl.SSLConnectionSocketFactory) is part of this same Apache library, which is very suspicious indeed.

My suspicion is then that your runtime classpath contains a different version of the Apache httpclient library. Since there's a whole lotta versions out there, I'm not going to test every single combination, so I will instead leave you with the following advice.

  1. If you want to fully understand the root cause of your issue, then identify exactly which jars (including their versions) are present in your error-case runtime classpath, including any jars that are packaged inside yours if you're creating a fat jar (more on this in point 3). It'd be great if you shared these details here; root cause analysis usually helps everyone to understand better :-)
  2. Where possible, avoid using dependencies in the manner of compile fileTree(dir: 'lib', include: ['*.jar']). Managed dependencies based on a repository such as Maven or JCenter are much easier to work with consistently than dependencies in a random directory. If these are internal libraries that you don't want to publish to an open-source artifact repository, then it may be worth setting up a local Nexus instance or similar.
  3. Consider producing a "fat jar" instead of a "thin jar" - this means that all runtime dependencies are packaged in the jar that you build. There's a good Shadow plugin for Gradle that I'd recommend - with this in place in my build.gradle, and running gradle clean shadow, I was able to run java -jar just fine without needing to manually add anything to my classpath.
Quincy answered 9/2, 2016 at 23:10 Comment(4)
I got java.lang.NoClassDefFoundError: org/apache/http/config/Lookup. I kept looking for presence of this class inside Apache Http JARs (httpclient, httpcore) under Maven Dependencies in Eclipse and did not find them. Realized that maven chose to resolve some other version of httpcore from parent POM instead of httpcore version which is a direct dependency of httpclient.Had to give an explicit httpcore version which matches the same version as that of version of direct dependency of httpclient.Guarani
At recent gradle versions, gradle dependencies produces a message: A web-based, searchable dependency report is available by adding the --scan option. And gradle build --scan produces a publically browsable report with deps that you can delete when completed.Jillane
Thank you for the hint on deps - I have a cosmo zoo of versions causing NoClassDef*.Jillane
Switching in IJ gradle setting to buildusing IJ did the trick for nowTrunnion
A
0

For Spring boot users, this can be solved with one line of code. I am using Gradle/Kotlin, so:

id("org.springframework.boot") version "2.5.5"

inside the plugins {} section of your build.gradle.kts

For more information visit the Spring Boot Gradle Plugin Reference Guide.

Azriel answered 1/10, 2021 at 7:0 Comment(0)
Y
-1

For my case, I turned on my InteliJ after 3 months, got some runtime errors like noclassdeffounderror. I have to *** refresh gradle ***, then the errors are gone.

Yann answered 5/1, 2022 at 20:54 Comment(1)
how does one refresh gradle?Calypso

© 2022 - 2024 — McMap. All rights reserved.