关于java:我可以在没有安装的情况下将jar添加到maven 2 build classpath吗?

Can I add jars to maven 2 build classpath without installing them?

Maven2在开发的实验/快速和肮脏的模拟阶段让我疯狂。

我有一个pom.xml文件,它定义了我想要使用的Web应用框架的依赖项,我可以从该文件快速生成入门项目。但是,有时我想链接到一个没有定义pom.xml文件的第三方库,所以我不想手动为第三方库创建pom.xml文件并安装它,并将依赖项添加到我的pom.xml中,我只想告诉maven:"除了我定义的依赖项之外,还包括我定义的所有jar在江户区也有1〔4〕。

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

关于如何做到这一点的任何建议都非常感谢。除此之外,如果有一种简单的方法可以将maven指向一个/lib目录,并轻松创建一个pom.xml,其中所有附带的jar都映射到一个依赖项,然后我就可以命名/安装并链接到一个fall-swoop,这也就足够了。


流行方法的问题

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

为什么不应用"安装到本地回购"方法

当您将依赖项安装到本地存储库时,它将保留在那里。只要您的分发工件有权访问这个存储库,它就可以正常工作。问题是在大多数情况下,此存储库将驻留在本地计算机上,因此无法解决对任何其他计算机的这种依赖。显然,让您的工件依赖于特定的机器并不是处理事情的方法。否则,这种依赖关系将必须在本地安装在每个与该项目一起工作的计算机上,而这并不是更好的。

为什么不应用"系统范围"方法

使用"系统范围"方法依赖的JAR既不能安装到任何存储库,也不能连接到目标包。这就是为什么您的分发包在使用时无法解决这种依赖关系的原因。我认为这就是为什么系统范围的使用被否决的原因。无论如何,您不希望依赖已弃用的功能。

静态项目存储库解决方案

把这个放在你的pom里之后:

1
2
3
4
5
6
7
8
9
10
11
<repository>
    <id>repo</id>
    <releases>
        <enabled>true</enabled>
        <checksumPolicy>ignore</checksumPolicy>
    </releases>
    <snapshots>
        <enabled>false</enabled>
    </snapshots>
    <url>file://${project.basedir}/repo</url>
</repository>

对于每个组ID为x.y.zmaven的工件,在搜索工件时,项目目录中的以下位置将包括:

1
2
3
4
5
6
7
repo/
| - x/
|   | - y/
|   |   | - z/
|   |   |   | - ${artifactId}/
|   |   |   |   | - ${version}/
|   |   |   |   |   | - ${artifactId}-${version}.jar

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

使用maven安装到项目repo

我建议不要手工创建这个结构,而是使用maven插件将jar安装为工件。因此,要将工件安装到repo文件夹下的项目存储库中,请执行以下操作:

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

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

1
2
3
4
<repository>
    <id>repo</id>
    <url>file://${project.basedir}/repo</url>
</repository>

助手脚本

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

在目标包中包含依赖项

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

为了克服这个问题,我建议在目标包中包含这些依赖项。您可以使用程序集插件,或者更好地使用Onejar插件。Onejar上的官方文档很容易理解。


仅用于丢弃代码

设置scope==system,只需组成groupid、artifactid和version

1
2
3
4
5
6
7
<dependency>
    <groupId>org.swinglabs</groupId>
    swingx</artifactId>
    <version>0.9.2</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/lib/swingx-0.9.3.jar</systemPath>
</dependency>

注意:系统依赖项不会复制到结果jar/war中。(请参阅如何在使用maven构建的战争中包含系统依赖项)


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

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

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

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

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

    1
    2
    3
    4
    5
    <dependency>
        <groupId>groupId</groupId>
        artifactId</artifactId>
        <version>version</version>
    </dependency>

仅此而已。

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


注意:当使用系统范围(如本页所述)时,Maven需要绝对路径。

如果JAR位于项目的根目录下,则需要在SystemPath值前面加上$basedir_。


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


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

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

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

1
2
3
4
5
6
<dependency>
    <groupId>com.dovetail</groupId>
    zoslog4j</artifactId>
    <version>1.0.1</version>
    <scope>runtime</scope>
</dependency>

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

我创建了下面的pom文件来表示下载的文件(这个步骤是可选的,但它删除了一个警告),并帮助下一个家伙找出从哪里开始获取文件。

1
2
3
4
5
6
7
8
9
10
11
12
<?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>
    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和jar的sha1校验和,用于删除缺少的校验和警告。

1
2
3
4
5
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中,它允许我引用本地存储库。

1
2
3
4
5
6
<repositories>
    <repository>
        <id>project</id>
        <url>file:///${basedir}/repo</url>
    </repository>
</repositories>


maven install plugin具有命令行用法,可以将jar安装到本地存储库中,pom是可选的,但您必须指定groupid、artifactid、版本和打包(所有pom内容)。


这就是我们如何添加或安装本地JAR的方法

1
2
3
4
5
6
7
    <dependency>
        <groupId>org.example</groupId>
        iamajar</artifactId>
        <version>1.0</version>
        <scope>system</scope>
        <systemPath>${project.basedir}/lib/iamajar.jar</systemPath>
    </dependency>

我给出了一些默认的groupid和artifactid,因为它们是必需的:)


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

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

建议

使用非maven jar maven插件。完全按照你的要求做,没有其他方法的缺点。


我找到了另一种方法来做这件事,从一个Heroku的柱子上看。

总结(对于复制和粘贴感到抱歉)

  • 在根文件夹下创建一个repo目录:
1
2
3
4
yourproject
+- pom.xml
+- src
+- repo
  • 运行此命令将jar安装到本地repo目录中
1
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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>
    mylib</artifactId>
    <version>1.0</version>  
