Alternative mechanism for reflective access control (#ReflectiveAccessToNonExportedTypes / #AwkwardStrongEncapsulation)
Sanne Grinovero
sanne at redhat.com
Wed Sep 28 14:11:29 UTC 2016
On Wed, Sep 28, 2016 at 1:01 PM, Alan Bateman <Alan.Bateman at oracle.com> wrote:
> On 28/09/2016 10:37, Gunnar Morling wrote:
>
>> :
>>
>> I don't think that is what those folks asking about using the SM had in
>> mind.
>>
>> Rather, the idea would be - IIUC - to grant code in module B (say an ORM
>> tool) reflective access to non-exported (and of course exported) types in
>> module A (say a module with entities) by default. If needed, the code in B
>> would then use setAccessible() for making private members in A accessible
>> before invoking them, allowing it to obtain the entity state. This is where
>> the SM is part of the picture: if in a given environment the user wants to
>> restrict who may call setAccessible(), they could use the SM for it, with a
>> fine grained policy, e.g. allowing the call only to the ORM module.
>>
>> I.e. ReflectiveAccessToNonExportedTypes would be granted by default, only
>> if an SM is enabled at runtime, actions to suppress accessibility checks
>> would be subject to the current security policy.
>>
>> This is not to say that I'm behind this idea, I just felt it hasn't been
>> discussed in the way it may have been meant.
>>
>> I can see though how JDK devs and library authors want to prevent access
>> to private code in their modules at all, hence relying on the SM to be
>> enabled at runtime is not an option to address that requirement.
>
>
> The original question mentioned "reflective access" and we've said, has
> always been specified to do the same access checks as the Java Language and
> VM.
>
> On setAccessible, then it wouldn't be hard to have setAccessible implement
> fine grain permission checks but not clear how useful this is given that the
> SM is opt-in and not widely used. Having setAccessible ignore module
> boundaries (assume no SM) goes against the goal of strong encapsulation and
> of course makes #AwkwardStrongEncapsulation a lot worse.
>
> In general then I think that we need to find ways to reduce the use of
> setAccessible over time. We really need a long term plan to degrade,
> deprecate and eventually remove it. This would of course mean working on
> some challenging problems and use-cases.
>
> So what would the alternative to setAccessible be? It would be nice if the
> framework libraries (you mention ORM tools and maybe the Hibernate ORM devs
> could be the guinea pig) would start to make use of the "new reflection API"
> that is java.lang.invoke. So rather than bypassing access checks with legacy
> core reflection then they would instead use MH.Lookup objects as
> capabilities. Think code in a consumer module creating a Lookup object with
> the appropriate lookup class + mode that it cooperatively hands to the
> framework. This puts the access check in the consumer module so that the
> frameworks don't need to break in. This direction isn't without challenges
> of course as there may be initialization issues to deal with. It might, for
> example, involve injecting helper code into a submissive consumer module
> when there isn't explicit initialization. John Rose has good write-ups in
> JIRA with ideas in this area.
As an "Hibernate dev" I'd be happy to help, but please bear in mind
that Hibernate is not used only within the scope of a container.
Hibernate is included - among others - in WildFly (an EE server) which
is why we have some good experience with David Lloyd's modular system,
it's also run in OSGi environments, but lots of users expect to use
JPA in the following "Java SE style" way:
EntityManagerFactory emf = Persistence.createEntityManagerFactory(
"some-name-matching-the-configuration" );
and then people use the `emf` directly, without ever bothering with
classloaders, modules or deployment units.
Most users probably never use the ClassLoader API and would be a bit
scared about even discussing touching it.
In the case of OSGi one might have helpers such as Service management,
in the case of Java EE containers the EntityManagerFactory is
created/managed by the container and injected as requested, but it is
essential for JavaSE users to have such a one-liner simple boot
process.
In a modular world, the EntityManagerFactory API (the JPA interfaces)
would be visible to the users code at compile time and runtime, while
our implementations are usually not visible - although it is also
quite common for people to want to access specific Hibernate features
which are not standardized; obviously this implies it's also quite
common for people to want to have visibility on the implementation and
I'd hope this could be made available to them at minimal complexity.
To not break user experience, tons of legacy code (not least tons of
university literature!) it is essential that the implementor of the
JPA API can access the domain model (the user code) without the user
having to explicitly export it. This process is called "auto
discovery" as in most common use cases the
`createEntityManagerFactory` method will have access to a simple
configuration resource, but is not pointed to a specific class or
module and is expected to find the classes automatically - usually
from the same classloader which invoked it (but not necessarily, for
example in container managed environments the rules vary).
Often such models are generated by (graphical) modelling tools, so
tools could help when generating the user domain model to also
generate some marker files, or otherwise setup the project to generate
the right flags at compile / packaging time, but how that could work
is unclear now and would certainly take a lot of time for tooling to
catch up.
So we'd love that people could still boot such frameworks without
needing to deal with modules explicitly; I think the strongest reason
is that this wasn't the case so far and so it is expected for existing
apps to still work; another reason is that while we (library
implementors) love the benefits of modularity, most users would rather
get the benefits indirectly without having to learn about it: they
certainly don't want to need adding new flags, marker annotations,
etc..
I like David's idea that by declaring a dependency on a module (say I
need "javax.persistence") that automatically allows all forms of
visibility to persistence providers; it's good as there is minimal
redundancy in the user's declaration, and the user module wouldn't
even compile without it.
Thanks,
Sanne
>
> -Alan.
>
More information about the jigsaw-dev
mailing list