简体   繁体   English

如何使用Ant创建捆绑的可运行jar

[英]how to create a bundled runnable jar using Ant

I looked at this question , but it didn't really solve my problem, so I figured I'd post a new one. 我看了这个问题 ,但它并没有真正解决我的问题,所以我想我会发布一个新问题。

I need to create a runnable jar (runnable simply by double clicking) using Ant. 我需要使用Ant创建一个可运行的jar(只需双击即可运行)。 I have the following java code and build.xml file, which compiles the code just fine and creates a jar file, but when I try to run the jar by double clicking, i get a message saying "Could not find main class: HttpController.java." 我有以下java代码和build.xml文件,它编译代码很好并创建一个jar文件,但是当我尝试通过双击运行jar时,我收到一条消息“无法找到主类:HttpController。 java的“。

I have the suspicion that my problem has to do with loading the external Apache Http.jar , as I have successfully built and run a jar for a project that is identical, except that it does not reference any external jars. 我怀疑我的问题与加载外部Apache Http.jar ,因为我已成功构建并运行一个相同的项目的jar,除了它没有引用任何外部jar。

Here is my code: 这是我的代码:

HttpController.java: 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: 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>

MANIFEST.MF: MANIFEST.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 has been updated as per Mike's answer. EDIT build.xml已根据Mike的回答进行了更新。 Problem is still not solved. 问题仍未解决。 Also posted contents of manifest file, as per Danation's answer. 还根据Danation的回答发布了清单文件的内容。

Snip... 喀嚓...

I have reworked your build.xml file to properly include the libraries in the jar file and in the Manifest classpath. 我已经重新编写了build.xml文件,以便在jar文件和Manifest类路径中正确包含这些库。 I'm assuming that your "apache http.jar" file is a wrapper for Apache Core, and contains several other jar files in it for the apache client, etc. 我假设您的“apache http.jar”文件是Apache Core的包装器,并且包含其他几个用于apache客户端的jar文件等。

build.xml 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="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>

Your Class-Path entry is wrong, you have to specify each jar file individually, you cannot specify a directory with .jar files (only directories with .class files) 您的Class-Path条目错误,您必须单独指定每个jar文件,不能使用.jar文件指定目录(只有.class文件的目录)

This is documented in the JAR File specification and explained quite nicely in the Java tutorial 这在JAR文件规范中有记录,并在Java教程中进行了很好的解释

If you have two libraries name FirstLib.jar and SeconLib.jar your Class-Path entry should look like this: 如果您有两个库名为FirstLib.jarSeconLib.jar Class-Path条目应如下所示:

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

Edit : 编辑
Inside your build.xml this would look like this: 在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>

This is more of a general solution for making executable jar files but this is the code I use: 这是制作可执行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>

I've used this structure to make many different executable jar files, plus it is simpler than what you had :-) 我已经使用这个结构来制作许多不同的可执行jar文件,而且它比你拥有的更简单:-)

All data put in the manifest tags under the jar tags will become an automatically generated manifest file with the given data. 放在jar标签下的清单标签中的所有数据将成为包含给定数据的自动生成的清单文件。

Take a look at your manifest file, it's most likely an issue in there. 看看你的清单文件,它很可能是一个问题。 I've only seen that error when the manifest file is incorrect. 我只是在清单文件不正确时才看到错误。

Just speculation, but I think it's trying to run a ".java" file as it's main class, which isn't going to work. 只是推测,但我认为它试图运行一个“.java”文件作为它的主类,这是行不通的。

See the oracle tutorial: http://docs.oracle.com/javase/tutorial/deployment/jar/appman.html . 请参阅oracle教程: http//docs.oracle.com/javase/tutorial/deployment/jar/appman.html

If that doesn't help at all, post the contents of your manifest file as well as the directory structure of the .jar file in your original question. 如果这根本没有帮助,请在原始问题中发布清单文件的内容以及.jar文件的目录结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM