我可以将jar添加到Maven 2构建类路径而无需安装它们吗?

Maven 2在开发的实验/快速和肮脏的模型阶段让我发疯。

我有一个pom.xml文件,它定义了我要使用的Web应用程序框架的依赖项,我可以从该文件快速生成入门项目。然而,有时我想链接到还没有定义pom.xml文件的第三方库,所以与其手动为第三方lib创建pom.xml文件并安装它,并将依赖项添加到我的pom.xml,我只想告诉Maven:“除了我定义的依赖项,还包括/lib中的任何jar。”

看起来这应该很简单,但如果是这样,我错过了一些东西。

除此之外,如果有一种简单的方法将maven指向/lib目录并轻松创建一个pom.xml,其中所有封闭的jar映射到一个依赖项,然后我可以一举命名/安装并链接到该依赖项也就足够了。

439113 次浏览

这并没有回答如何将它们添加到您的POM中,并且可能是一个没有头脑的问题,但是将lib dir添加到您的类路径工作吗?我知道当我需要一个我不想添加到我的Maven存储库的外部jar时,我会这样做。

希望这有帮助。

仅适用于丢弃代码

设置作用域==系统,然后组成一个group pId、artifactId和version

<dependency>
<groupId>org.swinglabs</groupId>
<artifactId>swingx</artifactId>
<version>0.9.2</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/swingx-0.9.3.jar</systemPath>
</dependency>

注意:系统依赖项不会复制到结果jar/war中
(见如何在使用maven构建的war中包含系统依赖项

注意:使用System作用域(如本页所述)时,Maven需要绝对路径。

如果您的jar位于项目的根目录下,您需要在system Path值前加上${base dir}。

Maven安装插件使用命令行将jar安装到本地存储库中,POM是可选的,但您必须指定GroupId、ArtifactId、版本和包装(所有POM内容)。

你真的应该通过存储库建立一个框架,并预先识别你的依赖项。使用系统范围是人们使用的一个常见错误,因为他们“不关心依赖管理”。问题是这样做最终会得到一个不正常的maven构建,不会在正常情况下显示maven。你最好遵循这个这样的方法。

我发现了一个奇怪的解决方案:

使用eclipse

  • 创建简单的(非maven)java项目
  • 添加一个Main类
  • 将所有jar添加到类路径
  • 导出Runnable JAR(这很重要,因为这里没有其他方法可以做到)
  • 选择将所需的库提取到生成的JAR中
  • 决定许可证问题
  • 将生成的jar安装到您的m2repo
  • 将此单个依赖项添加到您的其他项目中。

干杯。 巴林特

即使它并不完全适合你的问题,我还是把它放在这里。我的要求是:

  1. 在线maven存储库中找不到的Jars应该在SVN中。
  2. 如果一个开发人员添加了另一个库,其他开发人员不应该为手动安装它们而烦恼。
  3. IDE(在我的例子中是NetBeans)应该能够找到源代码和javadocs来提供自动完成和帮助。

让我们先谈谈(3):仅仅将jar放在一个文件夹中并以某种方式将它们合并到最终的jar中在这里不起作用,因为IDE不会理解这一点。这意味着所有库都必须正确安装。然而,我不想让每个人都使用“mvn安装文件”安装它。

在我的项目中,我需要metawidget。在这里我们去:

  1. 创建一个新的maven项目(将其命名为“共享库”或类似的名称)。
  2. 下载metawidget并将zip解压到src/main/lib中。
  3. 文件夹doc/api包含javadocs。创建内容的zip(doc/api/api.zip)。
  4. 修改pom像这样
  5. 构建项目并安装库。
  6. 将库作为依赖项添加到您的项目中,或者(如果您在共享库项目中添加了依赖项)将共享库作为依赖项添加以一次获取所有库。

每次你有一个新的库,只需添加一个新的执行,并告诉每个人再次构建项目(你可以用项目层次结构来改进这个过程)。

这就是我们如何添加或安装本地jar

    <dependency>
<groupId>org.example</groupId>
<artifactId>iamajar</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/iamajar.jar</systemPath>
</dependency>

我给出了一些默认的group pId和artifactId,因为它们是强制性的:)

如果您想要一个快速而肮脏的解决方案,您可以执行以下操作(尽管我不建议在测试项目之外的任何情况下使用此方法,但maven会详细抱怨这是不合适的)。

为您需要的每个jar文件添加一个依赖项,最好使用perl脚本或类似的东西,并将其复制/粘贴到您的pom文件中。

#! /usr/bin/perl


