Search code examples
javaproxy-classescglib

Serializing a proxy class to file


I have a proxy (generated either as a JDKProxy or a CGLIB one) that is generated at runtime in the JVM. I wanted to know if there is a way to write the contents of this class (which looks like com.sun.proxy$Proxy123.class) to a file so that I may use a jd-eclipse like decompiler to see the kind of code generated. Since the class is present in the JVM, I wanted to know if there is a way we can ask the ClassLoader to provide an InputStream/URL to the actual class that can then be used to write contents to disk - and this file on the disk can be read using either jd-eclipse or javap. I know that this is not a production use case, but I was curious to see the contents of this dynamically generated class.

Thanks!


Solution

  • You can use Instrumentation to register a retransform-capable ClassFileTransformer and request a re-transformation of the Proxy class. Then, within the transformer’s transform method you have hands on the byte array which makes up the class. After saving the array to a class file you can simply return the array unmodified to let the JVM proceed unaffected.

    But I’m not sure what you expect from looking into these classes. They are implemented straight-forward and offer no surprises. Here is an example of javap’s output after doing the steps described above on the java.lang.Runnable Proxy as generated with Oracle’s jdk1.7.0_40:

    public final class com.sun.proxy.$Proxy0 extends java.lang.reflect.Proxy implements java.lang.Runnable {
      private static java.lang.reflect.Method m1;
    
      private static java.lang.reflect.Method m3;
    
      private static java.lang.reflect.Method m0;
    
      private static java.lang.reflect.Method m2;
    
      public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler);
        Code:
           0: aload_0       
           1: aload_1       
           2: invokespecial #8                  // Method java/lang/reflect/Proxy."<init>":(Ljava/lang/reflect/InvocationHandler;)V
           5: return        
    
      public final int hashCode();
        Code:
           0: aload_0       
           1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
           4: aload_0       
           5: getstatic     #55                 // Field m0:Ljava/lang/reflect/Method;
           8: aconst_null   
           9: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
          14: checkcast     #57                 // class java/lang/Integer
          17: invokevirtual #60                 // Method java/lang/Integer.intValue:()I
          20: ireturn       
          21: athrow        
          22: astore_1      
          23: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
          26: dup           
          27: aload_1       
          28: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
          31: athrow        
        Exception table:
           from    to  target type
               0    21    21   Class java/lang/Error
               0    21    21   Class java/lang/RuntimeException
               0    21    22   Class java/lang/Throwable
    
      public final boolean equals(java.lang.Object);
        Code:
           0: aload_0       
           1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
           4: aload_0       
           5: getstatic     #20                 // Field m1:Ljava/lang/reflect/Method;
           8: iconst_1      
           9: anewarray     #22                 // class java/lang/Object
          12: dup           
          13: iconst_0      
          14: aload_1       
          15: aastore       
          16: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
          21: checkcast     #30                 // class java/lang/Boolean
          24: invokevirtual #34                 // Method java/lang/Boolean.booleanValue:()Z
          27: ireturn       
          28: athrow        
          29: astore_2      
          30: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
          33: dup           
          34: aload_2       
          35: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
          38: athrow        
        Exception table:
           from    to  target type
               0    28    28   Class java/lang/Error
               0    28    28   Class java/lang/RuntimeException
               0    28    29   Class java/lang/Throwable
    
      public final java.lang.String toString();
        Code:
           0: aload_0       
           1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
           4: aload_0       
           5: getstatic     #65                 // Field m2:Ljava/lang/reflect/Method;
           8: aconst_null   
           9: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
          14: checkcast     #67                 // class java/lang/String
          17: areturn       
          18: athrow        
          19: astore_1      
          20: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
          23: dup           
          24: aload_1       
          25: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
          28: athrow        
        Exception table:
           from    to  target type
               0    18    18   Class java/lang/Error
               0    18    18   Class java/lang/RuntimeException
               0    18    19   Class java/lang/Throwable
    
      static {};
        Code:
           0: ldc           #70                 // String java.lang.Object
           2: invokestatic  #76                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
           5: ldc           #77                 // String equals
           7: iconst_1      
           8: anewarray     #72                 // class java/lang/Class
          11: dup           
          12: iconst_0      
          13: ldc           #70                 // String java.lang.Object
          15: invokestatic  #76                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
          18: aastore       
          19: invokevirtual #81                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
          22: putstatic     #20                 // Field m1:Ljava/lang/reflect/Method;
          25: ldc           #83                 // String java.lang.Runnable
          27: invokestatic  #76                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
          30: ldc           #84                 // String run
          32: iconst_0      
          33: anewarray     #72                 // class java/lang/Class
          36: invokevirtual #81                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
          39: putstatic     #50                 // Field m3:Ljava/lang/reflect/Method;
          42: ldc           #70                 // String java.lang.Object
          44: invokestatic  #76                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
          47: ldc           #85                 // String hashCode
          49: iconst_0      
          50: anewarray     #72                 // class java/lang/Class
          53: invokevirtual #81                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
          56: putstatic     #55                 // Field m0:Ljava/lang/reflect/Method;
          59: ldc           #70                 // String java.lang.Object
          61: invokestatic  #76                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
          64: ldc           #86                 // String toString
          66: iconst_0      
          67: anewarray     #72                 // class java/lang/Class
          70: invokevirtual #81                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
          73: putstatic     #65                 // Field m2:Ljava/lang/reflect/Method;
          76: return        
          77: astore_1      
          78: new           #90                 // class java/lang/NoSuchMethodError
          81: dup           
          82: aload_1       
          83: invokevirtual #93                 // Method java/lang/Throwable.getMessage:()Ljava/lang/String;
          86: invokespecial #96                 // Method java/lang/NoSuchMethodError."<init>":(Ljava/lang/String;)V
          89: athrow        
          90: astore_1      
          91: new           #100                // class java/lang/NoClassDefFoundError
          94: dup           
          95: aload_1       
          96: invokevirtual #93                 // Method java/lang/Throwable.getMessage:()Ljava/lang/String;
          99: invokespecial #101                // Method java/lang/NoClassDefFoundError."<init>":(Ljava/lang/String;)V
         102: athrow        
        Exception table:
           from    to  target type
               0    77    77   Class java/lang/NoSuchMethodException
               0    77    90   Class java/lang/ClassNotFoundException
    
      public final void run();
        Code:
           0: aload_0       
           1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
           4: aload_0       
           5: getstatic     #50                 // Field m3:Ljava/lang/reflect/Method;
           8: aconst_null   
           9: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
          14: pop           
          15: return        
          16: athrow        
          17: astore_1      
          18: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
          21: dup           
          22: aload_1       
          23: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
          26: athrow        
        Exception table:
           from    to  target type
               0    16    16   Class java/lang/Error
               0    16    16   Class java/lang/RuntimeException
               0    16    17   Class java/lang/Throwable
    }