Gradle dependency issue, java.lang.NoClassDefFoundError, but compiles - java

new to gradle and java here and I am trying to use Android's Log method from android.util.Log. It seems I can compile and it finds what it needs, but it can not find it at runtime. I have tried using 'runtime' instead of 'compile' in the dependencies section, but not luck.
java -jar build/libs/testJavaHttp.jar
Exception in thread "main" java.lang.NoClassDefFoundError: android/util/Log
at myproject.test.HttpToFile.downloadFile(HttpToFile.java:20)
at myproject.test.Main.main(Main.java:12)
Caused by: java.lang.ClassNotFoundException: android.util.Log
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)
... 2 more
In build.gradle
apply plugin: 'java'
dependencies {
compile files('../androidsdk/platforms/android-25/android.jar')
}
jar {
manifest {
attributes 'Main-Class': 'myproject.test.Main'
}
}

You are trying to run the jar and the jar is not packed with dependencies, use shadow jar plugin or pack required artifacts in, by extending the jar task.
jar {
archiveName = 'Name.jar'
manifest {
attributes 'Main-Class': 'myproject.test.Main',
'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' '),
'Implementation-Version': 1.0
}
from(configurations.myconfig.collect { it.isDirectory() ? it : zipTree(it) }) {
// in here you can exclude what you need as well if needed.
}
}
To not pull the 'entire world' into a jar you can create configuration just with libraries you require:
configurations{
myconfig // to create configuration
compile.extendsFrom(myConfig) //to include it in compile as well
}
and then use this config in the jar creation and in dependecies.
dependencies {
myconfig files('../androidsdk/platforms/android-25/android.jar')
}
But looking at your code there is not much to pull there. You need to consider packing all needed artifacts and transitives if you expect it to be a runnable jar, as you run it with 'java -jar [...]' command.
PS. Everything that is in compile is going to be included in runtime configuration as well.

Related

Gradle Build Jar with Local Dependencies

I am building a jar file using gradle. I have local jar files as dependencies. Those jars have additional local dependencies stored in the same directory. I used the following build.gradle file
plugins { id 'application' }
repositories {
flatDir{ dirs 'lib'
}
dependencies {
implementation name: 'localjar1'
implementation name: 'localjar2'
}
application { mainClass = 'mypackage.MyApp' }
jar {
from { configurations.runtimeClasspath.collect {it.isDirectory ? : zipTree(it) } }
manifest { attributes 'Main-Class': 'mypackage.MyApp' }
}
I built the jar using gradle jar, but when I try to run the jar:
java -jar myapp\build\libs\myapp.jar
I get the following error:
Unable to initialize main class mypackage.MyApp
Caused by java.lang.NoClassDefFoundError: com/localpackage/SomeClass
How do bring that dependency in correctly?
I also tried to include the entire local library as a dependency
implementation fileTree(dir: 'lib', include: '*jar')
But when I do this I get the error: java.lang.ClassNotFoundException: mypackage.MyApp
What else should I try?
** Note: I can run the application using gradle run

Build an executable jar with external dependancies from intelij

I have a java console app with 5 classes and has one dependancy, gradle, com.google.code.gson.
I do build an executable jar successfully, however I get the following error when I execute the jar using the command java -jar <jarName>.jar
Exception in thread "main" java.lang.NoClassDefFoundError: com/google/gson/Gson
Caused by: java.lang.ClassNotFoundException: com.google.gson.Gson
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
Creating the artifact:
File -> Project Structure -> Artifacts -> "Click on Plus button" -> JAR -> From module with dependancies
I expected the jar file to run
build.gradle
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation 'com.google.code.gson:gson:2.10.1'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
test {
useJUnitPlatform()
}
jar {
manifest {
attributes "Main-Class": "org.example.Main"
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
IDEA Gui Right Side : Gralde Tab , YourProject -> Tasks -> jar
Find output jar file : YourProject -> build/libs : yourApp.jar
java -jar yourApp.jar
This method is create a fat jar, include dependencies class, only one jar.
No need other external jar files.

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.

Exporting Jar file with Manifest attribute in Android Studio?

I am trying to run a jar from Android studio. After a long Workaround, the jar file run perfectly.
Now i need to export the jar file from the android studio. I got the Jar file from the build/libs folder.
But the problem is that the jar file shows a error.
no main manifest attribute, in "app.jar"
So i found this solution. Can't execute jar- file: "no main manifest attribute"
Then i read about MANIFEST.MF & added the mail class to that file.
jar {
manifest.attributes(
'Main-Class': "com.Remo.server.RemoServerApp"
)
}
After adding those in my gradle. My MANIFEST.MF contains the MainClass.
But im still getting the same error? How can i solve this ?
Note: The objective is that I want to Export a Runnable Jar file from the project.
UPDATE:
After Adding the MainClass in MANIFEST.MF. I got stuck with the below error.
Exception in thread "main" java.lang.NoClassDefFoundError: com/Remo/protocol/RemoConnection
at com.Remo.server.RemoServerApp.<init>(RemoServerApp.java:33)
at com.Remo.server.RemoServerApp.main(RemoServerApp.java:97)
Caused by: java.lang.ClassNotFoundException: com.Remo.protocol.RemoConnection
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)
... 2 more
MANIFEST.MF
Manifest-Version: 1.0
Main-Class: com.Remo.server.RemoServerApp
UPDATE 2
From your solution what i understood is that we need to copy the remoprotocol jar file to the remoserver.
remoserver project gradle file
apply plugin: 'java'
sourceSets {
main {
resources.srcDirs = ['src/main/resources']
}
}
dependencies {
compile project(':remoprotocol')
compile files('libs/bluecove-2.1.1.jar')
}
jar {
manifest.attributes(
'Main-Class': "com.remo.server.remoServerApp"
)
manifest.attributes(
'Class-Path': configurations.runtime.files.collect { it.getName() }.join(' '))
}
task copyRTDependenciesToLib(type: Copy) {
into "$buildDir/output/lib"
from configurations.runtime
}
After running the gradle task also i am getting the same error.
First you want to copy all your runtime dependencies into the builddir/libs folder (or a different distribution folder if you so choose). Here is a custom task that would achieve this:
task copyRTDependenciesToLib(type: Copy) {
into "$buildDir/libs"
from configurations.runtime
}
Add your runtime dependency jars as a Class-Path attribute in your manifest file. The jars need to be in the same directory as your runnable jar - which the copy task above achieves. (alternatively, you can provide full relative path for your dependency jar location)
jar {
manifest {
attributes(
"Main-Class": "com.Remo.server.RemoServerApp",
"Class-Path": configurations.runtime.files.collect { it.getName() }.join(' '))
)
}
}
Some more things to consider:
The application plugin does the same thing; it adds a task installDist that produces a runnable set of jars along with any dependencies, any readme's, documentation you want to include.
If you want to produce a single runnable jar without having to bundle dependencies along with it, you should look into creating a "fatjar", for example:
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'Gradle Jar File Example',
'Implementation-Version': version,
'Main-Class': "com.Remo.server.RemoServerApp"
}
baseName = project.name
//collect all dependencies
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
I have no experience with Android Studio (or Gradle), but I have with Java. Aren't you trying to set main class instead?
Therefore I suggest changing Class-Path attribute to Main-Class as the manifest should contain Main-Class to be able to invoke something when "running" JAR.

