Maven – Compiling JAR with Dependencies

Although I’m familiar with Java, I don’t use it day-to-day. To keep current with arguably the worlds most popular programming language, I decided to use Java in a project that I’m working on in my off hours. In that project (which gathers and analyzes economic data) I decided to use Maven. Even-though my small project doesn’t necessitate the need for such a tool, Maven implements many industry best practices (or at least promises to do so). So, I figured that it would be worth while to learn to use it.

One of the things that I liked right off was the use of what they call Project Object Model. It enables deterministic builds and simplifies the Java build process. I do use Node.js daily and using a package.json file I can easily import and manage the dependencies (including which versions) my project uses as well as define properties of my project, such as which version it’s currently at and licensing and contact information. Similarly, Maven uses a pom.xml file. This has made importing 3rd party code into my project very easy. I simply add a dependency to the pom.xml file.

Add a Dependency

  <dependencies>
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.2.5</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

After doing so, when I attempt to compile my application, Maven reaches out to a repository where the dependency is made available and it’s imported into my project. At the moment, I don’t even know here the JAR(s) are imported to! Maven also sets the user up with a testing framework (junit and a test directory), so it’s been pretty easy to get things off the ground. After implementing some functionality, I wanted to execute a “pre-version” of the application. I used the mvn package command, but when I attempted to run the built JAR. I received the following error:

Error when Running Packaged JAR

java -cp target/Dollar-1.0-SNAPSHOT.jar com.jasonfavrod.dollar.App usdx
Exception in thread "main" java.lang.NoClassDefFoundError: org/json/JSONObject
        at com.jasonfavrod.dollar.Barchart.get(Barchart.java:47)
        at com.jasonfavrod.dollar.Forex.getLastPrice(Forex.java:76)
        at com.jasonfavrod.dollar.Forex.getUSDX(Forex.java:94)
        at com.jasonfavrod.dollar.App.indexDollar(App.java:76)
        at com.jasonfavrod.dollar.App.main(App.java:32)
Caused by: java.lang.ClassNotFoundException: org.json.JSONObject
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 5 more

Inspecting the error, I saw java.lang.NoClassDefFoundError so I knew one of the dependencies I added to the project was not included in the executed JAR. I needed to find a way to build the JAR with dependencies. I learned that I needed to use the Maven Assembly Plugin.

<build>
  <plugins>
    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>fully.qualified.MainClass</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </plugin>
  </plugins>
</build>

Then run

mvn clean compile assembly:single

After compiling with the plugin, I was able to execute the JAR from the command line.

java -jar ./target/[my_compiled.jar]

Thanks again to the Stack Overflow Community.

Leave a Reply

Your email address will not be published. Required fields are marked *