5 Replies Latest reply on Apr 3, 2009 8:48 AM by jaikiran pai

    VerifyError when instanciating a generated class (Bad type i

    beuha beuhbeuh Newbie

      Dear all,

      I'm using javassist to generate access class for reflection, following this tutorial:
      http://www.ibm.com/developerworks/java/library/j-dyn0610/index.html?S_TACT=105AGX02&S_CMP=EDU

      Everything works fine with my version, but it is not working with field without getter/setter. I need my generated access class to be able to access field directly in some case.

      So I wrote the following piece of code:

      ....
      protected static byte[] createAccess(final Class targetJavaClass, final String field, final String generatedClassName)
       throws Exception {
      
      //... code to get read/write method
      
       String targetName = targetJavaClass.getName();
       ClassPool pool = ClassPool.getDefault();
       CtClass accessClass = pool.makeClass(generatedClassName);
       CtClass targetClass = pool.get(targetName);
       final CtClass ctFieldClass = pool.get("java.lang.Object");
       final CtClass[] ctFieldClassParam = new CtClass[]{ctFieldClass};
       CtMethod meth;
      
       // add target object field to class
       accessClass.addField(new CtField(targetClass, "target", accessClass));
      
       // add public default constructor method to class
       CtConstructor cons = new CtConstructor(CT_NO_ARGS, accessClass);
       cons.setBody(";");
       accessClass.addConstructor(cons);
      
       // add public <code>setTarget</code> method
       meth = new CtMethod(CtClass.voidType, "setTarget", ctFieldClassParam, accessClass);
       meth.setBody("target = (" + targetJavaClass.getName() + ") $1;");
       accessClass.addMethod(meth);
      
      
       String src;
      
       // add public <code>setValue</code> method
       meth = new CtMethod(CtClass.voidType, "setValue", ctFieldClassParam, accessClass);
       final Class<?> fieldType = writer.getParameterTypes()[0];
       String cast$1 = "(" + fieldType.getName() + ") $1";
       if(directWriteField) src = "target." + field + " = " + " $1;";
       else src = "target." + writer.getName() + "(" + cast$1 + ");";
       meth.setBody(src);
       accessClass.addMethod(meth);
      
       // add public <code>getValue</code> method
       meth = new CtMethod(ctFieldClass, "getValue", CT_NO_ARGS, accessClass);
       if(directReadField) src = field;
       else src = reader.getName() + "()";
       meth.setBody("return (java.lang.Object) target." + src + ";");
       accessClass.addMethod(meth);
      
       // return binary representation of completed class
       accessClass.addInterface(pool.get(IAccess.class.getName()));
       accessClass.writeFile();
       return accessClass.toBytecode();
       }
      ...
      


      Execution of this code throws an exception after class generation, when calling newInstance on it:
      java.lang.VerifyError: (class: Accessor$com/bnpparibas/eqd/fish/fwk/introspection/TestCachedIntrospectionInfo$SampleBean_secret, method: setValue signature: (Ljava/lang/Object;)V) Bad type in
      putfield/putstatic
      at java.lang.Class.getDeclaredConstructors0(Native Method)
       at java.lang.Class.privateGetDeclaredConstructors(Class.java:2357)
       at java.lang.Class.getConstructor0(Class.java:2671)
       at java.lang.Class.newInstance0(Class.java:321)
       at java.lang.Class.newInstance(Class.java:303)
      


      The part of the code responsible of this is the following part of code:
      f(directWriteField) src = "target." + field + " = " + " $1;";
      


      If I remove this line, there are no error.

      Here is the decompiled code of the faulty generated class:
      package Accessor$com.bnpparibas.eqd.fish.fwk.introspection;
      
      import com.bnpparibas.eqd.fish.fwk.introspection.IAccess;
      import com.bnpparibas.eqd.fish.fwk.introspection.SampleBean;
      
      public class SampleBean_directAccessField
       implements IAccess {
      
       SampleBean target = null;
      
       public SampleBean_directAccessField() {
       }
      
       public void setTarget(Object obj) {
       target = (SampleBean)obj;
       }
      
       public void setValue(Object obj) {
       target.directAccessField = ((java.util.Date) (obj));
       }
      
       public Object getValue() {
       return (Object)target.directAccessField;
       }
      }
      


      And the directAccesField of the target object is a java.util.Date.

      I've spend to much time on this problem and I can't figure what the problem is.

      Thanks for any help you can provide.

      Regards.
      K.