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]>