1

The problem is solved, read the last section.

The "background"


I'm making a ToDoApp just for a side project, as an excuse to learn Gradle. The initial build worked fine and the JAR worked as expected.[a]. But that version had no external dependencies; it was self-contained.

I was encouraged to add persistence to the project and I decided to use the GSON library (version 2.6.2) to work with JSON. I use IntelliJ IDEA (2016.1.2) to write code.

Now, I added the gson-2.6.2 artifact via the Maven Repository option in IntelliJ (in Project Structure). While writing the code, I added the library to the classpath of the project when prompted by IntelliJ. The code compiles and works fine when I run it in my IDE. Here's a sample run:

========ToDo App========


The following commands are recognised:
 ► help
    Display this help message.
 ► add <name>
    Add a new Todo task with the given name and also displays its corresponding ID.
 ► get <id>
    Displays the task with the given id.
 ► mark <id>
    Toggles the given task as completed or incomplete.
 ► print
    Displays all tasks in order of their creation.
 ► update <id> <new text>
    Updates the item with the given id to store the new text.
 ► del <id>
    Deletes the task with the given id.
 ► exit
    Exit the program.


The tasks are :
>> add Get the Gradle build to work. 
New item added with id = 1
>> add Push the stable system to GitHub and wait for Travis to give the green signal.
New item added with id = 2
>> add Proceed
New item added with id = 3
>> print
The tasks are :
•  Get the Gradle build to work.  [ID: 1 Completed: false]
•  Push the stable system to GitHub and wait for Travis to give the green signal. [ID: 2 Completed: false]
•  Proceed [ID: 3 Completed: false]
>> exit

It works fine. The JSON data gets saved as I expect:

{"currentId":3,"toDos":{"1":{"id":1,"name":" Get the Gradle build to work. ","completed":false},"2":{"id":2,"name":" Push the stable system to GitHub and wait for Travis to give the green signal.","completed":false},"3":{"id":3,"name":" Proceed","completed":false}}}

When I rerun the code, the data is read back properly. I'm very happy with my code.

The "situation"


Here's my build.gradle:

group 'ml.cristatus'
version = '0.2'

apply plugin: 'java'

sourceCompatibility = 1.7

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.google.code.gson:gson:2.6.2'
}

jar {
    manifest {
        attributes 'Main-Class': 'ml.cristatus.todo.ToDoApp'
    }
}

When I run gradle build on my Ubuntu 16.04 terminal, the JAR file is built with the following output:

:compileJava
warning: [options] bootstrap class path not set in conjunction with -source 1.7
1 warning
:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build

BUILD SUCCESSFUL

Total time: 7.036 secs

This build could be faster, please consider using the Gradle Daemon: https://docs.gradle.org/2.13/userguide/gradle_daemon.html

So I somehow managed to make the thing compile. But when I try to run it, using java -jar build/libs/ToDoApp-0.2.jar, the code doesn't work:

========ToDo App========


Exception in thread "main" java.lang.NoClassDefFoundError: com/google/gson/Gson
    at ml.cristatus.todo.repository.ToDoRepositoryWithJSON.<init>(ToDoRepositoryWithJSON.java:25)
    at ml.cristatus.todo.ToDoApp.REPL(ToDoApp.java:38)
    at ml.cristatus.todo.ToDoApp.main(ToDoApp.java:17)
Caused by: java.lang.ClassNotFoundException: com.google.gson.Gson
    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)
    ... 3 more

I'm probably making some newbie mistake, but I can't seem to be able to put my finger on it. What am I doing wrong? It is also interesting to note that the code compiles yet it can't find the gson artifact. I'm guessing it has something to do with the classpath? I don't know. I'm not sure.

Please help me in this regard.

Solution

I just added this line to the jar {} block:

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

Courtesy of this tutorial.


[a]Here's the version 0.1 binary.

Hungry Blue Dev
  • 1,313
  • 16
  • 30

1 Answers1

2

You have to add jar file with gson jar to classpath. When you are starting application ("java -jar build/libs/ToDoApp-0.2.jar"). There is multiple ways it can be achiveved.

One possible way is:

Add task into your gradle, which copy dependencies (gson.jar in your case) into "lib" directory. And when you are starting your application, add it to classpath. For example in this way "java -cp build/lib/gson.jar -jar build/libs/ToDoApp-0.2.jar"

Maybe better for you will be:

Add dependencies into your manifest. It is discussed in this answer how to copy the dependencies libraries JARs in gradle It should work for you.

Next Option is:

Create an "uberjar" it means add all dependencies into one big jar file. Personally I don't like it. But it will work in your case. How to create uberjar in gradle is here discussed here: Building a uberjar with Gradle

Community
  • 1
  • 1
bugs_
  • 3,544
  • 4
  • 34
  • 39