Gradle - no main manifest attribute

I'm building a JAR file with Gradle. When I try to run it I get the following error
no main manifest attribute, in RxJavaDemo.jar
I tried manipulating the manifest property but I think I'm forgetting to add the dependencies or something to it. What exactly am I doing wrong?
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'demo.MainDashboard'
dependencies {
compile files ("H:/Processes/Development/libraries/hikari-cp/HikariCP-2.4.1.jar")
compile files ("H:/Processes/Development/libraries/controls-fx/controlsfx.jar")
compile files ("H:/Processes/Development/libraries/database_connections/sqlite-jdbc-3.8.6.jar")
compile files ("H:/Processes/Development/libraries/guava/guava-18.0.jar")
compile files ("H:/Processes/Development/libraries/rxjava/rxjava-1.0.12.jar")
compile files ("H:/Processes/Development/libraries/rxjava-extras/rxjava-extras-0.5.15.jar")
compile files ("H:/Processes/Development/libraries/rxjavafx/RxJavaFX-1.0.0-RC1-SNAPSHOT.jar")
compile files ("H:/Processes/Development/libraries/rxjavaguava/rxjava-guava-1.0.3.jar")
compile files ("H:/Processes/Development/libraries/rxjava-jdbc/rxjava-jdbc-0.6.3.jar")
compile files ("H:/Processes/Development/libraries/slf4j/slf4j-api-1.7.12.jar")
compile files ("H:/Processes/Development/libraries/tom-commons/tom-commons.jar")
}
sourceSets {
main.java.srcDir "src/main/java"
main.resources.srcDir "src/main/resources"
}
jar {
manifest {
attributes(
"Class-Path": configurations.compile.collect { it.getName() }.join(' '))
}
from configurations.compile.collect { entry -> zipTree(entry) }
}
Try to change your manifest attributes like:
jar {
manifest {
attributes(
'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
'Main-Class': 'hello.HelloWorld'
)
}
}
And then just change 'hello.helloWorld' to '<your packagename>.<the name of your Main class>' (where your Main class has a main method). In this case, you make in your manifest an attribute, which point to this class, then a jar is running.
To make the jar file executable (so that the java -jar command works), specify the Main-Class attribute in MANIFEST.MF.
In Gradle, you can do it by configuring the jar task.
for Groovy DSL see these answers ([1], [2])
for Kotlin DSL you can use the following code snippet:
tasks.withType<Jar> {
manifest {
attributes["Main-Class"] = "com.caco3.Main"
}
}
Why mainClassName does not work as expected?
Or why mainClassName does not specify the attribute in the manifest?
The mainClassName property comes from the application plugin. The plugin:
makes it easy to start the application locally during development, and to package the application as a TAR and/or ZIP including operating system specific start scripts.
So the application plugin does not aim at producing executable jars
When a mainClassName property set, then:
$ ./gradlew run will launch the main method in the class specified in the attribute
the zip/tar archive built using distZip/distTar tasks will contain a script, which will launch the main method of the specified previously class.
Here is the line of shell script setting the main class:
$ grep Main2 gradletest
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLETEST_OPTS -classpath "\"$CLASSPATH\"" com.caco3.gradletest.Main2 "$APP_ARGS"
To complement Denis Zavedeev answer, here are more ways for Kotlin DSL (build.gradle.kts):
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
}
tasks.jar {
manifest {
attributes["Main-Class"] = "com.example.MyMainClass"
}
}
Side note: to create a runnable fat JAR (also called uber JAR), see this post.
FWIW - I used the following jar task to assemble all my compile dependencies into the jar file, and used the above recommendation to get the class-path properly set
apply plugin: 'java-library'
jar {
manifest {
attributes(
'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
'Main-Class': 'your.main.class.goes.here'
)
}
// You can reference any part of the dependency configurations,
// and you can have as many from statements as you need
from configurations.compile
// I just copied them into the top of the jar, so it looks like the eclipse exported
// runnable jar, but you could designate a lib directory, and reference that in the
// classpath as "lib/$it.name" instead of it.getName()
into ''
}

Categories