【问题标题】:how to create a bundled runnable jar using Ant如何使用 Ant 创建捆绑的可运行 jar
【发布时间】:2012-04-10 02:23:33
【问题描述】:

我查看了this question,但它并没有真正解决我的问题,所以我想我会发布一个新的。

我需要使用 Ant 创建一个可运行的 jar(只需双击即可运行)。我有以下 java 代码和 build.xml 文件,它可以很好地编译代码并创建一个 jar 文件,但是当我尝试通过双击运行 jar 时,我收到一条消息“找不到主类:HttpController. java。”

我怀疑我的问题与加载外部 Apache Http.jar 有关,因为我已经成功地为一个相同的项目构建并运行了一个 jar,只是它没有引用任何外部 jar。

这是我的代码:

HttpController.java:

package pack;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpMessage;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

public class HttpController {
        public static void main(String[] args) {

        DefaultHttpClient client = new DefaultHttpClient();
        HttpHost httphost = new HttpHost("localhost", 80);

        try {

            HttpMessage req = new HttpGet("/test.html");
            HttpResponse resp = client.execute(httphost, (HttpGet) req);
            HttpEntity entity = resp.getEntity();

            BufferedReader in = new BufferedReader(new InputStreamReader(
                    entity.getContent()));

            String line = null;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // shutdown the connection
            client.getConnectionManager().shutdown();
        }
    }
}

build.xml:

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <project name="Test" basedir="." default="jar">
    <property name="source.dir"     value="src"/>
    <property name="lib.dir"        value="lib"/>
    <property name="class.dir"      value="bin"/>
    <property name="jar.dir"        value="dist"/>
    <property name="main-class"     value="pack.HttpController"/>

    <path id="libraries.path">    
        <fileset dir="${lib.dir}">
            <include name="*.jar"/>
        </fileset>
    </path>

    <target name="clean" description="delete old files">
        <delete dir="${class.dir}"/>
        <delete dir="${jar.dir}"/>
    </target>

    <target name="compile" description="build class files" depends="clean">
        <mkdir dir="${class.dir}"/>
        <javac srcdir="${source.dir}" destdir="${class.dir}">
            <classpath refid="libraries.path"/>
        </javac>
    </target>

    <target name="jar" depends="compile">
        <mkdir dir="${jar.dir}"/>
        <mkdir dir="${jar.dir}/${lib.dir}"/>
        <copy todir="${jar.dir}/${lib.dir}" flatten="true">
            <path refid="libraries.path"/>
        </copy>
        <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${class.dir}">
            <manifest>
                <attribute name="Main-Class" value="${main-class}"/>
                <attribute name="Class-Path" value="${jar.dir}/${lib.dir}/Apache HTTP.jar"/>
            </manifest>
        </jar>  
    </target>

    <target name="run" depends="jar">
        <java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/>
    </target>
</project>

清单.MF:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.6.0_31-b05 (Sun Microsystems Inc.)
Main-Class: HttpController
Class-Path: dist/lib

EDIT build.xml 已根据 Mike 的回答进行了更新。问题仍然没有解决。根据 Danation 的回答,还发布了清单文件的内容。

【问题讨论】:

  • @jayan 是否可以在没有任何外部工具的情况下做到这一点?即只使用 Ant 并编写我自己的 build.xml 文件?
  • SO 中有关于使用 Eclipse 等创建可运行 jar 的问题/答案。请参阅此 stackoverflow.com/questions/502960/…。我更喜欢 one-jar,因为它创建了一个可运行的文件。集成到 ant 需要 10 分钟。那为什么不试试看结果呢?
  • Class-Path 采用文档中的文件名列表。不是目录。
  • @jayan 使用 eclipse 导出到可执行 jar 不是我想要做的。我需要使用 Ant 生成一个可执行的 jar。最终目标是能够分发源代码并允许用户通过在命令行上执行ant 来执行代码,然后双击生成的 jar 文件。此外,我宁愿不必安装 Ant 本身以外的外部工具。我需要知道如何仅使用 Ant 来做到这一点。

标签: java ant jar


【解决方案1】:

截图...

我已经修改了您的 build.xml 文件,以便在 jar 文件和 Manifest 类路径中正确包含库。我假设您的“apache http.jar”文件是 Apache Core 的包装器,其中包含用于 apache 客户端等的其他几个 jar 文件。

构建.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Test" basedir="." default="jar">
    <property name="source.dir"     value="src"/>
    <property name="lib.dir"        value="lib"/>
    <property name="class.dir"      value="bin"/>
    <property name="jar.dir"        value="dist"/>
    <property name="jar.file"        value="${jar.dir}/${ant.project.name}.jar"/>
    <property name="main-class"     value="pack.HttpController"/>

    <path id="libraries.path">    
        <fileset dir="${lib.dir}">
            <include name="*.jar"/>
        </fileset>
    </path>

    <target name="clean" description="delete old files">
        <delete dir="${class.dir}"/>
        <delete dir="${jar.dir}"/>
    </target>

    <target name="compile" description="build class files" depends="clean">
        <mkdir dir="${class.dir}"/>
        <javac srcdir="${source.dir}" destdir="${class.dir}">
            <classpath refid="libraries.path"/>
        </javac>
    </target>

    <target name="jar" depends="compile">
        <mkdir dir="${jar.dir}"/>
        <mkdir dir="${class.dir}/${lib.dir}"/>
        <copy todir="${class.dir}/${lib.dir}" flatten="true">
            <path refid="libraries.path"/>
        </copy>

        <manifestclasspath property="manifest.classpath" jarfile="${jar.file}">
            <classpath refid="libraries.path"/>
        </manifestclasspath>

        <jar destfile="${jar.file}" basedir="${class.dir}">
            <manifest>
                <attribute name="Main-Class" value="${main-class}"/>
                <attribute name="Class-Path" value="${manifest.classpath}"/>
            </manifest>
        </jar>  
    </target>

    <target name="run" depends="jar">
        <java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/>
    </target>

</project>

【讨论】:

  • 我做了推荐的编辑。我必须更改一些东西(没有${dist} 属性,我认为您的意思是${jar.dir}),但构建仍然返回相同的错误。
  • 请同时包含jar文件的目录布局。我想知道 rt 是否对您的课程在默认包中感到不安。
  • 我将 HttpController.java 移动到 pack 包 (src/pack) 并调整 build.xml 文件以反映这一点,但发生了同样的错误。
  • 如果你把它移动到一个包中,那么你需要把文件放在一个子目录中。您还需要更改源代码,但我假设您已经这样做了。有空请贴出jar文件的目录结构。
  • 当你从命令行运行它时,你得到的确切信息是什么?
【解决方案2】:

您的Class-Path 条目有误,您必须单独指定每个 jar 文件,不能指定包含 .jar 文件的目录(仅限包含 .class 文件的目录)

这在JAR File specification 中有记录,在Java tutorial 中有很好的解释

如果您有两个库名称 FirstLib.jarSeconLib.jar,您的 Class-Path 条目应如下所示:

Class-Path: lib/FirstLib.jar lib/SecondLib.jar 

编辑
在您的 build.xml 中,它看起来像这样:

<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${class.dir}">
    <manifest>
        <attribute name="Main-Class" value="${main-class}"/>
        <attribute name="Class-Path" value="${lib.dir}/FirstLib.jar ${lib.dir}/SecondLib.jar"/>
    </manifest>
</jar>

【讨论】:

  • 我已经编辑了我的 build.xml 文件以反映这一点,但我仍然不断收到 no main class 错误。无论出于何种原因,它都无法识别我定义的主类
  • 你的主类真的没有包吗?因为那是Main-Class: HttpController 定义的。
  • 我会更新上面的代码。本来是没有包的,后来加了包还是遇到同样的问题
【解决方案3】:

这更像是制作可执行 jar 文件的通用解决方案,但这是我使用的代码:

<?xml version="1.0" encoding="UTF-8"?>

<!--
  Any words or attribute values which are capitalized and separated by
  underscores are places where you add the data.

  Example: PROJECT_NAME, enter your project name
-->

<project name="PROJECT_NAME" default="jar" basedir=".">
    <!-- source code package -->
    <property name="src" value="SOURCE_CODE_FOLDER"/>

    <!-- classes folder (will be deleted) -->
    <property name="cls" value="classes"/>

    <!-- the directory of the jar file -->
    <property name="jar.dir" value="JAR_FILE_DIRECTORY"/>

    <!-- the jar file itself -->
    <property name="jar.file" value="${jar.dir}/${ant.project.name}-launch.jar"/>

    <!-- the fully qualified name of the main class -->
    <property name="main" value="PATH.TO.MAIN_CLASS"/>

    <!-- initialization -->
    <target name="-init">

        <!-- the class folder* -->
        <mkdir dir="${cls}"/>

        <!-- the jar directory -->
        <mkdir dir="${jar.dir}"/>
    </target>

    <!-- compiling of files -->
    <target name="-post-init-comp" depends="-init">

        <!--
          turn all of the source java classes into class files
          located in the directory we made*
        -->
        <javac srcdir="${src}" destdir="${cls}"/>
    </target>

    <!-- creation of the jar file -->
    <target name="jar" depends="-post-init-comp">

        <!-- make the executable jar -->
        <jar destfile="${jar.file}" basedir="${cls}">
            <manifest>

                <attribute name="Manifest-Version" value="1.0"/>
                <attribute name="Ant-Version" value="Apache Ant 1.8.3"/>

                <attribute name="Main-Class" value="${main}"/>

                <!--
                  for some reason, this is needed for me in order
                  to have the jar function right
                -->
                <attribute name="Class-Path" value="${main}"/>

                <!-- Any other mainfest data is added here -->

            </manifest>
        </jar>

        <!-- remove the class folder -->
        <delete dir="${cls}"/>
    </target>
</project>

我已经使用这种结构制作了许多不同的可执行 jar 文件,而且它比你拥有的更简单:-)

所有放在jar标签下的manifest标签中的数据都会成为一个自动生成的manifest文件,里面有给定的数据。

【讨论】:

    【解决方案4】:

    查看您的清单文件,这很可能是其中的问题。我只在清单文件不正确时才看到该错误。

    只是猜测,但我认为它试图运行一个“.java”文件,因为它是主类,这是行不通的。

    查看oracle教程:http://docs.oracle.com/javase/tutorial/deployment/jar/appman.html

    如果这根本没有帮助,请在原始问题中发布清单文件的内容以及 .jar 文件的目录结构。

    【讨论】:

    • 我知道manifest文件有问题,但我需要知道如何重新配置​​build.xml,以便ant正确生成它。
    • @ewok:在原始问题中发布清单文件的内容以及 .jar 文件的目录结构。确定问题后,您应该更好地了解 build.xml 中的问题所在。
    猜你喜欢
    • 2014-08-30
    • 2015-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-10
    • 1970-01-01
    • 2014-04-01
    相关资源
    最近更新 更多