Multiple View Resolvers not working with thymeleaf - spring-mvc

When I use the following configuration of Thymeleaf for views as well as sending custom emails, it is not working
#Configuration
public class ThymeleafConfig {
#Bean
public ITemplateResolver classLoaderTemplateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("/templates/");
templateResolver.setCacheable(false);
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(StandardTemplateModeHandlers.LEGACYHTML5.getTemplateModeName());
templateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return templateResolver;
}
#Bean
public ITemplateResolver webTemplateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/public/");
resolver.setSuffix(".html");
resolver.setTemplateMode(StandardTemplateModeHandlers.LEGACYHTML5.getTemplateModeName());
resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
resolver.setCacheable(false);
return resolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(webTemplateResolver());
templateEngine.addTemplateResolver(classLoaderTemplateResolver());
return templateEngine;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return resolver;
}
}
View Resolution is working fine. But when I try to resolve a template by passing org.thymeleaf.context.Context to the template engine, following exception is thrown.
2017-10-06 13:36:27.962 ERROR 79725 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine : [THYMELEAF][http-nio-8080-exec-1] Exception processing template "resultPdf": Resource resolution by ServletContext with org.thymeleaf.resourceresolver.ServletContextResourceResolver can only be performed when context implements org.thymeleaf.context.IWebContext [current context: org.thymeleaf.context.Context]
org.thymeleaf.exceptions.TemplateProcessingException: Resource resolution by ServletContext with org.thymeleaf.resourceresolver.ServletContextResourceResolver can only be performed when context implements org.thymeleaf.context.IWebContext [current context: org.thymeleaf.context.Context]
at org.thymeleaf.resourceresolver.ServletContextResourceResolver.getResourceAsStream(ServletContextResourceResolver.java:78) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateRepository.getTemplate(TemplateRepository.java:221) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1104) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1060) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1011) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:924) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:898) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
Now since I have configured multiple template resolvers, the resolution should move on to the second one and IWebContext should not be required.
So what shuold be the correct configuration for viee resolution as well as mail sending templates?
EDIT:
I am using spring-boot-starter-thymeleaf with spring boot 1.4.0

Related

Thymeleaf View Resolver with SpringMVC webapp

How if one can use ThymeleafViewResolver as a defalt view resolver.
Currentely my WebMvcConfig looks like this
#Configuration
#ComponentScan(basePackages="com.greatLearning.ticketAPI.controller")
public class WebMvcConfig implements WebMvcConfigurer {
#Autowired
ApplicationContext applicationContext;
// #Override
// public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
// configurer.enable();
// }
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
//Thymeleaf ViewResolver
#Bean
public SpringResourceTemplateResolver templateResolver(){
// SpringResourceTemplateResolver automatically integrates with Spring's own
// resource resolution infrastructure, which is highly recommended.
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(this.applicationContext);
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
// HTML is the default value, added here for the sake of clarity.
templateResolver.setTemplateMode(TemplateMode.HTML);
// Template cache is true by default. Set to false if you want
// templates to be automatically updated when modified.
templateResolver.setCacheable(true);
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine(){
// SpringTemplateEngine automatically applies SpringStandardDialect and
// enables Spring's own MessageSource message resolution mechanisms.
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
// Enabling the SpringEL compiler with Spring 4.2.4 or newer can
// speed up execution in most scenarios, but might be incompatible
// with specific cases when expressions in one template are reused
// across different data types, so this flag is "false" by default
// for safer backwards compatibility.
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
#Bean
public ThymeleafViewResolver viewResolver(){
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
// NOTE 'order' and 'viewNames' are optional
viewResolver.setOrder(1);
viewResolver.setViewNames(new String[] {".html", ".xhtml"});
return viewResolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
for *.jsp view it is working just fine, but I want to use Thymeleaf to resolve my .html templates becasue I don't want to use *.jsp .
One thing to note is that in my controller
TestController.java
#RequestMapping("/hello")
public String method1() {
return "hello";
}
#RequestMapping("/hello2")
#ResponseBody
public String method2() {
return "hello"; //This works fine
}
when I hit /hello api this is what I get
How do I configre viewResolver so that spring picks up ThymeleafViewResolver to resolve html rather than jsp
Problem Solved!!!!!
Here is what I did after an hour of debugging the libraries
in WebMvcConfig.java I revomed the public InternalResourceViewResolver resolver() method as it is sed to configure jsp.
Now in ThymeleafViewResolver viewResolver() remove these two:
viewResolver.setOrder(1);
viewResolver.setViewNames(new String[] {".html", ".xhtml"});
got help through debgging and [this post](Problem Solved!!!!!
Here is what I did after an hour of debugging the libraries
in WebMvcConfig.java I revomed the public InternalResourceViewResolver resolver() method as it is sed to configure jsp.
Now in ThymeleafViewResolver viewResolver() remove these two:
viewResolver.setOrder(1);
viewResolver.setViewNames(new String[] {".html", ".xhtml"});
got help through debgging and this post.
As to why I will answer if anyone is interested. :)

addResourceHandler #EnableWebMvc setup

My handler was working prior to some dependency updates and ditching of the XML in my app. But now I get this error
org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping for GET /resources/img/logo.png
My view resolver is working fine, my controller is pointing to the right places it is just my css/js that doesn't seem to map.
public class ConfigClass {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
WebMvcConfigurationSupport appears to be essential.
public class ConfigClass extends WebMvcConfigurationSupport{
//Rest here
}
EDIT
The initial answer was based on an amateur "cached" answer. The actual solution was using
public class ConfigClass extends WebMvcConfigurerAdapter {
However, this is now deprecated. Am looking into an answer for that.

Spring Boot adding thymeleaf-layout-dialect

I am using spring boot (v1.5.3.BUILD-SNAPSHOT)
I am new to spring boot.
Using gradle
Note that the normal thymeleaf dialect works fine (th:...)
spring-boot-starter-thymeleaf\1.5.3.BUILD-SNAPSHOT
I want to add thymeleaf-layout-dialect
I added the dependency
compile('nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect')
the documentation says to add the dialect by doing the following
TemplateEngine templateEngine = new TemplateEngine(); // Or
SpringTemplateEngine for Spring config
templateEngine.addDialect(new LayoutDialect());
So i added a configuration class
#Configuration
public class MyConfiguration {
#Bean
public SpringTemplateEngine templateEngine(){
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addDialect(new LayoutDialect());
return templateEngine;
}
}
but when I try running the app I get the following error
org.thymeleaf.exceptions.ConfigurationException: Cannot initialize: no template resolvers have been set
at org.thymeleaf.Configuration.initialize(Configuration.java:203) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateEngine.initialize(TemplateEngine.java:827) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.spring4.view.ThymeleafView.renderFragment(ThymeleafView.java:203) ~[thymeleaf-spring4-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.spring4.view.ThymeleafView.render(ThymeleafView.java:190) ~[thymeleaf-spring4-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1282) ~[spring-webmvc-4.3.8.BUILD-SNAPSHOT.jar:4.3.8.BUILD-SNAPSHOT]
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037) ~[spring-webmvc-4.3.8.BUILD-SNAPSHOT.jar:4.3.8.BUILD-SNAPSHOT]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) ~[spring-webmvc-4.3.8.BUILD-SNAPSHOT.jar:4.3.8.BUILD-SNAPSHOT]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) ~[spring-webmvc-4.3.8.BUILD-SNAPSHOT.jar:4.3.8.BUILD-SNAPSHOT]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.8.BUILD-SNAPSHOT.jar:4.3.8.BUILD-SNAPSHOT]
Can someone tell me how to add the thymeleaf-layout-dialect correctly?
The issue is:
org.thymeleaf.exceptions.ConfigurationException: Cannot initialize: no template resolvers have been set
To integrate Thymeleaf with Spring, you need to configure 3 beans:
ThymeleafViewResolver Bean - You would be set it with a template engine
SpringTemplateEngine Bean - You would be set it with a template resolver
TemplateResolver Bean
In your templateEngine bean you didn't set any template resolver, so you might change your templateEngine() method as following:
#Bean
public SpringTemplateEngine templateEngine(TemplateResolver templateResolver){
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
templateEngine.addDialect(new LayoutDialect());
return templateEngine;
}
Spring will provide you with a templateResolver bean of SpringTemplateEngine.
BTW If you define spring-boot-starter-thymeleaf as dependency, it will provide thymeleaf-layout-dialect as a dependency with the convenient version, then Spring will use ThymeleafAutoConfiguration.java - Spring Boot 1.5.x to configure a default beans for the three required beans.
For example:
LayoutDialect bean is define here ThymeleafWebLayoutConfiguration.ThymeleafWebLayoutConfiguration():
#Configuration
#ConditionalOnClass(name = "nz.net.ultraq.thymeleaf.LayoutDialect")
protected static class ThymeleafWebLayoutConfiguration {
#Bean
#ConditionalOnMissingBean
public LayoutDialect layoutDialect() {
return new LayoutDialect();
}
}
SpringTemplateEngine bean is defined with a template resolver and dialect from here ThymeleafWebLayoutConfiguration.ThymeleafDefaultConfiguration():
#Configuration
#ConditionalOnMissingBean(SpringTemplateEngine.class)
protected static class ThymeleafDefaultConfiguration {
private final Collection<ITemplateResolver> templateResolvers;
private final Collection<IDialect> dialects;
public ThymeleafDefaultConfiguration(
Collection<ITemplateResolver> templateResolvers,
ObjectProvider<Collection<IDialect>> dialectsProvider) {
this.templateResolvers = templateResolvers;
this.dialects = dialectsProvider.getIfAvailable();
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
for (ITemplateResolver templateResolver : this.templateResolvers) {
engine.addTemplateResolver(templateResolver);
}
if (!CollectionUtils.isEmpty(this.dialects)) {
for (IDialect dialect : this.dialects) {
engine.addDialect(dialect);
}
}
return engine;
}
}
And finally a thymeleafViewResolver bean is defined here AbstractThymeleafViewResolverConfiguration.thymeleafViewResolver():
#Bean
#ConditionalOnMissingBean(name = "thymeleafViewResolver")
#ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
configureTemplateEngine(resolver, this.templateEngine);
resolver.setCharacterEncoding(this.properties.getEncoding().name());
resolver.setContentType(appendCharset(this.properties.getContentType(),
resolver.getCharacterEncoding()));
resolver.setExcludedViewNames(this.properties.getExcludedViewNames());
resolver.setViewNames(this.properties.getViewNames());
// This resolver acts as a fallback resolver (e.g. like a
// InternalResourceViewResolver) so it needs to have low precedence
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);
resolver.setCache(this.properties.isCache());
return resolver;
}
which is extended by ThymeleafAutoConfiguration.Thymeleaf2ViewResolverConfiguration:
#Bean
#ConditionalOnMissingBean(name = "thymeleafViewResolver")
#ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
configureTemplateEngine(resolver, this.templateEngine);
resolver.setCharacterEncoding(this.properties.getEncoding().name());
resolver.setContentType(appendCharset(this.properties.getContentType(),
resolver.getCharacterEncoding()));
resolver.setExcludedViewNames(this.properties.getExcludedViewNames());
resolver.setViewNames(this.properties.getViewNames());
// This resolver acts as a fallback resolver (e.g. like a
// InternalResourceViewResolver) so it needs to have low precedence
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);
resolver.setCache(this.properties.isCache());
return resolver;
}
Hope it is clear now.

