On 12/12/2016 08:56 PM, Alex Buckley wrote:
On 12/11/2016 8:16 AM, Rony G. Flatscher wrote:
On 23.11.2016 12:55, Alan Bateman wrote:
As people on this mailing list know, jake has the changes for
#AwkwardStrongEncapsulation [1]
where setAccessible has been changed so it can't be used to break
into non-public members/types in
exported packages of JDK modules. It was changed more than a year
ago to fail when attempting to
use it to break into non-exported packages. Dialing it up further is
a disruptive change that will
expose a lot of hacks and issues with existing code that is used to
accessing non-public
fields/methods in JDK classes. It will take some libraries and tools
a bit of time to digest this
change, even with the --add-opens command line option and Add-Opens
manifest in application JAR
files to keep existing code going. I plan to send mail to jdk9-dev
in advance of this integration
to create wider awareness of this change.
-Alan
[1]
http://openjdk.java.net/projects/jigsaw/spec/issues/#AwkwardStrongEncapsulation
Would #AwkwardStrongEncapsulation inhibit setAccessible to work on
protected methods (in addition to
private and package private members) as well?
As subclasses are allowed to access protected members in their
superclasses, setAccessible should
work for protected methods in classes that are invoked for objects
that are instances of their
subclasses?
The ability of protected members to be accessed from outside their
package means they are essentially public members for the purposes of
inheritance and reflection. So, setAccessible should work for
protected members of exported packages. I know what you mean about the
receiver object being of the correct class, but that's outside the
capability of setAccessible to check, so I don't believe it is checked.
Alex
That's right, currently setAccessible is allowed only within a module,
for any members of any classes in unnamed module(s), for public members
of public classes in exported packages of named module(s) and for any
members of any classes of open packages. Here's the actual code used to
check the ability to make a member setAccessible(true):
void checkCanSetAccessible(Class<?> caller, Class<?> declaringClass) {
Module callerModule = caller.getModule();
Module declaringModule = declaringClass.getModule();
if (callerModule == declaringModule) return;
if (callerModule == Object.class.getModule()) return;
if (!declaringModule.isNamed()) return;
// package is open to caller
String pn = packageName(declaringClass);
if (declaringModule.isOpen(pn, callerModule))
return;
// package is exported to caller and class/member is public
boolean isExported = declaringModule.isExported(pn, callerModule);
boolean isClassPublic =
Modifier.isPublic(declaringClass.getModifiers());
int modifiers;
if (this instanceof Executable) {
modifiers = ((Executable) this).getModifiers();
} else {
modifiers = ((Field) this).getModifiers();
}
boolean isMemberPublic = Modifier.isPublic(modifiers);
if (isExported && isClassPublic && isMemberPublic)
return;
// not accessible
String msg = "Unable to make ";
if (this instanceof Field)
msg += "field ";
msg += this + " accessible: " + declaringModule + " does not \"";
if (isClassPublic && isMemberPublic)
msg += "exports";
else
msg += "opens";
msg += " " + pn + "\" to " + callerModule;
Reflection.throwInaccessibleObjectException(msg);
}
This could be relaxed a bit for protected static fields/methods and for
protected constructors, but can't be for instance members, because there
is no target object to check against when setAccessible() is called...
Regards, Peter