3 Replies Latest reply on Jan 12, 2005 9:47 PM by chiba

    Field rename

    dechamps

      Hello,
      I'm trying to rename in a file C.class a Field LEAD with GOLD.
      Modern alchemy !
      When the field is a byte, it seems ok (Trace1) but if it's a byte[] instantiation of class C fails (Trace2).
      What's is wrong? What a I have to do to sastisfy clinit that deals with arrays?
      Thanks for any idea.

      Dominique Dechamps
      PS: FYI,the english translation of my name Dechamps is "Of Fields". Seriously!
      And of course my next step will be to change byte in BigDecimal ;-)

      //// The class to modify
      public class C {
      public final static byte LEAD=1;
      //public final static byte[] LEAD={1};
      }
      //// The class that modify C class
      import java.util.*;
      import javassist.*;
      import javassist.bytecode.*;
      import java.lang.reflect.*;
      public class FieldRename {
      private static ClassPool pool = null;
      private static ConstPool constPool=null;
      private static CtClass clazz = null;
      private static CtField doc =null;

      public static void sequence1()throws NotFoundException,CannotCompileException,java.lang.Exception{//java.io.IOException,java.lang.ClassNotFoundException,java.lang.InstantiationException,java.lang.IllegalAccessException{
      // Step 1
      String className="C";
      pool = ClassPool.getDefault();
      clazz = pool.get(className);
      constPool=new ConstPool(className);
      renameField("LEAD","GOLD");
      clazz.writeFile();
      // Step 2
      System.out.println("Step 2 try to instantiate "+className);
      Class c=Class.forName(className);
      Object o=c.newInstance();
      System.out.println("Step 2 object sucessfully instantiated");
      Class d=o.getClass();
      Field[] f=d.getDeclaredFields();
      for (int i=0;i<f.length;i++){System.out.println("Field found= "+f.toString());}
      }

      public static void renameField(String oldFieldName,String newFieldName)throws javassist.CannotCompileException{
      ClassFile cf=clazz.getClassFile();
      List l=cf.getFields();
      FieldInfo fi=null;
      for(int i=0;i<l.size();i++){
      fi=(FieldInfo)l.get(i);
      if (fi.getName().equals(oldFieldName)){
      ConstPool cp=fi.getConstPool();
      System.out.println("before="+oldFieldName);
      cp.print();
      fi.setName(newFieldName);
      l.set(i,fi);
      fi=(FieldInfo)l.get(i);
      System.out.println("after="+fi.getName());
      cp.print();
      }
      }
      System.out.println(oldFieldName+" should be replaced with expected "+newFieldName+" is "+fi.getName());
      }

      public static void main(String[] args) throws Exception {
      try{sequence1();}
      catch (Exception e){
      e.printStackTrace();
      System.exit(0);
      }
      }
      }
      //// Trace 1 when LEAD is a byte
      before=LEAD
      1 Method #3, name&type #14
      Class #15
      3 Class #16
      4 UTF8 "LEAD"
      5 UTF8 "B"
      6 UTF8 "ConstantValue"
      7 Integer 1
      8 UTF8 ""
      9 UTF8 "()V"
      10 UTF8 "Code"
      11 UTF8 "LineNumberTable"
      12 UTF8 "SourceFile"
      13 UTF8 "C.java"
      14 NameAndType #8, type #9
      15 UTF8 "C"
      16 UTF8 "java/lang/Object"
      after=GOLD
      1 Method #3, name&type #14
      2 Class #15
      3 Class #16
      4 UTF8 "LEAD"
      5 UTF8 "B"
      6 UTF8 "ConstantValue"
      7 Integer 1
      8 UTF8 ""
      9 UTF8 "()V"
      10 UTF8 "Code"
      11 UTF8 "LineNumberTable"
      12 UTF8 "SourceFile"
      13 UTF8 "C.java"
      14 NameAndType #8, type #9
      15 UTF8 "C"
      16 UTF8 "java/lang/Object"
      17 UTF8 "GOLD"
      LEAD should be replaced with expected GOLD is GOLD
      Step 2 try to instantiate C
      Step 2 object sucessfully instantiated
      Field found= public static final byte C.GOLD

      //// Trace 2 when Plum is a byte[]
      before=LEAD
      1 Method #4, name&type #14
      2 Field #3, name&type #15
      3 Class #16
      4 Class #17
      5 UTF8 "LEAD"
      6 UTF8 "[B"
      7 UTF8 ""
      8 UTF8 "()V"
      9 UTF8 "Code"
      10 UTF8 "LineNumberTable"
      11 UTF8 ""
      12 UTF8 "SourceFile"
      13 UTF8 "C.java"
      14 NameAndType #7, type #8
      15 NameAndType #5, type #6
      16 UTF8 "C"
      17 UTF8 "java/lang/Object"
      after=GOLD
      1 Method #4, name&type #14
      2 Field #3, name&type #15
      3 Class #16
      4 Class #17
      5 UTF8 "LEAD"
      6 UTF8 "[B"
      7 UTF8 ""
      8 UTF8 "()V"
      9 UTF8 "Code"
      10 UTF8 "LineNumberTable"
      11 UTF8 ""
      12 UTF8 "SourceFile"
      13 UTF8 "C.java"
      14 NameAndType #7, type #8
      15 NameAndType #5, type #6
      16 UTF8 "C"
      17 UTF8 "java/lang/Object"
      18 UTF8 "GOLD"
      LEAD should be replaced with expected GOLD is GOLD
      Step 2 try to instantiate C
      Exception in thread "main" java.lang.NoSuchFieldError: LEAD
      at C.(C.java:4)
      at java.lang.Class.forName0(Native Method)
      at java.lang.Class.forName(Class.java:164)
      at FieldRename.sequence1(FieldRename.java:21)
      at FieldRename.main(FieldRename.java:52)

        • 1. Re: Field rename
          chiba

          If the type is byte[], a constructor of C attempts to
          assign the initial value { 1 } to the field LEAD.
          You must substitute GOLD for all occurrences of LEAD
          in methods and constructors.

          • 2. Re: Field rename
            dechamps

            Yes, my C class doesn't contains any methods of my own !
            Does it means there are some masked methods inside any class?
            Or is it the classloader which products this ?

            • 3. Re: Field rename
              chiba

              If you don't define a constructor of C at all, your
              *compiler* define a constructor. It may also modify
              a constructor you defined so that it will insert some
              code fragment for field initialization.