Embedded Jetty + Spring MVC main method

I'm using Embedded Jetty and Spring MVC and i'm starting my WebApplication through the main function.
i don't like the way it's looks, it's not very clean and i have the feeling i'm doing something wrong even though it's working just fine.
my problem is that i want to initialize ServerHolder,ServletContextHandler and Server objects outside the main method, but i cannot do it because DispatcherServlet requires and ApplicationContext.
Any ideas?
public static void main(String[] args) throws Exception {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(EPConfiguration.class);
ServletHolder servletHolder = new ServletHolder(new DispatcherServlet(applicationContext));
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
context.addServlet(servletHolder, "/*");
BasicConfigurator.configure();
Server server = new Server();
server.setHandler(context);
//HTTP
ServerConnector connector = new ServerConnector(server);
connector.setPort(9999);
server.setConnectors(new Connector[]{connector});
server.start();
server.join();
}
I'm not familier with Jetty, but you can setup and initialize DispatcherServlet in the following way:
Declare a java class which implements the abstract class AbstractAnnotationConfigDispatcherServletInitializer (it usually will be called WebAppInitializer).
Implement its abstract methods - getRootConfigClasses() (which return the classes which configure Application Context), getServletConfigClasses() (which returns the classes which configure the ServletContext) and getServletMappings() (which sets the DispatcherServletmapping).
I usually call the class that configures the ServletContext as WebConfig. You should annotate it with the #Configuration and #EnableWebMvc. In addition you should use it to define a ViewResolver bean:
```java
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/view"):
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
```

SpringMVC, Shiro, and Java Configuration

