-
Thanks all, just to answer Amol, we do not actually want to implement Cloneable it was just an example to try with the simple project posted on the forum.
One of my team mates has been trying a few things and this is what was found:
Providing the method name in the transformer config does not work but providing my own Transformer interface or adding <aop:config proxy-target-class="true"/> does.
We have got it working with the <aop:config proxy-target-class="true"/> approach however it seems if we have one of our JPA repository interfaces with any method that is @Transactional we get the exception below, we do not actually need to make this method @Transactional but would be interested to know for future how to resolve this.
Code:
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class $Proxy132]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy132
at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:212)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:112)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:476)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:362)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:322)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:407)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1563)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:162)
... 38 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy132
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
at net.sf.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:200)
... 45 more
-
CGLIB creates a proxy by subclassing the class and overriding all the methods. If a class is marked 'private' then it can't be subclassed (as the exception states). It also can't override final methods.
I prefer the first solution (adding an interface to your transformer). This is generally considered good practice anyway (coding to interfaces), and it avoids these issues with forcing CGLIB proxying.
-
I agree programming to interfaces is a better solution so will probably just go with this if we need to but we do not have a final or private class so I guess it’s the proxies generated by JPA are the problem.
If you change the simple example posted by Amol to introduce a gateway like this you will also get the same exception. I guess any generated proxy has to be final?
Code:
<integration:service-activator input-channel="spiltterOutputChannel" output-channel="outputChannel" ref="transform.tx" method="transform"/>
<integration:gateway id="transform.tx" default-request-channel="transformChannel" service-interface="simple.Transformer" />
<bean id="transformer" class="com.nomura.spb.services.valuationservice.TransformerBean"/>
<integration:transformer input-channel="transformChannel" ref="transformer"/>
public interface Transformer {
@Transactional
public String transform(String payload);
}