Method
starksm64 Jan 2, 2006 4:31 AMI'm looking at using the CodeConverter.redirectMethodCall(CtMethod, CtMethod) to redirect a jdk5 autobox utility method call such as java.lang.Integer.valueOf(int) to another static utility method as part of a jdk5 to jdk1.4.2 conversion tool, but I'm not seeing the redirect show up. The following is the little test program and associated classes:
package org.jboss.test.weaver; import java.io.File; import java.io.DataInputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.DataOutputStream; import org.jboss.ant.tasks.retro.AutoboxCodeConverter; import javassist.bytecode.ClassFile; import javassist.CtClass; import javassist.ClassPool; public class WeaverTestCase { public static void main(String[] args) throws Exception { File inputFile = new File("/cvs/JBossHead/jbossretro/output/test-classes/org/jboss/test/weaver/AutoboxUsage.class"); DataInputStream is = new DataInputStream(new FileInputStream(inputFile)); ClassFile inputCF = new ClassFile(is); is.close(); CtClass clazz = ClassPool.getDefault().get(inputCF.getName()); clazz.instrument(new AutoboxCodeConverter()); File outputFile = new File("/cvs/JBossHead/jbossretro/output/test-classes14/org/jboss/test/weaver/AutoboxUsage.class"); FileOutputStream os = new FileOutputStream(outputFile); DataOutputStream dos = new DataOutputStream(os); inputCF.write(dos); dos.close(); }
package org.jboss.test.weaver; import java.util.ArrayList; // Sample autobox usage public class AutoboxUsage { public static void main(String[] args) { ArrayList<Integer> ial = new ArrayList<Integer>(); for(int i = 1; i <= 10; i ++) ial.add(i); if(ial.get(0) == 1); System.out.println("iol(0) == 1 as expected"); } }
package org.jboss.ant.tasks.retro; import javassist.CannotCompileException; import javassist.CodeConverter; import javassist.CtClass; import javassist.ClassPool; import javassist.NotFoundException; import javassist.CtMethod; // Registers the Integer.valueOf(int) to AutoboxCodeConverter.valueOf(int) redirect public class AutoboxCodeConverter extends CodeConverter { public AutoboxCodeConverter() throws NotFoundException, CannotCompileException { ClassPool defaultPool = ClassPool.getDefault(); CtClass integerClass = defaultPool.get("java.lang.Integer"); CtClass intClass = defaultPool.get("int"); CtClass[] intSig = {intClass}; CtClass autoboxClass = defaultPool.get("org.jboss.ant.tasks.retro.AutoboxCodeConverter"); CtMethod valueOfInt2 = autoboxClass.getDeclaredMethod("valueOf", intSig); CtMethod valueOfInt = integerClass.getDeclaredMethod("valueOf", intSig); System.out.println("redirecting: "+valueOfInt+" to: "+valueOfInt2); redirectMethodCall(valueOfInt, valueOfInt2); } public static Integer valueOf(int i) { return new Integer(i); } }
javap -verbose on the resulting output/test-classes14/org/jboss/test/weaver/AutoboxUsage.class is still showing an "invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;" rather than the desired invokestatic on the AutoboxCodeConverter.valueOf(int) method:
Compiled from "AutoboxUsage.java" public class org.jboss.test.weaver.AutoboxUsage extends java.lang.Object SourceFile: "AutoboxUsage.java" minor version: 0 major version: 48 Constant pool: const #1 = Method #13.#33; // java/lang/Object."<init>":()V const #2 = class #34; // java/util/ArrayList const #3 = Method #2.#33; // java/util/ArrayList."<init>":()V const #4 = Method #7.#35; // java/lang/Integer.valueOf:(I)Ljava/lang/Integer; const #5 = Method #2.#36; // java/util/ArrayList.add:(Ljava/lang/Object;)Z const #6 = Method #2.#37; // java/util/ArrayList.get:(I)Ljava/lang/Object; const #7 = class #38; // java/lang/Integer const #8 = Method #7.#39; // java/lang/Integer.intValue:()I const #9 = Field #40.#41; // java/lang/System.out:Ljava/io/PrintStream; const #10 = String #42; // iol(0) == 1 as expected const #11 = Method #43.#44; // java/io/PrintStream.println:(Ljava/lang/String;)V const #12 = class #45; // org/jboss/test/weaver/AutoboxUsage const #13 = class #46; // java/lang/Object const #14 = Asciz <init>; const #15 = Asciz ()V; const #16 = Asciz Code; const #17 = Asciz LineNumberTable; const #18 = Asciz LocalVariableTable; const #19 = Asciz this; const #20 = Asciz Lorg/jboss/test/weaver/AutoboxUsage;; const #21 = Asciz main; const #22 = Asciz ([Ljava/lang/String;)V; const #23 = Asciz i; const #24 = Asciz I; const #25 = Asciz args; const #26 = Asciz [Ljava/lang/String;; const #27 = Asciz ial; const #28 = Asciz Ljava/util/ArrayList;; const #29 = Asciz LocalVariableTypeTable; const #30 = Asciz Ljava/util/ArrayList<Ljava/lang/Integer;>;; const #31 = Asciz SourceFile; const #32 = Asciz AutoboxUsage.java; const #33 = NameAndType #14:#15;// "<init>":()V const #34 = Asciz java/util/ArrayList; const #35 = NameAndType #47:#48;// valueOf:(I)Ljava/lang/Integer; const #36 = NameAndType #49:#50;// add:(Ljava/lang/Object;)Z const #37 = NameAndType #51:#52;// get:(I)Ljava/lang/Object; const #38 = Asciz java/lang/Integer; const #39 = NameAndType #53:#54;// intValue:()I const #40 = class #55; // java/lang/System const #41 = NameAndType #56:#57;// out:Ljava/io/PrintStream; const #42 = Asciz iol(0) == 1 as expected; const #43 = class #58; // java/io/PrintStream const #44 = NameAndType #59:#60;// println:(Ljava/lang/String;)V const #45 = Asciz org/jboss/test/weaver/AutoboxUsage; const #46 = Asciz java/lang/Object; const #47 = Asciz valueOf; const #48 = Asciz (I)Ljava/lang/Integer;; const #49 = Asciz add; const #50 = Asciz (Ljava/lang/Object;)Z; const #51 = Asciz get; const #52 = Asciz (I)Ljava/lang/Object;; const #53 = Asciz intValue; const #54 = Asciz ()I; const #55 = Asciz java/lang/System; const #56 = Asciz out; const #57 = Asciz Ljava/io/PrintStream;; const #58 = Asciz java/io/PrintStream; const #59 = Asciz println; const #60 = Asciz (Ljava/lang/String;)V; { public org.jboss.test.weaver.AutoboxUsage(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 16: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lorg/jboss/test/weaver/AutoboxUsage; public static void main(java.lang.String[]); Code: Stack=2, Locals=3, Args_size=1 0: new #2; //class java/util/ArrayList 3: dup 4: invokespecial #3; //Method java/util/ArrayList."<init>":()V 7: astore_1 8: iconst_1 9: istore_2 10: iload_2 11: bipush 10 13: if_icmpgt 31 16: aload_1 17: iload_2 18: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 21: invokevirtual #5; //Method java/util/ArrayList.add:(Ljava/lang/Object;)Z 24: pop 25: iinc 2, 1 28: goto 10 31: aload_1 32: iconst_0 33: invokevirtual #6; //Method java/util/ArrayList.get:(I)Ljava/lang/Object; 36: checkcast #7; //class java/lang/Integer 39: invokevirtual #8; //Method java/lang/Integer.intValue:()I 42: iconst_1 43: if_icmpne 46 46: getstatic #9; //Field java/lang/System.out:Ljava/io/PrintStream; 49: ldc #10; //String iol(0) == 1 as expected 51: invokevirtual #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 54: return LineNumberTable: line 20: 0 line 21: 8 line 22: 16 line 21: 25 line 24: 31 line 25: 46 line 26: 54 LocalVariableTable: Start Length Slot Name Signature 10 21 2 i I 0 55 0 args [Ljava/lang/String; 8 47 1 ial Ljava/util/ArrayList; LocalVariableTypeTable: length = 0xC 00 01 00 08 00 2F 00 1B 00 1E 00 01 }
Is the CodeConverter.redirectMethodCall the correct way to try to do this?