I have a Spring web application which is configured to use JDK proxying for AOP. The AOP annotations (such as #Transactional) are declared on the interfaces, rather than the implementation classes.
The application itself works fine, but when I run the unit tests, it seems to be attempting to use CGLIB for the AOP functionality (instead of JDK proxying). This causes the tests to fail - I've appended the stack trace below.
I don't understand why CGLIB is being used when I run the tests, because the Spring configuration is largely the same as when the application is running. One possibly significant difference is that the test configuration uses a DataSourceTransactionManager instead of a JTA transaction manager. The test classes themselves all extend AbstractJUnit4SpringContextTests, could it be that this class is somehow hard-wired to use CGLIB?
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class $Proxy25]: 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 $Proxy25
at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:213)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:488)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:363)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:324)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:361)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1343)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
... 79 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy25
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:201)
... 86 more
EDIT: One of the commentators requested that I post the Spring configuration. I've included it below in abbreviated form (i.e. irrelevant beans and XML namespaces omitted).
spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- ANNOTATION SUPPORT -->
<!-- Include basic annotation support -->
<context:annotation-config/>
<!-- CONTROLLERS -->
<!-- Controllers, force scanning -->
<context:component-scan base-package="com.onebigplanet.web.controller,com.onebigplanet.web.ws.*"/>
<!-- Post-processor for #Aspect annotated beans, which converts them into AOP advice -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator">
<property name="proxyTargetClass" value="true"/>
</bean>
<!-- An #Aspect bean that converts exceptions thrown in POJO service implementation classes to runtime exceptions -->
<bean id="permissionAdvisor" class="com.onebigplanet.web.advisor.PermissionAdvisor"/>
<bean id="businessIntelligenceAdvisor" class="com.onebigplanet.web.advisor.bi.BusinessIntelligenceAdvisor"/>
<!-- Finds the controllers and sets an interceptor on each one -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<bean class="com.onebigplanet.web.interceptor.PortalInterceptor"/>
</list>
</property>
</bean>
<!-- METHOD HANDLER ADAPTER -->
<!-- Finds mapping of url through annotation on methods of Controller -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="cacheSeconds" value="0"/>
<property name="webBindingInitializer">
<bean class="com.onebigplanet.web.binder.WebBindingInitializer"/>
</property>
</bean>
</beans>
applicationContext-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- Declares a bunch of bean post-processors -->
<context:annotation-config/>
<context:component-scan base-package="com.onebigplanet.service.impl,com.onebigplanet.dao.impl.mysql" annotation-config="false"/>
<!-- Property configurer -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/WEB-INF/obp-service.properties" />
</bean>
<!-- Post-processor for #Aspect annotated beans, which converts them into AOP advice -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
<!-- An #Aspect bean that converts exceptions thrown in service implementation classes to runtime exceptions -->
<bean id="exceptionAdvisor" class="com.onebigplanet.service.advisor.ExceptionAdvisor"/>
<bean id="cachingAdvisor" class="com.onebigplanet.service.advisor.CacheAdvisor"/>
<bean id="businessIntelligenceAffiliateAdvisor" class="com.onebigplanet.service.advisor.BusinessIntelligenceAffiliateAdvisor"/>
<!-- Writable datasource -->
<jee:jndi-lookup id="dataSource" jndi-name="java:/ObpDS"/>
<!-- ReadOnly datasource -->
<jee:jndi-lookup id="readOnlyDataSource" jndi-name="java:/ObpReadOnlyDS"/>
<!-- Map the transaction manager to allow easy lookup of a UserTransaction -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
<!-- Annotation driven transaction management -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
applicationContext-test.xml This is only included when running the unit tests. It's purpose is to overwrite some of the beans declared in the other config files.
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- Overwrite the property configurer bean such that it reads the test properties file instead -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/obp-test.properties"/>
</bean>
<!-- All DAOs should use the test datasource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${testDataSource.driverClassName}"/>
<property name="url" value="${testDataSource.url}"/>
<property name="username" value="${testDataSource.username}"/>
<property name="password" value="${testDataSource.password}"/>
</bean>
<bean id="readOnlyDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${testDataSource.driverClassName}"/>
<property name="url" value="${testDataSource.url}"/>
<property name="username" value="${testDataSource.username}"/>
<property name="password" value="${testDataSource.password}"/>
</bean>
<!--
Overwrite the JTA transaction manager bean defined in applicationContent-service.xml with this one because
the implementation of the former is provided by JBoss
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<beans>
Sounds like you're referencing an implementation class instead of an interface. There is an excerpt here with more detail.
A Spring forum post: "Mixing JDK and CGLIB proxies"
A great blog post explaining pros and cons of JDK vs. CGLIB proxies.
Hey Jean, CGLib proxies are created by subclassing the class to be proxied -- you're attempting to proxy another proxy which isn't allowed since proxies are themselves final classes. Hence:
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy25
I don't know if the solution was already shared and I am also sure the original requester must have found a solution, since it is a one year old query. For public interest however let me mention it here. Spring was using CGLIB because of the following declaration.
<!-- Post-processor for #Aspect annotated beans, which converts them into AOP advice -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator">
<property name="proxyTargetClass" value="true"/>
</bean>
The property should be set to false, so that the CGLIB is not triggered instead JDK Dynamic Proxying.
<property name="proxyTargetClass" value="false"/>
Hope that helps.
Related
I am pretty new in Spring and I have a little doubt related the concept of namespace into my XML configuration files.
So for example into the root-context.xml file of a project on which I am working on there is this definition:
<jee:jndi-lookup jndi-name="java:jboss/datasources/myDbDS" id="datasource" expected-type="javax.sql.DataSource" />
that have the jee namepace that is also specified into the beans external container by:
xmlns:jee="http://www.springframework.org/schema/jee"
Now my doubt is, what exactly is this definition having id="datasource"? This one:
<jee:jndi-lookup jndi-name="java:jboss/datasources/myDbDS" id="datasource" expected-type="javax.sql.DataSource" />
Is it a classic bean of Spring having a specific namespace because it belong to a specific domain of bean (having a specific pourpose) or what?
As Explained in the spring doc:
The jee tags deal with Java EE (Java Enterprise Edition)-related
configuration issues, such as looking up a JNDI object and defining
EJB references
Here after an example from spring doc:
Without using jee jndi-lookup
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/MyDataSource"/>
</bean>
<bean id="userDao" class="com.foo.JdbcUserDao">
<!-- Spring will do the cast automatically (as usual) -->
<property name="dataSource" ref="dataSource"/>
</bean>
Using jee jndi-lookup
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource"/>
<bean id="userDao" class="com.foo.JdbcUserDao">
<!-- Spring will do the cast automatically (as usual) -->
<property name="dataSource" ref="dataSource"/>
</bean>
More details here
I had an existing spring application say App1 (not used spring annotation). Currently I am integrating some beans of this into another application say App2 which uses spring annotations for configuration.So I forced to use 'p' namespace for newly added beans. But after that the integrated application wont work.
This was my bean declaration in App1:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml" />
<property name="persistenceUnitName" value="org.jbpm.runtime"></property>
This is the same in App2 which caused issue:
<bean id="vendor"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:jpaVendorAdapter="vendor"
p:persistenceXmlLocation="classpath*:META-INF/persistence.xml"
p:persistenceUnitName="org.jbpm.runtime">
Is there anything wrong with this declaration?(both applications are spring 3.2)
Or is it must to use p namespace in annotation driven configurations.?
There is nothing wrong with this declaration if you didnt forget to declare xmlns:p="http://www.springframework.org/schema/p" in beans element
I am playing around with a Spring MVC + Hibernate + MySQL "Hello World" app, and am currently trying run the following integration test on a Spring MVC controller using jUnit.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"file:src/main/webapp/WEB-INF/springapp-servlet.xml"})
public class InventoryControllerIT
{
#Autowired
private InventoryController controller;
#Test
public void handleRequest_anyRequest_returnsSuccessfully() throws Exception
{
ModelAndView modelAndView = this.controller.handleRequest(null, null);
}
}
However, every time I do so I get the following exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [springapp.web.InventoryController] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
Previously I hadn't implemented any real data access and the test passed fine, but now that I have added a Hibernate implementation of my DAO along with spring transaction management I get this error. Here are the relevant parts of my applet context configuration 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:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean name="/hello.htm" class="springapp.web.InventoryController">
<property name="productManager" ref="productManager" />
<property name="productDao" ref="productDao" />
<property name="sessionFactory" ref="sessionFactory" />
</bean>
...
<!-- Hibernate -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="mappingJarLocations">
<list>
<value>WEB-INF/lib/springapp-dataaccess*.jar</value>
</list>
</property>
</bean>
<bean id="productDao" class="springapp.dataaccess.dao.ProductHibernateDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
</beans>
If I remove the <tx:annotation-driven /> from the config then the above exception does not occur, but then the test fails because the data access call that occurs in the handler no longer has an open transaction. The app runs just fine outside of the test. Anyone have any ideas as to what the issue is?
When InventoryController implements any interfaces Spring by default applies transactional aspect to it using interface-based proxy. Such a proxy implements interfaces of InventoryController, but it's not a subclass of InventoryController, therefore it cannot be injected into a field of type InventoryController.
You either need to use interface as a type of the field to be autowired, or configure Spring to apply target-class-based proxy instead.
See also:
7.6 Proxying mechanisms
I had a similar issues while running the unit tests of a small library I was building.
replace your :
<tx:annotation-driven />
with
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
Note that on my project I also had to add the following dependency (maven project) for the unit tests:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
<scope>test</scope>
</dependency>
Best regards.
I have some legacy Spring MVC code mixed with gwt code in same artifact (built using maven) and I cannot make it run. It wants validation provider at runtime which i do not need (since I'm not using any JSR-303 validation annotations) and do not want in CP (it may conflict with some app containers this artifact will be deployed in)
How to force spring not to do any JSR-303 validations and get rid of runtime dependency on validation provider?
PS artifact has validation-api in CP since GWT is using it somehow
PPS
Seems like removing <mvc:annotation-driven/> from Spring config fixes this.
Binding and classic validations still works (I have <context:annotation-config/> enabled)
As you already discovered, <mvc:annotation-driven/> sets a lot of features including JSR-303. The equivalent is
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="0" />
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="validator" ref="validator" />
</bean>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean id="conversion-service"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
So you may substitute the tag onto this xml configuration and remove parts you don't need.
In web.xml I have the following:
<servlet>
<description>JAX-WS endpoint - EARM</description>
<display-name>jaxws-servlet</display-name>
<servlet-name>jaxws-servlet</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSSpringServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jaxws-servlet</servlet-name>
<url-pattern>/webServices/*</url-pattern>
</servlet-mapping>
In my application context I have the following definitions:
<bean id="helloService" class="com.foo.HelloServiceImpl">
<property name="regularService" ref="regularService" />
</bean>
<wss:binding url="/webServices/helloService" service="#helloService" />
I get a NullPointerException when trying to access the WSDL:
java.lang.NullPointerException
at com.sun.xml.ws.transport.http.HttpAdapter.<init>(HttpAdapter.java:145)
at com.sun.xml.ws.transport.http.servlet.ServletAdapter.<init>(ServletAdapter.java:76)
at com.sun.xml.ws.transport.http.servlet.ServletAdapterList.createHttpAdapter(ServletAdapterList.java:5 0)
at com.sun.xml.ws.transport.http.servlet.ServletAdapterList.createHttpAdapter(ServletAdapterList.java:4 7)
at com.sun.xml.ws.transport.http.HttpAdapterList.createAdapter(HttpAdapterList.java:73)
at com.sun.xml.ws.transport.http.servlet.SpringBinding.create(SpringBinding.java:24)
at com.sun.xml.ws.transport.http.servlet.WSSpringServlet.init(WSSpringServlet.java:46)
Strange ... appears to be a configuration error but the darn thing just dies with a NullPointerException!!!!!!!! No logging is provided.
Deployed in Resin.
UPDATE: I finally figured out the real answer to this problem and posted
it here:
http://forum.springsource.org/showthread.php?p=286701
In short, Resin 3x ships with an
XSD-unaware parser and you have to
replace it with Apache Xerces or some
other parser (see above forum post).
=========================
The following bean definitions get the Spring JAX-WS working (without using the "stupid" xbean / namespace magic). To come by this, I had to read the source and figure out the correct classes to use - sometimes by intentionally providing a property value that I knew would cause an exception (such as an invalid Class - this allowed me to see the stack trace which lead back to the bean class).
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="webServiceMethodInterceptor"
class="com.webservice.util.interceptors.WebServiceMethodInterceptor">
<property name="userId" value="hello" />
<property name="password" value="world" />
<property name="roles" value="ROLE_ANONYMOUS,ROLE_MICKEY_MOUSE" />
</bean>
<bean id="webServiceLoggingInterceptor"
class="com.webservice.util.interceptors.LoggingInterceptor">
<property name="level" value="debug" />
</bean>
<bean id="webServiceExceptionTranslator"
class="com.webservice.util.interceptors.WebServiceExceptionTranslator"/>
<!-- The list of interceptors to apply to all web methods -->
<bean id="webServiceInterceptors" class="java.util.LinkedList">
<constructor-arg index="0">
<list>
<value>webServiceExceptionTranslator</value>
<value>webServiceLoggingInterceptor</value>
<value>webServiceMethodInterceptor</value>
</list>
</constructor-arg>
</bean>
<!-- Proxied ExampleWebService -->
<bean id="exampleWebService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<bean class="com.webservice.ExampleWebServiceImpl">
<!-- TODO: add dependencies for web service here, for example:
<property name="someService" ref="someService" />
-->
</bean>
</property>
<property name="interceptorNames" ref="webServiceInterceptors" />
<property name="proxyTargetClass" value="true" />
</bean>
<!-- JAX-WS Endpoint for ExampleWebService -->
<bean class="com.sun.xml.ws.transport.http.servlet.SpringBinding">
<property name="url" value="/webServices/exampleService" />
<property name="service">
<bean class="org.jvnet.jax_ws_commons.spring.SpringService">
<property name="bean">
<ref local="exampleWebService" />
</property>
<property name="impl"
value="com.webservice.ExampleWebServiceImpl" />
</bean>
</property>
</bean>
Everything else is as in the tutorial linked to above (you add the JAX-WS Spring servlet in web.xml, add the servlet filter so that web service requests get routed to the jaxws servlet).
The key to using the proxied web service instance (thus enabling dependency injection, AOP, etc.) was setting proxyTargetClass="true" to force a CGLIB proxy instead of a JDK dynamic proxy (which requires an interface). JAX-WS seems to not like interfaces for some reason.
I hope this helps some one!
Regards,
LES
LES2: Your implementation seem most complex.
What's wrong with simple usage of SpringBeanAutowiringSupport, as described in Spring manual