我想编写一个可以在运行时创建可执行jar的Java应用程序。我想做的“hello world”是编写一个Java app X,在运行时生成一个可执行的jar Y,在运行时打印hello world(或者可能是在Y运行之后才知道的另一个字符串)。
我该如何做到这一点?
答案 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配置作为项目的资源包括在内。