Disabling Spring MVC view resolution for a REST only application - spring

I would like to disable Spring MVC view resolution for my application.
My application only uses Thymeleaf for mail templates and Spring MVC for the REST API. It does not serve Thymleaf pages.
I have configured the following property in my application.properties:
spring.thymeleaf.enabled=false
But I still get errors such as:
20:28:51.851 [http-nio-8080-exec-10] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet dispatcherServlet threw exception
javax.servlet.ServletException: Circular view path [error]: would dispatch back to the current handler URL [/error] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
at org.springframework.web.servlet.view.InternalResourceView.prepareForRendering(InternalResourceView.java:205)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:145)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1257)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:726)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:471)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:394)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:311)
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:395)
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:254)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:177)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:784)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:802)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1410)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
How can I use Thymeleaf whilst disabling view resolution for Spring MVC?
edit: Actually the only view I am serving is the SPA's index.html as follows:
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index.html");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")//
.addResourceLocations("classpath:/")//
.setCachePeriod(ONE_YEAR);
registry.addResourceHandler("/")//
.addResourceLocations("classpath:/index.html")//
.setCachePeriod(0);
}

I think problem here is, when spring encounters an error, it is forwarding "user" to /error page. Try adding following in your properties.
spring.resources.add-mappings=false

You probably have a controller which returns some string which cannot be resolved by Spring View resolver. If you want to return JSON object use #RestController annotation for your class
MainController.java
#RestController
public class MainController {
#GetMapping("/")
public TestResponseDto greeting(/*here can be any params*/) {
System.out.println("here");
return new TestResponseDto();
}
}
TestResponse.java
public class TestResponseDto {
public String response = "test";
}

Related

The `JAX-RS` resource throwing org.glassfish.jersey.server.model.ModelValidationException after Progard Obfuscation

I am having a Spring boot multi-module maven project running with Java8. This below class is being used to determine which resources we should be registering for our Jersey set-up-
#Slf4j
#Configuration
#Component
#ApplicationPath("/")
public class JerseyConfig extends ResourceConfig {
#Autowired
private AutowireCapableBeanFactory beanFactory;
#PostConstruct
public void initialize() {
// We will just look for all the classes in our resources
// package annotated with #Path
Reflections reflections = new Reflections("org.example.resource");
Set<Class<? extends Object>> resources =
reflections.getTypesAnnotatedWith(Path.class);
resources.forEach(r -> {
log.debug("Registering resource " + r);
register(beanFactory.getBean(r));
});
register(ConstraintViolationExceptionMapper.class);
}
}
Whereas, the REST endpoint looks like below:
#Component
#Api(value = "/api/1/summary", description = "Manage Summary")
#Path("/api/1/summary")
#Produces(MediaType.APPLICATION_JSON)
public class SummaryResource extends AbstractUpdatableDomainResource<Summary> {
#ApiOperation(value = "Create new summary", notes = "Create a new summary and return with its unique id", response = Summary.class)
#POST
#Override
public User create(Summary newInstance) {
}
}
Now, if I ran with -dontobfuscate then everything is working as excepted but when obfuscate it ends up with the following errors:
[http-nio-8080-exec-1] ERROR o.a.c.c.C.[.[localhost].[/web-context-path] - org.apache.juli.logging.DirectJDKLog - Servlet.init() for servlet [org.example.JerseyConfig] threw exception
org.glassfish.jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization.
[[HINT] A HTTP GET method, public void org.example.resource.FDService.a(javax.servlet.http.HttpServletResponse,javax.servlet.http.HttpServletRequest), returns a void type. It can be intentional and perfectly fine, but it is a little uncommon that GET method returns always "204 No Content".; source='ResourceMethod{httpMethod=GET, consumedTypes=[], producedTypes=[application/pdf], suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS, invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class org.example.resource.FDService, handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor#508c06e3]}, definitionMethod=public void org.example.resource.FDService.a(javax.servlet.http.HttpServletResponse,javax.servlet.http.HttpServletRequest), parameters=[Parameter [type=interface javax.servlet.http.HttpServletResponse, source=null, defaultValue=null], Parameter [type=interface javax.servlet.http.HttpServletRequest, source=null, defaultValue=null]], responseType=void}, nameBindings=[]}'
at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:394)
at org.glassfish.jersey.server.ApplicationHandler.lambda$initialize$1(ApplicationHandler.java:316)
at org.glassfish.jersey.internal.Errors.process(Errors.java:316)
at org.glassfish.jersey.internal.Errors.process(Errors.java:298)
at org.glassfish.jersey.internal.Errors.processWithException(Errors.java:256)
at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:315)
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:282)
at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:335)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:178)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:370)
at javax.servlet.GenericServlet.init(GenericServlet.java:158)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1122)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:777)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:135)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
So my question is, what makes it NOT run if the code obfuscates? Why does obfuscation break the application? How to ignore ModelValidationException? What needs to tell proguard to exclude to make it run?

Serving static content results in Request method 'GET' not supported

