Skip to content

Commit 0eb937a

Browse files
committed
Document limitations of CGLIB proxy class generation in JPMS module setups
Includes extended exception messages with common hints and explanations. Closes gh-32671
1 parent 6250b64 commit 0eb937a

File tree

3 files changed

+27
-6
lines changed

3 files changed

+27
-6
lines changed

Diff for: framework-docs/modules/ROOT/pages/core/aop/proxying.adoc

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ you can do so. However, you should consider the following issues:
1919
since the CGLIB proxy instance is created through Objenesis. Only if your JVM does
2020
not allow for constructor bypassing, you might see double invocations and
2121
corresponding debug log entries from Spring's AOP support.
22+
* Your CGLIB proxy usage may face limitations with the JDK 9+ platform module system.
23+
As a typical case, you cannot create a CGLIB proxy for a class from the `java.lang`
24+
package when deploying on the module path. Such cases require a JVM bootstrap flag
25+
`--add-opens=java.base/java.lang=ALL-UNNAMED` which is not available for modules.
2226

2327
To force the use of CGLIB proxies, set the value of the `proxy-target-class` attribute
2428
of the `<aop:config>` element to true, as follows:

Diff for: spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java

+14-5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.aop.scope.ScopedProxyFactoryBean;
2929
import org.springframework.asm.Opcodes;
3030
import org.springframework.asm.Type;
31+
import org.springframework.beans.factory.BeanDefinitionStoreException;
3132
import org.springframework.beans.factory.BeanFactory;
3233
import org.springframework.beans.factory.BeanFactoryAware;
3334
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@@ -37,6 +38,7 @@
3738
import org.springframework.beans.factory.support.SimpleInstantiationStrategy;
3839
import org.springframework.cglib.core.ClassGenerator;
3940
import org.springframework.cglib.core.ClassLoaderAwareGeneratorStrategy;
41+
import org.springframework.cglib.core.CodeGenerationException;
4042
import org.springframework.cglib.core.SpringNamingPolicy;
4143
import org.springframework.cglib.proxy.Callback;
4244
import org.springframework.cglib.proxy.CallbackFilter;
@@ -106,12 +108,19 @@ public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader)
106108
}
107109
return configClass;
108110
}
109-
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
110-
if (logger.isTraceEnabled()) {
111-
logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
112-
configClass.getName(), enhancedClass.getName()));
111+
try {
112+
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
113+
if (logger.isTraceEnabled()) {
114+
logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
115+
configClass.getName(), enhancedClass.getName()));
116+
}
117+
return enhancedClass;
118+
}
119+
catch (CodeGenerationException ex) {
120+
throw new BeanDefinitionStoreException("Could not enhance configuration class [" + configClass.getName() +
121+
"]. Consider declaring @Configuration(proxyBeanMethods=false) without inter-bean references " +
122+
"between @Bean methods on the configuration class, avoiding the need for CGLIB enhancement.", ex);
113123
}
114-
return enhancedClass;
115124
}
116125

117126
/**

Diff for: spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,15 @@ public String getMessage() {
544544

545545
// No defineClass variant available at all?
546546
if (c == null) {
547-
throw new CodeGenerationException(t);
547+
throw new CodeGenerationException(t) {
548+
@Override
549+
public String getMessage() {
550+
return "No compatible defineClass mechanism detected: " +
551+
"JVM should be started with --add-opens=java.base/java.lang=ALL-UNNAMED " +
552+
"for ClassLoader.defineClass to be accessible. On the module path, " +
553+
"you may not be able to define this CGLIB-generated class at all.";
554+
}
555+
};
548556
}
549557

550558
// Force static initializers to run.

0 commit comments

Comments
 (0)