Java 9 modules, does static imply shallow reflection?
Asked Answered
M

0

7

To be able to better judge the risk of reflection while porting to Java 9 I wonder if shallow reflection in place of static compilation is safe as long as it references a accessible type:

I mean, can I always replace

PublicType p = (PublicType)(Factory.instance());
p.publicMethod();

(Where Factory.instance() has return type Object and will return an subtype of the API type (Package.PublicType) from a module which is not open).

with

Object p = Factory.instance();
Class<?> c = Class.forName("package.PublicType");
Method m = c.getMethod("publicMethod", (Class[])null);
// assert p instanceof package.PublicType
m.invoke(p, (Object[])null); // throws?

Earlier versions of this question where about a specific code problem which I have resolved meanwhile.

But the general question is interesting to discuss as well: Are there cases where a returned object is of the correct subtype but fails the access checks while invoke or MethodHandle resolve.

Medor answered 10/10, 2017 at 8:48 Comment(12)
As far as I understood, this could only happen when the resolved class is different from what static resolution would resolve to. But for accessible types, Class.forName("package.PublicType") is guaranteed to resolve to the same as package.PublicType.class, i.e. identical to static resolution. So as long as package.PublicType is an accessible type, using shallow reflection through its Class object should work, regardless of whether the instance has a non-exported subtype. But I didn’t check the specification for additional pitfalls.Nainsook
@Nainsook thanks Holger, i probably will update the question ones I run some tests with the failing webstart. Maybe JNLP API does not work static at all.Medor
Yes, if you have an actual failure, posting the details, e.g. which of the three operations actually failed, would help.Nainsook
Did you re-check that using static resolution would work in the same setup?Nainsook
I think it would be good to rephrase the question, so that it covers your specific use case and put the more general question towards the end. This way we can fix a specific problem and generalize/speculate later.Overtime
I added the specific problem (which I know how to fix with —add-Exports/Open), Will provide more details once I can reproduce it.Medor
I didn't phrase that well. Your general question about "static access ~?~> shallow reflection" is valid and interesting - I didn't want to turn it into "use --add-opens". It's just hard to parse the question when some of the interesting pieces of information are hidden behind "more comments", particularly when it is not clear whether these information are relevant or not.Overtime
I just verified that the Reflection code checks the module access against the declaring class of the Method object, not the type of the instance. Therefore, your exception indicates that you did use com.sun.jnlp.BasicServiceImpl for looking up the method, rather than the exported public type, as Class.forName("javax.jnlp.BasicService").getMethod(…) can’t return Method objects with a declaring class of com.sun.jnlp.BasicServiceImpl.Nainsook
The IllegalAccessException in the question doesn't look right. Is it possible that the code is p.getClass().getMethod(...) instead? That would return the method on the implementation class in the non-exported package and would explain the IAE.Danielson
I changed the question back to the general question, I will open a question for the actual problem (which was as @AlanBateman suspected.Medor
obj.getClass().getMethod(...) is a long standing reflection anti-pattern. The implementation class is not guaranteed to be public and so IAE is possible with JDK 8 and older too.Danielson
@AlanBateman yeah thats why I missed it in the first place, I did not expect it .)Medor

© 2022 - 2024 — McMap. All rights reserved.