2010-01-07 149 views
4

我想編寫一個Java應用程序,它可以在運行時創建可執行jar。我想要做的事情的「hello world」是編寫一個Java應用程序X,它在運行時生成一個可執行的jar,當運行時打印出hello world(或者直到運行Y之後纔會知道另一個字符串)。在運行時生成可執行jar

我怎樣才能做到這一點?

回答

5

其他的答案需要啓動一個新的進程,這是沒有的方法。這裏有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(); 
    } 
} 
2

您是否必須使用普通的Java編寫它?我會使用Gradle(基於Groovy的構建工具)。你可以有一個自定義任務來寫出Y的源文件(Groovy使寫模板文件變得非常容易)。 Gradle使得生成可執行的jar很容易。

如果你真的想從頭開始推出自己的,你需要使用ZipOutStream通過流程API調用的javac編譯源後拉上編譯後的文件。

也許你爲什麼想這樣做將有助於得到更好的答案

歡呼

0

第1步多一點信息:找出如何使用命令行手動去做。 步驟2:通過從Java內部調用程序來自動執行此操作。

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

第1步我會建議使用螞蟻 - 集成開發環境並不總是自動化。因此,要麼從Java中寫出所有文件,要麼在項目中包含一些作爲資源的ant配置。

+0

但是你可以做得比這更好。 Java編譯和JAR文件創建步驟都可以在當前的JVM中完成。 – 2010-01-07 03:44:59

+0

這就是我所希望的。除了安裝JRE之外,我不想生成新進程或依賴主機環境。斯蒂芬,你有一個例子嗎? – 2010-01-07 23:28:46

1

爲了詳細說明李的回答,您首先需要編譯源。您可以使用Process,也可以直接使用tools.jar中的代碼作爲explained here。然後寫出一個MANIFEST.MF文件,並使用ZipOutputStream將它們放在一起,如前所述。