Rename to MappingContentTypeResolver and replace "fileExtension" with
"key" in methods to be more general (e.g. file extension or query
param). Also switch from List to Set for the return values.
A pretty complete equivalent to the same in spring-webmvc except for
CORS checks, and custom HTTP methods. Another notable difference is
that the "params" condition works on query params strictly.
This commit adds AbstractHandlerMethodMapping, a starting point for
AbstractHandlerMapping, and HttpRequestPathHelper with a similar
purpose to UrlPathHelper but based with ServerWebExchange as input.
- correct name of HttpHandlerHandlerAdapter to WebHandlerHandlerAdapter
- shorten SimpleHandlerResultHandler to SimpleResultHandler
- add HandlerResult constructor without Model
- update tests
This commit adds the "*/*" media type in the list of compatible media
types for the StringDecoder. This allows this decoder to decoder
payloads of any media type as long as the target type is String.
Fixes#87
This commit underlines the fact that the request created by a
ClientHttpRequestFactory should be augmented with a message body using
the `ClientHttpRequest#setBody` method before it is executed.
See #82
This commit makes messageEncoders a required argument for building a
client request - those are needed to actually encode the body object as
a reactive stream to be written to the HTTP request body.
Removed raw types usage in DefaultHttpRequestBuilder.
DefaultHttpRequestBuilder now uses a UriTemplateHandler to expand URI
templates + variables into a concrete URI.
Fixes#80, fixes#85, fixes#86
This commit introduces the new `WebClientException` for wrapping
client-side exceptions.
This exception is now thrown when now message encoder can be found for
writing the request body as an HTTP request message.
Fixes#83
This commit adds generics support for WebResponseExtractors.
Types should be described using a ResolvableType, which can be
created with static methods like:
// for the type Event<Registration>
ResolvableType.forClassWithGenerics(Event.class, Registration.class)
Fixes#89
- Introcuces XmlEventDecoder which decodes from DataBuffer to
javax.xml.stream.events.XMLEvent. It uses the Aalto async XML API if
available, but falls back to a blocking default if not.
- Refacors Jaxb2Decoder to use said XmlEventDecoder, and split the
stream of events into separate substreams by using the JAXB annotation
value, one stream for each part of the tree that can be unmarshaled to
the given type.
- Various improvements in the JAXB code.
This commit resolves a few comments brought forward during a review
meeting, specifically:
- It renames AbstractResponseBodyPublisher to
AbstractRequestBodyPublisher.
- It separates out registration logic into a register method.
- It moves the RequestBodyPublisher and ResponseBodySubscriber for the
Servlet 3.1 support back into ServletHttpHandlerAdapter.
Currently there are clashes between io.netty:netty-common:4.1.0.Beta7 and
io.netty:netty-all:4.1.0.CR3 which can cause errors in the build related
to "VerifyError: Bad type on operand stack".
One solution would be to exclude the jars that duplicate the classes.
However, this can be fragile since additional dependencies may be added
that bring in the dependency transitively.
This commit locks the version for any artifiact with the group "io.nettty"
to ensure the correct version of netty is used.
WebResponseExtractor uses Mono.when with the response status, headers,
and the decoded body. However when the response body stream is empty
then when completes empty too.
This change adds defaultIfEmpty handling for en empty response body.
There is now an HttpCookie (simple name-value pair) and separately a
ServerHttpCookie sub-class with additional attributes that a server
can send to clients.
HttpHeaders is no longer the place to access cookies. Instead there is
a read-only HttpCookie map on ServerHttpRequest and a mutable
ServerHttpCookie map on ServerHttpResponse.
Cookies are stored in a map that preserves their order.
Claneup of the Servlet 3.1 support:
- moved RequestBodyPublisher to ServletServerHttpRequest
- moved ResponseBodySubscribera to ServletServerHttpResponse
- response body is now copied to ServletOutputStream in chunks, rather
than one big byte[]
This commit adds a View and ViewResolver contracts to support HTML
template based rendering.
ViewResolverResultHandler applies view resolution by iterating the
resolvers to resolve to a view and then use it to render.
A model is created and passed to argument resolvers including a new
ModelArgumentResolver. The model is then exposed for result handling
as a field in HandlerResult.
Rename result to returnValue and resultType to returnValueType to
reflect what they represent.
The returnValue getter is also wrapped as Optional since the value
returned from a handler may be null (e.g. void method, null value).
This commit adds `RxJava1WebResponseExtractors`, a static factory of
`WebResponseExtractor`s that are based on the RxJava1 composition API.
All extracted types are based on the `Single` and `Observable` types.
This commit adds the `WebClient`, which relies on several parts of our
infrastructure:
* a `ClientHttpRequestFactory` to drive the underlying client library
* a `HttpRequestBuilder` builder API to create the client request
* a `WebResponseExtractor` to extract the "low-level"
`ClientHttpResponse` into a higher level representation such as a
decoded body
The `WebResponseExtractors` helper class contains many extractor
implementations all based on the `Flux`/`Mono` composition API.
This commit adds the `ClientHttpRequest` and `ClientHttpResponse`
implementations for the RxNetty HTTP client.
This client library is based on the `Single` and `Observable`
composition API, so this has to be converted to the `Flux`/`Mono`
variants.
This commit introduces the `ClientHttpRequest` and `ClientHttpResponse`
implementations for the Reactor-Net HTTP client. This client is already
based on the `Flux` and `Mono` contracts.
This commit also adds a `AbstractClientHttpRequest` to support the
`ClientHttpRequest` implementations; it mirrors the
`AbstractServerHttpResponse` contract with a `beforeCommit` to register
`Supplier`s that should be notified before the request is committed.
This commit adds a `DefaultHttpRequestBuilder` and its companion static
builders in `HttpRequestBuilders`. This allows to build client requests
with a friendly builder API, inspired by Spring's MockMvc API.
This commit adds the base contracts for the Web client.
The "Reactive" prefixes of the previously commited contracts has been
removed to match the server ones.
Both the `ClientHttpRequest` and the `ServerHttpResponse` extend
`ReactiveHttpOutputMessage`, which now has a `beforeCommit` method,
necessary in both client and server implementations.
`HttpRequestBuilder` will be used by the developers to create requests
with a nice builder API. `ClientHttpRequestFactory` will provide support
for many HTTP client libraries in this new client.
WebServerExchange -> ServerWebExchange
Follows the same convention as in the http package also better allowing
the possibility for a client equivalent in the future.
WebToHttpHandlerBuilder -> WebHttpHandlerBuilder
WebToHttpHandlerAdapter -> WebHttpHandlerAdapter
More consistent with Spring conventions.
Introduce adapter and handler sub-packages under web.server following a
review prompted by the addition of the session package and the package
cycle it brought in based on dependency on session.WebSessionManager.
This commit adds initial support for a maintaining a server-side
session with attributes across HTTP requests. The WebSession
abstraction can be accessed via WebServerExchange from a WebFilter or
the target WebHandler.
The session sub-package contains additional abstractions for creating
and managing sessions providing a basis for extensibility (e.g. Spring
Session). Those include WebSessionManager, SessionIdStrategy, and
SessionStore along with a cookie-based session id strategy and an
in-memory session store in use by default.
Note that the current API does not provide a way to invalidate or
re-create the session from server side code.
setComplete replaces writeHeaders as a more general lifecycle method
to perform any kind of handling at the end of request processing, for
example to ensure headers are written if not already.
beforeCommit provides an extension point for an action to be invoked
just before the response is committed, e.g. adding headers/cookies.
Added DataBuffer and DataBufferAllocator, and provided a default NIO
ByteBuffer-based implementation of those, as well as a Netty
ByteBuf-based version.
Before this change use of ExceptionHandlingWebHandler did ensure no
error signals are allowed to escape (hence relying on runtime
behavior).
This change ensures the same is done even when
ExceptionHandlingWebHandler is not configured for use, at the lowest
level which is the WebToHttpHandlerAdapter.
When decoding buffers as plain strings, the StringDecoder returns a
Publisher that may produce one or more `onNext` events.
This is perfectly valid, but leads to errors when trying to convert the
resulting Publisher into a `reactor.Mono` or `rx.Single`.
If the original Publisher emits 2 or more `onNext` signals,
converting to:
* `rx.Single` will throw an error saying that the underlying Observable
"emitted too many elements"
* `reactor.Mono` may contain only the first emitted element
This commit adds a `AbstractRawByteStreamDecoder` that takes a
`SubscriberBarrier` to apply splitting/aggregation operations on the
received elements.
The `StringDecoder` class now inherits from this abstract class and
uses one of the provided `SubscriberBarrier` implementations to
buffer all received elements in a single buffer.
Before this commit, a handler method returning a stream with a JSON
content-type was producing a JSON object for single element streams
or a JSON array for multiple elements streams.
This kind of dynamic change of the output based on the number of
elements was difficult to handle on client side and not consistent
with Spring MVC behavior.
With this commit, we achieve a more consistent behavior by using
the Mono semantics to control this behavior. Mono (and Promise/Single)
are serialized to JSON object and Flux (and Observable/Stream) are
serialized to JSON array.
HttpCookie is now immutable with factory methods to create a client
cookie (name-value) vs a server cookie (name-value + attributes)
including a builder for the latter.
This commit brings back the writeHeaders method on ServerHttpResponse
that was once added (2a6a4f) and then removed (9c7151).
This version is a little simpler since writeHeaders doesn't explicitly
flush/send headers which runtimes are expected to do by default.
Instead the main purpose of writeHeaders now is to ensure changes made
via HttpHeaders are applied to the underlying runtime response at some
point and we now do that once at the very end.
This approach provides the most flexibility (vs keeping HttpHeaders in
sync) because it allows a full and consistent set of mutative
operations for both headers and cookies (to be added) regardless of the
API exposed by the underlying runtime.
This change adds a WebServerExchange and updates all contracts at the
the same level (i.e. org.springframework.web.server) as well as the
org.springframework.web.reactive level to use it so that all
framework-related code will have access to server-side processing
features such as request attributes (and others to come).
This change separates out lower-level HTTP adapter code from the more
(framework-specific) HTTP processing into a separate package under
org.springframework.web.server (not under org.springframework.http).
Flux and Mono are used both for implementation and exposed at API
level to express 1 versus N semantic and to provide default Rx
operators:
- Flux<T> for multiple values Publisher (issue #48)
- Mono<T> for single value Publisher (issue #50)
- Mono<Void> for Publisher with no value (issue #49)
For those runtimes that don't directly support Reacitve Streams this
commit separates more formally Reactive Streams bridge code out of
the request and response implementations which become simple adapters
to the ServerHttpRequest/Response contracts like their RxNetty and
Reactor Net counterparts.
ServerHttpResponse implementations now immediately propagate
HttpHeaders changes as they so there is no need to call applyHeaders().
The writeHeaders from ServerHttpResponse is also removed. RxNetty and
Reactor Net both support implicitly completing if the handler
completes without explicitly writing the headers or the response body.
The DispatcherHandler now has an errorMapper property that is a
function for transforming errors. By default this property is set to an
instance of DispatcherHandlerExceptionMapper which wraps "standard"
framework exceptions and @ResponseStatus-annotated exceptions as
ResponseStatusException.
This makes it easy to handle the exceptions downstream uniformly.
This change adds a ResponseStatusException to associate an exception
with a status code at runtime. Along with that is an
ResponseStatusExceptionHandler that handles ResponseStatusException
by setting the response status.
General improvements e.g. make use of Java 8 Stream. The main reason
for the refactoring however to tighten error handling. To that extent:
InvocableHandlerMethod turns all exceptions into Reactive Streams
error signals, in effect never allowing any Exceptions to bubble up.
HandlerMethodArgumentResolver may throw an Exception for sync resolution
or produce an error signal via the returned Publisher. Either way the
exception is consistently wrapped with helpful method argument details.
For the latter case using a custom mapError operator.
HandlerMethodArgumentResolver no longer needs to return Optional for
nullable argument values. Instead (for now) the defaultIfEmpty operator
of reactor.rx.Stream operator is used to ensure a default constant value
(called "NO_VALUE") is produced. That way an argument resolver may
produce 0..1 values where 0 means it did not resolve to any value and
that results in null passed as the argument value.
If a HandlerMethodArgumentResolver produces more than one value, all
additional values beyond the first one will be ignored with the help
of a custom "first" operator.
As HandlerMethod is invoked within the map operator, checked exceptions
are not allowed but instead of wrapping it in a runtime exception what
we really need is to unwrap the target exception for exception
resolution purposes. To this end concatMap is used to produce a nested
Publisher or an error Publisher with the unwrapped target exception.
Related to that InvocableHandlerMethod now returns
Publisher<HandlerResult> instead of Publisher<Object> so that no longer
needs to be externally mapped from Object to HandlerResult.
InvocableHandlerMethodTests provides tests for the above scenarios and
verifies the details of resulting error signals.
This change also removes reactor-stream variants of the request and
response since the request and response aren't used directly by
application code and get passed through reactor.Publishers anyway.
This is needed in order to be able to use Spring Reactive in standalone
applications. These are temporary classes that will return in
src/test/java when Spring Boot support for Reactive applications will
be implemented.
reactive.codec -> core.codec
reactive.io -> util
These may very well not be the final locations. For now they simply
express that there are classes that belong somewhere in core, i.e.
they are lower level dependencies than web.
RequestMappingHandlerMapping currently picks the first match and does
have logic to deal with selecting the best match. This caused a
random test failure depending on which controller method was matched
first. This change removes the test.
The web related code is now under org.springframework.web.reactive.
This is parallel to org.springframework.web (the top-level package of
spring-webmvc).
This change allows to be able to check generic type on the return value
at HandlerAdapter and ResultHandler level. For example, it allows to do
a Publisher<Void> check in SimpleHandlerResultHandler.
"Content-Type" is just a single MediaType.
For the response, the MediaType must be fully selected before
selecting and encoder.
The ResponseBodyResultHandler now includes actual content negotiation
with a potential 406 response.
This commit introduces the following changes:
- MessageToByteEncoder/Decoder renamed to Encoder/Decoder
- JsonObjectEncoder/Decoder are now used directly in
JacksonJsonEncoder/Decoder
- Codec uses MimeType instead of MediaType since they
are not specific to HTTP
- Default MimeType are now managed thanks to
Encoder/Decoder#getSupportedMimeTypes()
- AbstractEncoder/Decoder takes care of generic MimeType related behavior
This commit introduces the following changes:
- Publisher -> Observable/Stream/etc. conversion is now managed
in a dedicated ConversionService instead of directly in
RequestBodyArgumentResolver and ResponseBodyResultHandler
- More isolated logic that decides if the stream should be
serialized as a JSON array or not
- Publisher<ByteBuffer> are now handled by regular
ByteBufferEncoder and ByteBufferDecoder
- Handle Publisher<Void> return value properly
- Ensure that the headers are properly written even for response
without body
- Improve JsonObjectEncoder to autodetect JSON arrays