Simplify MockHttpServletRequestBuilders hierarchy

Closes gh-33231
This commit is contained in:
Stéphane Nicoll 2025-10-02 09:22:33 +02:00
parent d98179e137
commit e91abd442a
3 changed files with 6 additions and 319 deletions

View File

@ -16,22 +16,9 @@
package org.springframework.test.web.servlet.request;
import java.net.URI;
import java.nio.charset.Charset;
import java.security.Principal;
import java.util.Locale;
import java.util.Map;
import jakarta.servlet.http.Cookie;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.util.MultiValueMap;
/**
* Default builder for {@link MockHttpServletRequest} required as input to
@ -66,177 +53,4 @@ public class MockHttpServletRequestBuilder
super(httpMethod);
}
// Override to keep binary compatibility.
@Override
public MockHttpServletRequestBuilder uri(URI uri) {
return super.uri(uri);
}
@Override
public MockHttpServletRequestBuilder uri(String uriTemplate, @Nullable Object... uriVariables) {
return super.uri(uriTemplate, uriVariables);
}
@Override
public MockHttpServletRequestBuilder contextPath(String contextPath) {
return super.contextPath(contextPath);
}
@Override
public MockHttpServletRequestBuilder servletPath(String servletPath) {
return super.servletPath(servletPath);
}
@Override
public MockHttpServletRequestBuilder pathInfo(@Nullable String pathInfo) {
return super.pathInfo(pathInfo);
}
@Override
public MockHttpServletRequestBuilder secure(boolean secure) {
return super.secure(secure);
}
@Override
public MockHttpServletRequestBuilder characterEncoding(Charset encoding) {
return super.characterEncoding(encoding);
}
@Override
public MockHttpServletRequestBuilder characterEncoding(String encoding) {
return super.characterEncoding(encoding);
}
@Override
public MockHttpServletRequestBuilder content(byte[] content) {
return super.content(content);
}
@Override
public MockHttpServletRequestBuilder content(String content) {
return super.content(content);
}
@Override
public MockHttpServletRequestBuilder contentType(MediaType contentType) {
return super.contentType(contentType);
}
@Override
public MockHttpServletRequestBuilder contentType(String contentType) {
return super.contentType(contentType);
}
@Override
public MockHttpServletRequestBuilder accept(MediaType... mediaTypes) {
return super.accept(mediaTypes);
}
@Override
public MockHttpServletRequestBuilder accept(String... mediaTypes) {
return super.accept(mediaTypes);
}
@Override
public MockHttpServletRequestBuilder header(String name, Object... values) {
return super.header(name, values);
}
@Override
public MockHttpServletRequestBuilder headers(HttpHeaders httpHeaders) {
return super.headers(httpHeaders);
}
@Override
public MockHttpServletRequestBuilder param(String name, String... values) {
return super.param(name, values);
}
@Override
public MockHttpServletRequestBuilder params(MultiValueMap<String, String> params) {
return super.params(params);
}
@Override
public MockHttpServletRequestBuilder queryParam(String name, String... values) {
return super.queryParam(name, values);
}
@Override
public MockHttpServletRequestBuilder queryParams(MultiValueMap<String, String> params) {
return super.queryParams(params);
}
@Override
public MockHttpServletRequestBuilder formField(String name, String... values) {
return super.formField(name, values);
}
@Override
public MockHttpServletRequestBuilder formFields(MultiValueMap<String, String> formFields) {
return super.formFields(formFields);
}
@Override
public MockHttpServletRequestBuilder cookie(Cookie... cookies) {
return super.cookie(cookies);
}
@Override
public MockHttpServletRequestBuilder locale(Locale... locales) {
return super.locale(locales);
}
@Override
public MockHttpServletRequestBuilder locale(@Nullable Locale locale) {
return super.locale(locale);
}
@Override
public MockHttpServletRequestBuilder requestAttr(String name, Object value) {
return super.requestAttr(name, value);
}
@Override
public MockHttpServletRequestBuilder sessionAttr(String name, Object value) {
return super.sessionAttr(name, value);
}
@Override
public MockHttpServletRequestBuilder sessionAttrs(Map<String, Object> sessionAttributes) {
return super.sessionAttrs(sessionAttributes);
}
@Override
public MockHttpServletRequestBuilder flashAttr(String name, Object value) {
return super.flashAttr(name, value);
}
@Override
public MockHttpServletRequestBuilder flashAttrs(Map<String, Object> flashAttributes) {
return super.flashAttrs(flashAttributes);
}
@Override
public MockHttpServletRequestBuilder session(MockHttpSession session) {
return super.session(session);
}
@Override
public MockHttpServletRequestBuilder principal(Principal principal) {
return super.principal(principal);
}
@Override
public MockHttpServletRequestBuilder remoteAddress(String remoteAddress) {
return super.remoteAddress(remoteAddress);
}
@Override
public MockHttpServletRequestBuilder with(RequestPostProcessor postProcessor) {
return super.with(postProcessor);
}
}

View File

@ -16,28 +16,9 @@
package org.springframework.test.web.servlet.request;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.Part;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.mock.web.MockMultipartHttpServletRequest;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* Default builder for {@link MockMultipartHttpServletRequest}.
@ -47,12 +28,8 @@ import org.springframework.util.MultiValueMap;
* @author Stephane Nicoll
* @since 3.2
*/
public class MockMultipartHttpServletRequestBuilder extends MockHttpServletRequestBuilder {
private final List<MockMultipartFile> files = new ArrayList<>();
private final MultiValueMap<String, Part> parts = new LinkedMultiValueMap<>();
public class MockMultipartHttpServletRequestBuilder
extends AbstractMockMultipartHttpServletRequestBuilder<MockMultipartHttpServletRequestBuilder> {
/**
* Package-private constructor. Use static factory methods in
@ -76,100 +53,4 @@ public class MockMultipartHttpServletRequestBuilder extends MockHttpServletReque
}
/**
* Add a new {@link MockMultipartFile} with the given content.
* @param name the name of the file
* @param content the content of the file
*/
public MockMultipartHttpServletRequestBuilder file(String name, byte[] content) {
this.files.add(new MockMultipartFile(name, content));
return this;
}
/**
* Add the given {@link MockMultipartFile}.
* @param file the multipart file
*/
public MockMultipartHttpServletRequestBuilder file(MockMultipartFile file) {
this.files.add(file);
return this;
}
/**
* Add {@link Part} components to the request.
* @param parts one or more parts to add
* @since 5.0
*/
public MockMultipartHttpServletRequestBuilder part(Part... parts) {
Assert.notEmpty(parts, "'parts' must not be empty");
for (Part part : parts) {
this.parts.add(part.getName(), part);
}
return this;
}
@Override
public Object merge(@Nullable Object parent) {
if (parent == null) {
return this;
}
if (parent instanceof MockHttpServletRequestBuilder) {
super.merge(parent);
if (parent instanceof MockMultipartHttpServletRequestBuilder parentBuilder) {
this.files.addAll(parentBuilder.files);
parentBuilder.parts.keySet().forEach(name ->
this.parts.putIfAbsent(name, parentBuilder.parts.get(name)));
}
}
else {
throw new IllegalArgumentException("Cannot merge with [" + parent.getClass().getName() + "]");
}
return this;
}
/**
* Create a new {@link MockMultipartHttpServletRequest} based on the
* supplied {@code ServletContext} and the {@code MockMultipartFiles}
* added to this builder.
*/
@Override
protected final MockHttpServletRequest createServletRequest(ServletContext servletContext) {
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(servletContext);
Charset defaultCharset = (request.getCharacterEncoding() != null ?
Charset.forName(request.getCharacterEncoding()) : StandardCharsets.UTF_8);
this.files.forEach(request::addFile);
this.parts.values().stream().flatMap(Collection::stream).forEach(part -> {
request.addPart(part);
try {
String name = part.getName();
String filename = part.getSubmittedFileName();
InputStream is = part.getInputStream();
if (filename != null) {
request.addFile(new MockMultipartFile(name, filename, part.getContentType(), is));
}
else {
InputStreamReader reader = new InputStreamReader(is, getCharsetOrDefault(part, defaultCharset));
String value = FileCopyUtils.copyToString(reader);
request.addParameter(part.getName(), value);
}
}
catch (IOException ex) {
throw new IllegalStateException("Failed to read content for part " + part.getName(), ex);
}
});
return request;
}
private Charset getCharsetOrDefault(Part part, Charset defaultCharset) {
if (part.getContentType() != null) {
MediaType mediaType = MediaType.parseMediaType(part.getContentType());
if (mediaType.getCharset() != null) {
return mediaType.getCharset();
}
}
return defaultCharset;
}
}

View File

@ -215,9 +215,7 @@ public abstract class MockMvcRequestBuilders {
* @since 5.0
*/
public static MockMultipartHttpServletRequestBuilder multipart(String uriTemplate, @Nullable Object... uriVariables) {
MockMultipartHttpServletRequestBuilder builder = new MockMultipartHttpServletRequestBuilder();
builder.uri(uriTemplate, uriVariables);
return builder;
return new MockMultipartHttpServletRequestBuilder().uri(uriTemplate, uriVariables);
}
/**
@ -229,9 +227,7 @@ public abstract class MockMvcRequestBuilders {
* @since 5.3.22
*/
public static MockMultipartHttpServletRequestBuilder multipart(HttpMethod httpMethod, String uriTemplate, @Nullable Object... uriVariables) {
MockMultipartHttpServletRequestBuilder builder = new MockMultipartHttpServletRequestBuilder(httpMethod);
builder.uri(uriTemplate, uriVariables);
return builder;
return new MockMultipartHttpServletRequestBuilder(httpMethod).uri(uriTemplate, uriVariables);
}
/**
@ -240,9 +236,7 @@ public abstract class MockMvcRequestBuilders {
* @since 5.0
*/
public static MockMultipartHttpServletRequestBuilder multipart(URI uri) {
MockMultipartHttpServletRequestBuilder builder = new MockMultipartHttpServletRequestBuilder();
builder.uri(uri);
return builder;
return new MockMultipartHttpServletRequestBuilder().uri(uri);
}
/**
@ -253,9 +247,7 @@ public abstract class MockMvcRequestBuilders {
* @since 5.3.21
*/
public static MockMultipartHttpServletRequestBuilder multipart(HttpMethod httpMethod, URI uri) {
MockMultipartHttpServletRequestBuilder builder = new MockMultipartHttpServletRequestBuilder(httpMethod);
builder.uri(uri);
return builder;
return new MockMultipartHttpServletRequestBuilder(httpMethod).uri(uri);
}
/**