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

Reply via email to