在运行时生成可执行jar

时间:2010-01-07 03:12:22

标签: java jar

我想编写一个可以在运行时创建可执行jar的Java应用程序。我想做的“hello world”是编写一个Java app X,在运行时生成一个可执行的jar Y,在运行时打印hello world(或者可能是在Y运行之后才知道的另一个字符串)。

我该如何做到这一点?

4 个答案:

答案 0 :(得分:6)

其他答案需要启动一个新流程,这是一种不需要的方法。以下是3个类定义,它们产生了问题中描述的hello world场景。

运行XMain.main时,会生成/tmp/y.jar。然后,当您在命令行运行它时:

java -jar /tmp/y.jar cool

打印:

Hello darling Y!
cool

示例/ YMain.java

package example;

import java.io.IOException;
import java.io.InputStream;

public class YMain {

    public static void main(String[] args) throws IOException {
        // Fetch and print message from X
        InputStream fromx = YMain.class.getClassLoader().getResourceAsStream("fromx.txt");
        System.out.println(new String(Util.toByteArray(fromx)));

        // Print first command line argument
        System.out.println(args[0]);
    }
}

示例/ XMain.java

package example;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

public class XMain {

    public static void main(String[] args) throws IOException {
        Manifest manifest = new Manifest();
        manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
        manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, YMain.class.getName());
        JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream("/tmp/y.jar"), manifest);

        // Add the main class
        addClass(YMain.class, jarOutputStream);

        // Add the Util class; Y uses it to read our secret message
        addClass(Util.class, jarOutputStream);

        // Add a secret message
        jarOutputStream.putNextEntry(new JarEntry("fromx.txt"));
        jarOutputStream.write("Hello darling Y!".getBytes());
        jarOutputStream.closeEntry();

        jarOutputStream.close();
    }

    private static void addClass(Class c, JarOutputStream jarOutputStream) throws IOException
    {
        String path = c.getName().replace('.', '/') + ".class";
        jarOutputStream.putNextEntry(new JarEntry(path));
        jarOutputStream.write(Util.toByteArray(c.getClassLoader().getResourceAsStream(path)));
        jarOutputStream.closeEntry();
    }
}

示例/ Util.java

package example;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class Util {

    public static byte[] toByteArray(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buf = new byte[0x1000];
        while (true) {
            int r = in.read(buf);
            if (r == -1) {
                break;
            }
            out.write(buf, 0, r);
        }
        return out.toByteArray();
    }
}

答案 1 :(得分:2)

你必须用普通的旧Java编写吗?我使用Gradle(基于Groovy的构建工具)。您可以使用自定义任务写出Y的源文件(Groovy可以很容易地写出模板化文件)。 Gradle可以轻松生成可执行jar。

如果您真的想从头开始自己动手,那么在通过Process API调用javac来编译源代码之后,您需要使用ZipOutStream来压缩已编译的文件。

也许更多关于你想要这样做的信息将有助于获得更好的答案

欢呼声

答案 2 :(得分:1)

要详细说明Lee的回复,您需要先编译源代码。您可以使用“处理”,也可以将tools.jar中的代码直接用作explained here。然后写出一个MANIFEST.MF文件,并使用ZipOutputStream将它们放在一起,如上所述。

答案 3 :(得分:0)

步骤1:弄清楚如何使用命令行手动完成。 第2步:通过从Java中调用程序来自动执行此操作。

http://devdaily.com/java/edu/pj/pj010016/

对于第1步,我建议使用ant - IDE并不总是可自动化的。因此,要么从Java写出所有文件,要么将一些ant配置作为项目的资源包括在内。