2011-11-03 14 views
24

मैं पाया है कई संदर्भ समझा प्रोग्राम रूप JavaCompiler वर्ग का उपयोग कर एक जावा वर्ग को संकलित करने के:क्या जावा स्रोत कोड को केवल स्मृति में प्रोग्रामेटिक रूप से संकलित करना संभव है?

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
int result = compiler.run(null, null, null, "a_file_name"); 

हालांकि, मैं जानना चाहूंगा अगर वहाँ एक खुला स्रोत पुस्तकालय है कि मुझे संकलन स्रोत कोड प्रोग्राम के रूप में उत्पन्न करते हैं (है इसलिए एक src फ़ाइल शामिल किए बिना) और आउटपुट स्ट्रीम में कुछ बाइट कोड उत्पन्न करें (फ़ाइल सिस्टम में क्लास फ़ाइल उत्पन्न किए बिना)।

उदाहरण के लिए, मैं कुछ इस तरह लिखने के लिए सक्षम होने के लिए देख रहा हूँ:

InputStream input = generateSourceCode(); 
OutputStream output = getByteCode(input); 
doCoolStuffWithByteCode(output); 

किसी भी मदद के लिए धन्यवाद।

+0

एक डेमो के लिए [एसएससीसीई ** पाठ आधारित ** कंपाइलर] (http://pscode.org/stbc/) देखें। जेम्स और ब्रायन किस बात का जिक्र कर रहे हैं। एसटीबीसी 'JavaCompiler'/'SimpleJavaFileObject' का उपयोग करता है। –

उत्तर

38

में संग्रहीत कोड के संयोजन के साथ इसका उपयोग कैसे करें, JavaCompiler API देखें। असल में:

  1. स्ट्रिंग में जावा क्लास बनाएं।
  2. स्ट्रिंग को कक्षा में रखें जो SimpleJavaFileObject तक फैला हुआ है।
  3. JavaCompiler उदाहरण का उपयोग करके संकलित करें।

अंत में, नई कक्षा के तरीकों को कॉल करें।


यहाँ एक example कि JDK6 + के साथ काम करता है:

import java.io.IOException; 
import java.io.PrintWriter; 
import java.io.StringWriter; 
import java.lang.reflect.InvocationTargetException; 
import java.net.URI; 
import java.util.Arrays; 

import javax.tools.Diagnostic; 
import javax.tools.DiagnosticCollector; 
import javax.tools.JavaCompiler; 
import javax.tools.JavaFileObject; 
import javax.tools.SimpleJavaFileObject; 
import javax.tools.ToolProvider; 
import javax.tools.JavaCompiler.CompilationTask; 
import javax.tools.JavaFileObject.Kind; 

public class CompileSourceInMemory { 
    public static void main(String args[]) throws IOException { 
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 

    StringWriter writer = new StringWriter(); 
    PrintWriter out = new PrintWriter(writer); 
    out.println("public class HelloWorld {"); 
    out.println(" public static void main(String args[]) {"); 
    out.println(" System.out.println(\"This is in another java file\");");  
    out.println(" }"); 
    out.println("}"); 
    out.close(); 
    JavaFileObject file = new JavaSourceFromString("HelloWorld", writer.toString()); 

    Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file); 
    CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits); 

    boolean success = task.call(); 
    for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { 
     System.out.println(diagnostic.getCode()); 
     System.out.println(diagnostic.getKind()); 
     System.out.println(diagnostic.getPosition()); 
     System.out.println(diagnostic.getStartPosition()); 
     System.out.println(diagnostic.getEndPosition()); 
     System.out.println(diagnostic.getSource()); 
     System.out.println(diagnostic.getMessage(null)); 

    } 
    System.out.println("Success: " + success); 

    if (success) { 
     try { 
     Class.forName("HelloWorld").getDeclaredMethod("main", new Class[] { String[].class }) 
      .invoke(null, new Object[] { null }); 
     } catch (ClassNotFoundException e) { 
     System.err.println("Class not found: " + e); 
     } catch (NoSuchMethodException e) { 
     System.err.println("No such method: " + e); 
     } catch (IllegalAccessException e) { 
     System.err.println("Illegal access: " + e); 
     } catch (InvocationTargetException e) { 
     System.err.println("Invocation target: " + e); 
     } 
    } 
    } 
} 

class JavaSourceFromString extends SimpleJavaFileObject { 
    final String code; 

    JavaSourceFromString(String name, String code) { 
    super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),Kind.SOURCE); 
    this.code = code; 
    } 

    @Override 
    public CharSequence getCharContent(boolean ignoreEncodingErrors) { 
    return code; 
    } 
} 
+0

+1 पॉइंटर्स के लिए बहुत बहुत धन्यवाद। आखिरी लिंक लगभग जो दिखा रहा है वह दिखाता है। केवल अंतर यह है कि स्पष्ट रूप से इसे कक्षा के नाम को पहले से संकलित करने की आवश्यकता है, और मेरे पास केवल एक ही चीज़ है जिसका पूर्ण स्रोत कोड है। – Sergio

+0

क्या आप सिर्फ 'पब्लिक क्लास' शब्द के लिए कक्षा खोज सकते हैं और अगला शब्द शायद क्लास का नाम होगा। –

+0

मुझे पता है कि मैं मैन्युअल रूप से स्रोत कोड स्कैन कर सकता हूं, बस सोच रहा हूं कि कुछ और सुरुचिपूर्ण किया जा सकता है या नहीं। धन्यवाद ! – Sergio

0

हम (प्रश्न वर्ष की तरह है, लेकिन वहाँ कुछ ब्याज अभी भी हो रहा है JavaOne 2016 में उपयोग के इस मामले के बारे में भाषण दिया)।

जैवैक इन-मेमोरी का उपयोग कर व्यावहारिक कोड पीढ़ी के उदाहरणों के साथ repository है।

विशेष रूप से SimpleJavaCompiler पर एक उदाहरण के लिए थ्रेड सुरक्षा (हम सर्वर के संदर्भ में इसका उपयोग करते हैं) से संबंधित स्मृति में ऐसा करने के लिए उदाहरण के लिए SimpleJavaCompiler देखें। इसे आसानी से बहु-वर्ग परिदृश्य के लिए अनुकूलित किया जा सकता है।

कक्षा लोडिंग और कोड जनरेशन (चर के स्कॉइंग, अद्वितीय नाम उत्पन्न करने, नाम छायांकन इत्यादि) से निपटने के लिए कक्षाएं भी हैं।