开发者

Compile Java source code from a string? [duplicate]

This question already has answers here: 开发者_开发问答 How do I programmatically compile and instantiate a Java class? (3 answers) Closed 7 years ago.

Is there a way for a running Java program to compile Java source code (passed as a string)?

Class newClass = Compiler.compile ("class ABC { void xyz {etc. etc. } }");

Ideally, any classes referenced by the passed-in source code would be resolved by the program's class loader.

Does something like this exist?


Sure. Have a look at the JavaCompiler class and the other classes in the javax.tools package.

They've been around since Java 1.6.

Here is some example code.

(As pointed out by @Sergey Tachenov in the comments, it needs JDK to be installed as the necessary tools.jar file comes with JDK but not JRE.)


What you need is a class that extends JavaFileObject

import java.net.URI;

import javax.tools.SimpleJavaFileObject;

public class JavaSourceFromString extends SimpleJavaFileObject {
    final String code;

    public 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;
    }
}

Which can be used as follows:

JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
if( jc == null) throw new Exception( "Compiler unavailable");

String code = "public class CustomProcessor { /*custom stuff*/ }";
JavaSourceFromString jsfs = new JavaSourceFromString( "CustomProcessor", code);

Iterable<? extends JavaFileObject> fileObjects = Arrays.asList( jsfs);

List<String> options = new ArrayList<String>();
options.add("-d");
options.add( compilationPath);
options.add( "-classpath");
URLClassLoader urlClassLoader =
         (URLClassLoader)Thread.currentThread().getContextClassLoader();
StringBuilder sb = new StringBuilder();
for (URL url : urlClassLoader.getURLs()) {
    sb.append(url.getFile()).append(File.pathSeparator);
}
sb.append( compilationPath);
options.add(sb.toString());

StringWriter output = new StringWriter();
boolean success = jc.getTask( output, null, null, options, null, fileObjects).call(); 
if( success) {
    logger.info( LOG_PREFIX + "Class has been successfully compiled");
} else {
    throw new Exception( "Compilation failed :" + output);
}


Depends on what you want to do. If you just want to run some code you could use BeanShell. It's not a java compiled class, but is very usefull to make something flexible


You could try my essence jcf library which does this. When running in debug you can have the source written to a file so you can step into the code. Otherwise, it does everything in memory. It wraps the JavaCompiler in tools.jar

It takes a String, compiles and loads it into the current class loader and returns the Class. It handles nested/inner classes.

http://vanillajava.blogspot.com/2010/11/more-uses-for-dynamic-code-in-java.html

Note: I haven't got this working in OSGi. ;)


Javassist can generate and load at runtime classes and methods from Strings of source code. It is also possible to dump in the file system the generated class if you need to.

Currently there are minor limitations in the code you can pass in those strings, for example it cannot include generics, enumerations, or autoboxing and inboxing of primitives. More information here:

http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