On 01/03/2014 03:52 PM, Peter Levart wrote:
This is would be all right until such proxy class (com.sun.proxy.$Proxy1 in our example) has to access some package-private types in some specific package. This happens in your Named.List annotation implementation class. It implements a member method with the following signature:

public Named[] value() {...

...where the return type is an array of a package-private type Named. Public class in com.sun.proxy package can not access package-private types in other packages!

Investigating this further, I found that the declaration itself is not problematic. It's the code in the implemented proxy method that tries to access the package-private Named class. Here's how the bytecode looks like for such proxy method:


  public final pkg.Named[] value() throws ;
    Signature: ()[Lpkg/Named;
    flags: ACC_PUBLIC, ACC_FINAL
    Code:
      stack=10, locals=2, args_size=1
         0: aload_0
1: getfield #16 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
         4: aload_0
5: getstatic #67 // 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: checkcast     #69                 // class "[Lpkg/Named;"*
        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


... I think the error is thrown at the "checkcast" bytecode. The improvement suggested still holds. If the proxy class was generated in the specific package, error would not be thrown. But the requirement to take into account all implemented interfaces and all types encountered in the interface method signatures to calculate the package of proxy class it too strict. Only implemented interfaces and return types of all interface methods need to be taken into consideration. Here's an example of bytecode that illustrates how method parameters are passed to InvocationHandler:


  public final void doWith(pkg.Named[]) throws ;
    Signature: ([Lpkg/Named;)V
    flags: ACC_PUBLIC, ACC_FINAL
    Code:
      stack=10, locals=3, args_size=2
         0: aload_0
1: getfield #16 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
         4: aload_0
5: getstatic #57 // Field m3: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: pop
        22: return
        23: athrow
        24: astore_2
25: new #42 // class java/lang/reflect/UndeclaredThrowableException
        28: dup
        29: aload_2
30: invokespecial #45 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
        33: athrow
      Exception table:
         from    to  target type
             0    23    23   Class java/lang/Error
             0    23    23   Class java/lang/RuntimeException
             0    23    24   Class java/lang/Throwable


... as can be seen, no parameter types are referenced in order to wrap the parameters with Object[] array.

Regards, Peter

Reply via email to