在 Maven 中生成带有依赖项和测试的 jar 文件
Posted
技术标签:
【中文标题】在 Maven 中生成带有依赖项和测试的 jar 文件【英文标题】:Generate jar file in Maven with dependencies and tests 【发布时间】:2018-11-03 15:34:53 【问题描述】:我在 pom.xml 中使用这段代码来创建一个 jar 文件。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/log4j.properties</exclude>
</excludes>
<archive>
<manifest>
<mainClass>test.LeanFTest</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
我收到错误消息:
部署失败:未在 POM 中指定存储库元素 内部分布
更新:
我在 pom.xml 中添加了另一个插件。
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>test.LeanFTest</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
它生成一个jar文件,但似乎没有依赖关系。
线程“主”java.lang.NoClassDefFoundError 中的异常: org/apache/log4j/Logger
项目结构:
C:.
├───.idea
│ └───libraries
├───META-INF
├───out
│ └───artifacts
│ └───Test_LeanFT_jar
├───resources
│ ├───leanftjar
│ └───META-INF
├───RunResults
│ └───Resources
│ ├───Snapshots
│ └───User
├───src
│ ├───main
│ │ ├───java
│ │ │ ├───com
│ │ │ │ └───myproj
│ │ │ ├───jar
│ │ │ │ └───META-INF
│ │ │ ├───META-INF
│ │ │ ├───unittesting
│ │ │ └───utils
│ │ └───resources
│ └───test
│ └───java
│ └───test
├───target
│ ├───classes
│ │ ├───com
│ │ │ └───myproj
│ │ ├───unittesting
│ │ └───utils
│ ├───generated-sources
│ │ └───annotations
│ ├───generated-test-sources
│ │ └───test-annotations
│ ├───maven-archiver
│ ├───maven-status
│ │ └───maven-compiler-plugin
│ │ ├───compile
│ │ │ └───default-compile
│ │ └───testCompile
│ │ └───default-testCompile
│ ├───surefire
│ ├───surefire-reports
│ │ ├───Command line suite
│ │ ├───junitreports
│ │ └───old
│ │ └───Command line suite
│ └───test-classes
│ └───test
└───test-output
├───All Test Suite
├───junitreports
├───My_Suite
└───old
├───All Test Suite
└───My_Suite
pom.xml
文件:
<?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>groupId</groupId>
<artifactId>LeanFT</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Mytest</name>
<description>Regression test</description>
<properties>
<leanftsdk>C:/Program Files (x86)/HPE/Unified Functional Testing/SDK/Java/</leanftsdk>
<maven.test.skip>true</maven.test.skip>
</properties>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>com.hp.lft</groupId>
<artifactId>sdk</artifactId>
<version>14.0.0</version>
<scope>system</scope>
<systemPath>$leanftsdk/com.hp.lft.sdk-standalone.jar</systemPath>
</dependency>
<dependency>
<groupId>com.hp.lft</groupId>
<artifactId>report</artifactId>
<version>14.0.0</version>
<scope>system</scope>
<systemPath>$leanftsdk/com.hp.lft.report.jar</systemPath>
</dependency>
<dependency>
<groupId>com.hp.lft</groupId>
<artifactId>unittesting</artifactId>
<version>14.0.0</version>
<scope>system</scope>
<systemPath>$leanftsdk/com.hp.lft.unittesting.jar</systemPath>
</dependency>
<dependency>
<groupId>com.hp.lft</groupId>
<artifactId>verifications</artifactId>
<version>14.0.0</version>
<scope>system</scope>
<systemPath>$leanftsdk/com.hp.lft.verifications.jar</systemPath>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>appmodels</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>test.LeanFTest</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</project>
【问题讨论】:
***.com/questions/27153024/… 的可能重复项 @SagarRohankar :看起来不一样。 @plaidshirt 请完整描述项目结构并发布所有 pom.xml 文件。另外,放置控制台输出以查看何时抛出此错误消息。 @catta :我更新了我的问题。 @plaidshirt 请把 pom.xml 内容和控制台输出错误。 【参考方案1】:我的解决方案是构建一个存档(zip 或其他格式),其中包含您在 jar 中的类、依赖项 jar、一个包含运行时配置文件和脚本的文件夹以启动应用程序。范围是只需解压缩存档即可运行准备就绪的应用程序。
构建的存档内容为:
artifactId-version.zip:
<artifactId folder>
├─ config
| ├─ log4j2.xml
├─ lib
| ├─ <all dependencies jars>
├─ leanft.cmd
├─ leanft.sh
└─ artifactId-version.jar
您应该根据需要/是否需要配置文件来定制解决方案。您不需要带有 MANIFEST.MF 文件的 META-INF 文件夹,因为它将由 maven 插件自动生成。
项目结构
<maven_module_root>
├─ src
| ├─ main
| | ├─ assembly
| | | ├─ leanft-assembly.xml
| | ├─ java
| | | ├─ <your classes content>
| | ├─ resources
| | | ├─ log4j2.xml
| | | ├─ <your runtime configuration files>
| | ├─ scripts
| | | ├─ leanft.cmd
| | | ├─ leanft.sh
│ └───test
├─ pom.xml
项目结构与您当前的结构相似,但多了两个文件夹: - 程序集:在此文件夹中是用于自定义 maven-assembly-plugin 的leaft-assembly.xml。 - 脚本:此文件夹中是您的应用程序的启动器脚本。如果您需要有可用于编辑的运行时配置文件,这是必要的。在我的示例中,resources/log4j2.xml 将位于一个配置文件中,因此用户可以在不接触任何 jar/archive 的情况下编辑此文件。
程序集描述符
该解决方案基于具有自定义配置的 maven 程序集插件。我建议熟悉它,从描述符assembly descriptor开始
您的leaft-assembly.xml 可能如下所示:
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>dist</id>
<formats>
<!-- <format>tar.gz</format> -->
<format>zip</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<baseDirectory>$project.artifactId</baseDirectory>
<fileSets>
<fileSet>
<directory>$project.build.directory</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>$project.artifactId-$project.version.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>$project.build.directory/lib</directory>
<outputDirectory>/lib</outputDirectory>
<includes>
<include>*.*</include>
</includes>
</fileSet>
<fileSet>
<directory>$project.build.outputDirectory</directory>
<outputDirectory>/config</outputDirectory>
<includes>
<include>log4j2.xml</include>
</includes>
</fileSet>
<fileSet>
<directory>$project.basedir/src/main/scripts</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>leanft.*</include>
</includes>
</fileSet>
</fileSets>
</assembly>
Maven pom
最后,pom.xml 使用了 3 个插件:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>$project.build.directory/lib</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>test.LeanFTest</mainClass>
</manifest>
</archive>
<excludes>
<exclude>log4j2.xml</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<finalName>$project.artifactId-$project.version</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/leanft-assembly.xml</descriptor>
</descriptors>
</configuration>
</plugin>
我会解释maven插件的用法: - maven-dependency-plugin:将包阶段的所有依赖项复制到目标文件夹下的 lib 文件夹中。 - maven-jar-plugin: - 存档:生成清单文件,在清单中定义 lib 文件夹中的所有依赖项以及主类是什么,这样您也可以使用“java -jar”运行应用程序 - 排除:不要在模块 jar 中包含 log4j2.xml 文件,因为它将位于运行时从外部 jar 中可用的配置文件夹中。 - maven-assembly-plugin:在包阶段创建一个包含您的发行版的 zip 文件。存档放置在目标文件夹中。描述符标签引用您的程序集配置文件leaft-assembly.xml。
脚本
使用预定义参数启动应用程序调用 java 的脚本,脚本的主要行是:
%JAVA_HOME%\bin\java %JVM_ARGS% -cp %SCRIPT_DIR%\*;%SCRIPT_DIR%\config\ test.LeanFTest
【讨论】:
此代码生成了一个带有 jar 的单独 lib 文件夹和一个带有名为 lib 的文件夹和 jar 文件的 zip 文件。不能将其生成为单个 jar 文件吗? @plaidshirt 我必须研究您是否可以使用此解决方案生成一个 uber jar,但我的问题是您为什么想要这样的解决方案?为什么里面所有东西的拉链都不适合你? 我看到 HP TestExportTool 无法处理这个问题,这就是我需要单 jar 解决方案的原因。【参考方案2】:您需要在 maven-assembly-plugin 中指定执行阶段。使用以下 maven-assembly-plugin 配置。
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>test.LeanFTest</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
现在只需在项目 pom.xml(根目录)上运行 mvn package
,您将获得一个完全组装的 jar,其中包含您的 artifactId 加上“jar-with-dependencies”后缀。
【讨论】:
我尝试使用 jar 文件后收到错误消息:Exception in thread "main" java.lang.NoClassDefFoundError: javax/jms/JMSException
我使用 HP TestExportTool 来执行它:admhelp.microfocus.com/leanft/en/14.03/HelpCenter/Content/…java -jar <export tool jar><LeanFT project jar path>-classpath:<testng.jar path>‑framework:TestNG
【参考方案3】:
要创建一个 uber-jar(如 cmets 中所述),可以使用 Maven Shade 插件。此插件将生成一个 JAR,其中包含项目类以及依赖项 JAR 中的所有类。
注意:带有预定义 jar-with-dependencies
的 Maven 程序集插件会在未分类的 jar 旁边生成一个带有固定分类器 (jar-with-dependencies
) 的 uber-jar。似乎无法覆盖它(除了定义自定义程序集)。
【讨论】:
我将 Maven Shade 插件添加到pom.xml
,但在尝试使用生成的 jar 文件时收到另一条错误消息:Exception in thread "main" java.lang.NoClassDefFoundError: javax/jms/JMSException
这似乎是 JEE 的一部分,并且似乎不包含在您的依赖项中。您可能想要包含它。参见例如对于正确的工件mvnrepository.com/artifact/javax/javaee-api/7.0
我不确定,如果缺少依赖项,为什么直接从 IDE 执行成功。
也许你的 IDE 中的类路径设置与 pom 不完全匹配?例如Eclipse 维护一个单独的类路径定义,包括(如果使用 Maven 插件)来自 pom 的所有 dep,仍然可以选择其他项目(例如,服务器运行时,它将包含代码 JEE 类)以上是关于在 Maven 中生成带有依赖项和测试的 jar 文件的主要内容,如果未能解决你的问题,请参考以下文章