0

My previous post on the topic was marked as a duplicate of Java project with Maven dependency compiles but fails at runtime and closed.

To be clear, I don't believe it is a duplicate. I'm not asking how to make an executable jar. That should be clear when I run java -cp <jarName> <packageName> rather than just java -jar.

Also, unlike the post mine was associated as a duplicate of, my POM file looks like the example and dependency isn't causing compile errors.

I have a simple Maven project in Eclipse (2020-6). It was set up by doing the following in Eclipse:

1.  File -> New -> Other... Maven -> Maven Project
2.  Used the maven-archetype-quickstart archetype

    Group ID:  com.dogzilla.maven
    Artifact ID:  quickstart

Right click the pom file -> select Add Dependency -> enter:

Group ID: com.google.code.gson
Artifact ID: gson
Version: 2.8.6

Which I verified on https://search.maven.org/

Here's the POM file:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.dogzilla.maven</groupId>
  <artifactId>quickstart</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <name>quickstart</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.6</version>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

Here's the source code:

package com.dogzilla.maven.quickstart;

import com.google.gson.Gson;

public class App 
{
    public static void main( String[] args )
    {
        Gson gson = new Gson();
        System.out.println(gson.toJson("Hello World!") );
    }
}

I then right-clicked on the POM file -> Run As -> Maven Build...

