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

时间:2008-12-12 20:57:31

标签: java maven-2

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

我有一个pom.xml文件,用于定义我想要使用的Web应用程序框架的依赖关系,我可以从该文件快速生成启动项目。但是,有时我想链接到尚未定义pom.xml文件的第三方库,而不是手动创建第三方lib的pom.xml文件并安装它,并且将依赖项添加到我的pom.xml,我只想告诉Maven:“除了我定义的依赖项之外,还要包含/lib中的所有jar。”

这似乎应该很简单,但如果是这样的话,我就错过了一些东西。

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

24 个答案:

答案 0 :(得分:577)

流行方法的问题

您将在互联网上找到的大多数答案都建议您将依赖项安装到本地存储库或在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>

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

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

要详细说明,请阅读this blog post

使用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执行安装命令有点烦人并且肯定容易出错,我创建了一个utility script,它自动将所有jar从lib文件夹安装到项目存储库,同时自动解析来自文件名的所有元数据(groupId,artifactId等)。该脚本还会打印出依赖项xml,以便在pom中复制粘贴。

在目标包中包含依赖项

如果您已经创建了项目内存储库,那么您将解决使用其源代码分发项目依赖项的问题,但从那时起,项目的目标工件将依赖于未发布的jar,所以当您将它安装到存储库,它将具有无法解析的依赖项。

为了解决这个问题,我建议在目标包中包含这些依赖项。您可以Assembly Plugin使用OneJar Plugin或更好{{3}}。关于OneJar的官方文件很容易理解。

答案 1 :(得分:469)

仅限丢弃代码

设置范围==系统,只需组成groupId,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中 (见How to include system dependencies in war built using maven

答案 2 :(得分:54)

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

例如,如果项目结构中有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>
    

就是这样。

详细信息:How to add external libraries in Maven

答案 3 :(得分:31)

注意:使用系统范围(as mentioned on this page)时,Maven需要绝对路径。

如果您的jar位于项目的根目录下,则需要使用$ {basedir}为systemPath值添加前缀。

答案 4 :(得分:14)

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

答案 5 :(得分:13)

这就是我所做的,它也适用于包问题,它适用于检出的代码。

我在项目中创建了一个新文件夹,我使用了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>

答案 6 :(得分:12)

Maven install plugin有命令行用法将jar安装到本地存储库,POM是可选的,但您必须指定GroupId,ArtifactId,Version和Packaging(所有POM内容)。

答案 7 :(得分:10)

这是我们添加或安装本地jar的方式

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

我提供了一些默认的groupId和artifactId,因为它们是强制性的:)

答案 8 :(得分:8)

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

假设您不愿意将工件上传到公共存储库,Simeon建议使用帮助程序模块来完成工作。但现在有一种更简单的方法......

建议书

使用non-maven-jar-maven-plugin。正是你所要求的,没有其他方法的缺点。

答案 9 :(得分:8)

我找到了另一种方法,请参阅此处Heroku post

总结(抱歉有些复制和粘贴)

  • 在根文件夹下创建一个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>

答案 10 :(得分:6)

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

创建一个假的Maven项目,该项目将预先存在的JAR作为主要工件附加,运行到属于POM的安装:安装文件执行。以下是POM的这种kinf的一个例子:

 <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包装器和现有主项目。结构可以是:

  

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

     

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

     

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

     

主要存在的Maven子项目(WAR,JAR,EAR ....包装)

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

答案 11 :(得分:4)

systemPath的问题在于,依赖项的jar文件不会作为传递依赖项沿着工件分发。试试我在这里发布的内容:Is it best to Mavenize your project jar files or put them in WEB-INF/lib?

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

请阅读页脚说明。

答案 12 :(得分:3)

如果你想要一个快速而肮脏的解决方案,你可以做以下事情(虽然我不建议除了测试项目以外的任何事情,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>
";

答案 13 :(得分:3)

对我来说最简单的是配置你的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>

答案 14 :(得分:3)

quick&amp; dirty 批处理解决方案(基于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并将其内容复制为依赖项。

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

答案 15 :(得分:2)

即使它不完全适合您的问题,我也会放弃它。我的要求是:

  1. 在在线maven存储库中找不到的Jars应该在SVN中。
  2. 如果一个开发人员添加了另一个库,其他开发人员不应该为手动安装它们而烦恼。
  3. IDE(在我的案例中为NetBeans)应该能够找到源和javadoc来提供自动完成和帮助。
  4. 让我们首先谈谈(3):将jar放在一个文件夹中并以某种方式将它们合并到最终的jar中将不起作用,因为IDE不会理解这一点。这意味着必须正确安装所有库。但是,我不希望每个人都使用“mvn install-file”安装它。

    在我的项目中,我需要metawidget。我们走了:

    1. 创建一个新的maven项目(将其命名为“shared-libs”或类似名称)。
    2. 下载metawidget并将zip解压缩到src / main / lib。
    3. 文件夹doc / api包含javadocs。创建内容的zip(doc / api / api.zip)。
    4. 修改pom like this
    5. 构建项目并安装库。
    6. 将库作为依赖项添加到项目中,或者(如果在shared-libs项目中添加了依赖项)将shared-libs添加为依赖项以立即获取所有库。
    7. 每次有新库时,只需添加一个新执行并告诉每个人再次构建项目(您可以使用项目层次结构改进此过程)。

答案 16 :(得分:2)

我找到了一个奇怪的解决方案:

使用Eclipse

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

欢呼声, 巴林特

答案 17 :(得分:2)

对于那些在这里找不到好答案的人来说,这就是我们正在做的事情,以获得一个包含所有必要依赖关系的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>

答案 18 :(得分:2)

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

以下是步骤:

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

    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

    1. 在pom.xml中包含依赖关系,如下所示

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

    3. 以下是参考链接:

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

答案 19 :(得分:0)

Java中scope ='system'方法的解决方案:

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();
    }
}

答案 20 :(得分:0)

这不会回答如何将它们添加到您的POM中,并且可能没什么问题,但只是将lib目录添加到您的类路径工作中?我知道当我需要一个我不想添加到我的Maven回购中的外部jar时,我就会这样做。

希望这有帮助。

答案 21 :(得分:0)

我在@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

答案 22 :(得分:0)

在我们的项目中有用的是Archimedes Trajano所写的内容,但我们在.m2 / settings.xml中有这样的内容:

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

并且*应该更改为central。因此,如果他的答案对你不起作用,你应该检查你的settings.xml

答案 23 :(得分:-1)

我只想要一个快速而肮脏的解决方法......我无法运行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;