7 Replies Latest reply: Mar 11, 2006 8:24 PM by chung chung RSS

    On a faster java.lang.reflect.Method using Javassist

    Adrian Brock Master

      I've been playing with generating our own reflection objects
      rather than using the JDK classes.

      My Javassist reflection methods are significantly faster

       int iterations = 10000000;
      
       public void testStressJavassist() throws Throwable
       {
       ClassInfo typeInfo = getClassInfo(String.class);
       MethodInfo methodInfo = typeInfo.getDeclaredMethod("toString", null);
       String hello = "Hello";
       long start = System.currentTimeMillis();
       for (int i = 0; i < iterations; ++i)
       methodInfo.invoke(hello, null);
       long end = System.currentTimeMillis();
       System.out.println("testStressJavassist " + (end - start) + "ms");
       }
      
       public void testStressReflect() throws Throwable
       {
       Method method = String.class.getDeclaredMethod("toString", null);
       String hello = "Hello";
       long start = System.currentTimeMillis();
       for (int i = 0; i < iterations; ++i)
       method.invoke(hello, null);
       long end = System.currentTimeMillis();
       System.out.println("testStressReflect " + (end - start) + "ms");
       }
      
       public void testStressJavassist2() throws Throwable
       {
       ClassInfo typeInfo = getClassInfo(String.class);
       TypeInfo intInfo = getTypeInfo(Integer.TYPE);
       MethodInfo methodInfo = typeInfo.getDeclaredMethod("charAt", new TypeInfo[] { intInfo });
       String hello = "Hello";
       Object[] params = { new Integer(4) };
       long start = System.currentTimeMillis();
       for (int i = 0; i < iterations; ++i)
       methodInfo.invoke(hello, params);
       long end = System.currentTimeMillis();
       System.out.println("testStressJavassist2 " + (end - start) + "ms");
       }
      
       public void testStressReflect2() throws Throwable
       {
       Method method = String.class.getDeclaredMethod("charAt", new Class[] { Integer.TYPE });
       String hello = "Hello";
       Object[] params = { new Integer(4) };
       long start = System.currentTimeMillis();
       for (int i = 0; i < iterations; ++i)
       method.invoke(hello, params);
       long end = System.currentTimeMillis();
       System.out.println("testStressReflect2 " + (end - start) + "ms");
       }
      


      Output - you can also see the cost of Autoboxing the int ;-)
      testStressJavassist 479ms
      testStressReflect 2937ms
      testStressJavassist2 1153ms
      testStressReflect2 3344ms
      


      Rather than showing the code used to generate the class
      here is the generated code:
      java.lang.String.toString();
      
      public Object invoke(Object target, Object[] args) throws Throwable {if (target == null) throw new IllegalArgumentException("Null target for
       toString()Ljava/lang/String;");if (target instanceof java.lang.String == false) throw new IllegalArgumentException("Target " + target + " i
      s not an instance of java.lang.String for toString()Ljava/lang/String;");if (args != null && args.length != 0)throw new IllegalArgumentExcep
      tion("Expected no parameters for toString()Ljava/lang/String;");return ((java.lang.String)target).toString();}
      
      java.lang.String.charAt(int);
      
      public Object invoke(Object target, Object[] args) throws Throwable {if (target == null) throw new IllegalArgumentException("Null target for
       charAt(I)C");if (target instanceof java.lang.String == false) throw new IllegalArgumentException("Target " + target + " is not an instance
      of java.lang.String for charAt(I)C");if (args == null || args.length != 1) throw new IllegalArgumentException("Expected 1 parameter(s) for c
      harAt(I)C");if (args[0] == null) throw new IllegalArgumentException("Parameter 0 cannot be null for int for charAt(I)C");if (args[0] != null
       && args[0] instanceof java.lang.Integer == false) throw new IllegalArgumentException("Parameter 0 is not an instance of java.lang.Integer f
      or charAt(I)C");return new java.lang.Character(((java.lang.String)target).charAt(((java.lang.Integer)args[0]).intValue()));}
      


      I also have an option for turning off parameter checking,
      but this doen't seem to make any measurable difference to the numbers
      although the generated code is easier to understand :-)
      String.toString();
      
      public Object invoke(Object target, Object[] args) throws Throwable {return ((java.lang.String)target).toString();}
      
      String.charAt(int);
      
      public Object invoke(Object target, Object[] args) throws Throwable {return new java.lang.Character(((java.lang.String)target).charAt(((java
      .lang.Integer)args[0]).intValue()));}
      


        • 1. Re: On a faster java.lang.reflect.Method using Javassist
          Adrian Brock Master

          The only downside to this approach is support for

          AccessibleObject.setAccesible()
          


          But this is possible if class verfication is turned off (e.g. JRockit has this option).
          Or in Sun's JDK, you just make the class extend "MagicAccessorImpl" instead
          of Object.
          http://www.jroller.com/page/slava?entry=the_hotspot_source_code_is
          Which is like a per class flag to turn of class verification. :-)

          If such approaches fail, we can always revert back to reflection
          for the few use cases where this is needed.

          • 2. Re: On a faster java.lang.reflect.Method using Javassist
            Max Rydahl Andersen Master

            What is the difference between this and what have recently been added to javaassist to allow it be used on equal foot as cglib ?



            • 3. Re: On a faster java.lang.reflect.Method using Javassist
              Adrian Brock Master

              It provides an api like java.lang.reflect (e.g. per method)
              rather than a reflective class like cglib.

              • 4. Re: On a faster java.lang.reflect.Method using Javassist
                Max Rydahl Andersen Master

                ok, could be interesting to try and use this api for the hibernate core method reflection and lookup.

                • 5. Re: On a faster java.lang.reflect.Method using Javassist
                  chung chung Newbie

                  Hi,
                  Can help me pls,I try adrian sample but have error.

                   int iterations = 1000000;
                   public static void main(String[] args) {
                   myTest my = new myTest();
                   try {
                   my.testStressJavassist();
                   my.testStressReflect();
                   }catch(Throwable ex){
                   ex.printStackTrace(System.out);
                   }
                   }
                   public void testStressJavassist() throws Throwable
                   {
                   ClassInfo typeInfo = getClassInfo(String.class);
                   MethodInfo methodInfo = typeInfo.getDeclaredMethod("toString", null);
                   String hello = "Hello";
                   long start = System.currentTimeMillis();
                   for (int i = 0; i < iterations; ++i)
                   methodInfo.invoke(hello, null);
                   long end = System.currentTimeMillis();
                   System.out.println("testStressJavassist " + (end - start) + "ms");
                   }
                   public void testStressReflect() throws Throwable
                   {
                   Method method = String.class.getDeclaredMethod("toString", null);
                   String hello = "Hello";
                   long start = System.currentTimeMillis();
                   for (int i = 0; i < iterations; ++i)
                   method.invoke(hello, null);
                   long end = System.currentTimeMillis();
                   System.out.println("testStressReflect " + (end - start) + "ms");
                   }
                   public ClassInfo getClassInfo(Class clazz){
                   TypeInfoFactory typeFactory = new JavassistTypeInfoFactory();;
                   return(ClassInfo)typeFactory.getTypeInfo(clazz);
                   }
                  

                  error StackTrace is
                  java.lang.RuntimeException:
                  Cannot compile public Object invoke(Object target, Object[] args) throws Throwable
                  {if (target == null) throw new IllegalArgumentException("Null target for toString()Ljava/lang/String;");
                  if (target instanceof java.lang.String == false) throw new IllegalArgumentException("Target " + target + " is not an instance of java.lang.String for toString()Ljava/lang/String;");
                  if (args != null && args.length != 0)throw new IllegalArgumentException("Expected no parameters for toString()Ljava/lang/String;");
                  return ((java.lang.String)target).toString();}
                   at org.jboss.reflect.plugins.javassist.JavassistReflectionFactory.createMethod(JavassistReflectionFactory.java:229)
                   at org.jboss.reflect.plugins.javassist.JavassistMethodInfo.invoke(JavassistMethodInfo.java:157)
                   at mytest.myTest.testStressJavassist(myTest.java:33)
                   at mytest.MyJavassistTest.main(MyJavassistTest.java:15)
                  Caused by: javassist.CannotCompileException: [source error] incompatible array types
                   at javassist.CtNewMethod.make(CtNewMethod.java:78)
                   at javassist.CtNewMethod.make(CtNewMethod.java:44)
                   at org.jboss.reflect.plugins.javassist.JavassistReflectionFactory.createMethod(JavassistReflectionFactory.java:224)
                   ... 3 more
                  

                  My config are jvm 1.5 and javassist-3.0

                  thank

                  • 6. Re: On a faster java.lang.reflect.Method using Javassist
                    Adrian Brock Master

                    This stuff was tested with javaassist 3.1
                    available from jboss binary repository
                    http://repository.jboss.com/javassist/3.1/

                    • 7. Re: On a faster java.lang.reflect.Method using Javassist
                      chung chung Newbie

                      Hi,

                      Thanks for your help ;-)