United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6256803 : (proxy) Proxy class not in proper package

Details
Type:
Enhancement
Submit Date:
2005-04-18
Status:
Open
Updated Date:
2013-09-17
Project Name:
JDK
Resolved Date:
Component:
core-libs
OS:
windows_xp
Sub-Component:
java.lang:reflect
CPU:
x86
Priority:
P4
Resolution:
Unresolved
Affected Versions:
5.0
Targeted Versions:
tbd_major

Related Reports

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.5.0_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_02-b09)
Java HotSpot(TM) Client VM (build 1.5.0_02-b09, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
The generated proxy is not put in the proper package.

The Javadoc for java.lang.reflect.Proxy says:

"If a proxy class implements a non-public interface, then it will be defined in the same package as that interface. Otherwise, the package of a proxy class is also unspecified. Note that package sealing will not prevent a proxy class from being successfully defined in a particular package at runtime, and neither will classes already defined by the same class loader and the same package with particular signers."

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Put Outer.java and Test.java included below in package p1.
2) Compile them.
3) Run p1.Test.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Class class p1.$Proxy0
is in package p1
Class class p1.$Proxy1
is in package p1
ACTUAL -
Class class p1.$Proxy0
is in package p1
Class class $Proxy1
is in null

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Since the proxy is in the wrong package, this can lead to spurious and tricky IllegalAccessErrors like this:

java.lang.IllegalAccessError: tried to access class com.foo.Bar from class $Proxy1

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package p1;

interface Outer {
    interface Inner {
    }
}

============================================================

package p1;

import java.lang.reflect.*;

public class Test {
    
    public static void main(String[] args) {
        makeProxy(Outer.class);
        makeProxy(Outer.Inner.class);
    }

    private static void makeProxy(Class oneInterface) {
        ClassLoader loader = Test.class.getClassLoader();
        Class[] interfaces = new Class[] { oneInterface };
        InvocationHandler handler = new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) {
                System.out.println("doing " + method);
                return method;
            }
        };
        Object proxy = Proxy.newProxyInstance(
            loader,interfaces,handler);
        System.out.println("Class " + proxy.getClass());
        System.out.println("is in " + proxy.getClass().getPackage());
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Increase visibility from package to protected as required to eliminate any IllegalAccessErrors.
###@###.### 2005-04-18 19:34:48 GMT

                                    

Comments
Changing assignee to engineer currently working in this area.
                                     
2013-04-11
EVALUATION

The reported behavior actually does conform to the words of the quoted specification: the interface p1.Outer.Inner is public, because it is a member of interface p1.Outer, and all members of an interface are implicitly public (see JLS3 9.1.5); therefore, there is no requirement that the generated proxy class be in the same package (p1).

The point could be taken, however, that the words of the specification do not match their more abstract original intent, which was for the "right thing" to implicitly occur regarding the implicit choice of package for a dynamic proxy class, given the accessibility of its proxy interfaces, so that IllegalAccessErrors should not occur.

The Description of this bug report is not too specific about the negative ramifications of this behavior, other than mentioning IllegalAccessError (it's not demonstrated by the test case), but I think that I can guess the cause.  There is a general flaw with the specified algorithm for implicitly choosing the package for a dynamic proxy class based on the accessibility of its interfaces: even if a proxy interface is accessible to all code, implementing it still may require the proxy class to reference types that are not accessible to all code-- specifically, the return types of all of the interface's member methods (which the proxy class's implementations must cast the results of InvocationHandler.invoke invocations to) and certain of the declared exception types of the interface's member methods.  If one of these types is not generally accessible, then the generated proxy class will cause an IllegalAccessError if it is not in the same package as that type (note that the type is not necessarily even in the same package as the proxy interface, if the associated method is inherited, not declared, by the proxy interface).

I am disinclined to think that the specification should be amended so that the "right" package is implicitly chosen in consideration of the full generality of the issue described in the previous paragraph-- it would require adding quite complex rules for arguably academic cases.  It doesn't seem useful for a public interface to depend on non-public types.  In previous cases that I am aware of in which people have encountered this issue, they generally agreed that the interface being public was a mistake, and thus the problem was "worked around" by correcting that mistake.

The particular reported case, however, seems a little more special, because A) interface member interfaces are inevitably public and B) a normal class in an arbitrary package could not implement p1.Outer.Inner, because it would not be accessible (JLS3 8.1.5, 6.6.1).  It seems that the original intent of the specification regarding the implicit package choice would have been better met if it were conditioned on the interface not being accessible to code in all packages, rather than the interface being non-public.  The more general flaw described above would still exist, but for the reported case, the dynamic proxy class would then be created in the expected package, p1.  So, the specification and implementation could be fixed to allow this.  It's not yet clear to me how important this case is in practice, however.
                                     
2006-09-25



Hardware and Software, Engineered to Work Together