Description
Considering some scenarios raised in #22814, it seems that Boot's RestartClassLoader
is commonly the target of a newly defined proxy class there, with the original class living in the system class loader (either because of early loading or simply because it is a JDK library class). In such a scenario, we have to fall back to a ClassLoader
-specific defineClass
call - which we traditionally do through a reflective call to the protected defineClass
method, triggering an illegal access warning on JDK 9+ (and not working at all anymore with illegal access being denied, forcing us to fall back to defining the proxy class in the same class loader as the original class, i.e. the system class loader, since this is the only thing JDK 9's ´Lookup.defineClass` can do).
While we cannot generally solve the problem for arbitrary nested class loader scenarios, we can introduce a public hook for class loader implementations that we control. By extending the SmartClassLoader
interface to not only identify reloadable classes (its traditional purpose) but to also allow for flexible class definitions through a new publicDefineClass
method, Boot's RestartClassLoader
can implement it with a simple delegation to its ClassLoader-inherited protected defineClass
method:
@Override
public Class<?> publicDefineClass(String name, byte[] b, @Nullable ProtectionDomain protectionDomain) {
return defineClass(name, b, 0, b.length, protectionDomain);
}
Since we cannot detect the SmartClassLoader
interface at the CGLIB implementation level (for dependency reasons), we could instead simply detect the publicDefineClass
method by convention in CGLIB's ReflectUtils
. Any ClassLoader
implementation with such a method signature can therefore comply with that convention, without introducing a dependency on spring-core
.