Before this commit, when adding filters to a builder obtained via
`WebClient.mutate()`, the filters were added both to the original client
as well as the mutated builder. This commit fixes that.
Issue: SPR-16059
Prior to this commit, the `ResourceWebHandler` would itself handle the
response with an HTTP 404 in many cases, including a missing static
resource.
This does not give a chance to `WebExceptionHandler` instances to handle
that error and, for example, display an error page.
See spring-projects/spring-boot#8625
Issue: SPR-16023
Concrete server and client, reactive request and response
implementations should not have to be accessed outside their package.
They could be seen as private to their HttpHandler adapters and
ClientHttpConnector's respectively.
The one exception, WebSocket upgrades in spring-webflux, is an internal
framework use case, accommodated via downcast + accessors in the
abstract base classes.
Prior to this commit, the `WebClient` always throws a `ClassCastException`
when an error occurs in `bodyToMono(ParameterizedTypeReference)``, and
not the expected exception, as set up by `onStatus`
Issue: SPR-16025
Prior to this commit, asking for a `Void` type using any of the
`ClientResponse#bodyTo*` methods would immediately return an empty
`Publisher` without consuming the response body.
Not doing so can lead to HTTP connection pool inconsistencies and/or
memory leaks, since:
* a connection that still has a response body being written to it cannot
be properly recycled in the connection pool
* incoming `DataBuffer` might not be released
This commit detects when `Void` types are asked as body types and in
those cases does the following:
1. Subscribe to the response body `Publisher` to allow the connection to
be returned to the connection pool
2. `cancel()` the body `Publisher` if the response body is not empty; in
that case, we choose to close the connection vs. consume the whole
response body
Those changes imply that `ClientHttpResponse` and other related
contracts don't need a `close()` method anymore.
Issue: SPR-16018
Includes unified detection of Kotlin's optional parameters in MethodParameter.isOptional(), reduces BeanUtils.findPrimaryConstructor to Kotlin semantics (for reuse in AutowiredAnnotationBeanPostProcessor), and finally introduces a common KotlinDetector delegate with an isKotlinType(Class) check.
Issue: SPR-15877
Issue: SPR-16020
Prior to this issue, SPR-15920 added this new `close()` method which was
supposed to be called to clean resources after response processing.
This commit changes the meaning of that method: calling `close()` will
close the underlying HTTP connection. This has to be called if the
response body is not consumed by the application, since at that point
the underlying connection might be in an inconsistent state if shared in
a connection pool.
Issue: SPR-15993
This commit moves WebFluxUriComponentsBuilder.fromServerRequest to the
ServerRequest interface itself.
Consequently, the WebFluxUriComponentsBuilder is removes itself, as it
contained no other methods.
Issue: SPR-15953
The typical way to load DispatcherHandler is to use
WebHttpHandlerBuilder#applicationContext which also detecs filters,
exception handlers, as well as other beans that are injected into every
ServerWebExchange -- custom session manager, localecontext resolver,
codecs for form data, multipart data, etc
WebHttpHandlerBuilder is the preferred and way so removing the ones on
DispatcherHandler. They could always be added back later.
This commit introduces a visitor for router functions
(RouterFunctions.Visitor), allowing to iterate over all the components
that make up a router function.
This commit also introduces a ToStringVisitor, which creates a nicely
formatted string for use with toString().
Issue: SPR-15711, SPR-15711
This commit introduces the WebFluxUriComponentsBuilder, with a single
method that creates a UriComponentsBuilder for a ServerRequest. More
methods to be added by @rstoyanchev.
Issue: SPR-15953
This commit introduces a methodName() method to the ServerRequest,
returning the String name of the method. This method is useful for
non-standard HTTP methods.
This commit introduces the following changes.
1) It adds a new Spring @NonNull annotation which allows to apply
@NonNullApi semantic on a specific element, like @Nullable does.
Combined with @Nullable, it allows partial null-safety support when
package granularity is too broad.
2) @Nullable and @NonNull can apply to ElementType.TYPE_USE in order
to be used on generic type arguments (SPR-15942).
3) Annotations does not apply to ElementType.TYPE_PARAMETER anymore
since it is not supported yet (applicability for such use case is
controversial and need to be discussed).
4) @NonNullApi does not apply to ElementType.FIELD anymore since in a
lot of use cases (private, protected) it is not part for the public API
+ its usage should remain opt-in. A dedicated @NonNullFields annotation
has been added in order to set fields default to non-nullable.
5) Updated Javadoc and reference documentation.
Issue: SPR-15756
This commit fixes a typo in the `DefaultWebClient` implementation.
Instead of forwarding resolved `WebClientException` instances as error
signals, the `bodyToMono(ParameterizedTypeReference)` variant would just
forward those exceptions as `onNext` signals.
Issue: SPR-15946
Prior to that commit, the `ResponseSpec` `WebClient` would process error
responses (4xx, 5xx HTTP status) and transform those into error signals
with a `WebClientResponseException`. But this would only work if the
HTTP response would have a non-empty response body.
An empty error response would not send an error signal and only
translate in an `onComplete` signal.
This commit fixes this behavior and makes sure that this error signal is
sent in all cases.
Issue: SPR-15946
Before this commit, there was no way to signal the HTTP client that we
were done consuming the response. Without that, the underlying client
library cannot know when it is safe to release the associated resources
(e.g. the HTTP connection).
This commit adds new `close()` methods on both `ClientHttpResponse`
and `ClientResponse`. This methods is non-blocking and its behavior
depends on the library, its configuration, HTTP version, etc.
At the `WebClient` level, `close()` is called automatically if we
consume the response body through the `ResponseSpec` or the
`ClientResponse` itself.
Note that it is *required* to call `close()` manually otherwise; not
doing so might create resource leaks or connection issues.
Issue: SPR-15920
This commit moves `encodeUrl` and `registerUrlEncoder` from
ServerHttpResponse to ServerWebExchange.
It also renames `encodeUrl` to `transformUrl` and `registerUrlEncoder`
to `addUrlTransformer` to make it clearer that these methods do not
perform actual URL encodings (i.e. they do not replaceinvalid
characters).
The `add` prefix (instead of `register`) makes it clearer that each
function is added in addition to the previous one.
Issue: SPR-15924
This commit applies the Dependency Management Plugin to modules that
require it; right now Spring Framework is importing BOMs for Netty and
Reactor dependencies only.
Instead of applying those BOMs to all modules, they're applied only
where they're needed.
Issue: SPR-15885
The main `build.gradle` file contains now only the common build
infrastructure; all module-specific build configurations have
been moved to their own build file.
Issue: SPR-15885
The PathPattern compareTo method is now consistent with equals when
two patterns are of the same specificity but otherwise different.
Separately PathPattern now exposes a Comparator by specificity that
offers the current functionality of compareTo. This can be used for
actual sorting where we only care about specificity.
Consistent behavior with matches(PathContainer), the two had slightly
different logic for handling of empty paths.
Make matchAndExtract independantly usable without the need to call
matches(PathContainer) first. Essentially no longer raising ISE if the
pattern doesn't match but simply returning null.
Rename getPathRemaining to matchStartOfPath since the method does
match and to be more clear about what the method and the return value
intuitively follows.
Remove matchStart which matches the start of the pattern (rather than
the start of the path). It is a use case that does not come up in
request mapping.
This commit changes the WebClient so that it now throws a
`WebClientResponseException` for `ResponseSpec.bodyTo`. This newly
introduces exception contains the status code, headers, and body of the
response message.
As a consequence of the above, we had to change `onStatus` so that the
`exceptionFunction` now returns a `Mono<Throwable>` rather than a
`Throwable`, which it was before. The Mono allows for asynchronous
operations, such as reading the contents of the body.
Issue: SPR-15824
Removed superfluous `fromServerSentEvent` variants from `BodyInserters`,
as their functionality can also be obtained by passing a stream of
strings or POJOs (to be encoded as JSON) to
`fromPublisher(Publisher, Class)}`, and specifying a `text/event-stream`
Content-Type.
Issue: SPR-15826
This commit also removes WebFlux non-extension functions in favor of
regular Kotlin extensions leveraging ParameterizedTypeReference parameter.
Issue: SPR-15818
This commit changes the usage of two separate attributes (username and
password) into one: a single `Credentials` object.
Additionally, the attributes key under which the credentials are stored
is changed to be specific to Basic Authentication, in order to allow for
other sorts of authentication later.
Issue: SPR-15764
This commit changes adds overloaded `ParameterizedTypeReference `
variants to body-related methods in `ServerRequest` and
`ServerResponse`.
It also adds a single PTR variant to ClientRequest, which was missing
before.
Issue: SPR-15817
This commit changes all consumers of CodecConfigurer to consume a `List`
of HttpMessageReaders or HttpMessageWriters instead of consuming the
Server- or ClientCodecConfigurer directly.
Issue: SPR-15816
This commit ensure that null-safety is consistent between
getters and setters in order to be able to provide beans
with properties with a common type when type safety is
taken in account like with Kotlin.
It also add a few missing property level @Nullable
annotations.
Issue: SPR-15792
Since there is no reason for an exchange to ever complete without a
ClientResponse I've added a switchIfEmpty check at the WebClient level.
Also, temporarily a second check closer to the problem in the
ReactorClientHttpConnector suggesting a workaround and providing a
reference to the Reactor Netty issue #138.
Issue: SPR-15784
Collapse the base interface VersionPathStrategy into its extension
VersionStrategy and then turn the prefix nad fliename based
implementations into abstract base classes (vs delegate strategies).
It is simpler to have one VersionStrategy hierarchy vs that plus a
separate VersionPathStrategy as a delegate. In practice each
VersionStrategy is suited to be prefix or filename based. Also none
of our code cares about the distinction between those two interfaces.
Since `PathPattern.combine` now returns another `PathPattern` instance
(it was previously returning a String instance), we can now safely
remove the parser instance included in `PatternsRequestCondition`.
Issue: SPR-15663
Use copy constructor to refresh a session with lastAccessTime and a
save function referencing the current exchange. As a result both fields
are now final and ConfigurableWebSession is no longer needed.
This commit introduces overloaded variants of `bodytoMono`,
`bodyToFlux`, `toEntity`, and `toEntityList` that take a
`ParameterizedTypeReference`. It also adds similar methods to
`WebClient.ResponseSpec`.
Issue: SPR-15725
This binary format more efficient than JSON should be useful for server
to server communication, for example in micro-services use cases.
Issue: SPR-15424
This commit introduces an apply method to `WebClient.Builder`, allowing
users to make multiple changes to the builder in one consumer.
Issue: SPR-15743
The failures look like older failures possibly exposed by recent
changes in Reactor.
The one in ViewResolutionResultHandler is very old test error.
The one in Jackson2JsonDecoderTests is more recent but went unreported.
This commit moves `toEntity(Class<T>)` and `toEntityList(Class<T>)`
from WebClient.ResponseSpec to ClientResponse. The main reason for doing
so is that the newly introduced `onStatus` method (see
2f9bd6e075) does not apply to these two
methods, and the result would be confusing. Also, `ClientResponse` and
`ResponseEntity` represent the same data: status code, headers, and a
body.
Issue: SPR-15724
This commit introduces a way to customize the WebClientExceptions, as
thrown by WebClient.ResponseSpec.bodyTo[Mono|Flux]. The first
customization will override the defaults, additional customizations are
simply tried in order.
Issue: SPR-15724
This commit changes `ServerRequest.attribute(String)`` to return
`Optional<Object>` instead of `Optional<T>`, where `T` was infered
from a type parameter.
This commit makes the `uri` step of the WebClient optional, so that
users who have specified a base URL during WebClient config do not need
to provide an empty one (i.e. `url("")`).
The basic idea of this fix is that the HTTP method methods in WebClient
(`get`, `post`, etc.) should be able to "bypass" the uri stage, and skip
straight to defining headers, or even doing an exchange or retrieve
(i.e. call methods on `RequestHeaderSpec` or `RequestBodySpec`).
I have accomplished this by adding two new composed interfaces:
`RequestHeadersUriSpec` and `RequestBodyUriSpec`.
`RequestHeadersUriSpec` extends from the existing `UriSpec` and
`RequestHeaderSpec`, while `RequestBodyUriSpec` extends from `UriSpec`
and `RequestBodySpec`. These types are returned from the HTTP methods
(`get`, `post` etc). The `uri` methods on these types return a plain
`RequestHeaderSpec` and `RequestBodySpec` (i.e. types without the `uri`
methods), so that you can call `uri` once only.
Issue: SPR-15695
Explicitly pass the client-side JSR-356 WebSocketContainer to the
TomcatWebSocketClient to prevent the ContainerProvider from finding
the one from undertow-websockets-jsr through the ServiceLoader API.
This commit disables the "failOnServerError" feature on the
`HttpClientRequest`, as wrapped by ReactorClientHttpRequest. 5xx errors
are supposed to be dealt with in the WebClient, not in the lower-level
components.
Issue: SPR-15739
This commit introduces client-side request attributes, similar to those
found on the server-side. The attributes can be used, for instance, for
passing on request-specific information to a globally registered
ExchangeFilterFunction.
The client request builder, as well as WebClient.RequestHeadersSpec and
WebTestClient.RequestHeaderSpec, add methods for adding a single
attribute, as well as manipulating the entire attributes map.
The client request itself adds a accessor for the (immutable) attributes
map.
This commit also introduces a new variant of the basic authentication
filter in ExchangeFilterFunctions. This variant takes the username and
password from well-known attributes.
Issue: SPR-15691
Previously `UrlBasedCorsConfigurationSource` was relying on
`PathMatcher` implementations for matching incoming request lookup paths
with the configured path patterns for CORS configuration.
This commit replaces the use of `PathMatcher` with a `PathPatternParser`
that parses the string patterns into `PathPattenr` instances and allows
for faster matching against lookup paths.
Issue: SPR-15688
This commit changes ServerRequest.queryParams from returning a
List<String> given a String name, to returning a
MultiValueMap<String, String>, which gives more flexibility.
This commit uses the newly introduced `PathContainer` and `RequestPath`
support in the functional web framework. It exposes the path container
as property in `ServerRequest`, and uses that in the path-based
`RequestPredicates`.
Direct comparison of a pattern (as a String) to the path does not make
much sense now that we deal with URL encoding through PathContainer
which exposes (safely) decoded path segments.
Removing the PathPatternComparator also means we can keep patterns
pre-sorted instead of sorting them all the time. That probably offsets
any benefits from comparing to the lookup path for direct matches and
patterns are still sorted according to specificity.
This commits extends nullability declarations to the field level, formalizing the interaction between methods and their underlying fields and therefore avoiding any nullability mismatch.
Issue: SPR-15720
This commit adds a new `cloneBuilder()` method on `WebClient.Builder`;
we can now reuse the customizations of an existing builder without
sharing its state across several `WebClient` building code paths.
Issue: SPR-15690
This commit introduces 2 new public methods in HttpHeaders in order
to leverage Java 8 ZonedDateTime in addition to the existing long
(with GMT time zone implied) variants:
- ZonedDateTime getFirstZonedDateTime(String headerName)
- void setZonedDateTime(String headerName, ZonedDateTime date)
This commit also leverages Java 8 thread-safe DateTimeFormatter for
HttpHeader implementation instead of SimpleDateFormat. As a consequence
of the usage of DateTimeFormatter.RFC_1123_DATE_TIME, HTTP date header
serialization could change slightly for single digit days from for
example "Thu, 01 Jan 1970 00:00:00 GMT" to
"Thu, 1 Jan 1970 00:00:00 GMT".
Issue: SPR-15661
This commit adds support for Void response body types in the WebClient,
both when using `exchange` with a response.bodyToMono(Void.class), as
well as using `retrieve` with `toEntity(Void.class)`.
Issue: SPR-15679
This commit replaces the WebClient.filter method with
WebClient.Builder.filter. The reason for this change is that filters
added via WebClient.filter would be applied in the opposite order of
their declaration, due to the compositional nature of the method,
combined with the immutable nature of the WebClient.
WebClient.Builder.filter does keep the order of the filters, as
registered.
Furthermore, this commit introduces a WebClient.mutate() method,
returning a WebClient.Builder. This method allow to add/remove filters
and other defaults from a given WebClient.
Issue: SPR-15657
Add WebClient.Builder.addFilter
Add Consumer-based headers and cookies methods to builders.
Add WebClient.mutate
This commit changes the `ExchangeStrategies` and `HandlerStrategies`
interfaces to consistently use the `CodecConfigurer` (and
sub-interfaces) for configuring codecs on the server and on the client.
Issue: SPR-15682
Supporting ScriptEngine#eval(String, Bindings) when no render function
is specified allows to support use cases where script templates are
simply evaluating a script expression with an even more simplified
configuration.
This improvement also makes it possible to use script engines that
do not implement Invocable.
Issue: SPR-15115
This commit introduces LocaleContextResolver interface, which is used
at ServerWebExchange level to resolve Locale, TimeZone and other i18n
related informations.
It follows Spring MVC locale resolution patterns with a few differences:
- Only LocaleContextResolver is supported since LocaleResolver is less
flexible
- Support is implemented in the org.springframework.web.server.i18n
package of spring-web module rather than in spring-webflux in order
to be able to leverage it at ServerWebExchange level
2 implementations are provided:
- FixedLocaleContextResolver
- AcceptHeaderLocaleContextResolver
It can be configured with both functional or annotation-based APIs.
Issue: SPR-15036
Previously `HandlerMapping` implementation were heavily relying on
`String` path patterns, `PathMatcher` implementations and dedicated maps
for matching incoming request URL to an actual request handler.
This commit adds the `PathPatternRegistry` that holds `PathPattern`
instances and the associated request handler — matching results are then
shared as `PathMatchResult` instances. `AbstractUrlHandlerMapping` will
use this registry directly, but other components dealing with request
matching (like `PatternsRequestCondition`) will directly use ordered
`PathPattern` collections since ordering is important there.
This opens the door for faster request matching and simplifies the
design of this part.
Issue: SPR-15608
This commit removes the headers(HttpHeaders) method on ClientRequest and
ServerResponse, in favor of headers(Consumer<HttpHeaders>), which is
more flexible.
The revised builder emphasizes creating a list of resolvers either
built-in or custom with each top-level builder method resulting in
adding a resolver.
By default only the Header resolver is configured.
The path extension resolver is removed altogether to discourage its use
but is trivial to create manually with the helpf of
UriUtils#extractFileExtension + MediaTypeFactory.
Issue: SPR-15639
After the removal of suffix pattern matches, there is no longer a need
to expose the list of registered file extensions.
Also polish, refactor, and simplify the abstract base class
AbstractMappingContentTypeResolver and its sub-classes.
Issue: SPR-15639
There is no need for ResourceWebHandler to go through the
PathExtensionContentTypeResolver when MediaTypeFactory makes it easy to
perform such lookups for a given Resource.
This does not support any extensions explicitly registered through a
WebFluxConfigurer but it would be easy enough to pass those into
ResourceWebHandler as a simple Map<String, MediaType>, should the need
arise.
Issue: SPR-15639
The use of the undecoded URL path by default and the removal of suffix
pattern matching effectively means HttpRequestPathHelper is no longer
needed.
Issue: SPR-15640, SPR-15639
Introduce pathWithinApplication() in ServerHttpRequest and use it for
request mapping purposes instead of LookupPath.
In turn this means that for request mapping purposes:
1) the path is not decoded
2) suffix pattern matching is not supported
Issue: SPR-15640
This commit changes the use of `ResolvableType` to
`ParameterizedTypeReference` in all public-facing WebFlux APIs. This
change removes the necessity for providing the parameterized type
information twice: once for creating the `ResolvableType`, and once for
specifying a `BodyExtractor`.
Issue: SPR-15636
This commit also removes nullability from two common spots: ResolvableType.getType() and TargetSource.getTarget(), both of which are never effectively null with any regular implementation. For such scenarios, a non-null empty type/target is the cleaner contract.
Issue: SPR-15540
This commit adds two Consumer based methods to ClientRequest that allow
for direct manipulation of the underlying headers or cookies map. As
such, these methods can be used to override or remove existing entries.
Issue: SPR-15635
This commit changes the `headers(HttpHeaders)` method in
DefaultClientRequestBuilder so that it copies the individual header
values instead of using the `List<String>` value directly. The reason
for this change is that the list of values can be immutable, and adding
additional values after that could result in
UnsupportedOperationExceptions.
Beyond just formally declaring the current behavior, this revision actually enforces non-null behavior in selected signatures now, not tolerating null values anymore when not explicitly documented. It also changes some utility methods with historic null-in/null-out tolerance towards enforced non-null return values, making them a proper citizen in non-null assignments.
Some issues are left as to-do: in particular a thorough revision of spring-test, and a few tests with unclear failures (ignored as "TODO: NULLABLE") to be sorted out in a follow-up commit.
Issue: SPR-15540
Restore matrix variable parsing code not resorting to the use of
WebUtils which brings Servlet API dependencies with it.
Instead the parsing logic is now exposed through HttpRequestPathHelper
which already contained the decoding logic and also the knowledge of
whether to decode the parsed variables or not.
Issue: SPR-15397
This commit adds the `LookupPath` class that contains the full
request path relative to the web context; the application can
get from it various information, including the file extension
and path parameters (if any).
Since that operation is done multiple times for each request, this
object is stored as an attribute at the `ServerWebExchange` level.
Issue: SPR-15397
With the new `ParsingPathMatcher` implementation, new patterns are now
allowed, such as `"/foo/{*bar}". The `"{*bar}"` segment will capture
everything until the end of the given path. Adding other elements after
that segment is illegal and will throw exceptions.
One can configure on a `PathMatchConfigurer` various options like
`useTrailingSlashMatch` and `useSuffixPatternMatch`; those options, when
enabled, will try to append suffixes like `".*"` and `"/"` to existing
path patterns. In case of a "capture the rest" pattern segment, those
options won't be honored.
This is why this commit ensures that an exception is thrown at the start
of the application if an illegal configuration is applied to the
`PathMatchConfigurer`.
Issue: SPR-15303, SPR-15558