Jar

描述

将一组文件打包成 Jar 包。

basedir 属性是打包的参考目录。

请注意,生成的 Jar 包中不会存储文件权限。

可以对要打包的文件进行细化。这可以通过 includesincludesfileexcludesexcludesfiledefaultexcludes 属性来实现。使用 includesincludesfile 属性,您可以使用模式指定要包含的文件。使用 excludeexcludesfile 属性指定要排除的文件。这也使用模式来完成。最后,使用 defaultexcludes 属性,您可以指定是否使用默认排除。有关如何进行文件包含/排除以及如何编写模式,请参阅有关 基于目录的任务 的部分。

此任务形成一个隐式的 FileSet,并支持 <fileset> 的大多数属性(dir 变为 basedir),以及嵌套的 <include><exclude><patternset> 元素。

您还可以使用嵌套的文件集来获得更大的灵活性,并指定多个文件集将不同的文件树合并到一个 JAR 中。zip 任务中的扩展 filesetgroupfileset 子元素在 jar 任务中也可用。有关更多详细信息和示例,请参阅 Zip 任务。

update 参数控制如果 JAR 文件已经存在会发生什么。如果设置为 yes,则使用指定的文件更新 JAR 文件。如果设置为 no(默认值),则覆盖 JAR 文件。在 Zip 任务文档 中提供了此功能的示例用法。请注意,ZIP 文件以 2 秒的粒度存储文件修改时间。如果文件比存档中的条目新不到 2 秒,Ant 不会将其视为更新。

如果省略清单,Apache Ant 将提供一个简单的清单。

whenmanifestonly 参数控制当除了清单文件或嵌套服务之外没有文件匹配时会发生什么。如果为 skip,则不创建 JAR 并发出警告。如果为 fail,则不创建 JAR 并使用错误停止构建。如果为 create(默认值),则创建一个空 JAR 文件(仅包含清单和服务)。

Jar 任务有一个用于指定 JAR 文件的清单文件的快捷方式。使用 Zip 任务中 zipfilesetfullpath 属性可以实现相同的效果。唯一的区别是,如果未指定 manifest 属性,Jar 任务将为您包含一个空的清单。)

清单由 Jar 任务根据 Jar 文件规范 进行处理。特别要注意,这可能会导致大于 72 字节的清单行被换行并继续到下一行。

Jar 任务检查您是否根据 版本控制规范 指定了包信息。

请注意,ZIP 格式允许在单个存档中存在多个具有相同完全限定名称的文件。这已被记录为对毫无戒心的用户造成各种问题。如果您希望避免这种行为,则必须将 duplicate 属性设置为除其默认值 add 之外的其他值。

要对 JAR 文件进行加密签名,请使用此任务创建的 JAR 上的 SignJar 任务

要创建 JEP 238 多版本 jar 的简单版本,您不需要任何特殊工具。只需设置所需的 manifest 条目并将文件放置在所需的位置,如 JEP 238 示例 中所示。如果您想调整这种类型的 jar,例如通过从版本分支中删除“相同”类来减小大小,您需要做更多的事情...

参数

