2012-04-20 158 views
1

如何從java代碼本身運行編譯代碼(.class)java?從java代碼運行.class文件

我正在做一種提供服務,如在服務器端編譯和運行java代碼並將輸出提供給最終用戶。

任何人都可以提出一個方法來實現這個目標嗎?

import java.io.*; 

public class demo { 

    public static void main(String args[]) throws IOException, InterruptedException { 
     int result; 
     try { 

      System.out.println("command output:"); 
      Process proc = Runtime.getRuntime().exec("java -cp . demoh"); 
      InputStream in = proc.getInputStream(); 
      result = proc.waitFor(); 

      BufferedInputStream buffer = new BufferedInputStream(proc.getInputStream()); 

      BufferedReader commandOutput = new BufferedReader(new InputStreamReader(buffer)); 
      System.out.print(commandOutput); 

      String line = null; 
      try { 
       while ((line = commandOutput.readLine()) != null) { 
        System.out.print(line); 
        System.out.println("command output: " + line); 
      }//end while 
      commandOutput.close(); 

      } catch (IOException e) { 
       //log and/or handle it 
      } 
     } catch (IOException e) { 
      System.err.println("IOException raised: " + e.getMessage()); 
     } 
    } 
} 
+1

*「我在做類似的服務,比如在服務器端編譯和運行java代碼,並給出最終用戶?」*不妨安裝tomcat並讓用戶訪問上傳servlet,這將是關於同樣的安全噩夢。事實上,想想看,如果你繼續這樣做,你不妨同時把鑰匙給你的房子。 ;) – 2012-04-20 16:12:36

+0

@AndrewThompson可以在沙箱中運行它 – siamii 2012-04-20 16:23:11

+2

@ bizso09確實如此,但那意味着許多有趣的代碼類型將無法運行。即使這樣,你也必須考慮編程錯誤('OutOfMemroyError','StackOverflowError',無限循環..)。事實上,一旦我有一個在線編譯器(無法運行代碼)。一位對我正在使用的編譯器有深入瞭解的人聯繫了並警告我完全基於***編譯***代碼的DOS攻擊。至少(至少很久以前)的代碼可能會使編譯器佔用30分鐘或更長的時間! – 2012-04-20 16:27:50

回答

1

創建.jar文件和文件添加到構建路徑

+0

謝謝你的ans.but我想建立像codepad.org這樣的應用程序來提供服務器端編譯ñ運行它顯示出來給user.so你能指導我如何使用.jar文件嗎? – 2012-04-20 16:10:09

1

如果您有.class文件放在磁盤上,簡單地產生新的進程,並像你從命令行將運行java命令:

Process p = Runtime.getRuntime().exec("java <java class file>"); 

一些測試後左​​右,下面的代碼爲我工作:

public static void main(String args[]) throws IOException, InterruptedException { 
    int result; 

    try { 

     System.out.println("command output:"); 
     Process proc = Runtime.getRuntime().exec("java -cp . Test"); 

     InputStream errin = proc.getErrorStream(); 
     InputStream in = proc.getInputStream(); 
     BufferedReader errorOutput = new BufferedReader(new InputStreamReader(errin)); 
     BufferedReader output = new BufferedReader(new InputStreamReader(in)); 
     String line1 = null; 
     String line2 = null; 
     try { 
      while ((line1 = errorOutput.readLine()) != null || 
        (line2 = output.readLine()) != null) {     
       if(line1 != null) System.out.print(line1); 
       if(line2 != null) System.out.print(line2);    
      }//end while 
      errorOutput.close(); 
      output.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     }//end catc 
     result = proc.waitFor(); 
    } catch (IOException e) { 
     System.err.println("IOException raised: " + e.getMessage()); 
    } 
} 

注意這裏有兩件事:

  1. 由java進程給出的運行時錯誤被髮送到錯誤流,而不是輸入流,所以你必須讀取它們兩個!
  2. 您必須在流程運行時讀取流。在讀取流之前等待進程完成會導致死鎖,因爲進程輸出緩衝區已滿並正在等待父進程讀取數據,而父進程正在等待子進程完成!
+0

感謝tudor,但在此之後,我正在寫BufferedInputStream buffer = new BufferedInputStream(proc.getInputStream()); BufferedReader commandOutput = new BufferedReader(new InputStreamReader(buffer)); String line = line = commandOutput.readLine();但沒有包含任何內容。任何想法? – 2012-04-20 16:12:07

+1

@Madhav庫馬爾:你可以在原始問題中發佈此代碼嗎? – Tudor 2012-04-20 16:15:54

+0

謝謝,....這裏是我的問題..我正在開發類似codepad.org的webapp,爲此我需要編譯並運行我從客戶端獲得的代碼到服務器,並編譯並運行了代碼服務器端使用java。所以我已經在服務器端完成了編譯運算,並生成了.class文件,現在我想在服務器端運行該.class文件,並且想要顯示該文件輸出到提交代碼的用戶。 :) – 2012-04-20 16:33:38

0

嘗試

Process process = Runtime.getRuntime().exec("java " + filePath); // without .class 
Scanner output = new Scanner(process.getInputStream()); 
while (output.hasNext) { 
    String token = output.next(); 
    ... 
} 
+0

但現在做System.out.print(token.toString());在裏面而不打印輸出? – 2012-04-20 16:35:29

+0

@MadhavKumar文件是否有類和主要方法? – siamii 2012-04-20 16:41:35

+0

是的,我有主要方法 – 2012-04-20 17:16:13

0

還有很多建築/編譯工具,即Ant或Maven,你可以檢查你寫你自己的了。

0

其中一個選項是使用類加載器創建類的實例。類加載器可以將您的類作爲一個字節數組,然後您可以創建它的一個實例並運行它。請參閱JDK文檔中的this method

0

下面是一個示例應用程序,它將編譯Java源文件,加載類,實例化實例以及打印類HelloWorld的toString()。我相信你需要classpath上的tools.jar。示例代碼需要src文件夾中的源文件。 src文件夾在類路徑中是必需的,因爲.class文件將在默認情況下生成。

有關Java編譯器的更多控制,請閱讀javax.tools包。

package sourcerunner; 

import java.io.IOException; 
import java.util.concurrent.TimeUnit; 
import javax.tools.JavaCompiler; 
import javax.tools.ToolProvider; 

public class SourceRunner { 

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, InterruptedException { 
     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 

     compiler.run(System.in, System.out, System.err, "src/sourcerunner/HelloWorld.java"); 

     TimeUnit.SECONDS.sleep(1L); 

     Class<?> cls = Class.forName("sourcerunner.HelloWorld"); 

     Object instance = cls.newInstance(); 

     System.out.println(instance); 
    } 
} 

而這裏的HelloWorld類:

package sourcerunner; 

public class HelloWorld { 

    @Override 
    public String toString() { 
     return "Hello Java Compiler World."; 
    } 
} 

上面的代碼是出奇的沒有安全感。一旦理解了代碼,請修改它以使用新的ClassLoader加載和實例化類。確保ClassLoader的權限最小。