BAEL-4860: Java IllegalStateException: "getInputStream() has already been called for this request" (#14121)

* [BAEL-6203] Deserialize Generic Type with Jackson

* BAEL-4860: Java IllegalStateException: "getInputStream() has already been called for this request"

* BAEL-4860: Move code to new module spring-web-module/spring-mvc-java-3.

* BAEL-4860: update pom

* BAEL-4860: make the test methods public
This commit is contained in:
Forb Yuan 2023-06-12 11:49:15 +08:00 committed by GitHub
parent 680ddfef9c
commit 643f99281f
5 changed files with 112 additions and 0 deletions

View File

@ -28,6 +28,7 @@
<module>spring-mvc-forms-thymeleaf</module>
<module>spring-mvc-java</module>
<module>spring-mvc-java-2</module>
<module>spring-mvc-java-3</module>
<module>spring-mvc-velocity</module>
<module>spring-mvc-views</module>
<module>spring-mvc-webflow</module>

View File

@ -0,0 +1 @@
### Relevant Articles:

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-mvc-java-3</artifactId>
<version>0.1-SNAPSHOT</version>
<name>spring-mvc-java-3</name>
<packaging>war</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
</dependencies>
<build>
<finalName>spring-mvc-java-3</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>

View File

@ -0,0 +1,23 @@
package com.baeldung.filters;
import org.springframework.web.util.ContentCachingRequestWrapper;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@WebFilter(urlPatterns = "/*")
public class CacheRequestContentFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
if (request instanceof HttpServletRequest) {
String contentType = request.getContentType();
if (contentType == null || !contentType.contains("multipart/form-data")) {
request = new ContentCachingRequestWrapper((HttpServletRequest) request);
}
}
chain.doFilter(request, response);
}
}

View File

@ -0,0 +1,47 @@
package com.baeldung.filters;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.util.ContentCachingRequestWrapper;
import javax.servlet.Filter;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.*;
public class HttpRequestUnitTest {
@Test
public void givenHttpServletRequest_whenCalling_getReaderAfter_getInputStream_thenThrowIllegalStateException() throws IOException {
HttpServletRequest request = new MockHttpServletRequest();
try (ServletInputStream ignored = request.getInputStream()) {
IllegalStateException exception = assertThrows(IllegalStateException.class, request::getReader);
assertEquals("Cannot call getReader() after getInputStream() has already been called for the current request",
exception.getMessage());
}
}
@Test
public void givenServletRequest_whenDoFilter_thenCanCallBoth() throws ServletException, IOException {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
Filter filter = new CacheRequestContentFilter();
filter.doFilter(req, res, chain);
ServletRequest request = chain.getRequest();
assertTrue(request instanceof ContentCachingRequestWrapper);
// now we can call both getInputStream() and getReader()
request.getInputStream();
request.getReader();
}
}