Had to leave, hence continuing here.

The purpose of demonstrating that compilable and runnable Java program is 
simply to proof, that it
is legal to access public members of package private classes, if the access 
occurs via an instance
of a public subclass.

The reflective version that behaves like the presented compiled version, may be 
coded like:

    import java.lang.reflect.*;

    public class UseC2Reflective
    {
        public static void main (String args[]) {
            p.C2 o=new p.C2();
            System.out.println("o="+o);

            Class sc=o.getClass().getSuperclass();

            Method rm    =null;
            Object result=null;
            try {
                rm=sc.getDeclaredMethod("m",new Class[0]);

                try {
                    result=rm.invoke(o,new Object[0]);
                }
                catch (Exception e1)
                {
                    rm.setAccessible(true);
                    result=rm.invoke(o,new Object[0]);
                }
            }
            catch (Exception e)
            {
                System.err.println("getDefinedMethod(...) caused exception: 
"+e);
                e.printStackTrace();
                System.exit(-1);
            }

            System.out.println("o.m()="+o.m());
        }
    }

Running it with Java 9 gives:

    G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." 
UseC2Reflective
    o=p.C2@3cd1f1c8
    o.m()=-1

So this behaves like in the past: it is possible to mimickry a compiled Java 
program using
reflection with setAccessible.

-----------------

Now turning to the use of setAccessible() and looking up the Javadocs for Java 
6, 7, 8 and 9, is
interesting:

  * Javadocs 6:

    public class AccessibleObject
    extends Object
    implements AnnotatedElement

    The AccessibleObject class is the base class for Field, Method and 
Constructor objects. It
    provides the ability to flag a reflected object as suppressing default Java 
language access
    control checks when it is used. The access checks--for public, default 
(package) access,
    protected, and private members--are performed when Fields, Methods or 
Constructors are used to
    set or get fields, to invoke methods, or to create and initialize new 
instances of classes,
    respectively.

    Setting the accessible flag in a reflected object permits sophisticated 
applications with
    sufficient privilege, such as Java Object Serialization or other 
persistence mechanisms, to
    manipulate objects in a manner that would normally be prohibited.

    Since:
        1.2
    See Also:
        Field, Method, Constructor, ReflectPermission

  * Javadocs 7; this adds a paragraph to the documentation:

    public class AccessibleObject
    extends Object
    implements AnnotatedElement

    The AccessibleObject class is the base class for Field, Method and 
Constructor objects. It
    provides the ability to flag a reflected object as suppressing default Java 
language access
    control checks when it is used. The access checks--for public, default 
(package) access,
    protected, and private members--are performed when Fields, Methods or 
Constructors are used to
    set or get fields, to invoke methods, or to create and initialize new 
instances of classes,
    respectively.

    Setting the accessible flag in a reflected object permits sophisticated 
applications with
    sufficient privilege, such as Java Object Serialization or other 
persistence mechanisms, to
    manipulate objects in a manner that would normally be prohibited.

    *By default, a reflected object is not accessible.*

  * Javadocs 8; this is the same as for the Javadocs 7.

So the rule is, that a reflected object is not accessible by default, such that 
one needs to use the
setAccessible() method.

  * Javadocs 9; this rewrites the documentation to read:

    public class AccessibleObject
    extends Object
    implements AnnotatedElement

    The AccessibleObject class is the base class for Field, Method, and 
Constructor objects (known
    as reflected objects). It provides the ability to flag a reflected object 
as suppressing checks
    for Java language access control when it is used. This permits 
sophisticated applications with
    sufficient privilege, such as Java Object Serialization or other 
persistence mechanisms, to
    manipulate objects in a manner that would normally be prohibited.

    Java language access control prevents use of private members outside their 
class; package access
    members outside their package; protected members outside their package or 
subclasses; and public
    members outside their module unless they are declared in an exported 
package and the user reads
    their module. By default, Java language access control is enforced (with 
one variation) when
    Fields, Methods, or Constructors are used to get or set fields, to invoke 
methods, or to create
    and initialize new instances of classes, respectively. Every reflected 
object checks that the
    code using it is in an appropriate class, package, or module.

    The one variation from Java language access control is that the checks by 
reflected objects
    assume readability. That is, the module containing the use of a reflected 
object is assumed to
    read the module in which the underlying field, method, or constructor is 
declared.

    Whether the checks for Java language access control can be suppressed (and 
thus, whether access
    can be enabled) depends on whether the reflected object corresponds to a 
member in an exported
    or open package (see setAccessible(boolean)).

    Since:
        1.2

All of a sudden it states that "access control prevents use of (...) package 
access members outside
their package (...)" by the "Java language access control", however the 
compiled Java program is
allowed to do so! I think it makes perfect sense that if a public subclass 
having package access and
returning an object that the receiver of that object is rightfully entitled to 
use its public
members available in its class and all of its superclasses. There is no risk 
that the one who has a
reference to such an object can do any harm, if using public members. (As 
package classes have
always access to their peer package classes and access to their peer's package 
members it would
probably not make sense to allow "public" in that context, if access to those 
members was not
allowed to become "public" outside of the package eventually.)

For the module system it states "(...) prevents (...) public members outside 
their module unless
they are declared in an exported package and the user reads their module". I 
think this is not
specified enough. Using the same arguments as in the above paragraph: once an 
object is handed out,
and if its class or one of its superclasses got exported, then starting with 
the exported class all
public members of that class and all of its superclasses should be accessible 
via reflection as
well. There is no risk that the one who has a reference to such an object can 
do any harm to the
module system, if being restricted of using public members starting with the 
first exported class
and then all of its superclasses as well.

---rony



On 24.01.2018 16:42, Rony G. Flatscher wrote:
> Changed the subject to hint at the "p" package example.
>
>
>
> On 24.01.2018 15:28, Alan Bateman wrote:
>> On 23/01/2018 14:52, Rony G. Flatscher wrote:
> ... cut ...
>
>  
>> I don't think the questions and observations in this thread are strictly 
>> modules related. One
>> suggestion is to start with a simpler scenario like this:
>>
>> package p;
>> class C1 {
>>     public static final int K = 99;
>>     public static int k() { return K; }
>>     public final int F = -1;
>>     public int m() { return F; }
>> }
>>
>> package p;
>> public class C2 extends C1 { }
>>
>> No modules or qualified exports in the picture for now. The important part 
>> is that C1 is not
>> public but it has public members. You can try tests to see if references to 
>> C2.K, C2.k(), new
>> C2().F, and new C2().m() will compile and run. You can try the equivalent 
>> with core reflection to
>> see how it differs to static references (you may have to change method m to 
>> be final to prevent
>> javac generating a bridge method in C2).
> OK, now add to this the following class that uses p.C2 objects to access e.g. 
> m() via it:
>
>     G:\xfer\java9modules\03-20180124-AlanBatmanP\p>type UseC2.java
>
>     public class UseC2
>     {
>         public static void main (String args[]) {
>             p.C2 o=new p.C2();
>             System.out.println("o="+o);
>             System.out.println("o.m()="+o.m());
>         }
>     }
>
> Compiling all three classes works.
>
> Running "UseC2" works and outputs:
>
>     G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2
>     o=p.C2@66048bfd
>     o.m()=-1
>
> So it is possible to access m() via the p.C2 object from UseC2.
>
> ---
>
> The modules seem to come into play when reflection or unreflect try to 
> determine whether
> accessibility should be granted or not. The current implementations 
> (mistakingly, I think) assume
> that access is only to be grantable if the package of the object to reflect 
> is exported to the
> reflector.
>
> Rather, it should check whether the reflected member is in a class with a 
> package that gets exported
> to the reflector *or* is a superclass of a class which package got exported 
> to the reflector. Or
> with other words, once a class is determined that gets exported to the 
> reflector all public members
> in all superclasses should be accessible in order to avoid "crippled Java 
> objects CJO" ;) .
>
> java.lang.reflect.* could do that check. In the case of unreflection probably 
> one should be able to
> supply an exported class to check accessibility and then only accept object 
> that are instances of at
> least that class.
>
> ---rony
>
>
>
>

Reply via email to