Java 在运行时生成可执行jar

Java 在运行时生成可执行jar,java,jar,Java,Jar,我想写一个Java应用程序,它可以在运行时创建可执行的JAR。我想做的“hello world”是编写一个Java应用程序X,在运行时生成一个可执行的jar Y,在运行时打印hello world(或者可能是另一个直到Y运行后才知道的字符串) 我如何才能做到这一点?您必须用普通的旧Java编写它吗?我会使用(基于构建的工具)。您可以有一个自定义任务来为Y写出源文件(Groovy使写出模板文件变得非常容易)。Gradle使生成可执行jar变得很容易 如果你真的想从头开始,你需要在通过过程API调用

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


我如何才能做到这一点?

您必须用普通的旧Java编写它吗?我会使用(基于构建的工具)。您可以有一个自定义任务来为Y写出源文件(Groovy使写出模板文件变得非常容易)。Gradle使生成可执行jar变得很容易

如果你真的想从头开始,你需要在通过过程API调用javac编译源代码后使用ZipOutStream来压缩编译后的文件

也许多了解一点你为什么要这么做会有助于得到更好的答案

干杯


Lee

第1步:了解如何使用命令行手动执行此操作。 步骤2:通过在Java中调用程序来实现自动化


对于步骤1,我建议使用ant-IDE并不总是可以自动化的。因此,要么写出Java中的所有文件,要么将一些ant配置作为参考资料包含在项目中。

要详细说明Lee的回答,您需要首先编译源代码。您可以使用Process,也可以直接使用
tools.jar
中的代码。然后写出一个MANIFEST.MF文件,并使用前面提到的ZipOutputStream将其放在一起。

其他答案需要启动一个新的流程,这是一种不需要的方法。下面是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]);
    }
}
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();
    }
}
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();
    }
}
示例/XMain.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]);
    }
}
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();
    }
}
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();
    }
}
示例/Util.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]);
    }
}
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();
    }
}
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();
    }
}

但你可以做得更好。Java编译和JAR文件创建步骤都可以在当前的JVM中完成,这正是我所希望的。除了安装JRE之外,我不想产生新的进程或依赖于主机的环境。斯蒂芬,你有一个例子的链接吗?