NoClassDefFoundError in jar but not in Intellij - java

I'm trying to run a jar with dependencies. The application runs fine in Intellij but when I try to run the jar I get:
>> java -jar test-0.1.0.jar
Exception in thread "main" java.lang.NoClassDefFoundError: com/atlassian/httpclient/apache/httpcomponents/DefaultHttpClient
at com.atlassian.jira.rest.client.internal.async.AsynchronousHttpClientFactory.createClient(AsynchronousHttpClientFactory.java:53)
at com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory.create(AsynchronousJiraRestClientFactory.java:35)
at com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory.createWithBasicHttpAuthentication(AsynchronousJiraRestClientFactory.java:42)
at Main.main(Main.java:19)
Caused by: java.lang.ClassNotFoundException: com.atlassian.httpclient.apache.httpcomponents.DefaultHttpClient
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 4 more
My build.gradle looks like this:
group 'test'
version '1.0-SNAPSHOT'
task wrapper(type: Wrapper) {
gradleVersion = '2.9'
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'application'
sourceCompatibility = 1.8
mainClassName = "Main"
repositories {
mavenCentral()
maven {
url 'https://maven.atlassian.com/content/repositories/atlassian-public/'
}
}
jar {
baseName = 'test'
version = '0.1.0'
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
}
manifest {
attributes 'Main-Class': 'Main'
}
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
compile 'com.atlassian.jira:jira-rest-java-client-parent:4.0.0'
compile 'com.atlassian.jira:jira-rest-java-client-core:4.0.0'
compile 'com.atlassian.jira:jira-rest-java-client-api:4.0.0'
compile 'com.atlassian.jira:jira-rest-java-client-plugin:3.0.0'
compile 'com.atlassian.fugue:fugue-parent:2.6.1'
compile 'com.atlassian.fugue:fugue:2.6.1'
}
I've also tried adding transitive=true to each compile clause to no avail.

You need to set CLASSPATH
The class path is the path that the Java runtime environment searches for classes and other resource files. The class search path (more commonly known by the shorter name, "class path") can be set using either the -classpath option when calling a JDK tool (the preferred method) or by setting the CLASSPATH environment variable. The -classpath option is preferred because you can set it individually for each application without affecting other applications and without other applications modifying its value.
UPDATE:
By default, Gradle doesn't copy dependencies to build folder or include it into the jar. There are three ways to solve the problem with dependencies:
Download them separately and put into the appropriate directory.
Use plugins to build fat jar. Something like shadow.
Add to build.gradle task that copies dependencies into build folder.
For example
task copyDependencies(type: Copy) {
into "$buildDir/libs"
from configurations.runtime
}

Related

Gradle throws NoClassDefFoundError for dependencies with implementation keyword

I'm using Intellij Idea, with gradlew version 6.8.
Whenever I point implementation keyword for dependencies in build.gradle - I get(example with gson dependency) this exception:
Exception in thread "main" java.lang.NoClassDefFoundError: com/google/gson/Gson
at com.epam.adnocove.search.job.EmailVerifier.<clinit>(EmailVerifier.java:19)
at com.epam.adnocove.search.job.UserIndexPipeline.<clinit>(UserIndexPipeline.java:31)
Caused by: java.lang.ClassNotFoundException: com.google.gson.Gson
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:636)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:182)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:519)
... 2 more
my build.gradle file:
plugins {
id 'java'
}
group 'com.epam.adnocove'
version '1.0'
repositories {
mavenCentral()
}
jar {
manifest {
attributes 'Main-Class': 'Program'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA'
}
dependencies {
implementation 'com.google.code.gson:gson:2.8.2'
testImplementation 'junit:junit:4.12'
}
If I put compile instead of implementation - everything works as expected. But what if I don't want transitive dependency. Why gradle doesn't put my dependency to my jar?
The problem is that by default build along with java plugin only - Gradle doesn't pack dependencies into jar - therefore we get an exception.
The solution:
we can use fat jars(by separate task), or use java application plugin which will create OS-specific startup applications which can run built jar.

How to exclude dependencies from BOOT-INF/classes?

I have a spring boot project and I get this error when I try to build it:
> gradle build
:processResources
:compileJava
:classes
:jar FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':jar'.
> archive contains more than 65535 entries.
To build this archive, please enable the zip64 extension.
See: https://docs.gradle.org/3.5.1/dsl/org.gradle.api.tasks.bundling.Zip.html#org.gradle.api.tasks.bundling.Zip:zip64
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
Ok, I added the zip64 = true option to the jar task in the gradle configuration.
Now it can build the jar successfully but when I try to execute the jar, I get the following exception:
Exception in thread "main" java.lang.IllegalStateException: java.lang.IndexOutOfBoundsException
at org.springframework.boot.loader.ExecutableArchiveLauncher.<init>(ExecutableArchiveLauncher.java:43)
at org.springframework.boot.loader.JarLauncher.<init>(JarLauncher.java:37)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:58)
Caused by: java.lang.IndexOutOfBoundsException
at org.springframework.boot.loader.jar.AsciiBytes.<init>(AsciiBytes.java:69)
at org.springframework.boot.loader.jar.CentralDirectoryFileHeader.load(CentralDirectoryFileHeader.java:95)
at org.springframework.boot.loader.jar.CentralDirectoryParser.parseEntries(CentralDirectoryParser.java:68)
at org.springframework.boot.loader.jar.CentralDirectoryParser.parse(CentralDirectoryParser.java:57)
at org.springframework.boot.loader.jar.JarFile.<init>(JarFile.java:118)
at org.springframework.boot.loader.jar.JarFile.<init>(JarFile.java:106)
at org.springframework.boot.loader.jar.JarFile.<init>(JarFile.java:92)
at org.springframework.boot.loader.jar.JarFile.<init>(JarFile.java:83)
at org.springframework.boot.loader.archive.JarFileArchive.<init>(JarFileArchive.java:61)
at org.springframework.boot.loader.archive.JarFileArchive.<init>(JarFileArchive.java:57)
at org.springframework.boot.loader.Launcher.createArchive(Launcher.java:129)
at org.springframework.boot.loader.ExecutableArchiveLauncher.<init>(ExecutableArchiveLauncher.java:40)
... 2 more
It turned out that SpringBoot doesn't even support the zip64 format, so I had to make further investigation.
Where do the 65535+ entries come from? Obviously these come from dependencies, because the issue exists since
I added a new dependency in the build.gradle file. While examining the zip64 jar, I have found that
all the dependency classes! are under the BOOT-INF/classes folder.
As I understand, the structure must look like
BOOT-INF/
classes/
<only this application's compiled classes>
libs/
<all the dependency jars>
But my classes folder has all the dependency jars "extracted" to it.
(As you can see)
I extracted the jar, removed all the dependency classes from this folder and rezipped it. (Like this)
This way it can be run without any problem, so I'm sure these files are unneccesary.
Can somebody help me, how to exclude these dependency classes from the structure? Thank you in advance!
Here's my relevant gradle configuration:
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'application'
apply plugin: 'org.springframework.boot'
ext.springBootVersion = '1.4.2.RELEASE'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.4.2.RELEASE")
}
}
configurations {
provided.all*.exclude group: 'javax.servlet'
}
mainClassName = 'com.path.to.my.MainClass'
repositories {
mavenCentral()
maven {
url "https://repository.jboss.org/nexus/content/repositories/releases"
}
maven {
url "https://repo.eclipse.org/content/groups/releases/"
}
}
jar {
//zip64 = true
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
manifest {
attributes("Main-Class": mainClassName)
}
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile 'aopalliance:aopalliance:1.0'
compile 'com.google.code.gson:gson:2.7'
compile 'com.google.gdata:core:1.47.1'
compile 'com.google.guava:guava:19.0'
compile 'commons-io:commons-io:2.4'
compile 'javax.json:javax.json-api:1.0'
compile 'mysql:mysql-connector-java:5.1.22'
compile 'org.apache.commons:commons-csv:1.4'
compile 'org.flywaydb:flyway-core:4.0.3'
compile 'org.glassfish:javax.json:1.0.4'
......
testCompile 'org.springframework.boot:spring-boot-starter-test'
}
bootRun {
addResources = true
}
task wrapper(type: Wrapper) {
gradleVersion = '2.3'
}

ClassNotFoundException error for Kotlin (non-android) project on Android Studio