属性 描述 必需
destfile 要创建的 JAR 文件。
basedir 打包文件的目录。
compress 不仅存储数据,还要压缩它们。除非您将 keepcompression 属性设置为 false,否则这将应用于整个存档,而不仅仅是您在更新时添加的文件。 否;默认为 true
keepcompression 对于来自现有存档(如嵌套的 zipfileset 或更新存档时)的条目,保持其原始压缩方式,而不是使用 compress 属性。自 Ant 1.6 起 否;默认为 false
encoding 用于存档中文件名字符编码。不建议更改此值,因为否则创建的存档很可能无法被 Java 读取。
另请参阅 zip 任务页面中的讨论
否;默认为 UTF8
filesonly 仅存储文件条目 否;默认为 false
includes 必须包含的文件模式的逗号或空格分隔列表 否;默认为全部(**
includesfile 文件名称。此文件的每一行都被视为一个包含模式
excludes 必须排除的文件模式的逗号或空格分隔列表 否;默认为默认排除,如果 defaultexcludesno,则为无
excludesfile 文件名称。此文件的每一行都被视为一个排除模式
defaultexcludes 指示是否使用默认排除(yes|no 否;默认为 yes
manifest 要使用的清单文件。这可以是清单的位置,也可以是通过文件集添加的 jar 的名称。如果它是添加的 jar 的名称,则任务期望清单位于 jar 中的 META-INF/MANIFEST.MF
filesetmanifest zipfilesetzipgroupfileset 文件中找到清单时的行为。有效值为 skipmergemergewithoutmainmerge 将所有清单合并在一起,并将此合并到任何其他指定的清单中。 mergewithoutmain 合并所有内容,但清单的主部分除外。 否;默认为 skip
update 指示如果目标文件已存在,是否更新或覆盖它 否;默认为 false
whenmanifestonly 当没有文件匹配时的行为。有效值为 failskipcreate 否;默认为 create
duplicate 找到重复文件时的行为。有效值为 addpreservefail 否;默认为 add
index 是否创建 索引列表 以加快类加载速度。除非您使用嵌套的 indexjars 元素指定其他 jar,否则只有此 jar 的内容将包含在索引中。 否;默认为 false
indexMetaInf 是否将 META-INF 及其子目录包含在索引中。如果 indexfalse,则没有任何效果。
Sun 的 jar 实现过去会跳过 META-INF 目录,Ant 遵循了该示例。该行为已在 Java 5 中更改。为了避免在 Java 1.4 或更早版本上使用 Ant 生成的 jar 出现问题,除非明确要求,否则 Ant 不会包含 META-INF自 Ant 1.8.0 起
否;默认为 false
manifestencoding 用于读取 JAR 清单的编码,当指定清单文件时。任务在写入清单时始终使用 UTF-8。 否;默认为默认 JVM 字符编码
roundup 文件修改时间是否向上舍入到下一个偶数秒。
Zip 存档以 2 秒的粒度存储文件修改时间,因此时间将向上或向下舍入。如果您向下舍入,则每次重新运行任务时存档将始终显示为过期,因此默认情况下向上舍入。向上舍入可能会导致其他类型的问题,例如 Web 存档中的 JSP 似乎比预编译页面略微更新,从而使预编译变得毫无用处。自 Ant 1.6.2 起
否;默认为 true
level 执行文件压缩的非默认级别。有效值范围为 0(无压缩/最快)到 9(最大压缩/最慢)。自 Ant 1.7 起
strict 配置如何处理打包版本规范的违规
  • fail = 抛出 BuildException
  • warn = 在警告级别记录一条消息
  • ignore = 在详细级别记录一条消息(默认值)
自 Ant 1.7.1 起
否;默认为 ignore
preserve0permissions 在更新存档或从其他存档添加条目时,Ant 将假设 Unix 权限值为 0(没有人被允许对文件/目录执行任何操作)意味着权限根本没有存储,而不是实际权限,并将改为应用其自己的默认值。
如果您确实要保留原始权限字段,请将此属性设置为 true自 Ant 1.8.0 起
否;默认为 false
useLanguageEncodingFlag 如果编码为 UTF-8,是否设置语言编码标志。如果编码不是 UTF-8,则此设置没有任何效果。自 Ant 1.8.0 起
另请参阅 zip 任务页面中的讨论
否;默认为 true
createUnicodeExtraFields 是否创建 Unicode 额外字段以在条目元数据中第二次存储文件名。
可能的值为 neveralwaysnot-encodeable,它将仅在文件名无法编码时添加 Unicode 额外字段。
另请参阅 zip 任务页面中的讨论
否;默认为 never
fallbacktoUTF8 如果文件名无法使用指定的编码进行编码,是否使用 UTF-8 和语言编码标志而不是指定的编码。自 Ant 1.8.0 起
另请参阅 zip 任务页面中的讨论
否;默认为 false
mergeClassPathAttributes 是否合并不同清单中找到的 Class-Path 属性(如果合并清单)。如果为 false,则仅保留最后一个合并的清单的属性。自 Ant 1.8.0 起
除非您还将 flattenAttributes 设置为 true,否则这可能会导致清单包含多个 Class-Path 属性,这违反了清单规范。
否;默认为 false
flattenAttributes 是否将一个部分中出现多次的属性(这只能发生在 Class-Path 属性中)合并到单个属性中。自 Ant 1.8.0 起 否;默认为 false
zip64Mode 何时对条目使用 Zip64 扩展。可能的值为 neveralwaysas-needed自 Ant 1.9.1 起
另请参阅 zip 任务页面中的讨论
否;默认为 never
modificationtime 将所有存储的文件修改时间设置为给定时间。这可以是解释为自 1970-01-01T00:00:00Z 以来的毫秒数,也可以是可解析为带可选时区的 ISO 8601 时间戳的字符串。自 Ant 1.10.2 起

作为嵌套元素指定的参数

metainf

嵌套的 metainf 元素指定一个 FileSet。此文件集中包含的所有文件最终将位于 jar 文件的 META-INF 目录中。如果此文件集包含一个名为 MANIFEST.MF 的文件,则该文件将被忽略,您将收到警告。

manifest

嵌套的manifest元素允许在构建文件中内联提供 Jar 文件的清单,而不是在外部文件中。此元素与manifest任务相同,但必须省略filemode属性。

如果同时指定了内联清单和外部文件,则会合并这些清单。

使用内联清单时,Jar任务将检查清单内容是否已更改(即,指定的清单是否与 jar 中存在的清单(如果存在)有任何不同。如果清单值已更改,则将根据需要更新或重建 jar。

indexjars

自 Ant 1.6.2 起

嵌套的indexjars元素指定一个类似路径的结构。除非将任务的index属性设置为true,否则其内容将被完全忽略。

此任务创建的索引将包含此路径中包含的存档的索引,用于存档的名称取决于您的清单

此任务不会为为空或仅包含META-INF目录中的文件的存档创建任何索引条目,除非indexmetainf属性已设置为true

indexjarsmapper

自 Ant 1.10.9 起

如果默认文件名转换不足,则可以使用嵌套的indexjarsmapper元素对indexjars指定的存档执行自定义文件名转换。

service

自 Ant 1.7.0 起

嵌套的service元素指定一个服务。服务在服务提供者概述中进行了描述。该方法是让提供者 JAR 包含以提供的服务命名的文件,例如META-INF/services/javax.script.ScriptEngineFactory,其中可以包含实现类名,每行一个(通常每个 JAR 只有一个)。

服务的名称由type属性设置。实现服务的类名是provider属性,或者如果要指定多个实现服务的类,则通过provider嵌套元素。

属性 描述 必需
type 服务的名称。
provider 实现服务的类的类名。 是的,除非存在嵌套的<provider>元素。

提供者类名由provider属性或嵌套的<provider>元素指定,该元素具有单个classname属性。如果 JAR 文件具有多个服务的实现,则可以使用多个嵌套的<provider>元素。

示例

简单

${build}/classes目录中的所有文件打包到${dist}/lib目录中名为app.jar的文件中。

<jar destfile="${dist}/lib/app.jar" basedir="${build}/classes"/>

使用过滤器

${build}/classes目录中的所有文件打包到${dist}/lib目录中名为app.jar的文件中。排除名为Test.class的文件。

<jar destfile="${dist}/lib/app.jar"
     basedir="${build}/classes"
     excludes="**/Test.class"/>

${build}/classes目录中的所有文件打包到${dist}/lib目录中名为app.jar的文件中。仅使用mypackage/test目录下的文件,并排除名为Test.class的文件。

<jar destfile="${dist}/lib/app.jar"
     basedir="${build}/classes"
     includes="mypackage/test/**"
     excludes="**/Test.class"/>

多个文件集

${build}/classes目录和${src}/resources目录中的所有文件一起打包到${dist}/lib目录中名为app.jar的文件中。排除名为Test.class的文件。如果存在诸如${build}/classes/mypackage/MyClass.class${src}/resources/mypackage/image.gif的文件,它们将出现在 jar 中的同一目录中(因此被 Java 视为同一包)。

<jar destfile="${dist}/lib/app.jar">
    <fileset dir="${build}/classes"
             excludes="**/Test.class"/>
    <fileset dir="${src}/resources"/>
</jar>

合并存档

创建一个可执行的 jar 文件,其主类为com.acme.checksites.Main,并将来自 jar lib/main/some.jar 的所有类嵌入其中。

<jar destfile="build/main/checksites.jar">
    <fileset dir="build/main/classes"/>
    <zipfileset includes="**/*.class" src="lib/main/some.jar"/>
    <manifest>
      <attribute name="Main-Class"
                 value="com.acme.checksites.Main"/>
    </manifest>
</jar>

创建一个可执行的 jar 文件,其主类为com.acme.checksites.Main,并将来自lib/main中所有 jar 的所有类嵌入其中。

<jar destfile="build/main/checksites.jar">
    <fileset dir="build/main/classes"/>
    <restrict>
       <name name="**/*.class"/>
       <archives>
           <zips>
               <fileset dir="lib/main" includes="**/*.jar"/>
           </zips>
       </archives>
    </restrict>
    <manifest>
        <attribute name="Main-Class"
              value="com.acme.checksites.Main"/>
    </manifest>
</jar>

内联清单

<jar destfile="test.jar" basedir=".">
    <include name="build"/>
    <manifest>
        <!-- If this is an Applet or Web Start application, include
             the proper attributes from https://docs.oracle.com/javase/8/docs/technotes/guides/jweb/index.html -->
        <attribute name="Permissions" value="sandbox"/>
        <attribute name="Codebase" value="example.com"/>
        <!-- Who is building this jar? -->
        <attribute name="Built-By" value="${user.name}"/>
        <!-- Information about the program itself -->
        <attribute name="Implementation-Vendor" value="ACME inc."/>
        <attribute name="Implementation-Title" value="GreatProduct"/>
        <attribute name="Implementation-Version" value="1.0.0beta2"/>
        <!-- details -->
        <section name="common/MyClass.class">
            <attribute name="Sealed" value="false"/>
        </section>
    </manifest>
</jar>

这是一个内联清单规范的示例,包括构建程序的版本(Implementation-Version)。请注意,Built-By属性将采用 Ant 属性user.name的值。上面生成的清单将如下所示

Manifest-Version: 1.0
Permissions: sandbox
Codebase: example.com
Built-By: conor
Implementation-Vendor: ACME inc.
Implementation-Title: GreatProduct
Implementation-Version: 1.0.0beta2
Created-By: Apache Ant 1.9.2

Name: common/MyClass.class
Sealed: false

服务提供者

以下显示了如何创建一个 jar 文件,该文件指定一个具有脚本接口实现的服务

<jar destfile="pinky.jar">
    <fileset dir="build/classes"/>
    <service type="javax.script.ScriptEngineFactory"
             provider="org.acme.PinkyLanguage"/>
</jar>

以下显示了如何创建一个 jar 文件,该文件指定一个具有两个脚本接口实现的服务

<jar destfile="pinkyandbrain.jar">
    <fileset dir="classes"/>
    <service type="javax.script.ScriptEngineFactory">
        <provider classname="org.acme.PinkyLanguage"/>
        <provider classname="org.acme.BrainLanguage"/>
    </service>
</jar>

JEP 238 示例:多版本 JAR 文件

在这里,我们希望根据规范JEP 238创建一个多版本 JAR 文件。它在 JAR 之上定义了将附加类或覆盖类放置在 jar 中的可能性,这些类根据您运行的 Java 版本可用。
基本上,它说您必须设置清单条目Multi-Release: true并将所有附加类或覆盖类放置在META-INF/versions/number/package-structure中,例如META-INF/versions/9/org/apache/ant/MyClass.class

在此示例中,我们预计普通类将编译到${java.classes}中,而 Java 9 类将编译到${java9.classes}中。

<jar destfile="mrjar.jar">
    <manifest>
        <!-- special mf-entry according to the spec -->
        <attribute name="Multi-Release" value="true"/>
    </manifest>
    <!-- directory structure according to the spec ... -->
    <!-- ... default classes loadable by old (<Java 9) versions -->
    <fileset dir="${java.classes}"/>
    <!-- ... per release classes, require Java 9+ for loadable via standard ClassLoader -->
    <zipfileset prefix="META-INF/versions/9/" dir="${java9.classes}"/>
</jar>