diff --git a/spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java b/spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java index ffa79b6dfd..f817bd9294 100644 --- a/spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java +++ b/spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java @@ -491,7 +491,10 @@ public class ReflectUtils { ProtectionDomain protectionDomain, Class contextClass) throws Exception { Class c = null; - if (contextClass != null && privateLookupInMethod != null && lookupDefineClassMethod != null) { + + // Preferred option: JDK 9+ Lookup.defineClass API if ClassLoader matches + if (contextClass != null && contextClass.getClassLoader() == loader && + privateLookupInMethod != null && lookupDefineClassMethod != null) { try { MethodHandles.Lookup lookup = (MethodHandles.Lookup) privateLookupInMethod.invoke(null, contextClass, MethodHandles.lookup()); @@ -510,29 +513,52 @@ public class ReflectUtils { throw new CodeGenerationException(ex); } } - if (protectionDomain == null) { - protectionDomain = PROTECTION_DOMAIN; - } - if (c == null) { - if (classLoaderDefineClassMethod != null) { - Object[] args = new Object[]{className, b, 0, b.length, protectionDomain}; - try { - if (!classLoaderDefineClassMethod.isAccessible()) { - classLoaderDefineClassMethod.setAccessible(true); - } - c = (Class) classLoaderDefineClassMethod.invoke(loader, args); - } - catch (InvocationTargetException ex) { - throw new CodeGenerationException(ex.getTargetException()); + + // Classic option: protected ClassLoader.defineClass method + if (c == null && classLoaderDefineClassMethod != null) { + if (protectionDomain == null) { + protectionDomain = PROTECTION_DOMAIN; + } + Object[] args = new Object[]{className, b, 0, b.length, protectionDomain}; + try { + if (!classLoaderDefineClassMethod.isAccessible()) { + classLoaderDefineClassMethod.setAccessible(true); } - catch (Throwable ex) { + c = (Class) classLoaderDefineClassMethod.invoke(loader, args); + } + catch (InvocationTargetException ex) { + throw new CodeGenerationException(ex.getTargetException()); + } + catch (Throwable ex) { + // Fall through if setAccessible fails with InaccessibleObjectException on JDK 9+ + // (on the module path and/or with a JVM bootstrapped with --illegal-access=deny) + if (!ex.getClass().getName().endsWith("InaccessibleObjectException")) { throw new CodeGenerationException(ex); } } - else { - throw new CodeGenerationException(THROWABLE); + } + + // Fallback option: JDK 9+ Lookup.defineClass API even if ClassLoader does not match + if (c == null && contextClass != null && contextClass.getClassLoader() != loader && + privateLookupInMethod != null && lookupDefineClassMethod != null) { + try { + MethodHandles.Lookup lookup = (MethodHandles.Lookup) + privateLookupInMethod.invoke(null, contextClass, MethodHandles.lookup()); + c = (Class) lookupDefineClassMethod.invoke(lookup, b); + } + catch (InvocationTargetException ex) { + throw new CodeGenerationException(ex.getTargetException()); + } + catch (Throwable ex) { + throw new CodeGenerationException(ex); } } + + // No defineClass variant available at all? + if (c == null) { + throw new CodeGenerationException(THROWABLE); + } + // Force static initializers to run. Class.forName(className, true, loader); return c;