Spring - Classcast exception as CGLIB proxy cannot be forced
Here's the scenario that's driving me nuts.
- I have a class that has a lookup method - createOther()
- createOther should create an object of type Other. Other implements OtherInterfac开发者_开发百科e and in addition has a method doSomething that's marked @Async
- Since Other implements OtherInterface, Spring gives me a JDK proxy that I cant cast as Other.
- Spring docs suggest using
<aop:config proxy-target-class="true">
- but I'm a newbie to that and using that doesnt seem to help.
Question: how do I tell Spring that I need a CGLib proxy that targets the Other class?
Code below fails with a classcastexception.
Exception in thread "main" java.lang.ClassCastException: $Proxy4 cannot be cast to scratch.Other
at scratch.App$$EnhancerByCGLIB$$82d16307.createOther(<generated>)
at scratch.App.main(App.java:19)
App.java:
public class App {
public Other createOther() {
throw new UnsupportedOperationException();
}
public static void main(final String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
App app = (App) context.getBean("app");
Other oth = app.createOther();
oth.doSomething();
System.out.println("Other created");
}
}
** Other.java **
public interface OtherInterface {
}
class Other implements OtherInterface {
@Async
public void doSomething() {
System.out.println("did something");
}
}
** appcontext.xml **
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:config proxy-target-class="true"></aop:config>
<bean name="app" class="scratch.App">
<lookup-method bean="otherBean" name="createOther" />
</bean>
<bean name="otherBean" class="scratch.Other" scope="prototype">
</bean>
<task:executor id="workflowExecutorSvcPool" pool-size="5-50"
queue-capacity="1000" keep-alive="60" />
<task:annotation-driven executor="workflowExecutorSvcPool" />
</beans>
Everything seems fine - this is the proper way to tell spring to use cglib proxies. In fact, the documentation states that it will by default make cglib proxies. The only requirement is to have cglib on your classpath. Make sure you have the cglib jar.
The task:annotation-driven
element should support a proxy-target-class
attribute of its own that would need to be set to true for cglib proxies, for example
Other oth = app.createOther();
This line is the issue. As the object returned is actually a proxy the method createOther()
should return a OtherInterface
which the proxy will implement.
It it trying to cast the Proxy version of the OtherInterface
to the Other
class and failing.
精彩评论