Re-examine ClassLoader.getPackage(s) methods
Mandy Chung
mandy.chung at oracle.com
Fri Sep 25 22:38:30 UTC 2015
In Jake, we fixed several long-standing issues about
ClassLoader::getPackage(s) and ClassLoader::definePackage method.
4302423: class loaders should support "local" creation of Package
objects
4841786: (cl) flaw in ClassLoader getPackage/definePackage API
4302406 Package sealing and creation of java.lang.Package objects is
inconsistent.
8061804: Re-examine Package of the same name allowed from
ClassLoader.getPackages
Background:
JDK 9 ClassLoader.definePackage and ClassLoader.getPackage walk the
class loader hierarchy and attempt to ensure one Package object of a
package name exists. Main problems of this design:
1. A class loader may get IAE when it attempts to define a Package while
its parent class loader or ancestor has defined the Package object of
the same package name.
2. The meta-information associated with a Package object of "p" could be
different depending on which class loader in the hierarchy and which JAR
file a class of package "p" is first defined from.
3. Package sealing not working as it is intended due to the class loader
hierarchy traversal
In Jake, ClassLoader::definePackage and ClassLoader::getPackage(s) no
longer walk the class loader hierarchy but instead, it only looks at its
local package map. Package objects maintained in a class loader are all
Packages it defined. ClassLoader::defineClass will automatically define
a Package when the package of the newly defined class is not defined.
So a Class object always has a Package associated with it (it hasn't
been the case in JDK 9 since it relies on the defining class loader to
call definePackage that cannot be enforced).
Problem: this breaks NetBeans [1]. NetBeans depends on
ClassLoader.getPackage to find the given package in the class loader
hierarchy for NB module dependency validation. Specifically NB fails to
startup since NB's ProxyClassLoader calling
ClassLoader.getPackage("com.sun.jdi") returns null and interpets it as
JDI doesn't exist which is required for NB debugger module.
One possible solution is to have NB to change to use Package.getPackage
which is not trivial since it requires a class defined by
ProxyClassLoader to invoke Package.getPackage. Another solution I
suggest NetBeans (they need to investigate) would be to replace
ClassLoader.getPackage("com.sun.jdi") by
Class.forName("com.sun.jdi.VirtualMachineManager").getPackage()
I propose to minimize the compatibility risk and revert JDK 9 behavior
of ClassLoader.getPackage(s) methods. Instead add two new methods:
ClassLoader::getDefinedPackage(String) and getDefinedPackages() to
return the defined packages by this class loader.
I considered deprecating ClassLoader::getPackage(s). These methods are
not doing anything inherently wrong or causing any risk although the
spec and impl version, title, vendor, annotation might not be th
expected value. The Package design and implementation has been flawed
since 1.2. This patch leaves it with @apiNote to make it clear.
Webrev:
http://cr.openjdk.java.net/~mchung/jigsaw/webrevs/get-package/webrev/
Specdiff against jake:
http://cr.openjdk.java.net/~mchung/jigsaw/webrevs/get-package/specdiff/overview-summary.html
Specdiff against javadoc:
http://cr.openjdk.java.net/~mchung/jigsaw/webrevs/get-package/jake-jdk9-specdiff/overview-summary.html
Thanks to Alex for the suggested text and improvement on the javadoc.
Mandy
[1] https://bugs.openjdk.java.net/browse/JDK-8136444
More information about the jigsaw-dev
mailing list