foreach my $n (@ARGV) {


$n=~s@.*/@@;


print "<dependency>
<groupId>local.dummy</groupId>
<artifactId>$n</artifactId>
<version>0.0.1</version>
<scope>system</scope>
<systemPath>\${project.basedir}/lib/$n</systemPath>
</dependency>
";

systemPath的问题在于依赖项的jar不会作为传递依赖项沿着您的工件分布。试试我在这里发布的内容:最好是将项目jar文件Mavenise还是将它们放在WEB-INF/lib中?

然后像往常一样声明依赖项。

请阅读页脚注释。

流行方法的问题

你在互联网上找到的大多数答案都建议你要么将依赖项安装到本地存储库,要么在pom中指定一个“系统”范围,并将依赖项与项目的源一起分发。但这两种解决方案实际上都是有缺陷的。

为什么不应该应用“安装到本地回购”方法

当您将依赖项安装到本地存储库时,它会保留在那里。只要您的分发工件可以访问此存储库,它就会运行良好。问题是在大多数情况下,此存储库将驻留在您的本地机器上,因此无法在任何其他机器上解决此依赖项。显然让您的工件依赖于特定机器不是处理事情的方法。否则,这种依赖项将不得不本地安装在使用该项目的每台机器上,这也不好。

为什么不应该应用“系统范围”方法

你使用“系统范围”方法依赖的jar既不会安装到任何存储库,也不会附加到你的目标包。这就是为什么你的分发包在使用时没有办法解决这种依赖关系。我相信这就是为什么使用系统范围甚至被弃用的原因。无论如何,你不想依赖一个弃用的功能。

静态项目内存储库解决方案

把这个放在你的pom中:

<repository>
<id>repo</id>
<releases>
<enabled>true</enabled>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<url>file://${project.basedir}/repo</url>
</repository>

对于每个具有x.y.z形式组ID的工件,Maven将在搜索工件时在项目目录中包含以下位置:

repo/
| - x/
|   | - y/
|   |   | - z/
|   |   |   | - ${artifactId}/
|   |   |   |   | - ${version}/
|   |   |   |   |   | - ${artifactId}-${version}.jar

要详细说明这一点,您可以阅读这篇博客文章

使用Maven安装到项目仓库

与其手动创建此结构,我建议使用Maven插件将您的jar作为工件安装。因此,要将工件安装到repo文件夹下的项目内存储库,请执行:

mvn install:install-file -DlocalRepositoryPath=repo -DcreateChecksum=true -Dpackaging=jar -Dfile=[your-jar] -DgroupId=[...] -DartifactId=[...] -Dversion=[...]

如果您选择这种方法,您将能够将pom中的存储库声明简化为:

<repository>
<id>repo</id>
<url>file://${project.basedir}/repo</url>
</repository>

一个辅助脚本

由于为每个lib执行安装命令有点烦人而且肯定容易出错,我创建了一个实用脚本,它会自动将lib文件夹中的所有jar安装到项目存储库,同时自动从文件名中解析所有元数据(group pId、artifactId等)。该脚本还打印出依赖项xml供您复制粘贴到pom中。

在目标包中包含依赖项

当您创建项目内存储库时,您将解决分发项目与其源的依赖关系的问题,但从那时起,您的项目的目标工件将依赖于未发布的jar,因此当您将其安装到存储库时,它将具有无法解决的依赖关系。

为了解决这个问题,我建议将这些依赖项包含在您的目标包中。您可以使用汇编插件或更好地使用OneJar插件。OneJar上的官方文档很容易掌握。

这就是我所做的,它也可以解决包问题,并且可以处理签出的代码。

我在项目中创建了一个新文件夹,在我的情况下我使用repo,但随意使用src/repo

在我的POM中,我有一个不在任何公共maven存储库中的依赖项

<dependency>
<groupId>com.dovetail</groupId>
<artifactId>zoslog4j</artifactId>
<version>1.0.1</version>
<scope>runtime</scope>
</dependency>

然后我创建了以下目录repo/com/dovetail/zoslog4j/1.0.1并将JAR文件复制到该文件夹中。

我创建了以下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.dovetail</groupId>
<artifactId>zoslog4j</artifactId>
<packaging>jar</packaging>
<version>1.0.1</version>
<name>z/OS Log4J Appenders</name>
<url>http://dovetail.com/downloads/misc/index.html</url>
<description>Apache Log4j Appender for z/OS Logstreams, files, etc.</description>
</project>

我创建的两个可选文件是用于POM的SHA1校验和和用于删除缺失校验和警告的JAR。

shasum -b < repo/com/dovetail/zoslog4j/1.0.1/zoslog4j-1.0.1.jar \
> repo/com/dovetail/zoslog4j/1.0.1/zoslog4j-1.0.1.jar.sha1


shasum -b < repo/com/dovetail/zoslog4j/1.0.1/zoslog4j-1.0.1.pom \
> repo/com/dovetail/zoslog4j/1.0.1/zoslog4j-1.0.1.pom.sha1

最后,我将以下片段添加到我的pom.xml,允许我引用本地存储库

<repositories>
<repository>
<id>project</id>
<url>file:///${basedir}/repo</url>
</repository>
</repositories>

在我们的项目中有效的是阿基米德·特拉哈诺写的,但是我们在. m2/settings.xml中有这样的东西:

 <mirror>
<id>nexus</id>
<mirrorOf>*</mirrorOf>
<url>http://url_to_our_repository</url>
</mirror>

*应该改为中央。所以如果他的答案对你不起作用,你应该检查你的settings.xml

您可以在项目上创建本地存储库

例如,如果您在项目结构中有libs文件夹

  • libs文件夹中,您应该创建目录结构,例如:/groupId/artifactId/version/artifactId-version.jar

  • 在您的pom.xml中,您应该注册存储库

     <repository>
    <id>ProjectRepo</id>
    <name>ProjectRepo</name>
    <url>file://${project.basedir}/libs</url>
    </repository>
    
  • 并像往常一样添加依赖项

     <dependency>
    <groupId>groupId</groupId>
    <artifactId>artifactId</artifactId>
    <version>version</version>
    </dependency>
    

仅此而已。

有关详细信息:如何在Maven中添加外部库(存档)

在与CloudBees的人就如何正确地包装这种JAR进行了长时间的讨论之后,他们提出了一个有趣的解决方案:

创建一个虚假的Maven项目,它附加一个预先存在的JAR作为主要工件,运行到属于POM的安装:安装文件执行中。这是POM的一个示例:

 <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.3.1</version>
<executions>
<execution>
<id>image-util-id</id>
<phase>install</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<file>${basedir}/file-you-want-to-include.jar</file>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<packaging>jar</packaging>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

但是为了实现它,现有的项目结构应该改变。首先,你应该记住,对于每种类型的JAR,应该创建不同的假Maven项目(模块)。应该创建一个父Maven项目,包括所有子模块,即:所有JAR包装器和现有的主项目。结构可以是:

根项目(包含父POM文件,包括所有带有模块 XML元素的子模块)(POM打包)

JAR 1包装器Maven子项目(POM包装)

JAR 2包装器Maven子项目(POM包装)

主要现有的Maven子项目(WAR,JAR,EAR…包装)

当通过mvn: install或mvn:打包运行父级时,将强制执行子模块。这可能是一个减号,因为项目结构应该改变,但在最后提供了一个非静态的解决方案

使用<scope>system</scope>是一个糟糕的想法,原因由其他人解释,手动将文件安装到本地存储库会使构建无法重现,使用<url>file://${project.basedir}/repo</url>也不是一个好主意,因为(1)这可能不是格式良好的file URL(例如,如果项目在具有不寻常字符的目录中签出),(2)如果此项目的POM用作其他人项目的依赖项,则结果是不可用的。

假设您不愿意将工件上传到公共存储库,Simeon建议的辅助模块可以完成这项工作。但是现在有一个更简单的方法…

该建议

使用非maven-jar-maven-插件。完全符合您的要求,没有其他方法的缺点。

我找到了另一种方法来做到这一点,从Heroku邮报看这里

总结(对不起一些复制和粘贴)

  • 在您的根文件夹下创建一个repo目录:
yourproject
+- pom.xml
+- src
+- repo
  • 运行此命令将jar安装到本地repo目录
mvn deploy:deploy-file -Durl=file:///path/to/yourproject/repo/ -Dfile=mylib-1.0.jar -DgroupId=com.example -DartifactId=mylib -Dpackaging=jar -Dversion=1.0
  • 添加您的pom.xml
<repositories>
<!--other repositories if any-->
<repository>
<id>project.local</id>
<name>project</name>
<url>file:${project.basedir}/repo</url>
</repository>
</repositories>




<dependency>
<groupId>com.example</groupId>
<artifactId>mylib</artifactId>
<version>1.0</version>
</dependency>

我在@alex lehmann的评论中提到了一些python代码,所以我在这里发布。

def AddJars(jarList):
s1 = ''
for elem in jarList:
s1+= """
<dependency>
<groupId>local.dummy</groupId>
<artifactId>%s</artifactId>
<version>0.0.1</version>
<scope>system</scope>
<systemPath>${project.basedir}/manual_jars/%s</systemPath>
</dependency>\n"""%(elem, elem)
return s1

我只是想要一个快速而肮脏的解决方法……我无法运行Nikita Volkov的脚本:语法错误+它需要一个严格的jar名称格式。

我制作了这个Perl脚本,它适用于jar文件名的任何格式,它在xml中生成依赖项,因此可以直接复制粘贴到pom中。

如果您想使用它,请确保您了解脚本在做什么,您可能需要更改lib文件夹和groupIdartifactId的值…

#!/usr/bin/perl


use strict;
use warnings;


open(my $fh, '>', 'dependencies.xml') or die "Could not open file 'dependencies.xml' $!";
foreach my $file (glob("lib/*.jar")) {
print "$file\n";
my $groupId = "my.mess";
my $artifactId = "";
my $version = "0.1-SNAPSHOT";
if ($file =~ /\/([^\/]*?)(-([0-9v\._]*))?\.jar$/) {
$artifactId = $1;
if (defined($3)) {
$version = $3;
}
`mvn install:install-file -Dfile=$file -DgroupId=$groupId -DartifactId=$artifactId -Dversion=$version -Dpackaging=jar`;
print $fh "<dependency>\n\t<groupId>$groupId</groupId>\n\t<artifactId>$artifactId</artifactId>\n\t<version>$version</version>\n</dependency>\n";
print " => $groupId:$artifactId:$version\n";
} else {
print "##### BEUH...\n";
}
}
close $fh;

对我来说最简单的是配置您的maven-compiler-plugin以包含您的自定义jar。此示例将加载lib目录中的任何jar文件。

        <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<includes>
<include>lib/*.jar</include>
</includes>
</configuration>
</plugin>

快速和肮脏批处理解决方案(基于Alex的回答):

libs.bat

@ECHO OFF
FOR %%I IN (*.jar) DO (
echo ^<dependency^>
echo ^<groupId^>local.dummy^</groupId^>
echo ^<artifactId^>%%I^</artifactId^>
echo ^<version^>0.0.1^</version^>
echo ^<scope^>system^</scope^>
echo ^<systemPath^>${project.basedir}/lib/%%I^</systemPath^>
echo ^</dependency^>
)

像这样执行它:libs.bat > libs.txt。 然后打开libs.txt并将其内容复制为依赖项。

在我的情况下,我只需要库来编译我的代码,这个解决方案是最好的。

要安装不在maven存储库中的第三方jar,请使用maven-install-plugin。

下面是步骤:

  1. 从源代码(网站)手动下载jar文件
  2. 创建一个文件夹并将您的jar文件放入其中
  3. 运行以下命令在本地maven存储库中安装第三方jar

mvn安装:安装文件-Dfile=-Dgroup pId= -DartifactId=-Dversion=-D包装=

下面是一个我用它为simonsite log4j

mvn安装:安装文件 -Dfile=/用户/athanka/git/MyProject/repo/log4j-rolling-appender.jar-DGroupId=uk.org.simonsite-DartifactId=log4j-滚动-附录-Dversion=20150607-2059-D包装=jar

  1. 在pom.xml包含如下依赖项

      <dependency>
    <groupId>uk.org.simonsite</groupId>
    <artifactId>log4j-rolling-appender</artifactId>
    <version>20150607-2059</version>
    </dependency>
    
  2. 运行mvn Clean install命令来创建你的包

下面是参考链接:

对于那些在这里没有找到好答案的人来说,这就是我们正在做的事情,以获得一个包含所有必要依赖项的jar。这个答案(https://stackoverflow.com/a/7623805/1084306)提到使用Maven Assembly插件,但实际上并没有在答案中给出示例。如果你不一直阅读到答案的末尾(它相当长),你可能会错过它。将以下内容添加到你的pom.xml将生成target/${PROJECT_NAME}-${VERSION}-jar-with-dependencies.jar

        <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<!-- get all project dependencies -->
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<!-- MainClass in mainfest make a executable jar -->
<archive>
<manifest>
<mainClass>my.package.mainclass</mainClass>
</manifest>
</archive>


</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!-- bind to the packaging phase -->
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>

Java中范围='系统'方法的解决方案:

public static void main(String[] args) {
String filepath = "/Users/Downloads/lib/";
try (Stream<Path> walk = Files.walk(Paths.get(filepath))) {


List<String> result = walk.filter(Files::isRegularFile)
.map(x -> x.toString()).collect(Collectors.toList());


String indentation = "    ";
for (String s : result) {
System.out.println(indentation + indentation + "<dependency>");
System.out.println(indentation + indentation + indentation + "<groupId>"
+ s.replace(filepath, "").replace(".jar", "")
+ "</groupId>");
System.out.println(indentation + indentation + indentation + "<artifactId>"
+ s.replace(filepath, "").replace(".jar", "")
+ "</artifactId>");
System.out.println(indentation + indentation + indentation + "<version>"
+ s.replace(filepath, "").replace(".jar", "")
+ "</version>");
System.out.println(indentation + indentation + indentation + "<scope>system</scope>");
System.out.println(indentation + indentation + indentation + "<systemPath>" + s + "</systemPath>");
System.out.println(indentation + indentation + "</dependency>");
}


} catch (IOException e) {
e.printStackTrace();
}
}