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 21:49:22 GMT
James,

Thanks for the pointer.... sounds to be what I'm looking for at this
stage...  I'll have a go and let you know if I have any problems..

cheers
dim

----- Original Message -----
From: "Juozas Baliuka" <baliuka@centras.lt>
To: "BCEL Users List" <bcel-user@jakarta.apache.org>
Sent: Monday, October 14, 2002 1:33 AM
Subject: Re: two questions: classloading, and NoSuchMethodFoundErrors on
on-the-fly generated classes


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