Hi,
I have implemented case when I need XSD validation of output XML messages. To support multiple reads of responses, I have ended up with this code as part of my primary configuration:
@Bean
@Primary
public DispatcherServlet dispatcherServlet(WebApplicationContext context) {
return new DispatcherServlet(context) {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
super.service(request, responseWrapper);
responseWrapper.copyBodyToResponse();
}
};
}
I access this wrapper in my HandlerInterceptor like this:
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex
) throws Exception {
if (response instanceof ContentCachingResponseWrapper) {
// pseudo code
if (!response.valid) {
response.resetBuffer();
response.getWriter().println("doh")
}
}
}
Thing is that this works perfectly fine if I run this from JAR, repackaged WAR or from IDE. Problem starts to show up when I deploy WAR to any application server (wildfly/tomcat) and this happens for both original and also repackaged WAR. If I implement this type of wrapping request by caching its content (as shown in example above - I have also tried custom implementation), all the responses are empty.
The most curious thing is that this happens only using JDK11. Everything worked fine until I switched to JDK 11. I have just added some extra configuration to war plugin since it failed without this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven.war.plugin.version}</version>
<configuration>
<warName>${project.name}</warName>
<archive>
<manifestEntries>
<Dependencies>jdk.unsupported</Dependencies>
</manifestEntries>
</archive>
</configuration>
</plugin>
Sadly, I cannot provide any example project right now.
Thank you for your responses.
Comment From: wilkinsona
Thanks for the report. Unfortunately, from what you've shared thus far, I can't see why you wouldn't see any content in the response, particularly only on Java 11. There's no Java 11-specific code in Spring Boot or, as far as I know, Spring Framework so no behaviour differences are expected.
Given the nature of the unexpected behaviour that you are seeing and that it only occurs on Java 11, I think we'll need to be able to reproduce the problem to be able to help you identify its cause. To that end, if you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.
Comment From: Drezir
Thanks for the report. Unfortunately, from what you've shared thus far, I can't see why you wouldn't see any content in the response, particularly only on Java 11. There's no Java 11-specific code in Spring Boot or, as far as I know, Spring Framework so no behaviour differences are expected.
Given the nature of the unexpected behaviour that you are seeing and that it only occurs on Java 11, I think we'll need to be able to reproduce the problem to be able to help you identify its cause. To that end, if you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.
I have created minimal example. Its (un)fortunately failing even by running from IDE (not just by running on app server). See if this helps. Thank you. example.zip
Comment From: bclozel
I've checked out your sample application; it seems the issue is coming from an improper use of the ContentCachingResponseWrapper
. This should be used in a Servlet filter, properly ordered relatively to the other filters and their purpose.
Wrapping the response at the DispatcherServlet
level can cause issues, like this instance.
Your Controller handler returns a Callable<String>
, which in Spring MVC means that you'd like asynchronous management of the response. In Servlet containers, this means that the processing of the response will be dealt with in a different thread and then dispatched back into the Servlet. What happens here is that the response is wrapped once initially, and then once again once the Callable
has been processed. Since the response is wrapped twice with the ContentCachingResponseWrapper
, nothing is being written to the actual response.
Replacing your Controller handler with a public String ping()
shows a working example. But wrapping requests with a ContentCachingResponseWrapper
is still problematic. I'm closing this issue as a result.