-
CSR
-
Resolution: Unresolved
-
P4
-
None
-
None
-
behavioral
-
low
Summary
ClassLoader.definePackage
to be changed to avoid custom class loaders having to deal with IllegalArgumentExceptions
due to concurrent calls to definePackage()
(loading two classes in the same package concurrently).
Problem
Concurrent calls to definePackage()
can yield IllegalArgumentException
s if the package is already defined. Some built-in class loaders, like URLClassLoader
, already handle this case, but custom class loaders (would) all have to implement the handling of concurrent class loading.
The CDI reference implementation's default behavior (Weld) [1] and Quarkus [2] are known to run into IAEs due to concurrent calls to definePackage()
.
Solution
Change the implementation of CL.definePackage()
to only throw an IllegalArgumentException
if the given package properties are incompatible with the already existing one.
Properties to consider for the "compatible check" are those defined in Package
and its super class NamedPackage
:
specTitle
,specVersion
,specVendor
,implTitle
,implVersion
,implVendor
(via.equals()
)module
(object identity comparison)sealBase
viaPackage.isSealed()
andPackage.isSealed(URL)
The core implementation change in java.lang.ClassLoader
is to functionally replace the check around packages.putIfAbsent()
from
protected Package definePackage(String name, String specTitle,
implTitle, implVersion, implVendor,
sealBase, this);
...
Package p = new Package(name, specTitle, specVersion, specVendor,
implTitle, implVersion, implVendor,
sealBase, this);
if (packages.putIfAbsent(name, p) != null)
throw new IllegalArgumentException(name);
return p;
to
...
NamedPackage ex = packages.putIfAbsent(name, p);
if (ex == null)
return p;
// '.equals' here for simplicity for the CSR.
// Implementation to check the individual properties
// and use 'isSealed(URL)'.
if (ex.equals(p))
return (Package) ex;
throw new IllegalArgumentException(
"Incompatible redefinition of package " + name);
}
Additionally, the thrown IAE's message shall indicate the package name and a description.
The existing special handling in BuiltinClassLoader
and URLClassLoader
can be removed.
Specification
--- a/src/java.base/share/classes/java/lang/ClassLoader.java
+++ b/src/java.base/share/classes/java/lang/ClassLoader.java
@@ -2036,14 +2036,19 @@ private Package toPackage(String name, NamedPackage p, Module m) {
* respect to the given code source {@link java.net.URL URL}
* object. Otherwise, the package is not sealed.
*
- * @return The newly defined {@code Package} object
+ * @return The {@code Package} object for the given implementation
+ * and specification title/version/vendor and seal-base
+ * properties.
*
* @throws NullPointerException
* if {@code name} is {@code null}.
*
* @throws IllegalArgumentException
* if a package of the given {@code name} is already
- * defined by this class loader
+ * defined by this class loader with non-equal values for
+ * the package properties (implementation and specification
+ * version, vendor, title) or a different {@code sealBase}
+ * or module.
*
*
* @since 1.2
References
- csr of
-
JDK-8349545 ClassLoader.definePackage() throws IllegalArgumentException if package already defined
-
- Open
-