脚本
ScriptEngineManager manager = new ScriptEngineManager();
for (ScriptEngineFactory factory : manager.getEngineFactories()) {
System.out.println(factory.getEngineName());
}
final ScriptEngine engine = manager.getEngineByName("js");
JFrame frame = (JFrame) Class.forName("buttons1.ButtonFrame").newInstance();
private static void getComponentBindings(Component c, ScriptEngine engine) {
String name = c.getName();
if (name != null) engine.put(name, c);
if (c instanceof Container) {
for (Component child : ((Container) c).getComponents())
getComponentBindings(child, engine);
}
}
getComponentBindings(frame, engine);
final Properties events = new Properties();
InputStream in = frame.getClass().getResourceAsStream("js.properties");
events.load(in);
for (final Object e : events.keySet()) {
String[] s = ((String) e).split("\\.");
addListener(s[0], s[1], (String) events.get(e), engine);
}
private static void addListener(String beanName, String eventName, final String scriptCode,
final ScriptEngine engine) throws ReflectiveOperationException, IntrospectionException {
Object bean = engine.get(beanName);
EventSetDescriptor descriptor = getEventSetDescriptor(bean, eventName);
if (descriptor == null) return;
descriptor.getAddListenerMethod().invoke(bean, Proxy.newProxyInstance(null, new Class[] { descriptor.getListenerType() },
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
engine.eval(scriptCode);
return null;
}
}
));
}
private static EventSetDescriptor getEventSetDescriptor(Object bean, String eventName) throws IntrospectionException{
for (EventSetDescriptor descriptor : Introspector.getBeanInfo(bean.getClass()).getEventSetDescriptors())
if (descriptor.getName().equals(eventName)) return descriptor;
return null;
}
编译
动态生成类
JavaFileObject source = buildSource("buttons2.ButtonFrame");
static JavaFileObject buildSource(String superclassName) throws IOException, ClassNotFoundException {
StringBuilderJavaSource source = new StringBuilderJavaSource("x.Frame");
source.append("package x;\n");
source.append("public class Frame extends " + superclassName + " {");
source.append("protected void addEventHandlers() {");
final Properties props = new Properties();
props.load(Class.forName(superclassName).getResourceAsStream("action.properties"));
for (Map.Entry<Object, Object> e : props.entrySet()) {
String beanName = (String) e.getKey();
String eventCode = (String) e.getValue();
source.append(beanName + ".addActionListener(new java.awt.event.ActionListener() {");
source.append("public void actionPerformed(java.awt.event.ActionEvent event) {");
source.append(eventCode);
source.append("} } );");
}
source.append("} }");
return source;
}
public class StringBuilderJavaSource extends SimpleJavaFileObject {
private StringBuilder code;
public StringBuilderJavaSource(String name) {
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
code = new StringBuilder();
}
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return code;
}
public void append(String str) {
code.append(str);
code.append('\n');
}
}
编译类
final List<ByteArrayJavaClass> classFileObjects = new ArrayList<>();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
JavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
fileManager = new ForwardingJavaFileManager<JavaFileManager>(fileManager) {
public JavaFileObject getJavaFileForOutput(Location location, final String className,
Kind kind, FileObject sibling) throws IOException {
if (className.startsWith("x.")) {
ByteArrayJavaClass fileObject = new ByteArrayJavaClass(className);
classFileObjects.add(fileObject);
return fileObject;
} else return super.getJavaFileForOutput(location, className, kind, sibling);
}
};
public class ByteArrayJavaClass extends SimpleJavaFileObject {
private ByteArrayOutputStream stream;
public ByteArrayJavaClass(String name) {
super(URI.create("bytes:///" + name), Kind.CLASS);
stream = new ByteArrayOutputStream();
}
public OutputStream openOutputStream() throws IOException {
return stream;
}
public byte[] getBytes() {
return stream.toByteArray();
}
}
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, Arrays.asList(source));
boolean result = task.call();
使用类
Map<String, byte[]> byteCodeMap = new HashMap<>();
for (ByteArrayJavaClass cl : classFileObjects)
byteCodeMap.put(cl.getName().substring(1), cl.getBytes());
ClassLoader loader = new MapClassLoader(byteCodeMap);
JFrame frame = (JFrame) loader.loadClass("x.Frame").newInstance();
public class MapClassLoader extends ClassLoader {
private Map<String, byte[]> classes;
public MapClassLoader(Map<String, byte[]> classes) {
this.classes = classes;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classBytes = classes.get(name);
if (classBytes == null) throw new ClassNotFoundException(name);
Class<?> cl = defineClass(name, classBytes, 0, classBytes.length);
if (cl == null) throw new ClassNotFoundException(name);
return cl;
}
}