Hi,
Using Apache BCEL (Byte Code Engineering Library), I create a BeanFactory that
wraps node with classes that can be evaluated using jxpath or EL. (I removed
the DynClass dependency in favor of BCEL, because BCEL is more actively
maintained and lots of project use and test it with the latest JDK features).
Below is the code of the BeanFactory class. Comments welcome.
------------------------------ Code below -------------------------------------
package org.mmbase.bridge.beans;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.Type;
import org.mmbase.bridge.Field;
import org.mmbase.bridge.FieldList;
import org.mmbase.bridge.Node;
import org.mmbase.bridge.NodeManager;
/**
* Usage: Object nodeBean = BeanFactory.createBean(n);
*
*
* TODO: Use the right property type for the getter/setter methods, now string
* Add methods for other part of the objectmodel, maybe even to retrieve the
* node and nodeManager
*/
public class BeanFactory {
private static class MMBeanClassLoader extends
org.apache.bcel.util.ClassLoader implements Constants {
public static final String SUFFIX = "$$BCEL$$";
private NodeManager mgr;
public MMBeanClassLoader(ClassLoader parent) {
super(parent);
}
/**
* Method to inject the node manager into the classloader to construct the
bean.
* @param nodeMgr
* @TODO Once related nodes are wrapped automatically, the classloader
* should be able to retrieve the nodemanagers itself.
*/
public void defineManager(NodeManager nodeMgr) {
this.mgr = nodeMgr;
}
/**
* Derive the java class from the node manager
*/
protected JavaClass createClass(String className) {
ClassGen cg = new ClassGen(className, "java.lang.Object", null,
ACC_PUBLIC | ACC_INTERFACE | ACC_ABSTRACT, new String[] {});
ConstantPoolGen cp = cg.getConstantPool();
FieldList fl = mgr.getFields();
for (int i = 0; i < fl.size(); i++) {
Field f = fl.getField(i);
String methodName = "get"
+ Character.toUpperCase(f.getName().charAt(0))
+ f.getName().substring(1);
// TODO: get the appropriate property/field type
String type = "Ljava/lang/String;";
Type t = Type.STRING;
InstructionList il = new InstructionList();
MethodGen method = new MethodGen(ACC_PUBLIC | ACC_ABSTRACT, t,
Type.NO_ARGS, new String[] {}, methodName, className,
il, cp);
method.setMaxStack();
method.setMaxLocals();
cg.addMethod(method.getMethod());
il.dispose();
}
for (int i = 0; i < fl.size(); i++) {
Field f = fl.getField(i);
String methodName = "set"
+ Character.toUpperCase(f.getName().charAt(0))
+ f.getName().substring(1);
String type = "Ljava/lang/String;";
Type t = Type.STRING;
InstructionList il = new InstructionList();
MethodGen method = new MethodGen(ACC_PUBLIC | ACC_ABSTRACT,
Type.VOID, new Type[] { t }, new String[] { "arg" },
methodName, className, il, cp);
method.setMaxStack();
method.setMaxLocals();
System.out.println("Method : " + method.toString());
cg.addMethod(method.getMethod());
il.dispose();
}
return cg.getJavaClass();
}
}
/**
* The invocationhandler that handles the actual method
* calls on the bean.
*/
private static class MMBeanInvocationHandler implements InvocationHandler {
private final Node adapter;
public MMBeanInvocationHandler(Node adapter) {
this.adapter = adapter;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
if (methodName.startsWith("set")) {
String propName = Character.toLowerCase(methodName.charAt(3))
+ methodName.substring(4);
adapter.setObjectValue(propName, args[0]);
return null;
} else if (methodName.startsWith("get")) {
String propName = Character.toLowerCase(methodName.charAt(3))
+ methodName.substring(4);
return adapter.getObjectValue(propName);
}
throw new RuntimeException("No such method : " + method.toString());
}
}
private static MMBeanClassLoader loader = new MMBeanClassLoader(
BeanFactory.class.getClassLoader());
public static Object createBean(Node node) {
try {
NodeManager mgr = node.getNodeManager();
String className = mgr.getName() + MMBeanClassLoader.SUFFIX;
// Inject the nodemanager before loading the class
loader.defineManager(node.getNodeManager());
Class ifcClass = loader.loadClass(className);
// Implement proxy
return Proxy.newProxyInstance(loader, new Class[] { ifcClass },
new MMBeanInvocationHandler(node));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
Disclaimer
Dit bericht met eventuele bijlagen is vertrouwelijk en uitsluitend bestemd voor
de geadresseerde. Indien u niet de bedoelde ontvanger bent, wordt u verzocht de
afzender te waarschuwen en dit bericht met eventuele bijlagen direct te
verwijderen en/of te vernietigen. Het is niet toegestaan dit bericht en
eventuele bijlagen te vermenigvuldigen, door te sturen, openbaar te maken, op
te slaan of op andere wijze te gebruiken. Ordina N.V. en/of haar
groepsmaatschappijen accepteren geen verantwoordelijkheid of aansprakelijkheid
voor schade die voortvloeit uit (de inhoud van) de verzending van dit bericht.
This e-mail and any attachments are confidential and is solely intended for the
addressee only. If you are not the intended recipient, please notify the sender
and delete and/or destroy this message and any attachments immediately. It is
prohibited to copy, to distribute, to disclose or to use this e-mail and any
attachments in any other way. Ordina N.V. and/or its group companies do not
accept any responsibility nor liability for any damage resulting from (the
content of) the transmission of this message.
_______________________________________________
Developers mailing list
[email protected]
http://lists.mmbase.org/mailman/listinfo/developers