I am trying to use Shiro 1.2.2 with my SpringMVC 3.2.3 I have seen several examples of how to configure Shiro using ini files. But we are using JavaConfig and I have only found one partial example on that. I have several #Configuration files:
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 {
AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
root.scan( "com.company.config" );
root.register( EdmConfiguration.class, SecurityConfig.class );
servletContext.addListener( new ContextLoaderListener( root ) );
ServletRegistration.Dynamic appServlet = servletContext.addServlet( DISPATCHER_SERVLET_NAME,
new DispatcherServlet( root ) );
appServlet.setLoadOnStartup( 1 );
Set<String> mappingConflicts = appServlet.addMapping( DISPATCHER_SERVLET_MAPPING );
servletContext
.addFilter( "shiroFilter", new DelegatingFilterProxy( "shiroFilter", root ) )
.addMappingForUrlPatterns( null, false, DISPATCHER_SERVLET_MAPPING );
servletContext.addFilter( "Spring OpenEntityManagerInViewFilter",
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.class ).addMappingForUrlPatterns(
null, false, "/*" );
My beans are defined here:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.company.service", "com.company.utility",
"com.company.controller", "com.company.utility.startup",
"com.company.security", "com.company.security.model" })
#EnableTransactionManagement
#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();
...
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 ContentNegotiationManagerFactoryBean contentNegotiationManager() {
Properties properties = new Properties();
properties.setProperty( "xml", "application/xml" );
properties.setProperty( "json", "application/json" );
properties.setProperty( "html", "application/html" );
ContentNegotiationManagerFactoryBean contentNegotiationManager = new ContentNegotiationManagerFactoryBean();
contentNegotiationManager.setFavorParameter( true );
contentNegotiationManager.setMediaTypes( properties );
contentNegotiationManager.setDefaultContentType( MediaType.APPLICATION_JSON );
return contentNegotiationManager;
}
#Bean
public JavaMailSenderImpl mailSender() {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
int port = Integer.parseInt( environment.getRequiredProperty( "mail.smtp.socketFactory.port" ) );
mailSender.setHost( environment.getRequiredProperty( "mail.smtp.host" ) );
mailSender.setPort( port );
mailSender.setUsername( environment.getRequiredProperty( "mail.login.username" ) );
mailSender.setPassword( environment.getRequiredProperty( "mail.login.password" ) );
Properties properties = new Properties();
properties.setProperty( "mail.smtp.auth", environment.getRequiredProperty( "mail.smtp.auth" ) );
properties.setProperty( "mail.smtp.starttls.enable", "true" );
mailSender.setJavaMailProperties( properties );
return mailSender;
}
#Bean
public VelocityEngine getVelocityEngine() throws VelocityException, IOException {
VelocityEngineFactory factory = new VelocityEngineFactory();
Properties props = new Properties();
props.put( "resource.loader", "class" );
props.put( "class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader" );
factory.setVelocityProperties( props );
factory.setResourceLoaderPath( "/com/edelweissco/dental/templates" );
factory.setPreferFileSystemAccess( false );
return factory.createVelocityEngine();
}
#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);
return shiroFilter;
}
#Bean
#DependsOn(value = "lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true); // it's false by default
return creator;
}
I have broken the Shiro configuraton into its own file:
#Configuration
public class SecurityConfig {
#Bean
public CustomSecurityRealm customSecurityRealm() {
return new CustomSecurityRealm();
}
#Bean
public SaltAwareJdbcRealm saltAwareJdbcRealm() {
return new SaltAwareJdbcRealm();
}
#Bean
public org.apache.shiro.authc.credential.DefaultPasswordService passwordService() {
return new DefaultPasswordService();
}
#Bean
public TempFixPasswordMatcher passwordMatcher() {
TempFixPasswordMatcher tempFixPasswordMatcher = new TempFixPasswordMatcher();
tempFixPasswordMatcher.setPasswordService( passwordService() );
return tempFixPasswordMatcher;
}
#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 DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
#Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager( securityManager() );
return authorizationAttributeSourceAdvisor;
}
When I try to deploy I get exceptions such as :
This is the full stack trace I get once I remove the #Transaction from my OfficeService:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'menuService': Injection of resource dependencies failed; nested exception is 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.$Proxy68]: 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.$Proxy68
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:306)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1116)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4937)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)
at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1551)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:835)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:771)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:622)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:569)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:835)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:771)
at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1455)
at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:75)
at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1296)
at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1388)
at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:819)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:303)
at sun.rmi.transport.Transport$1.run(Transport.java:159)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:680)
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.$Proxy68]: 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.$Proxy68
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.$Proxy68]: 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.$Proxy68
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.$Proxy68
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
Nov 9, 2013 4:10:04 PM org.apache.catalina.core.ApplicationContext log
INFO: Closing Spring root WebApplicationContext
Presumably you have some #RequiresAuthentication or #RequiresRole annotations on your service classes. To enable those, Shiro (Spring) has to proxy the beans it creates. It does this with the DefaultAdvisorAutoProxyCreator bean. However, this bean proxies with JDK proxies which create proxies based on interfaces, not on base classes.
For example, say Spring has to proxy OfficeService, it'll create a java.lang.reflect.Proxy instance that wraps the OfficeService bean. If you called getClass() on this object, it would return something like com.sun.proxy.$Proxy64. If your OfficeService was implementing any interfaces, that object would be an instance of those interfaces. However, the bean is not an instance of OfficeService, so Spring can't use it as an #Autowired target.
Instead, you have to tell Spring to use CGLIB proxies. You can do that by changing your config here
#Bean
#DependsOn(value = "lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true); // it's false by default
return creator;
}
And adding the CGLIB libraries (jars) to your classpath.
Note that if this is not a Shiro issue, you need to post the rest of your config. If you are doing any other proxying in your context, you'll need to do something similar to disable JDK proxies.
It seems like the only other thing that can create proxies is the transaction management, so change to
#EnableTransactionManagement(proxyTargetClass = true)

Resources