Skip to content

Introduce ValidationPackageOpener to relay open directives to validation providers (JPMS package opens -> validation provider)#340

Open
marko-bekhta wants to merge 1 commit into
jakartaee:mainfrom
marko-bekhta:feat/package-opener
Open

Introduce ValidationPackageOpener to relay open directives to validation providers (JPMS package opens -> validation provider)#340
marko-bekhta wants to merge 1 commit into
jakartaee:mainfrom
marko-bekhta:feat/package-opener

Conversation

@marko-bekhta

Copy link
Copy Markdown
Member

Following the idea described in https://in.relation.to/2018/03/21/spec-api-modularity-patterns/

Asking users to open packages with their constrained classes only to the Validation API module, without specifying the provider modules, and placing that responsibility on the API/provider to share the opened packages makes the applications more portable and not tied to a specific validation provider.

The idea is that the package opener is tied to a specific validation provider, and such an opener would only work from inside the provider module -- we require a lookup tied to the provider module. Since lookups are supposed to be caller sensitive, even if the opener "leaks" to another module, it will be useless, as the other module's lookup won't match the one from the provider (to which the opener is bound).

Opening this one to discuss the idea (and potentially include it in 4.0).

cc: @yrodiere @beikov

}

@Override
public void openPackage(MethodHandles.Lookup providerLookup, Module targetModule, String packageName) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to ensure this method is only ever called from the module of the provider?

We could use StackWalker to find all the stack frames until the provider module is reached and assert that there are no stack frames from other modules, which are not reflection related. That way, we'd ensure that only the provider can call this, as an additional safety net.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to ensure this method is only ever called from the module of the provider

+1 , that definitely was the intention, yes! I thought that I got it addressed by:

		if ( !providerLookup.lookupClass().getModule().equals( providerModule ) ) {

the idea being that we pass the lookup created at a callsite opener.openPackage(MethodHandles.lookup(), ...) and as this carries the info of who called the lookup + it cannot be "faked" we get that safty net ? Or did you mean to add the stack walker as an extra check to this one?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about adding the StackWalker code as an extra safety, but it seems like your proposed solution is good enough, assuming safe usage from the provider.

@yrodiere yrodiere left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me overall, but the devil being in the details... it would be great to have the opinion of an expert such as @dmlloyd, who has been working extensively on using/hijacking the Java module system for Quarkus.
David, could you please tell us what you think of this? Of course this is outside of the context of Quarkus and I suppose native compilation will through a lot of it outside the window, but at least we'd want this to work / be safe in a generic "Java with modulepath" application.

Another question I have, but for @marko-bekhta: is the module opening transitive? I.e. once the provider got a module opened to it, can it open that module to another module (e.g. hibernate-validator opening user modules to a hypothetical hibernate-validator-extras module)?

@marko-bekhta

Copy link
Copy Markdown
Member Author

is the module opening transitive? I.e. once the provider got a module opened to it, can it open that module to another module (e.g. hibernate-validator opening user modules to a hypothetical hibernate-validator-extras module)?

yes, but one must do it "manually". At least, that's my understanding and what I've seen from my "experiments", if a package is opened to the current module, then this module can open that package to some other module. It would mean that we'd either have move package openers in our projects, or, for example, like with accessors, we could just open the package to us (HV core) and right away open that same package to the accessor lib, assuming that HV itslef won't be doing actual work and just delegate to the accessor lib, we need that inital "open" (form the package opener) to get the ability to pass it over.

Also from the javadoc (https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Module.html#addOpens(java.lang.String,java.lang.Module)):

API Note:
This method can be used for cases where a consumer module uses a qualified opens to open a package to an API module but where the reflective access to the members of classes in the consumer module is delegated to code in another module. Code in the API module can use this method to open the package in the consumer module to the other module.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants