3

I am writing a simple test program to convert json into java objects using jackson 2.

My code is,

package test;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URL;

public class UseJson{

    public static void main(String[] args){

        ObjectMapper mapper = new ObjectMapper();
        try{
            SomeClass obj = mapper.readValue(new URL("http://someurl"), SomeClass.class);
        }
        catch(Exception ex){
            System.out.println(ex.toString());
        }
    }
}

And the build.gradle file is

repositories {
    mavenCentral()
}

apply plugin: 'java'

dependencies{
    compile('com.fasterxml.jackson.core:jackson-databind:2.8.6')
    compile('com.fasterxml.jackson.core:jackson-core:2.8.6')
    compile('com.fasterxml.jackson.core:jackson-annotations:2.8.6')
}

jar {
        manifest {
                attributes 'Main-Class': 'test.UseJson'
        }
}

But I am getting an exception when trying to execute the program

java -jar ./build/libs/JsonTest.jar
Exception in thread "main" java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/ObjectMapper
        at test.UseJson.main(UseJson.java:10)
Caused by: java.lang.ClassNotFoundException: com.fasterxml.jackson.databind.ObjectMapper
        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)
        ... 1 more

The related posts java.lang.ClassNotFoundException / NoClassDefFoundError for com/fasterxml/jackson/databind/ObjectMapper with Maven and Correct set of dependencies for using Jackson mapper don't solve the problem.


Edit: When I tried to compile the program manually using javac and the jar files of the dependencies, it worked. The issue must be with the gradle build file.

Community
  • 1
  • 1
Registered User
  • 2,239
  • 3
  • 32
  • 58
  • Well, you're not adding Jackson in the classpath when running your jar, so it's not available in the classpath. Why do you think it should be? Use the application plugin, to make it generate a runnable jar file with all its dependencies listed in the Class-Path manifest entry, and make it generate a distribution of the app containing everything needed, including start scripts. – JB Nizet Feb 25 '17 at 08:22
  • @JBNizet Thanks! I also found the shadow plugin to create a uber jar. Can you tell if it's better to create a uber jar or create a zip file as in the application plugin? – Registered User Feb 25 '17 at 12:35
  • The application plugin is better. An uber-jar is a hack, and more often than not, people start using uber jars as libraries, and wonder why nothing works as expected. – JB Nizet Feb 25 '17 at 17:02
  • @JBNizet Ok thanks! – Registered User Feb 25 '17 at 17:03
  • @InjuredThePatient It seems I had forgotten to accept the answer. – Registered User Apr 03 '17 at 10:55

1 Answers1

4

You will need to pack your libraries with your app.

jar {
archiveName = 'Name.jar'

manifest {
    attributes 'Main-Class': 'Main',
            'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' '),
            'Implementation-Version': project.version (if any)
}

from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) })
}

Other solution would be using Shadow jar plugin.

The most recommended solution is to use application plugin. Why ? it's supported, it's Gradle, it's used by most developers.

LazerBanana
  • 6,865
  • 3
  • 28
  • 47
  • The only way it worked for me is when using Shadow jar plugin... I would like to know, how it would be possible to configure application plugin correctly... – skryvets May 26 '18 at 16:23