简体   繁体   English

具有 Maven 依赖项的 Java 项目编译但在运行时失败

[英]Java project with Maven dependency compiles but fails at runtime

EDIT: This question should absolutely not be closed.编辑:这个问题绝对不应该被关闭。 I'm NOT asking how to create an executable jar.我不是在问如何创建一个可执行的 jar。 A jar doesn't need to be executable to be run from the terminal. jar 不需要可执行即可从终端运行。 For example, if I have have this code: package com.dogzilla.maven.quickstart;例如,如果我有这个代码:

public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World" );
    }
}

...and Maven builds it, it creates quickstart-0.0.1-SNAPSHOT.jar. ...和 Maven 构建它,它创建 quickstart-0.0.1-SNAPSHOT.jar。 Which is not, ahem, 'executable'.嗯,这不是“可执行的”。

I can run it from the terminal quite successfully with this:我可以用这个从终端非常成功地运行它:

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

The problem, as I have written below, is experienced when using an external dependency.正如我在下面所写的,在使用外部依赖项时会遇到这个问题。 </end edit> </结束编辑>

I have a simple Maven project in Eclipse (2020-6).我在 Eclipse (2020-6) 中有一个简单的 Maven 项目。 It was set up by doing the following in Eclipse:它是通过在 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:右键pom文件->select添加依赖->输入:

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

Which I verified on https://search.maven.org/我在https://search.maven.org/上进行了验证

Here's the POM file:这是POM文件:

<?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...然后我右键单击 POM 文件 -> 运行方式 -> Maven Build...

and here is the output:这是 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;") ).问题是如果我更改 System.out.println(gson.toJson("Hello World;") )。 to plain 'ol System.out;println("Hello World").到普通的 'ol System.out;println("Hello World")。 it works.有用。 So I know the porblem isn't with my java command or how I set the project up outside of the dependency getting resolved.所以我知道问题不在于我的 java 命令或者我如何在依赖项之外设置项目得到解决。

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.我的印象是 Maven 为您管理了所有这些。 Why is this failing to run?为什么这无法运行?

The jar file that created from your project only contains classes that written by you.从您的项目创建的 jar 文件仅包含您编写的类。 If you need to run the application, you need to include all the necessary dependencies (either direct or transitive) in your classpath.如果您需要运行应用程序,则需要在类路径中包含所有必要的依赖项(直接的或传递的)。

If you need a single jar file that you can execute without other dependencies, Please follow this to create a fatjar.如果您需要一个可以在没有其他依赖项的情况下执行的 jar 文件,请按照创建一个 fatjar。

Use the Maven plugin mentioned in comment https://stackoverflow.com/a/65486325/679858 or use the Maven Shade plugin described here: https://maven.apache.org/plugins/maven-shade-plugin/ Use the Maven plugin mentioned in comment https://stackoverflow.com/a/65486325/679858 or use the Maven Shade plugin described here: https://maven.apache.org/plugins/maven-shade-plugin/

Your question was "Why does it run from Eclipse and not from console?": If you run it from Eclipse then the Maven plugin in Eclipse knows the full runtime classpath and so it works. Your question was "Why does it run from Eclipse and not from console?": If you run it from Eclipse then the Maven plugin in Eclipse knows the full runtime classpath and so it works. If you run it in console with the created JAR file then that JAR file only contains the classes of your sources but not the transitive dependencies, eg Google GSON.如果您使用创建的 JAR 文件在控制台中运行它,则该 JAR 文件仅包含源的类,但不包含传递依赖项,例如 Google GSON。 But if you use the Maven Assembly plugin or the Maven Shade plugin then you can create a JAR file which contains all the transitive dependencies of your project.但是,如果您使用 Maven 程序集插件或 Maven 阴影插件,那么您可以创建一个 JAR 文件,其中包含项目的所有传递依赖项。 That jar could be executed like you wrote it in your example. jar 可以像您在示例中编写的那样执行。

You are not providing the path to the additional, transitive, dependencies of your project in the java command, which is why it fails.您没有在 java 命令中提供项目的附加、传递、依赖项的路径,这就是它失败的原因。

You are using maven to build your project, not to execute your class: this is not Maven purpose, although it can do it using maven-exec-plugin .您正在使用 maven 来构建您的项目,而不是执行您的 class:这不是 Maven 的目的,尽管它可以使用maven-exec-plugin来实现。 Eclipse is different: it uses Maven information (with m2e) and provides a context to run classes, context that includes dependencies. Eclipse 不同:它使用 Maven 信息(带有 m2e)并提供运行类的上下文,包括依赖项的上下文。

The option -cp , explained in depth at Oracle Web Site: java (15) , accepts one or more path to list of directories, jar and zip to search for class files: The option -cp , explained in depth at Oracle Web Site: java (15) , accepts one or more path to list of directories, jar and zip to search for class files:

