I have been trying to find an answer to this problem for days, and I hope someone can point me in the right direction. I have a SpringMVC app that uses Java Configuration and I was doing fine until I tried to integrate Apache-Shiro into it. I am able to build and run my tests. But my deploy fails because of Proxy/CGLIB issues.
Here is the exception I get on deploy/restart:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'menuRepository': Post-processing of the FactoryBean's object failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy69]: 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 com.sun.proxy.$Proxy69
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:165)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:102)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1454)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:442)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:416)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:550)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303)
... 55 more
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy69]: 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 com.sun.proxy.$Proxy69
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:217)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:111)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:477)
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:409)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1625)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:162)
... 65 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy69
at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
at org.springframework.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:285)
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:205)
... 72 more
Here is my current setup:
pom.xml
<org.springframework.version>3.2.3.RELEASE</org.springframework.version>
<shiro.version>1.2.2</shiro.version>
<org.hibernate.version>4.1.7.Final</org.hibernate.version>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.3.RELEASE</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.3.RELEASE</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>$3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.apache.shiro</groupId>-->
<!--<artifactId>shiro-aspectj</artifactId>-->
<!--<version>${shiro.version}</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${org.hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${org.hibernate.version}</version>
</dependency>
<!-- Hibernate metamodel annotation processor -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>1.1.1.Final</version>
</dependency>
...
</>
I use this web config:
public class EdmWebInitializer implements WebApplicationInitializer {
private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
private static final String DISPATCHER_SERVLET_MAPPING = "/*";
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new
AnnotationConfigWebApplicationContext();
//I have two @Configuration classes:
rootContext.register( EdmConfiguration.class, SecurityConfig.class );
// Manage the lifecycle of the root application context
servletContext.addListener( new ContextLoaderListener( rootContext ) );
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.setServletContext( servletContext );
dispatcherContext.setParent( rootContext );
// it seems I have to register the Configuration classes again or I can't @Autowire
dispatcherContext.register( EdmConfiguration.class, SecurityConfig.class );
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = servletContext.addServlet( "dispatcher", new DispatcherServlet( dispatcherContext ) );
dispatcher.setLoadOnStartup( 1 );
dispatcher.addMapping( "/" );
servletContext.addFilter( "shiroFilter", new DelegatingFilterProxy( "shiroFilter", dispatcherContext ) )
.addMappingForUrlPatterns( null, false, "/*" );
}
}
Here is my primary Configuration class:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.company.product.service", "com.company.product.utility",
"com.company.product.controller", "com.company.product.utility.startup",
"com.company.product.security", "com.company.product.repository.people" })
@EnableTransactionManagement(proxyTargetClass=false)
@ImportResource({ "classpath:applicationContext.xml" })
@PropertySource({ "classpath:application.properties", "classpath:mail.properties" })
public class EdmConfiguration extends WebMvcConfigurationSupport {
@Resource
private Environment environment;
@Autowired
private org.apache.shiro.web.mgt.WebSecurityManager securityManager;
@Bean
public DataSource dataSource() {
BoneCPDataSource dataSource = new BoneCPDataSource();
dataSource.setDriverClass( environment.getRequiredProperty( PROPERTY_NAME_DATABASE_DRIVER ) );
dataSource.setJdbcUrl( environment.getRequiredProperty( PROPERTY_NAME_DATABASE_URL ) );
dataSource.setUsername( environment.getRequiredProperty( PROPERTY_NAME_DATABASE_USERNAME ) );
dataSource.setPassword( environment.getRequiredProperty( PROPERTY_NAME_DATABASE_PASSWORD ) );
return dataSource;
}
@Bean
public JpaTransactionManager transactionManager() throws ClassNotFoundException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory( entityManagerFactoryBean().getObject() );
return transactionManager;
}
@Bean
public DelegatingFilterProxy springSecurityFilterChain() {
return new DelegatingFilterProxy();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() throws ClassNotFoundException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource( dataSource() );
entityManagerFactoryBean.setPackagesToScan( environment
.getRequiredProperty( PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN ) );
entityManagerFactoryBean.setPersistenceProviderClass( HibernatePersistence.class );
Properties jpaProperties = new Properties();
...
entityManagerFactoryBean.setJpaProperties( jpaProperties );
return entityManagerFactoryBean;
}
@Bean
public PersistenceExceptionTranslator exTranslator() {
return new HibernateExceptionTranslator();
}
@Bean(initMethod = "init")
public StartupListener startupListener() {
return new StartupListener();
}
@Bean
public StandardPasswordEncoder encoder() {
return new org.springframework.security.crypto.password.StandardPasswordEncoder();
}
@Bean
public ShiroFilterFactoryBean shiroFilter() {
ShiroFilterFactoryBean shiroFilter = new org.apache.shiro.spring.web.ShiroFilterFactoryBean();
shiroFilter.setSecurityManager( securityManager);
shiroFilter.setLoginUrl( "/login" );
shiroFilter.setUnauthorizedUrl( "/" );
return shiroFilter;
}
@Bean
@DependsOn(value = "lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
}
And here is the other Configuration class. It is the addition of this that causes the proxy issues.
@Configuration
public class SecurityConfig {
@Bean
public SaltAwareJdbcRealm saltAwareJdbcRealm() {
return new SaltAwareJdbcRealm();
}
@Bean
public WebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm( saltAwareJdbcRealm() );
return securityManager;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setStaticMethod( "org.apache.shiro.SecurityUtils.setSecurityManager" );
methodInvokingFactoryBean.setArguments( new Object[]{ securityManager() } );
return methodInvokingFactoryBean;
}
@Bean
@DependsOn(value = "lifecycleBeanPostProcessor")
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authori
zationAttributeSourceAdvisor.setSecurityManager( securityManager() );
return authorizationAttributeSourceAdvisor;
}
}
the offending class is just a spring jparepository:
public interface MenuRepository extends CrudRepository<Menu, Long>, JpaSpecificationExecutor<Menu> {
...}
I have added the @EnableTransactionManagement(proxyTargetClass=false) which I thought would address the Proxy issue but apparently isn't.
Thank you for your time in reading all this.