Re: (reflect) Accessing members of inner annotations types

2014-01-10 Thread Gunnar Morling
Hi,

Many thanks for the investigation and suggested workarounds.

Bean Validation recommends to declare an inner @List annotation to specify
several constraints of the same type on a given element, but its ok to
deviate from that pattern in the rare cases of package-private constraint
types.

> I can file a bug/rfe for this.

I think that would be great; Taking the referenced types into account when
determining the package for generated proxy classes sounds reasonable to me.

Thanks again,

--Gunnar



2014/1/8 Joel Borggren-Franck 

> On 2014-01-08, Peter Levart wrote:
> > On 01/08/2014 01:00 PM, Joel Borggren-Franck wrote:
> > >>
> > >Perhaps an alternative would be to check if the interface a proxy is
> > >proxying is nested. In that case use the outermost interface's access
> > >level for the package calculation.
> > >
> > >This would probably lead to a few more proxies being generated into the
> > >"real" package compared to your proposal. I don't know if that is ok or
> > >not.
>
> > The nested public interface need not be referencing the outer
> > class/interface. In this case, proxy class can be generated in
> > com.sun.proxy.
>
> Yes, this is the reason for my remark about more proxies being generated
> into the real package. I'm not sure this is a problem, however it is
> moot considering you second point.
>
> > More importantly, even if the outer interface/class
> > was public, the nested interface could be referencing some other
> > package-private type. For example:
> >
>
> Ugh. Acknowledged. (This feels like a really bad practice but that
> doesn't matter here.)
>
> cheers
> /Joel
>


Re: (reflect) Accessing members of inner annotations types

2014-01-08 Thread Joel Borggren-Franck
On 2014-01-08, Peter Levart wrote:
> On 01/08/2014 01:00 PM, Joel Borggren-Franck wrote:
> >>
> >Perhaps an alternative would be to check if the interface a proxy is
> >proxying is nested. In that case use the outermost interface's access
> >level for the package calculation.
> >
> >This would probably lead to a few more proxies being generated into the
> >"real" package compared to your proposal. I don't know if that is ok or
> >not.

> The nested public interface need not be referencing the outer
> class/interface. In this case, proxy class can be generated in
> com.sun.proxy.

Yes, this is the reason for my remark about more proxies being generated
into the real package. I'm not sure this is a problem, however it is
moot considering you second point.

> More importantly, even if the outer interface/class
> was public, the nested interface could be referencing some other
> package-private type. For example:
> 

Ugh. Acknowledged. (This feels like a really bad practice but that
doesn't matter here.)

cheers
/Joel


Re: (reflect) Accessing members of inner annotations types

2014-01-08 Thread Peter Levart

On 01/08/2014 01:00 PM, Joel Borggren-Franck wrote:

Hi Peter,

On 2014-01-03, Peter Levart wrote:

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:
... 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:


Perhaps an alternative would be to check if the interface a proxy is
proxying is nested. In that case use the outermost interface's access
level for the package calculation.

This would probably lead to a few more proxies being generated into the
"real" package compared to your proposal. I don't know if that is ok or
not.


Hi Joel,

The nested public interface need not be referencing the outer 
class/interface. In this case, proxy class can be generated in 
com.sun.proxy. More importantly, even if the outer interface/class was 
public, the nested interface could be referencing some other 
package-private type. For example:



public class Outer {

@Retention(RUNTIME)
@interface PkgPrivate {}

@Retention(RUNTIME)
public @interface Public {
PkgPrivate value();
}


@Public(@PkgPrivate)
public void m() {}
}


I think the criteria for package selection should be closely tied to 
requirements of the generated proxy class code. And the generated code 
references the return type of the method.


Regards, Peter



cheers
/Joel




Re: (reflect) Accessing members of inner annotations types

2014-01-08 Thread Joel Borggren-Franck
Hi Peter,

On 2014-01-03, Peter Levart wrote:
> 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:

> ... 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:
> 

Perhaps an alternative would be to check if the interface a proxy is
proxying is nested. In that case use the outermost interface's access
level for the package calculation.

This would probably lead to a few more proxies being generated into the
"real" package compared to your proposal. I don't know if that is ok or
not.

cheers
/Joel


Re: (reflect) Accessing members of inner annotations types

2014-01-03 Thread Peter Levart

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."":(Ljava/lang/Throwable;)V

28: athrow
  Exception table:
 fromto  target type
 01818   Class java/lang/Error
 01818   Class java/lang/RuntimeException
 01819   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."":(Ljava/lang/Throwable;)V

33: athrow
  Exception table:
 fromto  target type
 02323   Class java/lang/Error
 02323   Class java/lang/RuntimeException
 02324   Class java/lang/Throwable


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


Regards, Peter



Re: (reflect) Accessing members of inner annotations types

2014-01-03 Thread Peter Levart
I think the problem is as follows... Annotations are implemented as Java 
dynamic Proxy classes. The generated proxy class for a package-private 
interface is created in the same package as the interface so that it has 
access to the interface. The top level interface can be package private, 
but nested interface (nested inside another interface) is by default 
public (all interface members are by default public). The consequence is 
that proxy class of an interface nested inside the interface is 
generated in com.sun.proxy package:


package pkg;

import java.lang.reflect.Proxy;

public class ProxyTest {
public static void main(String[] args) throws Exception {
Class iClass = Proxy.getProxyClass(I.class.getClassLoader(), 
new Class[]{I.class});
Class nClass = Proxy.getProxyClass(I.class.getClassLoader(), 
new Class[]{I.N.class});

System.out.println("iClass: " + iClass);
System.out.println("nClass: " + nClass);
}
}

interface I {
interface N {}
}

prints:

iClass: class pkg.$Proxy0
nClass: class com.sun.proxy.$Proxy1


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!


Your best solution currently is to implement the top-level annotations 
as public, or have all package-private annotations as top-level annotations.


In future, I think the logic to calculate the package of a proxy class 
could be improved. It currently is as follows:


String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

/*
 * Record the package of a non-public proxy interface so 
that the
 * proxy class will be defined in the same package.  Verify 
that

 * all non-public proxy interfaces are in the same package.
 */
for (Class intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n 
+ 1));

if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different 
packages");

}
}
}

