62

我对一些外部 jar 有运行时依赖项,我想将它们“重新压缩”到单个 jar 中。这些外部依赖项存储在 external_jars 目录中,我希望不必将它们全部列出(即,如果我的依赖项发生更改,则无需更改构建脚本)。有什么想法吗?

谷歌给了我一个关于如何做到这一点的好答案——如果你不介意将每个 jar 列为依赖项:

http://markmail.org/message/zijbwm46maxzzoo5

粗略地说,我想要以下内容,它将 lib 目录中的所有 jar 合并到 out.jar 中(带有一些理智的覆盖规则)。

jar -combine -out out.jar -in lib/*.jar
4

11 回答 11

67

弗拉基米尔的回答是正确的,但我觉得他的建议意味着将所有罐子重新包装在一个大的 out.jar 中,然后将其作为单个<zipfileset>或类似的东西提供给 Ant Jar 任务。这种两步法是不必要的。我不确定这是否与 Ant 版本有关,但我有 Ant 1.7.1,它的<jar>任务理解<zipgroupfileset>,它允许直接提供第三方 jar 的所有内容。

<jar destfile="MyApplication.jar">
  <zipgroupfileset dir="lib" includes="*.jar" /> 
  <!-- other options -->
  <manifest>
    <attribute name="Main-Class" value="Main.MainClass" />
  </manifest>
</jar>
于 2009-10-24T21:14:27.143 回答
58

只需zipgroupfileset与 Ant Zip 任务一起使用

<zip destfile="out.jar">
    <zipgroupfileset dir="lib" includes="*.jar"/>
</zip>

这将展平所有包含的 jar 库的内容。

于 2009-02-05T21:38:14.403 回答
23

你可以查看jarjar:

http://code.google.com/p/jarjar/

于 2009-02-05T11:03:41.593 回答
9

尝试先将您的 JAR 提取到编组目录:

<target name="combine-jars">
    <mkdir dir="${marshall.dir}"/>
    <unzip dest="${marshall.dir}">
        <fileset dir="${external.jar.dir}">
            <include name="**/*.jar"/>
        </fileset>
    </unzip>
    <jar destfile="${combined.jar}" basedir="${marshall.dir"}>
    <delete dir="${marshall.dir}"/>
</target>

where${marshall.dir}是一个临时目录,${external.jar.dir}是您保存 JAR 的位置,并且${combined.jar}是目标 JAR。

于 2009-02-05T12:55:14.677 回答
3

如果使用maven,你为什么不呢?:) 只需使用 maven-shade-plugin,就像一个魅力!

  <project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>1.5</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <mainClass>com.YOUR_COMPANY.YOUR_MAIN_CLASS</mainClass>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>
于 2012-01-31T15:15:34.007 回答
2

这是我的解决方案:

<target name="-post-jar">
    <echo>Packaging ${application.title} into a single JAR</echo>

    <jar destfile="${basedir}${file.separator}${dist.dir}${file.separator}_${ant.project.name}_.jar">
        <zipgroupfileset dir="${basedir}${file.separator}${dist.dir}" includes="${ant.project.name}.jar"/>
        <zipgroupfileset dir="${basedir}${file.separator}${dist.dir}${file.separator}lib" includes="*.jar"/>
        <manifest>
            <attribute name="Main-Class" value="${main.class}"/>
        </manifest>
    </jar>
</target>
于 2011-01-14T13:40:38.933 回答
1

这个问题很好回答。我想提一个我觉得有用的工具 - One-Jar。One-Jar 更干净地处理资源(通过保留所有资源)。如果代码需要处理 MANIFEST 文件,这将更加有用。

从网站复制的示例 XML..

<import file="one-jar-ant-task.xml"/>   

    <target name="hello" depends="init">
        <!-- Build lib.jar -->   
        <javac destdir="${classes.dir}/lib">
            <src path="${lib.dir}" />
        </javac>
        <jar destfile="${build.dir}/lib.jar" >
            <fileset dir="${classes.dir}/lib"/>
        </jar>   
        <!-- Build classes for main.jar -->   
        <javac destdir="${classes.dir}/src">
            <src path="${src.dir}" />
            <classpath path="${build.dir}/lib.jar"/>   
        </javac>
        <!-- Construct the One-JAR file -->   
        <one-jar destfile="hello.jar" manifest="hello.mf">
            <main>
                <!-- Construct main.jar from classes and source code -->
                <fileset dir="${classes.dir}/src"/>
            </main>
            <lib>
                <fileset file="${build.dir}/lib.jar" />
            </lib>
        </one-jar>
        <echo>
          Now you can run the Hello One-JAR example using 
          $ java -jar hello.jar
        </echo>   

    </target>
于 2012-03-14T05:11:59.400 回答
1

如果您正在使用 ant 构建(我正在使用来自 eclipse 的 ant),您可以通过告诉 ant 添加额外的 jar 文件来添加它们......如果您有一个由多人维护的项目,这不一定是最好的方法,但它可以工作对于一个人的项目,很容易。

例如,我构建 .jar 文件的目标是:

<jar destfile="${plugin.jar}" basedir="${plugin.build.dir}">
    <manifest>
        <attribute name="Author" value="ntg"/>
        ................................
        <attribute name="Plugin-Version" value="${version.entry.commit.revision}"/>
    </manifest>
</jar>

我只是添加了一行来实现它:

<jar ....">
    <zipgroupfileset dir="${external-lib-dir}" includes="*.jar"/>
    <manifest>
        ................................
    </manifest>
</jar>

在哪里

<property name="external-lib-dir" value="C:\...\eclipseWorkspace\Filter\external\...\lib" />

是带有外部罐子的目录。就是这样……您也可以添加多个 zipgroupfileset 标签。

于 2012-04-25T18:41:33.940 回答
0

您是否考虑过使用Maven或其他自动管理依赖项的系统?然后,您无需指定每个库的位置、它们的名称以及您的直接依赖项具有哪些传递依赖项。您只需在一处说明依赖项及其版本是什么,系统将负责下载库、配置类路径和构建项目。

于 2009-02-05T18:50:32.883 回答
0

好吧,我不太喜欢编程 - 但更简单的东西对我有用......如果问题意味着 - 将 jar 文件合并为一个。当然,这是手动的、肮脏的解决方案。我只是解压缩了所有的 tar 文件……然后……创建了一个新的 tar 文件,方法是将 untarring- 形成的所有目录添加到新的 tar 文件中。有效。

于 2010-03-18T03:57:26.060 回答
0

Maven 或其他构建工具无法“管理”多个版本的类文件的解析。事实上,Maven 首先通过传递包含项目未明确要求的所有下游 jar 文件来导致这些问题。

假设在一个项目的传递闭包中(项目所需的所有库和模块,以及所有它的依赖项目,递归地)有两个版本的类文件。Maven 怎么可能知道哪一个是“正确的”?程序员想要的是哪一个?

不能,因为当显式依赖被丢弃以支持传递依赖(以节省 XML 类型)时,此信息丢失了。

于 2010-04-15T08:56:47.987 回答