jakarta-bcel-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Dmitri Colebatch" <...@bigpond.net.au>
Subject Re: two questions: classloading, and NoSuchMethodFoundErrors on on-the-fly generated classes
Date Sun, 13 Oct 2002 15:08:42 GMT
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" <dim@colebatch.com>
To: <bcel-user@jakarta.apache.org>
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:bcel-user-unsubscribe@jakarta.apache.org>
> For additional commands, e-mail:
<mailto:bcel-user-help@jakarta.apache.org>
>
>


--
To unsubscribe, e-mail:   <mailto:bcel-user-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:bcel-user-help@jakarta.apache.org>


Mime
View raw message