I want to serve static content from my static directory in my project resources, but I get error: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported.
I have added configured Spring Security to ignore requests starting with "/static/". I have added resource handler to WebMvcConfig to look for the static content in various different locations, I have tried removing the resource handler altogether.
I have tried adding permitAll() to the "/static/" path.
I have googled the error message and various combinations of it to find solutions. This is where I came up with the Spring Security and WebMvcConfigs. Just that these did not solve the problem for me.
Finally I have tried placing static files into different locations. The directory structure is as follows:
\resources\static\hello.css
\resources\static\css\hello.css
\resources\templates\home.html
\resources\templates\error.html
Thymeleaf works correctly, taking the templates from the templates directory.
The WebMvcConfig:
// Config Thymeleaf
private static final String VIEWS = "classpath:templates/";
#Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
private ISpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
return engine;
}
private ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix(VIEWS);
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
// Enable static resources
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/static/**")
.addResourceLocations("/resources/static/", "classpath:static/", "/static/", "classpath:resources/static");
}
The Spring Security config:
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/static/**");
}
I expect to see my css file, but instead I see the error page generated by exception handler with the message "Request method 'GET' not supported"
Here is the debug trace from the point I request the css file:
2019-06-07 11:30:29.694 DEBUG 5398 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/static/css/hello.css'; against '/static/**'
2019-06-07 11:30:29.694 DEBUG 5398 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /static/css/hello.css has an empty filter list
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:200)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:419)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:365)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:65)
at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:401)
at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1232)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1015)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:209)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:836)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1747)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
After hours of debugging I found the reason static content was not served!
It was because of a controller with mapping without the path:
#PostMapping()
After adding a path to the mapping, the configuration above works as it should.
Very weird that it messed up the serving of static files!
Big thanks to #Ganesh for his tip in Spring Boot not serving static content
thanks #Avaruuskadetti you saved hours of my time
DEBUG:
package org.springframework.web.servlet >>>> HandlerExecutionChain
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping hm = (HandlerMapping)var2.next();
if (this.logger.isTraceEnabled()) {
this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}

Spring boot Integration unit testing NoSuchBeanDefinitionException exception

I created a sample IntegrationFlow as shown below:
#Configuration
#EnableIntegration
#IntegrationComponentScan
#ComponentScan
public class RegisterHostFlow {
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
#MessagingGateway
public interface RegisterHostGateway{
#Gateway(requestChannel = "registerHostInputChannel")
Host registerHost(Host host);
}
#Bean
public IntegrationFlow httpInboundGatewayFlow() {
return IntegrationFlows.from("registerHostInputChannel")
.handle((host, headers) -> {
return host;
})
.enrich(e -> e
.requestPayload(Message::getPayload)
.property("uuid", "34563456345634563456")
.property("id", "1234")
)
.get();
}
}
I am calling this from a spring MVC controller as below:
RegisterHostFlow.RegisterHostGateway registerHostGateway = applicationContext.getBean(RegisterHostFlow.RegisterHostGateway.class);
Host host1 = registerHostGateway.registerHost(host);
When I write a unit test to do some sanity testing as shown below, application fails to load with the error, NoSuchBeanException:
#RunWith(SpringRunner.class)
#WebMvcTest(HostController.class)
#EnableIntegration
#IntegrationComponentScan
public class HostControllerTest {
#Autowired
private MockMvc mvc;
#Test
public void registerHost_passedInHost_returnJson() throws Exception {
this.mvc.perform(post("/hostservice/v1/hosts").contentType(MediaType.APPLICATION_JSON). content('someJsonStringGoesHere'))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
}
Below is the exception I see:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'registerHostInputChannel' available
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:155)
Any pointers to how to have ApplicationContext autowire the integration beans when in test mode?
According the #WebMvcTest JavaDocs:
* Typically {#code #WebMvcTest} is used in combination with {#link MockBean #MockBean} or
* {#link Import #Import} to create any collaborators required by your {#code #Controller}
* beans.
You have to make your test class config like:
#RunWith(SpringRunner.class)
#WebMvcTest(HostController.class)
#Import(RegisterHostFlow.class)
public class HostControllerTest {
So, this way you have an MVC slice and collaborator in face of Spring Integration and target flow configuration.

Spring Boot doesn't use CommonsMultipartResolver?

I have a problem with REST web service running with Spring Boot (Jetty).
One of my REST method is file upload and I'm guessing that CommonsMultipartResolver is not using during multipart requests.
Signature of this upload method is :
#ResponseBody
#RequestMapping(value = "/upload", method = RequestMethod.POST, produces = "application/json")
public BaseResponse upload(#RequestParam("login") String login, #RequestParam("passwd") String passwd,
#RequestParam("partner") String partner, #RequestParam("fileName") String fName,
#RequestParam("length") int fLen, #RequestParam("file") MultipartFile file) throws IOException
I also have a root application class like below :
#SpringBootApplication
public class BootApplication {
private static final Logger _logger = Logger.getLogger(BootApplication.class.getName());
public static void main(String[] args) {
SpringApplication app = new SpringApplication(BootApplication.class,
new ClassPathResource("WEB-INF/applicationContext.xml"),
new ClassPathResource("WEB-INF/dispatcher-servlet.xml"));
app.run(args);
}
#Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver(ServletContext servletContext) {
_logger.log(Level.INFO, "[BootApplication] Fetching CommonsMultipartResolver");
return new CommonsMultipartResolver(servletContext);
}
}
When I'm calling this method I got an error :
org.springframework.web.bind.MissingServletRequestParameterException: Required MultipartFile parameter 'file' is not present
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:253)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:94)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:808)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)
at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:224)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:295)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:102)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:68)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:497)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:745)
What's strange in this stack trace I cannot see any CommonsMultipartResolver calls.
Another thing is that exactly the same code was working in GlassFish environment - I could upload files with no problem. What changed is that multipartResolver bean in GlassFish was defined in dispatcher-servlet.xml and in Spring Boot I initialize it in BootApplication class. I also tried to left multipartResolver in dispatcher-servlet.xml which I'm also loading for configuration but none of this solution worked.
When I'm looking at /beans endpoint in Spring Boot I can see multipartResolver bean. No other bean has dependency to this multipartResolver bean - maybe this is wrong, but I have no idea how to configure it properly.
Below you have my dispatcher-servlet.xml if it will help :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.my.package" />
<mvc:annotation-driven />
</beans>
You are using Spring Boot then use it, you are trying to work around it.
Spring Boot by default already configures file uploading so you can remove your definition. If you want to control certain values you can configure those by adding properties to the application.properties. See this section of the reference guide.
I would suggest removing your dispatcher-servlet.xml because Spring Boot already enables MVC configuration and you enabling it interferes with the auto configuration. Assuming that your BootApplication is inside the com.my.package you can already remove the file as it adds nothing, if the BootApplication is in a different package add #ComponentScan("com.my.package") to the configuration.
To import the applicationContext.xml add a #ImportResource to your BootApplication instead of what you are doing now. However depending on what is in there (probably some datasource, JPA, etc. configuration you might even remove it and replace it with some simple properties instead).
#SpringBootApplication
#ComponentScan("com.my.package")
#ImportResource("WEB-INF/applicationContext.xml")
public class BootApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(BootApplication.class, args);
}
}
The main problem is is that you are disabling part of the Spring Boot auto configuration to properly let it configure things.
I think they have resolved the issue in Spring-Boot 1.4.2.RELEASE
#Bean
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver multipart = new CommonsMultipartResolver();
multipart.setMaxUploadSize(3 * 1024 * 1024);
return multipart;
}
#Bean
#Order(0)
public MultipartFilter multipartFilter() {
MultipartFilter multipartFilter = new MultipartFilter();
multipartFilter.setMultipartResolverBeanName("multipartResolver");
return multipartFilter;
}
You also need to exclude Spring-Boot's MulipartAutoConfiguration.class
#EnableAutoConfiguration(exclude = {MultipartAutoConfiguration.class})
This worked for me.

Spring Boot with SiteMesh 3

I'm writing a new web app using Spring Boot for the first time and am trying to use SiteMesh 3 without success.
I'm using a web initializer to bootstrap;
public class WebInitializer extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
I've configured the filter in the Application config class as below;
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application {
#Bean
public FilterRegistrationBean siteMeshFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new MySiteMeshFilter());
return filterRegistrationBean;
}
}
MySiteMeshFilter is as follows;
public class MySiteMeshFilter extends ConfigurableSiteMeshFilter {
#Override
protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
builder.addDecoratorPath("/*", "/decorators/decorator.html");
}
}
Under src/main/webapp/WEB-INF/ I have a folder decorators containing decorator.html;
<html>
<head>
<title><sitemesh:write property='title'/></title>
<sitemesh:write property='head'/>
</head>
<body>
<p>This has been decorated!!!</p>
<sitemesh:write property='body'/>
</body>
</html>
and under src/main/webapp/static I have a basic html file;
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<p>Just a test html page</p>
</body>
</html>
But ... on running web app (I'm deploying the war on tomcat - not embedded) and going to localhost:8080/static/test.html I get ...
2014-09-18 16:17:53.696 ERROR 7233 --- [io-8080-exec-10] o.s.boot.context.web.ErrorPageFilter : Forwarding to error page from request [/static/test.htmlnull] due to exception [Cannot forward after response has been committed]
java.lang.IllegalStateException: Cannot forward after response has been committed
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:348)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
at org.springframework.boot.context.web.ErrorPageFilter.handleErrorStatus(ErrorPageFilter.java:134)
at org.springframework.boot.context.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:111)
at org.springframework.boot.context.web.ErrorPageFilter.access$000(ErrorPageFilter.java:58)
at org.springframework.boot.context.web.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:87)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.boot.context.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:100)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
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:744)
If I comment out the SiteMesh filter in the configuration file (Application class) then I see the undecorated test.html find.
So am I missing something very obvious here?

Resources