</dependency>

在与Cloudbees的人就这种罐子的合适的Maven包装进行了很长时间的讨论之后,他们提出了一个有趣的很好的解决方案:

创建一个假maven项目,将一个预先存在的jar作为主要工件附加到所属的pom install:install文件执行中。下面是一个这样的POM扭结的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 <build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            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>
                        ${project.artifactId}</artifactId>
                        <version>${project.version}</version>
                        <packaging>jar</packaging>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

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

root project (this contains the parent POM file includes all sub-modules with module XML element) (POM packaging)

JAR 1 wrapper Maven child project (POM packaging)

JAR 2 wrapper Maven child project (POM packaging)

main existing Maven child project (WAR, JAR, EAR .... packaging)

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


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

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

请看脚注。


对我来说,最简单的就是将Maven编译器插件配置为包含自定义jar。此示例将在lib目录中加载任何jar文件。

1
2
3
4
5
6
7
8
9
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            maven-compiler-plugin</artifactId>
            <configuration>
                <includes>
                    <include>lib/*.jar</include>
                </includes>
            </configuration>
        </plugin>


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

蝙蝠

1
2
3
4
5
6
7
8
9
10
@ECHO OFF
FOR %%I IN (*.jar) DO (
echo ^<dependency^>
echo ^<groupId^>local.dummy^</groupId^>
echo ^%%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文件添加一个依赖项,最好使用Perl脚本或类似的东西,并将其复制/粘贴到POM文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#! /usr/bin/perl

foreach my $n (@ARGV) {

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

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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            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 -->
               
                  <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>

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

  • 在线Maven存储库中找不到的JAR应该在SVN中。
  • 如果一个开发人员添加了另一个库,其他开发人员不应该为手动安装它们而烦恼。
  • IDE(在我的例子中是NetBeans)应该能够找到源代码和JavaDoc来提供自动完成和帮助。
  • 让我们先谈谈(3):仅仅把jar放在一个文件夹中,然后以某种方式将它们合并到最终的jar中,在这里是行不通的,因为IDE不理解这一点。这意味着必须正确安装所有库。但是,我不希望每个人都使用"mvn安装文件"来安装它。

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

  • 创建一个新的Maven项目(将其命名为"共享libs"或类似的名称)。
  • 下载metawidget并将zip解压缩到src/main/lib中。
  • 文件夹doc/api包含javadocs。创建内容的zip(doc/api/api.zip)。
  • 像这样修改POM
  • 生成项目,将安装库。
  • 将库作为依赖项添加到项目中,或者(如果在共享libs项目中添加了依赖项)将共享libs作为依赖项添加到项目中,以同时获取所有库。
  • 每次有新的库时,只需添加一个新的执行,并告诉每个人重新构建项目(您可以使用项目层次结构改进此过程)。


    我发现了一个奇怪的解决办法:

    使用Eclipse

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

    干杯,巴林特


    要安装不在Maven存储库中的第三方JAR,请使用Maven安装插件。

    以下是步骤:

  • 从源(网站)手动下载JAR文件
  • 创建一个文件夹并将JAR文件放在其中
  • 运行以下命令在本地Maven存储库中安装第三方JAR
  • mvn install:install-file -Dfile= -DgroupId=
    -DartifactId= -Dversion= -Dpackaging=

    下面是我用于Simonsite Log4J的示例

    mvn install:install-file
    -Dfile=/Users/athanka/git/MyProject/repo/log4j-rolling-appender.jar -DgroupId=uk.org.simonsite -DartifactId=log4j-rolling-appender -Dversion=20150607-2059 -Dpackaging=jar

  • 在pom.xml中包含依赖项,如下所示


    1
    2
    3
    4
    5
      <dependency>
            <groupId>uk.org.simonsite</groupId>
            log4j-rolling-appender</artifactId>
            <version>20150607-2059</version>
      </dependency>
  • 运行mvn clean install命令以创建包

  • 以下是参考链接:

    https://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html网站


    这并不能回答如何将它们添加到POM中,这可能是一个很简单的方法,但是只需将lib dir添加到类路径工作中就行了?我知道当我需要一个不想添加到我的MavenRepos中的外部JAR时,这就是我要做的。

    希望这有帮助。


    在我们的项目中工作的是阿基米德·特拉亚诺写的,但是我们在.m2/settings.xml中有这样的功能:

    1
    2
    3
    4
    5
     <mirror>
      <id>nexus</id>
      <mirrorOf>*</mirrorOf>
      <url>http://url_to_our_repository</url>
     </mirror>

    *应该改为中央。因此,如果他的回答对您不起作用,您应该检查settings.xml。


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def AddJars(jarList):
      s1 = ''
      for elem in jarList:
       s1+="""
         <dependency>
            <groupId>local.dummy</groupId>
            %s</artifactId>
            <version>0.0.1</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/manual_jars/%s</systemPath>
         </dependency>
    "
    ""%(elem, elem)
      return s1

    我只是想要一个快速和肮脏的解决方案…我无法运行nikita volkov的脚本:语法错误+它要求JAR名称采用严格的格式。

    我制作了这个Perl脚本,它可以使用任何格式来处理jar文件名,它以XML形式生成依赖项,这样就可以将它直接复制粘贴到pom中。

    如果要使用它,请确保您了解脚本正在执行的操作,您可能需要更改lib文件夹和groupIdartifactId的值…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #!/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
    "
    ;
        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>
    \t<groupId>$groupId</groupId>
    \t$artifactId</artifactId>
    \t<version>$version</version>
    </dependency>
    "
    ;
            print" => $groupId:$artifactId:$version
    "
    ;
        } else {
            print"##### BEUH...
    "
    ;
        }
    }
    close $fh;