Merge branch '5.2.x'

This commit is contained in:
Juergen Hoeller 2020-09-18 19:14:57 +02:00
commit 2a74f20c99
3 changed files with 32 additions and 37 deletions

View File

@ -97,8 +97,6 @@ public abstract class StreamUtils {
/** /**
* Copy the contents of the given {@link ByteArrayOutputStream} into a {@link String}. * Copy the contents of the given {@link ByteArrayOutputStream} into a {@link String}.
* <p>This is a more effective equivalent of {@code new String(baos.toByteArray(), charset)}. * <p>This is a more effective equivalent of {@code new String(baos.toByteArray(), charset)}.
* <p>As long as the {@code charset} is already available at the point of
* invocation, no exception is expected to be thrown by this method.
* @param baos the {@code ByteArrayOutputStream} to be copied into a String * @param baos the {@code ByteArrayOutputStream} to be copied into a String
* @param charset the {@link Charset} to use to decode the bytes * @param charset the {@link Charset} to use to decode the bytes
* @return the String that has been copied to (possibly empty) * @return the String that has been copied to (possibly empty)
@ -108,10 +106,12 @@ public abstract class StreamUtils {
Assert.notNull(baos, "No ByteArrayOutputStream specified"); Assert.notNull(baos, "No ByteArrayOutputStream specified");
Assert.notNull(charset, "No Charset specified"); Assert.notNull(charset, "No Charset specified");
try { try {
// Can be replaced with toString(Charset) call in Java 10+
return baos.toString(charset.name()); return baos.toString(charset.name());
} }
catch (UnsupportedEncodingException ex) { catch (UnsupportedEncodingException ex) {
throw new RuntimeException("Failed to copy contents of ByteArrayOutputStream into a String", ex); // Should never happen
throw new IllegalArgumentException("Invalid charset name: " + charset, ex);
} }
} }
@ -262,6 +262,7 @@ public abstract class StreamUtils {
return new NonClosingOutputStream(out); return new NonClosingOutputStream(out);
} }
private static class NonClosingInputStream extends FilterInputStream { private static class NonClosingInputStream extends FilterInputStream {
public NonClosingInputStream(InputStream in) { public NonClosingInputStream(InputStream in) {

View File

@ -56,14 +56,15 @@ import org.springframework.web.util.UriComponentsBuilder;
/** /**
* Default {@link ServerRequest.Builder} implementation. * Default {@link ServerRequest.Builder} implementation.
*
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 5.2 * @since 5.2
*/ */
class DefaultServerRequestBuilder implements ServerRequest.Builder { class DefaultServerRequestBuilder implements ServerRequest.Builder {
private final List<HttpMessageConverter<?>> messageConverters; private final HttpServletRequest servletRequest;
private HttpServletRequest servletRequest; private final List<HttpMessageConverter<?>> messageConverters;
private String methodName; private String methodName;
@ -80,8 +81,8 @@ class DefaultServerRequestBuilder implements ServerRequest.Builder {
public DefaultServerRequestBuilder(ServerRequest other) { public DefaultServerRequestBuilder(ServerRequest other) {
Assert.notNull(other, "ServerRequest must not be null"); Assert.notNull(other, "ServerRequest must not be null");
this.messageConverters = other.messageConverters();
this.servletRequest = other.servletRequest(); this.servletRequest = other.servletRequest();
this.messageConverters = other.messageConverters();
this.methodName = other.methodName(); this.methodName = other.methodName();
this.uri = other.uri(); this.uri = other.uri();
headers(headers -> headers.addAll(other.headers().asHttpHeaders())); headers(headers -> headers.addAll(other.headers().asHttpHeaders()));
@ -157,10 +158,8 @@ class DefaultServerRequestBuilder implements ServerRequest.Builder {
@Override @Override
public ServerRequest build() { public ServerRequest build() {
return new BuiltServerRequest(this.servletRequest, this.methodName, this.uri,
return new BuiltServerRequest(this.servletRequest, this.headers, this.cookies, this.attributes, this.body, this.messageConverters);
this.methodName, this.uri, this.headers, this.cookies, this.attributes, this.body,
this.messageConverters);
} }
@ -174,7 +173,7 @@ class DefaultServerRequestBuilder implements ServerRequest.Builder {
private final HttpServletRequest servletRequest; private final HttpServletRequest servletRequest;
private MultiValueMap<String, Cookie> cookies; private final MultiValueMap<String, Cookie> cookies;
private final Map<String, Object> attributes; private final Map<String, Object> attributes;
@ -186,6 +185,7 @@ class DefaultServerRequestBuilder implements ServerRequest.Builder {
HttpHeaders headers, MultiValueMap<String, Cookie> cookies, HttpHeaders headers, MultiValueMap<String, Cookie> cookies,
Map<String, Object> attributes, byte[] body, Map<String, Object> attributes, byte[] body,
List<HttpMessageConverter<?>> messageConverters) { List<HttpMessageConverter<?>> messageConverters) {
this.servletRequest = servletRequest; this.servletRequest = servletRequest;
this.methodName = methodName; this.methodName = methodName;
this.uri = uri; this.uri = uri;
@ -251,9 +251,7 @@ class DefaultServerRequestBuilder implements ServerRequest.Builder {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T> T bodyInternal(Type bodyType, Class<?> bodyClass) private <T> T bodyInternal(Type bodyType, Class<?> bodyClass) throws ServletException, IOException {
throws ServletException, IOException {
HttpInputMessage inputMessage = new BuiltInputMessage(); HttpInputMessage inputMessage = new BuiltInputMessage();
MediaType contentType = headers().contentType().orElse(MediaType.APPLICATION_OCTET_STREAM); MediaType contentType = headers().contentType().orElse(MediaType.APPLICATION_OCTET_STREAM);
@ -313,6 +311,7 @@ class DefaultServerRequestBuilder implements ServerRequest.Builder {
return this.servletRequest; return this.servletRequest;
} }
private class BuiltInputMessage implements HttpInputMessage { private class BuiltInputMessage implements HttpInputMessage {
@Override @Override

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -54,6 +54,7 @@ import org.springframework.web.servlet.ModelAndView;
/** /**
* Default {@link ServerResponse.BodyBuilder} implementation. * Default {@link ServerResponse.BodyBuilder} implementation.
*
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 5.2 * @since 5.2
*/ */
@ -184,6 +185,7 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
@Override @Override
public ServerResponse build( public ServerResponse build(
BiFunction<HttpServletRequest, HttpServletResponse, ModelAndView> writeFunction) { BiFunction<HttpServletRequest, HttpServletResponse, ModelAndView> writeFunction) {
return new WriterFunctionResponse(this.statusCode, this.headers, this.cookies, writeFunction); return new WriterFunctionResponse(this.statusCode, this.headers, this.cookies, writeFunction);
} }
@ -241,7 +243,6 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
private final List<ErrorHandler<?>> errorHandlers = new ArrayList<>(); private final List<ErrorHandler<?>> errorHandlers = new ArrayList<>();
protected AbstractServerResponse( protected AbstractServerResponse(
int statusCode, HttpHeaders headers, MultiValueMap<String, Cookie> cookies) { int statusCode, HttpHeaders headers, MultiValueMap<String, Cookie> cookies) {
@ -322,8 +323,7 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
if (servletResponse.getCharacterEncoding() == null && if (servletResponse.getCharacterEncoding() == null &&
this.headers.getContentType() != null && this.headers.getContentType() != null &&
this.headers.getContentType().getCharset() != null) { this.headers.getContentType().getCharset() != null) {
servletResponse servletResponse.setCharacterEncoding(this.headers.getContentType().getCharset().name());
.setCharacterEncoding(this.headers.getContentType().getCharset().name());
} }
} }
@ -334,8 +334,8 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
} }
@Nullable @Nullable
protected abstract ModelAndView writeToInternal(HttpServletRequest request, protected abstract ModelAndView writeToInternal(
HttpServletResponse response, Context context) HttpServletRequest request, HttpServletResponse response, Context context)
throws ServletException, IOException; throws ServletException, IOException;
@Nullable @Nullable
@ -346,21 +346,20 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
.filter(errorHandler -> errorHandler.test(t)) .filter(errorHandler -> errorHandler.test(t))
.findFirst() .findFirst()
.map(errorHandler -> { .map(errorHandler -> {
ServerRequest serverRequest = ServerRequest serverRequest = (ServerRequest)
(ServerRequest) servletRequest servletRequest.getAttribute(RouterFunctions.REQUEST_ATTRIBUTE);
.getAttribute(RouterFunctions.REQUEST_ATTRIBUTE);
ServerResponse serverResponse = errorHandler.handle(t, serverRequest); ServerResponse serverResponse = errorHandler.handle(t, serverRequest);
try { try {
return serverResponse.writeTo(servletRequest, servletResponse, context); return serverResponse.writeTo(servletRequest, servletResponse, context);
} }
catch (ServletException ex) { catch (ServletException ex) {
throw new RuntimeException(ex); throw new IllegalStateException(ex);
} }
catch (IOException ex) { catch (IOException ex) {
throw new UncheckedIOException(ex); throw new UncheckedIOException(ex);
} }
}) })
.orElseThrow(() -> new RuntimeException(t)); .orElseThrow(() -> new IllegalStateException(t));
} }
@ -373,6 +372,7 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
public ErrorHandler(Predicate<Throwable> predicate, public ErrorHandler(Predicate<Throwable> predicate,
BiFunction<Throwable, ServerRequest, T> responseProvider) { BiFunction<Throwable, ServerRequest, T> responseProvider) {
Assert.notNull(predicate, "Predicate must not be null"); Assert.notNull(predicate, "Predicate must not be null");
Assert.notNull(responseProvider, "ResponseProvider must not be null"); Assert.notNull(responseProvider, "ResponseProvider must not be null");
this.predicate = predicate; this.predicate = predicate;
@ -387,8 +387,6 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
return this.responseProvider.apply(t, serverRequest); return this.responseProvider.apply(t, serverRequest);
} }
} }
} }
@ -396,24 +394,21 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
private final BiFunction<HttpServletRequest, HttpServletResponse, ModelAndView> writeFunction; private final BiFunction<HttpServletRequest, HttpServletResponse, ModelAndView> writeFunction;
public WriterFunctionResponse(
public WriterFunctionResponse(int statusCode, HttpHeaders headers, int statusCode, HttpHeaders headers, MultiValueMap<String, Cookie> cookies,
MultiValueMap<String, Cookie> cookies,
BiFunction<HttpServletRequest, HttpServletResponse, ModelAndView> writeFunction) { BiFunction<HttpServletRequest, HttpServletResponse, ModelAndView> writeFunction) {
super(statusCode, headers, cookies); super(statusCode, headers, cookies);
Assert.notNull(writeFunction, "WriteFunction must not be null"); Assert.notNull(writeFunction, "WriteFunction must not be null");
this.writeFunction = writeFunction; this.writeFunction = writeFunction;
} }
@Override @Override
protected ModelAndView writeToInternal(HttpServletRequest request, protected ModelAndView writeToInternal(
HttpServletResponse response, Context context) { HttpServletRequest request, HttpServletResponse response, Context context) {
return this.writeFunction.apply(request, response); return this.writeFunction.apply(request, response);
} }
} }
} }