Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proxy creation improvements for JPMS, remove the need for --add-opens in some cases #25132

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

OndroMih
Copy link
Contributor

@OndroMih OndroMih commented Sep 6, 2024

Raising as a draft, because this improves only a few places. Hopefully all tests pass and we can add more improvements gradually.

In short, use JPMS compatible MethodHandles.Lookup instead of calling ClassLoader.defineClass by reflection. This approach has some limitations. We need a class to be used as a template (the generated class will have the same classloader and protection domain derived from it). And the generated class must have the same package name as the template class.

For Weld proxies, I decided to generate a class with a different name than Weld requests, because the generated class must be in the same package as the anchor class and Weld requests a different package name for the generated classes. It looks like Weld doesn't care and all worked on my sample app with EJBs.

Ideally, all methods in ClassGenerator that I marked as deprecated, will be removed and callers will be refactored to use the non-deprecated methods. The deprecated methods use reflection incompatible with JPMS, the other ones use the JPMS compatible MethodHandles. There are still a lot of places, though, where the deprecated methods are used, so it will take some time.

Yet to refactor:

  • ProxyServicesImpl.classPoolMap should be moved to a global service rather than be a static field. It must be global because ProxyServicesImpl is created for each app deployment, while the classloader where the classes are generated, is shared. So the cache needs to be preserved, otherwise we'd attempt to create a new class that already exists in the classloader.

The best way to define a class is to define using an anchor class, which defines its classloader and security policies, and is the only way to define a class in Java 9+ without --add-opens on the command line. The package name of the anchor class must be the same as the new class.

If the conditions are not met, we fall back to calling private methods on the ClassLoader to define classes. This needs --add-opens, otherwise a exception is raised.

Moved global references to the private ClassLoader methods to a separate ClassLoaderMethods class. This means that the global references will be initialized lazily only when needed, to avoid getting an exception on accessing the private methods (if not --add-opens, e.g. in GF Embedded) if they are not needed.
Weld specifies a different package name for proxies than for the original class. 
We change the name of the proxy class using Javassist to keep the original package name so that we can use the Lookup method.
We keep separate Javassist class pools for separate application classloaders, so that applications don't share them.
Discovered a flaw in the solution for ProxyServiceImpl
@OndroMih
Copy link
Contributor Author

OndroMih commented Nov 7, 2024

Hi @dmatej, @avpinchuk, @pzygielo, could you please review this and tell me whether this is a viable approach to make the code compatible with JPMS?

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.

1 participant