I attempted to create a normal Kotlin project (non-android, just desktop/command line project) with Android Studio 2.3.3.
I followed the steps as laid out here but with different build.gradle content whose content I shared here.
Actually that content of build.gradle I copied from build.gradle file after generating a new project with IntelliJ Community Edition (2017.2).
Then I create a configuration to be able to run it on desktop with proper set up like Main Class, Working directory, and Use classpath of module. You can see in the image below.
and following is the project file structure I have
Then I sync the project, it succeeds. But error kicks in when I try to Run the project. I got the following error.
"/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java" -Didea.launcher.port=7534 "-Didea.launcher.bin.path=/Applications/Android Studio.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath "/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/charsets.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/ext/localedata.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/ext/sunec.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/jce.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/jsse.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/management-agent.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/resources.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/rt.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/lib/dt.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/lib/jconsole.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/lib/sa-jdi.jar:/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/lib/tools.jar:/Users/haxpor/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar:/Users/haxpor/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jre7/1.1.4-2/272a21c30432c943d618008fbbd34762eb0d6c8a/kotlin-stdlib-jre7-1.1.4-2.jar:/Users/haxpor/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.1.4-2/fec983b2608a8a91a1b87dba18d247d692cf6b51/kotlin-stdlib-1.1.4-2.jar:/Users/haxpor/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jre8/1.1.4-2/168cc3f45c307edda6c867dd0635a7d451257551/kotlin-stdlib-jre8-1.1.4-2.jar:/Applications/Android Studio.app/Contents/lib/idea_rt.jar" com.intellij.rt.execution.application.AppMain io.wasin.testjavaapp.Main
Exception in thread "main" java.lang.ClassNotFoundException: io.wasin.testjavaapp.Main
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)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:123)
Process finished with exit code 1
I saw the classpath parameter as supplied in above /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java has no related directory to my project. I don't know how to add classpath directory via gradle despite I set up it in configurations already.
How can I solve this problem?
Update:
The following is my Main.kt code. It's just for testing purpose. So just printing something out.
package io.wasin.testjavaapp
object Main {
#JvmStatic fun main(arg: Array<String>) {
println("Hello world")
}
}
Also I updated build.gradle for Kotlin version to match the version of Kotlin plugin on Android Studio. It's now ext.kotlin_version = '1.1.4-2'. Although still doesn't solve the problem.
Update 2
I checked inside build directory at the same level of src directory. There are no .class or intermediates files generated/built over there, only kotlin-build/caches/version.txt and that's it. No other files. So the problem might be due to the source files are not compiled at all?
Update 3
I tried creating a new module to see if it's the root cause or not. Also created assets folder just to act as Working Directory, rearranged source folder again to be as following.
We now have 2 modules.
testJavaApp - root one
desktop - consists of Main.kt and used as desktop executable
testJavaApp has the following code for build.gradle
group 'io.wasin'
version '1.0-SNAPSHOT'
// Top-level build file where you can add configuration options common to
all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.1.4-2'
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
also desktop module has following code for build.gradle
apply plugin: 'kotlin'
sourceSets.main.java.srcDirs = [ "src/" ]
project.ext.mainClassName = "io.wasin.testjavaapp.Main"
project.ext.assetsDir = new File("../assets");
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
repositories {
mavenCentral()
}
task run(dependsOn: classes, type: JavaExec) {
main = project.mainClassName
classpath = sourceSets.main.runtimeClasspath
standardInput = System.in
workingDir = project.assetsDir
ignoreExitValue = true
}
Unfortunately, it still didn't work and it's the same error that shown up.
Update 4
#aristotll provided info in a comment that he tested with Android Studio and faced the same problem, but not with IntelliJ. He said it might be Android Studio bug. So I guess, I would try a few more times then decide whether it's solid enough to report as a bug. Thanks for taking time to testing out.
I also met this problem and solved it.
Add runtimeClasspath files("build/classes/kotlin/main") in build.gradle
dependencies {
// This dependency is found on compile classpath of this component and consumers.
compile 'com.google.guava:guava:23.0'
// Use JUnit test framework
testCompile 'junit:junit:4.12'
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compile group: 'dom4j', name: 'dom4j', version: '1.6.1'
runtimeClasspath files("build/classes/kotlin/main")
}
because Android Studio doesn't find classes in build/classes/kotlin/main. Add runtimeClasspath and it works!

Successful Gradle project build produces NoClassDefFoundError at runtime

I am using Gradle to build my Java project in Eclipse. gradle.build is as follows
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile group: 'com.flowpowered', name: 'flow-nbt', version: '1.0.0'
compile group: 'org.reflections', name: 'reflections', version: '0.9.10'
}
All libraries are functioning properly when run through Eclipse. But sometimes it is useful to work on the command line. When run on the command line, the runtime error Exception in thread "main" java.lang.NoClassDefFoundError: com/flowpowered/nbt/regionfile/SimpleRegionFileReader occurs, even though the build is successful and the code contains imports from those libraries. I have tried cleans and rebuilds, along with gradlew build --refresh-dependencies, but I still encounter the same runtime error.
I would assume that the libraries are just never actually imported? Or that they are not being stored where the java project thinks they are? I'm unfamiliar with Gradle, so any advice on this is welcome.
Based on the posted build.gradle file you are not packaging the application as an executable JAR.
First apply the application plugin. But this will not be enough as you won't be able to run the executable as a single JAR without all of its dependencies. Apply the shadow plugin too.
These two plugins will give you access to the following tasks:
run: execute the application from gradle's command line.
runShadow: execute the application but with all dependencies packaged in a single JAR, alongside your compiled classes and resources.
shadowJar: create a single "fat JAR" with compiled classes and all dependencies.
Thus your build.gradle may look like this
plugins {
id 'java'
id 'application'
id 'com.github.johnrengelman.shadow' version '1.2.4'
}
mainClassName = 'com.acme.YourMainClassName'
repositories {
mavenCentral()
}
dependencies {
compile group: 'com.flowpowered', name: 'flow-nbt', version: '1.0.0'
compile group: 'org.reflections', name: 'reflections', version: '0.9.10'
}
Plugin documentation:
https://github.com/johnrengelman/shadow
https://docs.gradle.org/3.4/userguide/application_plugin.html#useApplicationPlugin
Another solution without using any plugins and still end up with a runnable fat jar
jar {
archiveName = 'NameOfYourApp.jar'
manifest {
attributes 'Main-Class': 'uk.co.cdl.Main',
'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' '),
'Implementation-Version': project.version
}
from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) {
include/exclude anything if need to if not take the curlys off
}
}

Gradle: How to use one-jar output as input for launch4j

I'd like to create a exe file, without having to put all required libraries beside the exe.
Formerly with ant I created a self-contained jar file with one-jar and then wrapped this into a exe file with launch4j.
Gradle has plugins for both and standalone both work very well with almost no configuration.
But how can I manage to use the created one-jar as the input for launch4j?
This is my current buildfile:
apply plugin: 'java'
apply plugin: 'launch4j'
apply plugin: 'gradle-one-jar'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'edu.sc.seis.gradle:launch4j:1.0.6'
classpath 'com.github.rholder:gradle-one-jar:1.0.4'
}
}
launch4j {
mainClassName = "de.my.umkopierer.Umkopierer"
launch4jCmd = "C:/Program Files (x86)/Launch4j/launch4j"
jar = "lib/Umkopierer-1.0.jar"
headerType = "console"
dontWrapJar = false
}
sourceCompatibility = 1.7
version = '1.0'
jar {
manifest {
attributes 'Implementation-Title': 'Umkopierer', 'Implementation-Version': version
}
}
repositories {
mavenCentral()
}
dependencies {
compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
compile 'com.google.guava:guava:18.0'
compile 'com.fasterxml.jackson.core:jackson-core:2.4.4'
compile 'com.fasterxml.jackson.datatype:jackson-datatype-jdk7:2.4.4'
compile 'com.fasterxml.jackson.core:jackson-databind:2.4.4'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
task oneJar(type: OneJar) {
mainClass = "de.stiffi.umkopierer.Umkopierer"
}
I solved this by making the launch4j task 'createExe' dependent on the onejar/fatjar (or any other fat jar creation method). E.g.:
tasks.createExe.dependsOn('oneJar')
task launch4j(overwrite: true, dependsOn: ['createExe']){
}
Also I think that your gradle build file should contain a main class attribute like
manifest {
attributes 'Main-Class':'com.example.MyMainClass'
}
(at least that's the case if you are using the fatjar gradle plugin).

Categories