Merge branch '5.3.x'

This commit is contained in:
rstoyanchev 2022-11-11 15:16:26 +00:00
commit e0b405869f
8 changed files with 67 additions and 36 deletions

View File

@ -2015,10 +2015,9 @@ generally supported for all return values.
to be written (however, `text/event-stream` must be requested or declared in the mapping
through the `produces` attribute).
| Any other return value
| If a return value is not matched to any of the above, it is, by default, treated as a view
name, if it is `String` or `void` (default view name selection applies), or as a model
attribute to be added to the model, unless it is a simple type, as determined by
| Other return values
| If a return value remains unresolved in any other way, it is treated as a model
attribute, unless it is a simple type as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty],
in which case it remains unresolved.
|===

View File

@ -2282,23 +2282,18 @@ supported for all return values.
| Write to the response `OutputStream` asynchronously. Also supported as the body of a
`ResponseEntity`. See <<mvc-ann-async>> and <<mvc-ann-async-http-streaming>>.
| Reactive types -- Reactor, RxJava, or others through `ReactiveAdapterRegistry`
| Alternative to `DeferredResult` with multi-value streams (for example, `Flux`, `Observable`)
collected to a `List`.
| Reactor and other reactive types registered via `ReactiveAdapterRegistry`
| A single value type, e.g. `Mono`, is comparable to returning `DeferredResult`.
A multi-value type, e.g. `Flux`, may be treated as a stream depending on the requested
media type, e.g. "text/event-stream", "application/json+stream", or otherwise is
collected to a List and rendered as a single value. See <<mvc-ann-async>> and
<<mvc-ann-async-reactive-types>>.
For streaming scenarios (for example, `text/event-stream`, `application/json+stream`),
`SseEmitter` and `ResponseBodyEmitter` are used instead, where `ServletOutputStream`
blocking I/O is performed on a Spring MVC-managed thread and back pressure is applied
against the completion of each write.
See <<mvc-ann-async>> and <<mvc-ann-async-reactive-types>>.
| Any other return value
| Any return value that does not match any of the earlier values in this table and that
is a `String` or `void` is treated as a view name (default view name selection through
`RequestToViewNameTranslator` applies), provided it is not a simple type, as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty].
Values that are simple types remain unresolved.
| Other return values
| If a return value remains unresolved in any other way, it is treated as a model
attribute, unless it is a simple type as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty],
in which case it remains unresolved.
|===

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -54,6 +54,10 @@ public abstract class InterceptingHttpAccessor extends HttpAccessor {
* Set the request interceptors that this accessor should use.
* <p>The interceptors will get immediately sorted according to their
* {@linkplain AnnotationAwareOrderComparator#sort(List) order}.
* <p><strong>Note:</strong> This method does not support concurrent changes,
* and in most cases should not be called after initialization on startup.
* See also related note on {@link org.springframework.web.client.RestTemplate}
* regarding concurrent configuration changes.
* @see #getRequestFactory()
* @see AnnotationAwareOrderComparator
*/

View File

@ -78,11 +78,17 @@ import org.springframework.web.util.UriTemplateHandler;
/**
* Synchronous client to perform HTTP requests, exposing a simple, template
* method API over underlying HTTP client libraries such as the JDK
* {@code HttpURLConnection}, Apache HttpComponents, and others.
* {@code HttpURLConnection}, Apache HttpComponents, and others. RestTemplate
* offers templates for common scenarios by HTTP method, in addition to the
* generalized {@code exchange} and {@code execute} methods that support of
* less frequent cases.
*
* <p>The RestTemplate offers templates for common scenarios by HTTP method, in
* addition to the generalized {@code exchange} and {@code execute} methods that
* support of less frequent cases.
* <p>RestTemplate is typically used as a shared component. However, its
* configuration does not support concurrent modification, and as such its
* configuration is typically prepared on startup. If necessary, you can create
* multiple, differently configured RestTemplate instances on startup. Such
* instances may use the same the underlying {@link ClientHttpRequestFactory}
* if they need to share HTTP client resources.
*
* <p><strong>NOTE:</strong> As of 5.0 this class is in maintenance mode, with
* only minor requests for changes and bugs to be accepted going forward. Please,

View File

@ -17,6 +17,7 @@
package org.springframework.web.reactive.function.client;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
@ -53,6 +54,7 @@ import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.BodyExtractor;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
@ -713,10 +715,22 @@ class DefaultWebClient implements WebClient {
}
private <T> Mono<T> insertCheckpoint(Mono<T> result, HttpStatusCode statusCode, HttpRequest request) {
HttpMethod httpMethod = request.getMethod();
HttpMethod method = request.getMethod();
URI uri = getUriToLog(request);
return result.checkpoint(statusCode + " from " + method + " " + uri + " [DefaultWebClient]");
}
private static URI getUriToLog(HttpRequest request) {
URI uri = request.getURI();
String description = statusCode + " from " + httpMethod + " " + uri + " [DefaultWebClient]";
return result.checkpoint(description);
if (StringUtils.hasText(uri.getQuery())) {
try {
uri = new URI(uri.getScheme(), uri.getHost(), uri.getPath(), null);
}
catch (URISyntaxException ex) {
// ignore
}
}
return uri;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -73,9 +73,12 @@ public abstract class AbstractWebSocketSession<T> implements WebSocketSession {
this.id = id;
this.handshakeInfo = info;
this.bufferFactory = bufferFactory;
this.attributes.putAll(info.getAttributes());
this.logPrefix = initLogPrefix(info, id);
info.getAttributes().entrySet().stream()
.filter(entry -> (entry.getKey() != null && entry.getValue() != null))
.forEach(entry -> this.attributes.put(entry.getKey(), entry.getValue()));
if (logger.isDebugEnabled()) {
logger.debug(getLogPrefix() + "Session id \"" + getId() + "\" for " + getHandshakeInfo().getUri());
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -62,7 +62,9 @@ public abstract class AbstractWebSocketSession<T> implements NativeWebSocketSess
*/
public AbstractWebSocketSession(@Nullable Map<String, Object> attributes) {
if (attributes != null) {
this.attributes.putAll(attributes);
attributes.entrySet().stream()
.filter(entry -> (entry.getKey() != null && entry.getValue() != null))
.forEach(entry -> this.attributes.put(entry.getKey(), entry.getValue()));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -36,6 +36,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
*
* @author Rossen Stoyanchev
*/
@SuppressWarnings("resource")
public class StandardWebSocketSessionTests {
private final HttpHeaders headers = new HttpHeaders();
@ -53,7 +54,6 @@ public class StandardWebSocketSessionTests {
}
@Test
@SuppressWarnings("resource")
public void getPrincipalWithNativeSession() {
TestPrincipal user = new TestPrincipal("joe");
@ -67,7 +67,6 @@ public class StandardWebSocketSessionTests {
}
@Test
@SuppressWarnings("resource")
public void getPrincipalNone() {
Session nativeSession = Mockito.mock(Session.class);
given(nativeSession.getUserPrincipal()).willReturn(null);
@ -82,7 +81,6 @@ public class StandardWebSocketSessionTests {
}
@Test
@SuppressWarnings("resource")
public void getAcceptedProtocol() {
String protocol = "foo";
@ -98,4 +96,14 @@ public class StandardWebSocketSessionTests {
verifyNoMoreInteractions(nativeSession);
}
@Test // gh-29315
public void addAttributesWithNullKeyOrValue() {
this.attributes.put(null, "value");
this.attributes.put("key", null);
this.attributes.put("foo", "bar");
assertThat(new StandardWebSocketSession(this.headers, this.attributes, null, null).getAttributes())
.hasSize(1).containsEntry("foo", "bar");
}
}