and here is the output:

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/opt/eclipse/java/plugins/org.eclipse.m2e.maven.runtime.slf4j.simple_1.16.0.20200610-1735/jars/slf4j-simple-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [file:/opt/eclipse/java/configuration/org.eclipse.osgi/5/0/.cp/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/opt/eclipse/java/plugins/org.eclipse.m2e.maven.runtime.slf4j.simple_1.16.0.20200610-1735/jars/slf4j-simple-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [file:/opt/eclipse/java/configuration/org.eclipse.osgi/5/0/.cp/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]
[INFO] Scanning for projects...
[INFO] 
[INFO] -------------------< com.dogzilla.maven:quickstart >--------------------
[INFO] Building quickstart 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ quickstart ---
[INFO] Deleting /opt/workspace/eclipse/java/quickstart/target
[INFO] 
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ quickstart ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /opt/workspace/eclipse/java/quickstart/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ quickstart ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /opt/workspace/eclipse/java/quickstart/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ quickstart ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /opt/workspace/eclipse/java/quickstart/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ quickstart ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /opt/workspace/eclipse/java/quickstart/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ quickstart ---
[INFO] 
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.dogzilla.maven.quickstart.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.022 s - in com.dogzilla.maven.quickstart.AppTest
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] 
[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ quickstart ---
[INFO] Building jar: /opt/workspace/eclipse/java/quickstart/target/quickstart-0.0.1-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.967 s
[INFO] Finished at: 2020-12-13T20:00:27-07:00
[INFO] ------------------------------------------------------------------------

But if I run:

java -cp /opt/workspace/eclipse/java/quickstart/target/quickstart-0.0.1-SNAPSHOT.jar com.dogzilla.maven.quickstart.App

It fails with:

Exception in thread "main" java.lang.NoClassDefFoundError: com/google/gson/Gson
        at com.dogzilla.maven.quickstart.App.main(App.java:13)
Caused by: java.lang.ClassNotFoundException: com.google.gson.Gson
        at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
        ... 1 more

The thing is if I change System.out.println(gson.toJson("Hello World!") ); to plain 'ol System.out.println("Hello World"); it works. So I know the problem isn't with my java command or how I set the project up outside of the dependency getting resolved.

So the question is, I'm not sure how this is failing on the dependency. I was under the impression Maven managed all that for you. Why is this failing to run?

MGoBlue93
  • 644
  • 2
  • 14
  • 31
  • First of all, If you want to run your application from the standalone jar, then your jar should have all the dependent jars. Now the jar which has created by you does not contain any dependent jar(gson in your case). So where do you think it should be picked up? – P.Sanjay Dec 15 '20 at 17:04
  • @P.Sanjay, thanks for the reply but I don't understand the question -- "where do you think it should be picked up?" Well, my POM has com.google.code.gson gson 2.8.6 So why isn't it getting picked up? – MGoBlue93 Dec 15 '20 at 22:55
  • @JFabianMeier, Thanks for that link. It was suggested when my last question was abruptly closed. I don't think that's the same. The moral of the story is I'm building my first Maven project, I'm using a the quickstart archetype, using gson, and when I run the Maven build as mentioned above, running the project fails. I'm not looking to build and EXECUTABLE jar. I'm happy to run it from the terminal... but I was under the impression the whole point of Maven is it manages dependencies. All the docs I have read on the topic say the extent of managing dependencies is configuring the POM file – MGoBlue93 Dec 15 '20 at 23:00
  • My point was, when you add a dependency to pom.xml it says to maven that please download this dependency for me, and this dependency jar is downloaded to .m2 folder. Now in IDE your application would work fine because the dependent jar are referred from .m2. But when you try to run your application through an independent jar, it does not know from where the dependency jar needs to be referred. Your application will only work if dependency jars are in your classpath. maven creates manifest file with jar and classpath information. – P.Sanjay Dec 16 '20 at 05:57
  • And for this there are two ways. 1. Create an executable jar which contains all your dependency jars. 2. Define classpath in pom.xml of local directory from where you want to refer these jars. please refer https://maven.apache.org/shared/maven-archiver/examples/classpath.html – P.Sanjay Dec 16 '20 at 05:58
  • example org.apache.maven.plugins maven-jar-plugin true lib/ com.myapp.MainClass – P.Sanjay Dec 16 '20 at 05:59
  • @MGoBlue93 an "executable" jar exactly means a jar that can be run from the terminal. – J Fabian Meier Dec 16 '20 at 07:54
  • @JFabianMeier, a jar does not need to be 'executable' to run from the terminal. – MGoBlue93 Dec 23 '20 at 05:19
  • So let me be more precise: An _executable_ jar is a jar, that you can run with `java -jar ...` from the terminal. If you mean something different, please tell me. If you just build a jar with Maven (without using the assembly plugin or the shade plugin), you cannot run it with `java` on the terminal unless you manually specify the full classpath including all dependencies. – J Fabian Meier Dec 23 '20 at 06:37
  • 1
    But of course, it does not make sense to have an argument about terminology. The answer below pretty much sums it up. Either you include all dependencies into the jar (uber jar or executable jar) or you specify the whole classpath on the command line with `-cp`. Maven does only resolve dependencies during the build, not when you run it on the terminal. – J Fabian Meier Dec 23 '20 at 09:35
  • @JFabianMeier > or you specify the whole classpath on the command line with -cp. Thanks. I thought I did that. I have two things in the classpath... the package where main is at and the external dependency... like so: java -cp /opt/workspace/eclipse/java/quickstart/target/quickstart-0.0.1-SNAPSHOT.jar com.dogzilla.maven.quickstart.App:/home/dogzilla/.m2/repository/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar – MGoBlue93 Dec 26 '20 at 03:11

1 Answers1

2

It looks like when you try to run it yourself, you are only putting your project JAR on the classpath (-cp ...). That will only contain the code from your project; it will not contain any dependencies -- those are still in their own JARs. So, you need to either:

  1. Manually add each dependent JAR (from your local Maven repo) to your classpath manually
  2. OR, build an UberJar that contains your project along with all of it's dependent JARs
  3. OR, use the Exec Maven Plugin to run your app

Good luck!

Jamie Bisotti
  • 2,605
  • 19
  • 23
  • I tried your option #1 (#2 isn't an option long story and avoiding #3 right now until I fundamentally understand how this works)... anyway, I put the imported dependency on the classpath like so and it still failed. Thoughts? java -cp /opt/workspace/eclipse/java/quickstart/target/quickstart-0.0.1-SNAPSHOT.jar com.dogzilla.maven.quickstart.App:com.google.code.gson – MGoBlue93 Dec 15 '20 at 22:51
  • The command-line you included above does not look like the correct way of doing #1. Sounds like you are new to Java; I'd suggest doing some more reading (or using #2 or #3 and letting Maven help you out). – Jamie Bisotti Dec 16 '20 at 15:33
  • instead of being insulting, trying being helpful. In the op, I'm demonstrating that I know how to use use -cp. If I do a System.out.println rather than System.out.println(gson.toJson, it works with this command java -cp /opt/workspace/eclipse/java/quickstart/target/quickstart-0.0.1-SNAPSHOT.jar com.dogzilla.maven.quickstart.App. I've also 'read' (thanks for the tip on reading BTW; very helpful) that to use multiple paths in the classpath, a colon is used as the deliminator. – MGoBlue93 Dec 23 '20 at 05:43
  • I was attempting to be helpful; sorry you did not interpret it as such. I don't appreciate your last response; I'm done here. Good luck resolving your issue. – Jamie Bisotti Dec 24 '20 at 05:12