Hi,
I am working on the same, possible you will find my project usefull.
http://cglib.sourceforge.net it has "Enhancer" for abstract classes.
You can use it like java.lang.reflect.Proxy. I believe it will help.
> Further to the below, if I override modifyClass to return null I fix the
> casting problem, but that then goes back to the same NoClassdefFoundError
> looking for the method that I think is there (o:
>
> again, be greatful for any assistance.
>
> cheers
> dim
>
> ----- Original Message -----
> From: "Dmitri Colebatch" <[EMAIL PROTECTED]>
> To: <[EMAIL PROTECTED]>
> Sent: Monday, October 14, 2002 1:05 AM
> Subject: two questions: classloading, and NoSuchMethodFoundErrors on
> on-the-fly generated classes
>
>
> > Hey all,
> >
> > I'm hoping this isn't too much of a newbie post - I have done a search
> > through the archives, and read the manual... if there's something else I
> > should have looked at before writing this, then please point me there
(o:
> >
> > First things first. My requirements are to dynamically implement an
> > abstract class. The test case I have (see end of email for my hacky src
> > code) is one where I create a class, and then load it using my
classloader
> > (subclasses bcel.util.ClassLoader), and then two tests - try to call a
> > method through reflection, and try to cast it to the superclass.
> >
> > reflection does all sorts of weird things:
> >
> > add method = public void
> > com.colebatch.$$BCEL$$GeneratedObject.add(java.lang.Object)
> > java.lang.reflect.InvocationTargetException: java.lang.NoSuchMethodError
> > at com.colebatch.$$BCEL$$GeneratedObject.add(<generated>)
> >
> > which comes from this bit of code:
> >
> > java.lang.reflect.Method method = o.getClass().getMethod("add", new
> > Class[] { Object.class } );
> > System.out.println("add method = " + method);
> > method.invoke(o, new Object[] {"foo"});
> >
> > which I find _really_ weird, I would have expected getMethod(..) line to
> > fail, but we get passed that, and then apparently the method doesn't
> exist.
> >
> > casting behaves a little more understandably.... in that, it does't
cast.
> > Simple though, because the superclass is loaded by two different class
> > loaders:
> >
> > TestSuperClass.class = sun.misc.Launcher$AppClassLoader@71732b
> > clazz.getSuperclass() = com.colebatch.TestBCEL$1@70eed6
> >
> > (from code:)
> >
> > System.out.println("TestSuperClass.class = " +
> > TestSuperClass.class.getClassLoader());
> > System.out.println("clazz.getSuperclass() = " +
> > clazz.getSuperclass().getClassLoader());
> >
> > I assume what happes here is that the bcel classloader loads the child
> > class, and all its superclasses.... looking through the code,
modifyClass
> > (whilst not doing anything) ensures that the class is loaded by the bcel
> cl.
> > Am I being naive/stupid thinking that I can use on-the-fly generated
> classes
> > without using JavaWrapper? At this stage there's no real reason why I
> > couldn't use it, but I'd prefer to be as hands-off as I can be at this
> > point.
> >
> > any feedback on either of the above issues would be greatly appreciated.
> >
> > cheers
> > dim
> >
> > ------------------- src code here -----------------
> >
> > package com.colebatch;
> >
> > import junit.framework.Test;
> > import junit.framework.TestCase;
> > import junit.framework.TestSuite;
> > import org.apache.bcel.Constants;
> > import org.apache.bcel.Repository;
> > import org.apache.bcel.classfile.ClassParser;
> > import org.apache.bcel.classfile.ConstantClass;
> > import org.apache.bcel.classfile.ConstantPool;
> > import org.apache.bcel.classfile.ConstantUtf8;
> > import org.apache.bcel.classfile.Field;
> > import org.apache.bcel.classfile.JavaClass;
> > import org.apache.bcel.classfile.Method;
> > import org.apache.bcel.generic.ALOAD;
> > import org.apache.bcel.generic.ClassGen;
> > import org.apache.bcel.generic.ConstantPoolGen;
> > import org.apache.bcel.generic.FieldGen;
> > import org.apache.bcel.generic.Instruction;
> > import org.apache.bcel.generic.InstructionFactory;
> > import org.apache.bcel.generic.InstructionList;
> > import org.apache.bcel.generic.MethodGen;
> > import org.apache.bcel.generic.ObjectType;
> > import org.apache.bcel.generic.RETURN;
> > import org.apache.bcel.generic.Type;
> >
> > import java.io.ByteArrayInputStream;
> > import java.io.ByteArrayOutputStream;
> > import java.io.IOException;
> > import java.lang.reflect.Constructor;
> > import java.util.ArrayList;
> > import java.util.HashMap;
> > import java.util.List;
> > import java.util.Map;
> >
> > public class TestBCEL extends TestCase implements Constants
> > {
> > public TestBCEL(String name)
> > {
> > super(name);
> > }
> >
> > public static Test suite()
> > {
> > return new TestSuite(TestBCEL.class);
> > }
> >
> > public static void main(String[] args) throws Exception
> > {
> > new TestBCEL("foo").testBCEL();
> > }
> >
> >
> >
>
//-------------------------------------------------------------------------
> > // tests
> >
> > public void testBCEL()
> > throws Exception
> > {
> > final String superClassName = "com.colebatch.TestSuperClass";
> > final String className = "com.colebatch.$$BCEL$$GeneratedObject";
> >
> > ClassGen cg = new ClassGen(className, superClassName,
> > "<generated>", ACC_PUBLIC | ACC_SUPER,
> > null);
> > ConstantPoolGen cp = cg.getConstantPool(); // cg creates constant
pool
> >
> > String ctxFieldName = "list";
> > ObjectType ctxType = new ObjectType("java.util.List");
> >
> > addField(ctxType, ctxFieldName, cp, cg);
> > addConstructor(cg, cp, superClassName, className, ctxFieldName,
> > ctxType);
> > addMethod(cg, cp, className, ctxFieldName, ctxType);
> >
> > final Map classes = new HashMap();
> >
> > ByteArrayOutputStream baos = new ByteArrayOutputStream();
> > cg.getJavaClass().dump(baos);
> > classes.put(className, baos.toByteArray());
> >
> > org.apache.bcel.util.ClassLoader cl = new
> > org.apache.bcel.util.ClassLoader()
> > {
> > protected JavaClass createClass(String class_name)
> > {
> > byte[] bytes = (byte[]) classes.get(class_name);
> > ClassParser parser = new ClassParser(new
> > ByteArrayInputStream(bytes), "<generated>");
> >
> > JavaClass clazz = null;
> >
> > try
> > {
> > clazz = parser.parse();
> >
> > dump(clazz, null, class_name);
> >
> > // Adapt the class name to the passed value
> > ConstantPool cp = clazz.getConstantPool();
> >
> > ConstantClass cl =
> > (ConstantClass)cp.getConstant(clazz.getClassNameIndex(),
> > Constants.CONSTANT_Class);
> > ConstantUtf8 name =
> > (ConstantUtf8)cp.getConstant(cl.getNameIndex(),
> > Constants.CONSTANT_Utf8);
> > name.setBytes(class_name.replace('.', '/'));
> >
> > return clazz;
> > }
> > catch (IOException e)
> > {
> > throw new RuntimeException(e.getMessage());
> > }
> > }
> > };
> > Class clazz = cl.loadClass(className);
> >
> > for (int i = 0; i < clazz.getMethods().length; i++)
> > {
> > java.lang.reflect.Method method = clazz.getMethods()[i];
> > System.out.println("method = " + method);
> > }
> >
> > List list = new ArrayList();
> > Constructor constructor = clazz.getConstructor(new Class[]
> > {List.class});
> > Object o = constructor.newInstance(new Object[] {list});
> > if (o instanceof TestSuperClass)
> > {
> > ((TestSuperClass) o).add("foo");
> > assertEquals("length not 1", 1, list.size());
> > assertEquals("first value not foo", "foo", list.get(0));
> > list.remove(0);
> > }
> > else
> > {
> > System.out.println("not TestSuperClass");
> > System.out.println("clazz.getSuperclass() = " +
> > clazz.getSuperclass());
> > for (int i = 0; i < clazz.getInterfaces().length; i++)
> > {
> > Class aClass = clazz.getInterfaces()[i];
> > System.out.println("implements " + aClass);
> > }
> >
> > System.out.println("-------------");
> > System.out.println("TestSuperClass.class = " +
> > TestSuperClass.class.getClassLoader());
> > System.out.println("clazz.getSuperclass() = " +
> > clazz.getSuperclass().getClassLoader());
> > }
> >
> > java.lang.reflect.Method method = o.getClass().getMethod("add", new
> > Class[] { Object.class } );
> > System.out.println("add method = " + method);
> > method.invoke(o, new Object[] {"foo"});
> > assertEquals("length not 1", 1, list.size());
> > assertEquals("first value not foo", "foo", list.get(0));
> >
> > // dump(className);
> > }
> >
> > private void addField(ObjectType ctxType, String ctxFieldName,
> > ConstantPoolGen cp, ClassGen cg)
> > {
> > FieldGen fieldGen = new FieldGen(Constants.ACC_PUBLIC, // |
> > Constants.ACC_FINAL,
> > ctxType,
> > ctxFieldName,
> > cp);
> > Field field = fieldGen.getField();
> > cg.addField(field);
> > }
> >
> > public static void dump(String className, String methodName)
> > {
> > JavaClass clazz = Repository.lookupClass(className);
> > dump(clazz, methodName, className);
> > }
> >
> > private static void dump(JavaClass clazz, String methodName, String
> > className)
> > {
> > Method[] methods = clazz.getMethods();
> > for (int i = 0; i < methods.length; i++)
> > {
> > Method method = methods[i];
> > if (methodName != null && !method.getName().equals(methodName))
> > continue;
> >
> > System.out.println("method = " + method);
> > ConstantPoolGen cp = new ConstantPoolGen();
> > MethodGen methodGen = new MethodGen(method, className, cp);
> > InstructionList instructionList = methodGen.getInstructionList();
> > Instruction[] instructions = instructionList.getInstructions();
> > for (int j = 0; j < instructions.length; j++)
> > {
> > Instruction instruction = instructions[j];
> > System.out.println("instruction = " + instruction);
> > }
> >
> > System.out.println("");
> > System.out.println("-----------------------------------");
> > System.out.println("");
> > }
> > }
> >
> > private void addConstructor(ClassGen cg, ConstantPoolGen cp, final
> String
> > superClassName, final String className, String ctxFieldName, ObjectType
> > ctxType)
> > {
> > InstructionList il = new InstructionList();
> > InstructionFactory factory = new InstructionFactory(cg, cp);
> > il.append(new ALOAD(0));
> > il.append(factory.createInvoke(superClassName, "<init>", Type.VOID,
> new
> > Type[0], Constants.INVOKESPECIAL));
> > il.append(new ALOAD(0)); // load ctx
> > il.append(new ALOAD(1)); // load ctx
> > il.append(factory.createPutField(className, ctxFieldName, ctxType));
> > il.append(new RETURN());
> > MethodGen constructorGen = new MethodGen(Constants.ACC_PUBLIC,
> > Type.VOID,
> > new Type[]{ctxType},
> > new String[]{"list"},
> > "<init>",
> > className,
> > il,
> > cp);
> > constructorGen.setMaxStack();
> > cg.addMethod(constructorGen.getMethod());
> >
> > il.dispose();
> > }
> >
> >
> > private void addMethod(ClassGen cg, ConstantPoolGen cp, String
> className,
> > String ctxFieldName, ObjectType ctxType)
> > {
> > // generated:
> > // method = public void add(Object o)
> > // instruction = aload_0[42](1)
> > // instruction = getfield[180](3) 14
> > // instruction = aload_1[43](1)
> > // instruction = invokeinterface[185](5) 25
> > // instruction = pop[87](1)
> > // instruction = return[177](1)
> > //
> > // -----------------------------------
> > //
> > // coded:
> > // method = public void add(Object o)
> > // instruction = aload_0[42](1)
> > // instruction = getfield[180](3) 109
> > // instruction = aload_1[43](1)
> > // instruction = invokeinterface[185](5) 110
> > // instruction = pop[87](1)
> > // instruction = return[177](1)
> >
> > InstructionList il = new InstructionList();
> > InstructionFactory factory = new InstructionFactory(cg, cp);
> > il.append(new ALOAD(0));
> > il.append(factory.createGetField(className, ctxFieldName, ctxType));
> > il.append(new ALOAD(1));
> > il.append(factory.createInvoke("java.util.List", "add", Type.VOID,
new
> > Type[] {Type.OBJECT}, Constants.INVOKEINTERFACE));
> > // il.append(new POP());
> > il.append(new RETURN());
> > MethodGen mg = new MethodGen(Constants.ACC_PUBLIC,
> > Type.VOID,
> > new Type[] {Type.OBJECT},
> > new String[]{"o"},
> > "add",
> > className,
> > il,
> > cp);
> > mg.setMaxStack();
> > cg.addMethod(mg.getMethod());
> >
> > il.dispose();
> > }
> >
> > }
> >
> >
> > package com.colebatch;
> >
> > public abstract class TestSuperClass
> > {
> > public TestSuperClass()
> > {
> > System.out.println("TestSuperClass.<init>()");
> > }
> >
> > public abstract void add(Object o);
> > }
> >
> >
> > --
> > To unsubscribe, e-mail:
> <mailto:[EMAIL PROTECTED]>
> > For additional commands, e-mail:
> <mailto:[EMAIL PROTECTED]>
> >
> >
>
>
> --
> To unsubscribe, e-mail:
<mailto:[EMAIL PROTECTED]>
> For additional commands, e-mail:
<mailto:[EMAIL PROTECTED]>
>
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>