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