java.lang.NoClassDefFoundError: org/telegram/telegrambots/meta/exceptions/TelegramApiException
java.lang.NoClassDefFoundError: org/telegram/telegrambots/meta/exceptions/TelegramApiException
我正在尝试使用 Maven 部署我的第一个 java 应用程序。在这种情况下,这只是一个简单的电报机器人,但我在本地尝试 运行 时遇到此错误。经过一番调查,我发现 java.lang.NoClassDefFoundError 是一个 jar 文件无法访问 运行 中的特定 class 时发生的错误为了解决这个问题,有必要在 classpath 上添加 class。
我知道在 Maven 上工作时,有一种简单的方法可以在 class 路径上添加 classes,它是通过在 pom.xml 文件上添加正确的依赖项来实现的。
这就是我添加的内容:
<dependencies>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-abilities</artifactId>
<version>5.0.1.1</version>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>5.0.1</version>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-meta</artifactId>
<version>5.0.1.1</version>
</dependency>
</dependencies>
而且我认为它已成功添加到 class 路径中,因为这是我在 jar 文件中读取 MANIFEST.MF 文件时得到的:
Manifest-Version: 1.0
Created-By: Apache Maven 3.6.3
Built-By: agujared
Build-Jdk: 15.0.1
Class-Path: telegrambots-abilities-5.0.1.1.jar commons-lang3-3.11.jar ma
pdb-3.0.8.jar kotlin-stdlib-1.2.71.jar kotlin-stdlib-common-1.2.71.jar
annotations-13.0.jar eclipse-collections-api-11.0.0.M1.jar eclipse-coll
ections-11.0.0.M1.jar eclipse-collections-forkjoin-11.0.0.M1.jar lz4-1.
3.0.jar elsa-3.0.0-M5.jar slf4j-api-1.7.30.jar telegrambots-5.0.1.jar j
ackson-annotations-2.11.3.jar jackson-jaxrs-json-provider-2.11.3.jar ja
ckson-jaxrs-base-2.11.3.jar jackson-module-jaxb-annotations-2.11.3.jar
jackson-core-2.11.3.jar jakarta.xml.bind-api-2.3.2.jar jakarta.activati
on-api-1.2.1.jar jackson-databind-2.11.3.jar jersey-hk2-2.32.jar jersey
-common-2.32.jar osgi-resource-locator-1.0.3.jar jakarta.activation-1.2
.2.jar hk2-locator-2.6.1.jar aopalliance-repackaged-2.6.1.jar hk2-api-2
.6.1.jar hk2-utils-2.6.1.jar javassist-3.25.0-GA.jar jersey-media-json-
jackson-2.32.jar jersey-entity-filtering-2.32.jar jersey-container-griz
zly2-http-2.32.jar jakarta.inject-2.6.1.jar grizzly-http-server-2.4.4.j
ar grizzly-http-2.4.4.jar grizzly-framework-2.4.4.jar jakarta.ws.rs-api
-2.1.6.jar jersey-server-2.32.jar jersey-client-2.32.jar jersey-media-j
axb-2.32.jar jakarta.annotation-api-1.3.5.jar jakarta.validation-api-2.
0.2.jar json-20180813.jar httpclient-4.5.13.jar httpcore-4.4.13.jar com
mons-logging-1.2.jar commons-codec-1.11.jar httpmime-4.5.13.jar commons
-io-2.8.0.jar telegrambots-meta-5.0.1.1.jar guava-30.0-jre.jar failurea
ccess-1.0.1.jar listenablefuture-9999.0-empty-to-avoid-conflict-with-gu
ava.jar jsr305-3.0.2.jar checker-qual-3.5.0.jar error_prone_annotations
-2.3.4.jar j2objc-annotations-1.3.jar
Main-Class: domain.Main
如您所见,telegrambots-meta-5.0.1.1.jar 是 classpath 属性的一部分。
我该如何解决?
顺便说一下,我正在使用 Heroku Cloud 来部署这个
听起来您想要并且需要创建一个运行可用/可执行 JAR 文件(具有外部依赖项)。
这需要通过此步骤增强您的构建过程,无论它在何处执行 Heroku、Jenkins、Bamboo 或在您的本地 - 这是一个 Maven 设置,将影响它们中的每一个。
同样在你的本地,你可以运行通过在你的 IDE 中执行 mvn clean package
来构建你的项目,然后 运行 从 target
文件夹:java -jar ${yourJarName}
。它可能会因同样的原因而失败。
这是因为 Maven 添加了所谓的范围依赖项。例如:
compile
provided
runtime
test
其中 compile
是默认值,并且在您未指定它的情况下隐式应用 - 就像您的情况一样。 (您可以阅读有关范围的更多信息 here)
这意味着 Maven 将在 编译时 [=96] 将您的依赖项添加到您的 IDE =],但在 运行 时间 ,当您尝试执行它时它会丢失。
解决方案是创建一个包含所有需要的依赖项的运行可用/可执行 JAR 文件(也称为 *fat JAR *)。
你可以直接在 Maven 中借助 maven-assembly-plugin[=96] =] 像这样:
<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>
然后您需要像这样构建您的 JAR:
mvn clean compile assembly:single
注意: 必须在assembly:single之前添加编译目标,否则不会包含您自己项目中的代码。
为了简化流程的处理,这个目标通常与 Maven 构建阶段相关联以自动执行。这确保在执行 mvn clean package
、mvn clean install
或执行部署/发布时构建 JAR:
<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>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
像这样,您可以使用 mvn clean package
命令(可能是最常见的命令)简单地构建您的项目,它将包括 运行nable/ 可执行文件的创建JAR 文件。这将包括您需要的所有依赖项,应该可以解决您的 java.lang.NoClassDefFoundError 问题。
只是一个简短的补充说明
分别创建运行可用/可执行 JAR 文件 fat JAR 不是唯一的解决方案,在某些情况下可能不需要.由于胖 JAR 文件包含所有需要的依赖项,因此它们相当大并具有所有相关的缺点(需要更多带宽来传输、下载大小增加、相同的依赖项可能包含在多个不同的 JAR 中,...)。
由于这个原因,在使用 Java EE 的 Web 应用程序开发中避免了胖 JAR 创建。依赖项仅在 编译时 添加,因为众所周知 Servlet Container 或 Application Container Tomcat 或 Wildfly 将在 运行time 提供这些以避免java.lang.NoClassDefFoundError。因此,不同的应用程序(JAR 或在此上下文中称为 WAR)不需要自己提供依赖项。
在您的情况下,您仍然可以构建瘦 JAR 的解决方案,但会在 运行 时提供所需的依赖项(例如,单独下载它,然后在类路径中指定执行)。
我正在尝试使用 Maven 部署我的第一个 java 应用程序。在这种情况下,这只是一个简单的电报机器人,但我在本地尝试 运行 时遇到此错误。经过一番调查,我发现 java.lang.NoClassDefFoundError 是一个 jar 文件无法访问 运行 中的特定 class 时发生的错误为了解决这个问题,有必要在 classpath 上添加 class。 我知道在 Maven 上工作时,有一种简单的方法可以在 class 路径上添加 classes,它是通过在 pom.xml 文件上添加正确的依赖项来实现的。 这就是我添加的内容:
<dependencies>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-abilities</artifactId>
<version>5.0.1.1</version>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>5.0.1</version>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-meta</artifactId>
<version>5.0.1.1</version>
</dependency>
</dependencies>
而且我认为它已成功添加到 class 路径中,因为这是我在 jar 文件中读取 MANIFEST.MF 文件时得到的:
Manifest-Version: 1.0
Created-By: Apache Maven 3.6.3
Built-By: agujared
Build-Jdk: 15.0.1
Class-Path: telegrambots-abilities-5.0.1.1.jar commons-lang3-3.11.jar ma
pdb-3.0.8.jar kotlin-stdlib-1.2.71.jar kotlin-stdlib-common-1.2.71.jar
annotations-13.0.jar eclipse-collections-api-11.0.0.M1.jar eclipse-coll
ections-11.0.0.M1.jar eclipse-collections-forkjoin-11.0.0.M1.jar lz4-1.
3.0.jar elsa-3.0.0-M5.jar slf4j-api-1.7.30.jar telegrambots-5.0.1.jar j
ackson-annotations-2.11.3.jar jackson-jaxrs-json-provider-2.11.3.jar ja
ckson-jaxrs-base-2.11.3.jar jackson-module-jaxb-annotations-2.11.3.jar
jackson-core-2.11.3.jar jakarta.xml.bind-api-2.3.2.jar jakarta.activati
on-api-1.2.1.jar jackson-databind-2.11.3.jar jersey-hk2-2.32.jar jersey
-common-2.32.jar osgi-resource-locator-1.0.3.jar jakarta.activation-1.2
.2.jar hk2-locator-2.6.1.jar aopalliance-repackaged-2.6.1.jar hk2-api-2
.6.1.jar hk2-utils-2.6.1.jar javassist-3.25.0-GA.jar jersey-media-json-
jackson-2.32.jar jersey-entity-filtering-2.32.jar jersey-container-griz
zly2-http-2.32.jar jakarta.inject-2.6.1.jar grizzly-http-server-2.4.4.j
ar grizzly-http-2.4.4.jar grizzly-framework-2.4.4.jar jakarta.ws.rs-api
-2.1.6.jar jersey-server-2.32.jar jersey-client-2.32.jar jersey-media-j
axb-2.32.jar jakarta.annotation-api-1.3.5.jar jakarta.validation-api-2.
0.2.jar json-20180813.jar httpclient-4.5.13.jar httpcore-4.4.13.jar com
mons-logging-1.2.jar commons-codec-1.11.jar httpmime-4.5.13.jar commons
-io-2.8.0.jar telegrambots-meta-5.0.1.1.jar guava-30.0-jre.jar failurea
ccess-1.0.1.jar listenablefuture-9999.0-empty-to-avoid-conflict-with-gu
ava.jar jsr305-3.0.2.jar checker-qual-3.5.0.jar error_prone_annotations
-2.3.4.jar j2objc-annotations-1.3.jar
Main-Class: domain.Main
如您所见,telegrambots-meta-5.0.1.1.jar 是 classpath 属性的一部分。 我该如何解决?
顺便说一下,我正在使用 Heroku Cloud 来部署这个
听起来您想要并且需要创建一个运行可用/可执行 JAR 文件(具有外部依赖项)。
这需要通过此步骤增强您的构建过程,无论它在何处执行 Heroku、Jenkins、Bamboo 或在您的本地 - 这是一个 Maven 设置,将影响它们中的每一个。
同样在你的本地,你可以运行通过在你的 IDE 中执行 mvn clean package
来构建你的项目,然后 运行 从 target
文件夹:java -jar ${yourJarName}
。它可能会因同样的原因而失败。
这是因为 Maven 添加了所谓的范围依赖项。例如:
compile
provided
runtime
test
其中 compile
是默认值,并且在您未指定它的情况下隐式应用 - 就像您的情况一样。 (您可以阅读有关范围的更多信息 here)
这意味着 Maven 将在 编译时 [=96] 将您的依赖项添加到您的 IDE =],但在 运行 时间 ,当您尝试执行它时它会丢失。
解决方案是创建一个包含所有需要的依赖项的运行可用/可执行 JAR 文件(也称为 *fat JAR *)。
你可以直接在 Maven 中借助 maven-assembly-plugin[=96] =] 像这样:
<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>
然后您需要像这样构建您的 JAR:
mvn clean compile assembly:single
注意: 必须在assembly:single之前添加编译目标,否则不会包含您自己项目中的代码。
为了简化流程的处理,这个目标通常与 Maven 构建阶段相关联以自动执行。这确保在执行 mvn clean package
、mvn clean install
或执行部署/发布时构建 JAR:
<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>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
像这样,您可以使用 mvn clean package
命令(可能是最常见的命令)简单地构建您的项目,它将包括 运行nable/ 可执行文件的创建JAR 文件。这将包括您需要的所有依赖项,应该可以解决您的 java.lang.NoClassDefFoundError 问题。
只是一个简短的补充说明
分别创建运行可用/可执行 JAR 文件 fat JAR 不是唯一的解决方案,在某些情况下可能不需要.由于胖 JAR 文件包含所有需要的依赖项,因此它们相当大并具有所有相关的缺点(需要更多带宽来传输、下载大小增加、相同的依赖项可能包含在多个不同的 JAR 中,...)。
由于这个原因,在使用 Java EE 的 Web 应用程序开发中避免了胖 JAR 创建。依赖项仅在 编译时 添加,因为众所周知 Servlet Container 或 Application Container Tomcat 或 Wildfly 将在 运行time 提供这些以避免java.lang.NoClassDefFoundError。因此,不同的应用程序(JAR 或在此上下文中称为 WAR)不需要自己提供依赖项。
在您的情况下,您仍然可以构建瘦 JAR 的解决方案,但会在 运行 时提供所需的依赖项(例如,单独下载它,然后在类路径中指定执行)。