if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy 
package

proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}


...It could be improved to take into account not only all interfaces 
being implemented but also all types that are encountered in interface 
method signatures. If any of those types is non-public than all of them 
should be in the same package and proxy class would be generated in that 
package...


I can file a bug/rfe for this.

Regards, Peter



On 01/03/2014 02:14 PM, Gunnar Morling wrote:

Hi,

In the course of running the Bean Validation TCK on JDK 8, I'm
investigating an issue around reflectively accessing members of annotations
which are declared as inner type of another, package-private annotation
type.

The following shows an example:

 @Retention( RetentionPolicy.RUNTIME )
 /*package-private */ @interface Named {

 @Retention( RetentionPolicy.RUNTIME )
 /*package-private */ @interface List {
 Named[] value();
 }
 }

The @List annotation is used as this on a type in the same package:

 public class Foo {

 @Named.List( @Named )
 public void getBar() {}
 }

I'm then trying to access the @Named annotation using reflection like this:

 Annotation listAnnotation = Foo.class.getMethod( "getBar"
).getAnnotations()[0];

 Method method = listAnnotation.getClass().getMethod( "value" );
 method.setAccessible( true );

 //fails
 Annotation namedAnnotation = ( (Annotation[]) method.invoke(
listAnnotation ) )[0];

This is the exception I get:

 IllegalAccessError: tried to access class com.example.Named from class
com.sun.proxy.$Proxy3
   at com.sun.proxy.$Proxy3.value(Unknown Source)

Interestingly, this only occurs when the List annotation is declared as an
inner type within the Named type; it works when the List annotation is a
top-level package-private type (the Named annotation still being
package-private) as well as when it 

(reflect) Accessing members of inner annotations types

2014-01-03 Thread Gunnar Morling
Hi,

In the course of running the Bean Validation TCK on JDK 8, I'm
investigating an issue around reflectively accessing members of annotations
which are declared as inner type of another, package-private annotation
type.

The following shows an example:

@Retention( RetentionPolicy.RUNTIME )
/*package-private */ @interface Named {

@Retention( RetentionPolicy.RUNTIME )
/*package-private */ @interface List {
Named[] value();
}
}

The @List annotation is used as this on a type in the same package:

public class Foo {

@Named.List( @Named )
public void getBar() {}
}

I'm then trying to access the @Named annotation using reflection like this:

Annotation listAnnotation = Foo.class.getMethod( "getBar"
).getAnnotations()[0];

Method method = listAnnotation.getClass().getMethod( "value" );
method.setAccessible( true );

//fails
Annotation namedAnnotation = ( (Annotation[]) method.invoke(
listAnnotation ) )[0];

This is the exception I get:

IllegalAccessError: tried to access class com.example.Named from class
com.sun.proxy.$Proxy3
  at com.sun.proxy.$Proxy3.value(Unknown Source)

Interestingly, this only occurs when the List annotation is declared as an
inner type within the Named type; it works when the List annotation is a
top-level package-private type (the Named annotation still being
package-private) as well as when it is declared as an inner type within
another package-private class.

I first thought that this might be related to 8004260 ("dynamic proxy class
should have the same Java language access as the proxy interfaces"), but
the issue occurs on on JDK 7 as well.

Is this a potential issue with the access check implementation or is
something wrong here with the way I'm accessing the annotation member?

Thanks for any help,

--Gunnar