java.lang.ClassCastException: class com.sun.proxy.$Proxy0 cannot be cast to class com.example.MyInterface (com.sun.proxy.$Proxy0 is in module java.base of loader 'app'; com.example.MyInterface is in unnamed module of loader 'app')
ID: java/classcastexception-proxy-invocationhandler
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| Java 8 | active | — | — | — |
| Java 11 | active | — | — | — |
| Java 17 | active | — | — | — |
| Spring Framework 5.3.x | active | — | — | — |
| Spring Framework 6.x | active | — | — | — |
Root Cause
This error occurs when a JDK dynamic proxy (Proxy.newProxyInstance) is created for an interface that is not visible to the proxy's class loader, typically because the interface is loaded by a different class loader or the proxy class is from a different module.
generic中文
当为代理的类加载器不可见的接口创建JDK动态代理(Proxy.newProxyInstance)时发生,通常因为接口由不同的类加载器加载或代理类来自不同模块。
Official Documentation
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/Proxy.htmlWorkarounds
-
85% success Ensure the interface is loaded by the same class loader as the proxy: `ClassLoader commonLoader = Thread.currentThread().getContextClassLoader(); MyInterface proxy = (MyInterface) Proxy.newProxyInstance(commonLoader, new Class[]{MyInterface.class}, handler);`
Ensure the interface is loaded by the same class loader as the proxy: `ClassLoader commonLoader = Thread.currentThread().getContextClassLoader(); MyInterface proxy = (MyInterface) Proxy.newProxyInstance(commonLoader, new Class[]{MyInterface.class}, handler);` -
90% success For Spring applications, configure proxy-target-class="true" to use CGLIB proxies instead of JDK dynamic proxies: `<aop:aspectj-autoproxy proxy-target-class="true"/>` or `@EnableAspectJAutoProxy(proxyTargetClass = true)`.
For Spring applications, configure proxy-target-class="true" to use CGLIB proxies instead of JDK dynamic proxies: `<aop:aspectj-autoproxy proxy-target-class="true"/>` or `@EnableAspectJAutoProxy(proxyTargetClass = true)`.
-
80% success Move the interface definition to a shared library jar that is loaded by the common class loader (e.g., the bootstrap or extension class loader) to avoid class loader isolation.
Move the interface definition to a shared library jar that is loaded by the common class loader (e.g., the bootstrap or extension class loader) to avoid class loader isolation.
中文步骤
Ensure the interface is loaded by the same class loader as the proxy: `ClassLoader commonLoader = Thread.currentThread().getContextClassLoader(); MyInterface proxy = (MyInterface) Proxy.newProxyInstance(commonLoader, new Class[]{MyInterface.class}, handler);`For Spring applications, configure proxy-target-class="true" to use CGLIB proxies instead of JDK dynamic proxies: `<aop:aspectj-autoproxy proxy-target-class="true"/>` or `@EnableAspectJAutoProxy(proxyTargetClass = true)`.
Move the interface definition to a shared library jar that is loaded by the common class loader (e.g., the bootstrap or extension class loader) to avoid class loader isolation.
Dead Ends
Common approaches that don't work:
-
Casting the proxy to the concrete class instead of the interface
95% fail
JDK dynamic proxies only implement interfaces, not concrete classes; casting to a concrete class will always fail.
-
Adding the interface to the classpath multiple times in different jars
70% fail
Multiple class loaders loading the same interface cause type identity issues; the proxy implements one version, but the cast expects another.
-
Using CGLIB proxies instead without changing the interface visibility
60% fail
CGLIB creates subclass proxies, which also require the target class to be accessible; the root cause (class loader mismatch) remains.