--class-path classpath, -classpath classpath, or -cp classpath --class-path 类路径、-classpath 类路径或 -cp 类路径

A semicolon (;) separated list of directories, JAR archives, and ZIP archives to search for class files. Specifying classpath overrides any setting of the CLASSPATH environment variable. If the class path option isn't used and

classpath isn't set, then the user class path consists of the current directory (.).未设置类路径,则用户 class 路径由当前目录 (.) 组成。

 As a special convenience, a class path element that contains a base name of an asterisk (*) is considered equivalent to specifying a

list of all the files in the directory with the extension.jar or.JAR.目录中所有扩展名为.jar 或.JAR 的文件的列表。 A Java program can't tell the difference between the two invocations. Java 程序无法区分两次调用之间的区别。 For example, if the directory mydir contains a.jar and b.JAR, then the class path element mydir/* is expanded to A.jar:b.JAR, except that the order of JAR files is unspecified. For example, if the directory mydir contains a.jar and b.JAR, then the class path element mydir/* is expanded to A.jar:b.JAR, except that the order of JAR files is unspecified. All.jar files in the specified directory, even hidden ones, are included in the list.指定目录下的所有.jar文件,即使是隐藏文件,都包含在列表中。 A class path entry consisting of an asterisk (*) expands to a list of all the jar files in the current directory.由星号 (*) 组成的 class 路径条目将扩展为当前目录中所有 jar 文件的列表。 The CLASSPATH environment variable, where defined, is similarly expanded.定义的 CLASSPATH 环境变量也同样被扩展。 Any class path wildcard expansion that occurs before the Java VM is started.在 Java VM 启动之前发生的任何 class 路径通配符扩展。 Java programs never see wildcards that aren't expanded except by querying the environment, such as by calling System.getenv("CLASSPATH"). Java 程序永远不会看到未扩展的通配符,除非通过查询环境,例如通过调用 System.getenv("CLASSPATH")。

So you need to fix your command to provides gson and any other compile/runtime/provided dependencies you may add later:因此,您需要修复您的命令以提供 gson 以及您以后可能添加的任何其他编译/运行时/提供的依赖项:

CLASSPATH=''
CLASSPATH+=";$HOME/.m2/repository/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar"
CLASSPATH+=";/opt/workspace/eclipse/java/quickstart/target/quickstart-0.0.1-SNAPSHOT.jar"
CLASSPATH="${CLASSPATH:1}" # remove leading ';'
java -cp "${CLASSPATH}" com.dogzilla.maven.quickstart.App

The man says that you can use ;男人说你可以用; to separate entries;分开条目; that is true at least for Windows.至少对于 Windows 来说是这样。 However on other Linux based OS (which seems to are on due to /opt being used), this can also be : : that what appassembler does when writing CLASSPATH .然而,在其他基于 Linux 的操作系统上(由于/opt正在使用,这似乎是打开的),这也可以是: : appassembler在编写CLASSPATH时所做的事情。

Do note that you will have to adapt the path manually to retarget the actual location of gson.jar (I guessed from what maven does by default).请注意,您必须手动调整路径以重新定位 gson.jar 的实际位置(我从 maven 默认情况下猜测)。

You can also use appassembler or launch4j to do the trick for you.您还可以使用appassemblerlaunch4j为您解决问题。 You can also use build-classpath to build the classpath (it may also work from command line).您还可以使用build-classpath来构建类路径(它也可以从命令行工作)。

try remove gson from.m2 folder then run maven install again.尝试从.m2 文件夹中删除 gson 然后再次运行 maven 安装。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在Java中将其他本地Maven项目的依赖项添加到本地Maven项目(运行时和编译时)? - How to add dependency of other local maven project to l local maven project in java (runtime and compile time)? Maven:项目编译时没有在pom.xml中定义的依赖项 - Maven: project compiles without dependency defined in pom.xml Eclipse Indigo中的Maven,项目对运行时的依赖 - Maven in eclipse Indigo, project dependency on Runtime 枚举,接口和(Java 8)lambdas:代码编译但在运行时失败;这是预期的吗? - Enum, interfaces and (Java 8) lambdas: code compiles but fails at runtime; is this expected? 将ObjectifyImpl转换为Ofy可以编译,但是在Eclipse / Java8中运行时失败 - A cast of ObjectifyImpl to Ofy compiles, but fails at runtime in Eclipse/Java8 Maven Web项目是否将Maven Java应用程序作为依赖项? - Maven Web project with Maven java application as a dependency? Java Maven依赖插件ClassNotFoundException在运行时 - Java maven-dependency-plugin ClassNotFoundException at runtime Java 在运行时获取 maven 依赖的版本 - Java get version of maven dependency at runtime 使用eclipse,java maven项目可以编译,但是在运行时会给出错误 - using eclipse, java maven project compiles but gives error when running Java项目使用Maven编译,但是Eclipse仍然显示错误 - Java project compiles with Maven but Eclipse still shows errors
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM