A PropertyEditor interface provides support for GUIs to enable editing a property value of a given type. The interface supports a variety of ways to display and update property values. One of these ways is to employ the string representation of a Java code fragment that can be obtained by getJavaInitializationString, the method all standard property editors implement. To test this feature, one could generate a source code with a method that returns a required string, compile the code, run the class, and verify the value. This is quite easy to do with the Java 6 Compiler API.

To start, let's define the class that will contain the source code to compile. To do so, override the getCharContent method of the SimpleJavaFileObject class:

class Source extends SimpleJavaFileObject {
    private final String content;

    Source(String name, Kind kind, String content) {
        super(URI.create("memo:///" + name.replace('.', '/') + kind.extension), kind);
        this.content = content;
    }

    @Override
    public CharSequence getCharContent(boolean ignore) {
        return this.content;
    }
}

Further, create a class to obtain the compiled binary code. Override the openOutputStream method of the SimpleJavaFileObject class and add the method to return a byte array written in the stream by the compiler:

class Output extends SimpleJavaFileObject {
    private final ByteArrayOutputStream baos = new ByteArrayOutputStream();

    Output(String name, Kind kind) {
        super(URI.create("memo:///" + name.replace('.', '/') + kind.extension), kind);
    }

    byte[] toByteArray() {
        return this.baos.toByteArray();
    }

    @Override
    public ByteArrayOutputStream openOutputStream() {
        return this.baos;
    }
}

Now create a class the compiler will use to manage files. The Output object is created and stored for each compiled class. Compiler is using this object to write the binary code.

class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
    private final Map<String, Output> map = new HashMap<String, Output>();

    MemoryFileManager(JavaCompiler compiler) {
        super(compiler.getStandardFileManager(null, null, null));
    }

    @Override
    public Output getJavaFileForOutput
            (Location location, String name, Kind kind, FileObject source) {
        Output mc = new Output(name, kind);
        this.map.put(name, mc);
        return mc;
    }
}

Finally, create a custom class loader, that compiles all sources when initiated (in its constructor). Later the loader creates a Class object from the binary code when the class is called. Two following Stringvariables are aimed to define the source code: the class full name (with the package) and the valid file content. If you need to compile several files at once, use the Map object, that contains the file content by the class full name. Below example has an obligatory set of compiling commands. Use the Compiler API for other options, for example, additional diagnostics or compilation output:

class MemoryClassLoader extends ClassLoader {
    private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    private final MemoryFileManager manager = new MemoryFileManager(this.compiler);

    public MemoryClassLoader(String classname, String filecontent) {
        this(Collections.singletonMap(classname, filecontent));
    }

    public MemoryClassLoader(Map<String, String> map) {
        List<Source> list = new ArrayList<Source>();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            list.add(new Source(entry.getKey(), Kind.SOURCE, entry.getValue()));
        }
        this.compiler.getTask(null, this.manager, null, null, null, list).call();
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        synchronized (this.manager) {
            Output mc = this.manager.map.remove(name);
            if (mc != null) {
                byte[] array = mc.toByteArray();
                return defineClass(name, array, 0, array.length);
            }
        }
        return super.findClass(name);
    }
}

Let's take a look at the example that calculates sin 30°. Use the Reflection API to invoke the method of the compiled class.

private static final String CLASS = "Test";
private static final String METHOD = "execute";
private static final String EXPRESSION = "Math.cos(Math.PI/6)";
private static final String CONTENT    
        = "public class " + CLASS + " {"
        + "    public static Object " + METHOD + "() {"
        + "        return " + EXPRESSION + ";"
        + "    }"
        + "}";

public static void main(String[] args) throws Exception {
    MemoryClassLoader mcl = new MemoryClassLoader(CLASS, CONTENT);
    System.out.println(mcl.loadClass(CLASS).getMethod(METHOD).invoke(null));
}

The source file of the example is available.