I just converted all of my xml config files to JavaConfig using Spring MVC 3.2.3 and Spring Security 3.2.1. I ran into some issues where entities that had members annotated with @ElementCollection(fetch=FetchType.EAGER) still weren't being fetched (a problem I didn't have with my XML config) and I had to add the @Fetch(FetchMode.JOIN) annotation. I'm still having problems retrieving data from my controllers, however.
Many of my requests get fully processed by the back-end, but when they're returned from my controller method, I get the error "HTTP Status 500 - Could not resolve view with name 'xxx' in servlet with name 'dispatcher'". The problem is, I only have 3 views: login, index, and admin. The index page is a single page site that does a lot of AJAX calls to controllers, most of which unmarshal JSON requests to DTOs using @RequestBody, and all of which write the response directly with @ResponseBody and get converted to JSON using Jackson. This has always worked in the past -- the controller methods should literally just be REST endpoints, but now, the dispatcher servlet wants to associate a view with almost all of my requests, but not all. I'm not sure how to tell the view resolver or dispatcher servlet to only treat index, admin, and login as views, and just treat everything else as a simple REST request. Any help would be appreciated! Here is my config:
Root Config:
@Configuration
@ComponentScan(value = "x.configuration", excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, value = RootConfig.class))
public class RootConfig {}
SecurityInitializer:
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {}
WebApp Initializer:
public class WebAppInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{
"/rest/*",
"/index.html",
"/login.html",
"/admin.html",
"/index/*",
"/login/*",
"/admin/*"
};
}
@Override
protected Filter[] getServletFilters() {
OpenEntityManagerInViewFilter openEntityManagerInViewFilter = new OpenEntityManagerInViewFilter();
openEntityManagerInViewFilter.setBeanName("openEntityManagerInViewFilter");
openEntityManagerInViewFilter.setPersistenceUnitName("HSQL");
return new javax.servlet.Filter[]{openEntityManagerInViewFilter};
}
}
Spring MVC config:
@Configuration
@EnableWebMvc
@EnableTransactionManagement
{@ComponentScan.Filter(type= FilterType.ANNOTATION, value=Controller.class)})
@ComponentScan(basePackages = "x.clients")
public class SpringMvcConfig extends WebMvcConfigurerAdapter {
@Bean
public InternalResourceViewResolver setupViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewNames(new String[] {"login", "index", "admin"});
return viewResolver;
}
@Bean
public DefaultAnnotationHandlerMapping getDefaultAnnotationHandlerMapping() {
DefaultAnnotationHandlerMapping handlerMapping = new DefaultAnnotationHandlerMapping();
handlerMapping.setAlwaysUseFullPath(true);
handlerMapping.setDetectHandlersInAncestorContexts(true);
return handlerMapping;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(getMappingJacksonHttpMessageConverter());
super.configureMessageConverters(converters);
}
@Bean
public JacksonAnnotationIntrospector getJacksonAnnotationIntrospector(){
return new JacksonAnnotationIntrospector();
}
@Bean
public ObjectMapper getObjectMapper(){
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(getJacksonAnnotationIntrospector());
mapper.registerModule(new Hibernate4Module());
return mapper;
}
@Bean MappingJackson2HttpMessageConverter getMappingJacksonHttpMessageConverter(){
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
messageConverter.setObjectMapper(getObjectMapper());
return messageConverter;
}
@Bean
public DefaultConversionService getDefaultConversionService(){
return new DefaultConversionService();
}
}
Spring Security Config:
@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
AuthenticationProvider rememberMeAuthenticationProvider = getRememberMeAuthenticationProvider();
TokenBasedRememberMeServices tokenBasedRememberMeServices = getTokenBasedRememberMeServices();
List<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>(2);
authenticationProviders.add(rememberMeAuthenticationProvider);
authenticationProviders.add(customAuthenticationProvider);
AuthenticationManager authenticationManager = getAuthenticationManager(authenticationProviders);
http
.csrf().disable()
.headers().disable()
.addFilter(new RememberMeAuthenticationFilter(authenticationManager, tokenBasedRememberMeServices))
.rememberMe().rememberMeServices(tokenBasedRememberMeServices)
.and()
.authorizeRequests()
.antMatchers("/js/**", "/css/**", "/img/**", "/login", "/processLogin").permitAll()
.antMatchers("/index.jsp", "/index.html", "/index").hasRole("USER")
.antMatchers("/admin", "/admin.html", "/admin.jsp").hasRole("ADMIN")
.and()
.formLogin().loginProcessingUrl("/processLogin").loginPage("/login").failureUrl("/login").permitAll()
.and()
.logout().permitAll();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**", "/css/**", "/img/**");
}
@Bean
public AuthenticationManager getAuthenticationManager(List<AuthenticationProvider> authenticationProviders) {
return new ProviderManager(authenticationProviders);
}
@Bean
public TokenBasedRememberMeServices getTokenBasedRememberMeServices() {
return new TokenBasedRememberMeServices("testKey", userDetailsService);
}
@Bean
public AuthenticationProvider getRememberMeAuthenticationProvider() {
return new org.springframework.security.authentication.RememberMeAuthenticationProvider("testKey");
}
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
}
All of my controller methods are accessed via the URL pattern /rest//.
The following controller simply returns a list of enumerated items and works fine:
@Controller
@RequestMapping("/swterms")
public class SwTermsController {
@RequestMapping(value = "/getSensorTypes", method = RequestMethod.GET)
@ResponseBody
public List<String> getSensorTypes() {
List<String> sensorTypes = new ArrayList<String>();
for (SensorTypes sensorType : SensorTypes.values()){
sensorTypes.add(sensorType.getURI());
}
return sensorTypes;
}
}
This controller returns a list of map layers. I can step through in debug mode and everything is built fine, but it produces the 500 error:
@Controller
@RequestMapping("/map")
public class MapLayerController {
@Autowired
@Resource(name="mapLayers") private List<OpenLayersMapLayer> mapLayers;
@RequestMapping(value = "/getLayerData", method = RequestMethod.GET)
@ResponseBody
public Map getMapLayers() {
Map model = new HashMap();
model.put("layers", this.mapLayers);
return model;
}
}
Here is the relevant part of the log:
00:12:21,034 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.FilterChainProxy] - /rest/map/getLayerData at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
00:12:21,034 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/logout'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/js/**'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/css/**'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/img/**'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/login'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/processlogin'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/index.jsp'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/index.html'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/index'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/admin'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/admin.html'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/admin.jsp'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - Checking match of request : '/rest/map/getlayerdata'; against '/js/saic/jswe/admin/**'
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - Public object - authentication not attempted
00:12:21,035 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.FilterChainProxy] - /rest/map/getLayerData reached end of additional filter chain; proceeding with original chain
00:12:21,041 (http-bio-8084-exec-77) DEBUG [org.springframework.web.servlet.DispatcherServlet] - DispatcherServlet with name 'dispatcher' processing GET request for [/swtc/rest/map/getLayerData]
00:12:21,041 (http-bio-8084-exec-77) DEBUG [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] - Looking up handler method for path /map/getLayerData
00:12:21,042 (http-bio-8084-exec-77) DEBUG [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] - Returning handler method [public org.springframework.ui.ModelMap x.clients.controllers.MapLayerController.getMapLayers(org.springframework.ui.ModelMap)]
00:12:21,042 (http-bio-8084-exec-77) DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'mapLayerController'
00:12:21,042 (http-bio-8084-exec-77) DEBUG [org.springframework.web.servlet.DispatcherServlet] - Last-Modified value for [/swtc/rest/map/getLayerData] is: -1
00:12:44,844 (http-bio-8084-exec-77) DEBUG [org.springframework.web.servlet.DispatcherServlet] - Could not complete request
javax.servlet.ServletException: Could not resolve view with name 'map/getLayerData' in servlet with name 'dispatcher'
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1190)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:992)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:939)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:180)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:146)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:146)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)
00:12:44,902 (http-bio-8084-exec-77) DEBUG [org.springframework.security.web.context.SecurityContextPersistenceFilter] - SecurityContextHolder now cleared, as request processing completed