2012-04-20 108 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的权限最小。