Avoid java.util.Optional signatures for simple field access
Issue: SPR-15576
This commit is contained in:
parent
ce5e2b94c4
commit
db69a082d9
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.core;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
|
@ -106,7 +105,6 @@ public class ReactiveAdapter {
|
|||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Publisher<T> toPublisher(Object source) {
|
||||
source = (source instanceof Optional ? ((Optional<?>) source).orElse(null) : source);
|
||||
if (source == null) {
|
||||
source = getDescriptor().getEmptyValue();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.http.server.reactive;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
@ -22,7 +23,6 @@ import java.nio.charset.Charset;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
@ -89,8 +89,8 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<InetSocketAddress> getRemoteAddress() {
|
||||
return Optional.ofNullable(this.remoteAddress);
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
return this.remoteAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.springframework.test.web.reactive.server;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
@ -199,8 +198,8 @@ class DefaultControllerSpec extends AbstractMockServerSpec<WebTestClient.Control
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<Validator> getValidator() {
|
||||
return Optional.ofNullable(this.validator);
|
||||
public Validator getValidator() {
|
||||
return this.validator;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,13 +17,12 @@
|
|||
package org.springframework.http;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* An {@code HttpCookie} sub-class with the additional attributes allowed in
|
||||
* An {@code HttpCookie} subclass with the additional attributes allowed in
|
||||
* the "Set-Cookie" response header. To build an instance use the {@link #from}
|
||||
* static method.
|
||||
*
|
||||
|
@ -35,9 +34,9 @@ public final class ResponseCookie extends HttpCookie {
|
|||
|
||||
private final Duration maxAge;
|
||||
|
||||
private final Optional<String> domain;
|
||||
private final String domain;
|
||||
|
||||
private final Optional<String> path;
|
||||
private final String path;
|
||||
|
||||
private final boolean secure;
|
||||
|
||||
|
@ -53,8 +52,8 @@ public final class ResponseCookie extends HttpCookie {
|
|||
super(name, value);
|
||||
Assert.notNull(maxAge, "Max age must not be null");
|
||||
this.maxAge = maxAge;
|
||||
this.domain = Optional.ofNullable(domain);
|
||||
this.path = Optional.ofNullable(path);
|
||||
this.domain = domain;
|
||||
this.path = path;
|
||||
this.secure = secure;
|
||||
this.httpOnly = httpOnly;
|
||||
}
|
||||
|
@ -72,16 +71,16 @@ public final class ResponseCookie extends HttpCookie {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the cookie "Domain" attribute.
|
||||
* Return the cookie "Domain" attribute, or {@code null} if not set.
|
||||
*/
|
||||
public Optional<String> getDomain() {
|
||||
public String getDomain() {
|
||||
return this.domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cookie "Path" attribute.
|
||||
* Return the cookie "Path" attribute, or {@code null} if not set.
|
||||
*/
|
||||
public Optional<String> getPath() {
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -17,21 +17,21 @@
|
|||
package org.springframework.http.codec;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder;
|
||||
|
||||
/**
|
||||
* Representation for a Server-Sent Event for use with Spring's reactive Web
|
||||
* support. {@code Flux<ServerSentEvent>} or {@code Observable<ServerSentEvent>} is the
|
||||
* Representation for a Server-Sent Event for use with Spring's reactive Web support.
|
||||
* {@code Flux<ServerSentEvent>} or {@code Observable<ServerSentEvent>} is the
|
||||
* reactive equivalent to Spring MVC's {@code SseEmitter}.
|
||||
*
|
||||
* @param <T> the type of data that this event contains
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.0
|
||||
* @see ServerSentEventHttpMessageWriter
|
||||
* @see <a href="https://www.w3.org/TR/eventsource/">Server-Sent Events W3C recommendation</a>
|
||||
* @since 5.0
|
||||
*/
|
||||
public class ServerSentEvent<T> {
|
||||
|
||||
|
@ -54,68 +54,69 @@ public class ServerSentEvent<T> {
|
|||
this.comment = comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a builder for a {@code SseEvent}.
|
||||
*
|
||||
* @param <T> the type of data that this event contains
|
||||
* @return the builder
|
||||
*/
|
||||
public static <T> Builder<T> builder() {
|
||||
return new BuilderImpl<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a builder for a {@code SseEvent}, populated with the give {@linkplain #data() data}.
|
||||
*
|
||||
* @param <T> the type of data that this event contains
|
||||
* @return the builder
|
||||
*/
|
||||
public static <T> Builder<T> builder(T data) {
|
||||
return new BuilderImpl<>(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code id} field of this event, if available.
|
||||
*/
|
||||
public Optional<String> id() {
|
||||
return Optional.ofNullable(this.id);
|
||||
public String id() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code event} field of this event, if available.
|
||||
*/
|
||||
public Optional<String> event() {
|
||||
return Optional.ofNullable(this.event);
|
||||
public String event() {
|
||||
return this.event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code data} field of this event, if available.
|
||||
*/
|
||||
public Optional<T> data() {
|
||||
return Optional.ofNullable(this.data);
|
||||
public T data() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code retry} field of this event, if available.
|
||||
*/
|
||||
public Optional<Duration> retry() {
|
||||
return Optional.ofNullable(this.retry);
|
||||
public Duration retry() {
|
||||
return this.retry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the comment of this event, if available.
|
||||
*/
|
||||
public Optional<String> comment() {
|
||||
return Optional.ofNullable(this.comment);
|
||||
public String comment() {
|
||||
return this.comment;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerSentEvent [id = '" + id + '\'' + ", event='" + event + '\'' +
|
||||
", data=" + data + ", retry=" + retry + ", comment='" + comment + '\'' +
|
||||
']';
|
||||
return ("ServerSentEvent [id = '" + this.id + '\'' + ", event='" + this.event + '\'' +
|
||||
", data=" + this.data + ", retry=" + this.retry + ", comment='" + this.comment + '\'' + ']');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a builder for a {@code SseEvent}.
|
||||
* @param <T> the type of data that this event contains
|
||||
* @return the builder
|
||||
*/
|
||||
public static <T> Builder<T> builder() {
|
||||
return new BuilderImpl<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a builder for a {@code SseEvent}, populated with the give {@linkplain #data() data}.
|
||||
* @param <T> the type of data that this event contains
|
||||
* @return the builder
|
||||
*/
|
||||
public static <T> Builder<T> builder(T data) {
|
||||
return new BuilderImpl<>(data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A mutable builder for a {@code SseEvent}.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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,8 +62,9 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructor with JSON {@code Encoder} for encoding objects. Support for
|
||||
* {@code String} event data is built-in.
|
||||
* Constructor with JSON {@code Encoder} for encoding objects.
|
||||
* Support for {@code String} event data is built-in.
|
||||
* @param encoder the Encoder to use (may be {@code null})
|
||||
*/
|
||||
public ServerSentEventHttpMessageWriter(Encoder<?> encoder) {
|
||||
this.encoder = encoder;
|
||||
|
@ -71,7 +72,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
|||
|
||||
|
||||
/**
|
||||
* Return the configured {@code Encoder}, possibly {@code null}.
|
||||
* Return the configured {@code Encoder}, if any.
|
||||
*/
|
||||
public Encoder<?> getEncoder() {
|
||||
return this.encoder;
|
||||
|
@ -85,8 +86,8 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
|||
|
||||
@Override
|
||||
public boolean canWrite(ResolvableType elementType, MediaType mediaType) {
|
||||
return mediaType == null || MediaType.TEXT_EVENT_STREAM.includes(mediaType) ||
|
||||
ServerSentEvent.class.isAssignableFrom(elementType.resolve(Object.class));
|
||||
return (mediaType == null || MediaType.TEXT_EVENT_STREAM.includes(mediaType) ||
|
||||
ServerSentEvent.class.isAssignableFrom(elementType.resolve(Object.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -100,23 +101,33 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
|||
private Flux<Publisher<DataBuffer>> encode(Publisher<?> input, DataBufferFactory factory,
|
||||
ResolvableType elementType, Map<String, Object> hints) {
|
||||
|
||||
ResolvableType valueType = ServerSentEvent.class.isAssignableFrom(elementType.getRawClass()) ?
|
||||
elementType.getGeneric(0) : elementType;
|
||||
ResolvableType valueType = (ServerSentEvent.class.isAssignableFrom(elementType.getRawClass()) ?
|
||||
elementType.getGeneric() : elementType);
|
||||
|
||||
return Flux.from(input).map(element -> {
|
||||
|
||||
ServerSentEvent<?> sse = element instanceof ServerSentEvent ?
|
||||
(ServerSentEvent<?>) element : ServerSentEvent.builder().data(element).build();
|
||||
ServerSentEvent<?> sse = (element instanceof ServerSentEvent ?
|
||||
(ServerSentEvent<?>) element : ServerSentEvent.builder().data(element).build());
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sse.id().ifPresent(v -> writeField("id", v, sb));
|
||||
sse.event().ifPresent(v -> writeField("event", v, sb));
|
||||
sse.retry().ifPresent(v -> writeField("retry", v.toMillis(), sb));
|
||||
sse.comment().ifPresent(v -> sb.append(':').append(v.replaceAll("\\n", "\n:")).append("\n"));
|
||||
sse.data().ifPresent(v -> sb.append("data:"));
|
||||
if (sse.id() != null) {
|
||||
writeField("id", sse.id(), sb);
|
||||
}
|
||||
if (sse.event() != null) {
|
||||
writeField("event", sse.event(), sb);
|
||||
}
|
||||
if (sse.retry() != null) {
|
||||
writeField("retry", sse.retry().toMillis(), sb);
|
||||
}
|
||||
if (sse.comment() != null) {
|
||||
sb.append(':').append(sse.comment().replaceAll("\\n", "\n:")).append("\n");
|
||||
}
|
||||
if (sse.data() != null) {
|
||||
sb.append("data:");
|
||||
}
|
||||
|
||||
return Flux.concat(encodeText(sb, factory),
|
||||
encodeData(sse, valueType, factory, hints),
|
||||
encodeData(sse.data(), valueType, factory, hints),
|
||||
encodeText("\n", factory));
|
||||
});
|
||||
}
|
||||
|
@ -129,10 +140,9 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Flux<DataBuffer> encodeData(ServerSentEvent<?> event, ResolvableType valueType,
|
||||
private <T> Flux<DataBuffer> encodeData(T data, ResolvableType valueType,
|
||||
DataBufferFactory factory, Map<String, Object> hints) {
|
||||
|
||||
Object data = event.data().orElse(null);
|
||||
if (data == null) {
|
||||
return Flux.empty();
|
||||
}
|
||||
|
@ -147,7 +157,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
|||
}
|
||||
|
||||
return ((Encoder<T>) this.encoder)
|
||||
.encode(Mono.just((T) data), factory, valueType, MediaType.TEXT_EVENT_STREAM, hints)
|
||||
.encode(Mono.just(data), factory, valueType, MediaType.TEXT_EVENT_STREAM, hints)
|
||||
.concatWith(encodeText("\n", factory));
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.springframework.http.server.reactive;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.netty.handler.codec.http.cookie.Cookie;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
@ -100,8 +99,8 @@ public class ReactorServerHttpRequest extends AbstractServerHttpRequest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<InetSocketAddress> getRemoteAddress() {
|
||||
return Optional.ofNullable(this.request.remoteAddress());
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
return this.request.remoteAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -42,15 +42,14 @@ import org.springframework.util.Assert;
|
|||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
public class ReactorServerHttpResponse extends AbstractServerHttpResponse
|
||||
implements ZeroCopyHttpOutputMessage {
|
||||
public class ReactorServerHttpResponse extends AbstractServerHttpResponse implements ZeroCopyHttpOutputMessage {
|
||||
|
||||
private final HttpServerResponse response;
|
||||
|
||||
|
||||
public ReactorServerHttpResponse(HttpServerResponse response, DataBufferFactory bufferFactory) {
|
||||
super(bufferFactory);
|
||||
Assert.notNull(response, "'response' must not be null.");
|
||||
Assert.notNull(response, "HttpServerResponse must not be null");
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
|
@ -98,8 +97,12 @@ public class ReactorServerHttpResponse extends AbstractServerHttpResponse
|
|||
if (!httpCookie.getMaxAge().isNegative()) {
|
||||
cookie.setMaxAge(httpCookie.getMaxAge().getSeconds());
|
||||
}
|
||||
httpCookie.getDomain().ifPresent(cookie::setDomain);
|
||||
httpCookie.getPath().ifPresent(cookie::setPath);
|
||||
if (httpCookie.getDomain() != null) {
|
||||
cookie.setDomain(httpCookie.getDomain());
|
||||
}
|
||||
if (httpCookie.getPath() != null) {
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
}
|
||||
cookie.setSecure(httpCookie.isSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
this.response.addCookie(cookie);
|
||||
|
@ -116,6 +119,4 @@ public class ReactorServerHttpResponse extends AbstractServerHttpResponse
|
|||
return Flux.from(dataBuffers).map(NettyDataBufferFactory::toByteBuf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.http.server.reactive;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
@ -35,11 +34,10 @@ import org.springframework.util.MultiValueMap;
|
|||
public interface ServerHttpRequest extends HttpRequest, ReactiveHttpInputMessage {
|
||||
|
||||
/**
|
||||
* Returns the portion of the URL path that represents the context path for
|
||||
* the current {@link HttpHandler}. The context path is always at the
|
||||
* beginning of the request path. It starts with "/" but but does not end
|
||||
* with "/". This method may return an empty string if no context path is
|
||||
* configured.
|
||||
* Returns the portion of the URL path that represents the context path for the
|
||||
* current {@link HttpHandler}. The context path is always at the beginning of
|
||||
* the request path. It starts with "/" but but does not end with "/".
|
||||
* <p>This method may return an empty string if no context path is configured.
|
||||
* @return the context path (not decoded) or an empty string
|
||||
*/
|
||||
default String getContextPath() {
|
||||
|
@ -57,10 +55,9 @@ public interface ServerHttpRequest extends HttpRequest, ReactiveHttpInputMessage
|
|||
MultiValueMap<String, HttpCookie> getCookies();
|
||||
|
||||
/**
|
||||
* Returns the remote address where this request is connected to.
|
||||
* @return remote address if available
|
||||
* Return the remote address where this request is connected to, if available.
|
||||
*/
|
||||
Optional<InetSocketAddress> getRemoteAddress();
|
||||
InetSocketAddress getRemoteAddress();
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -13,11 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.server.reactive;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.util.Optional;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
|
@ -79,7 +79,7 @@ public class ServerHttpRequestDecorator implements ServerHttpRequest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<InetSocketAddress> getRemoteAddress() {
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
return getDelegate().getRemoteAddress();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -23,7 +23,6 @@ import java.net.URISyntaxException;
|
|||
import java.nio.charset.Charset;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.AsyncListener;
|
||||
|
@ -32,10 +31,10 @@ import javax.servlet.ServletInputStream;
|
|||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.http.HttpCookie;
|
||||
|
@ -178,9 +177,8 @@ public class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<InetSocketAddress> getRemoteAddress() {
|
||||
return Optional.of(new InetSocketAddress(
|
||||
this.request.getRemoteHost(), this.request.getRemotePort()));
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
return new InetSocketAddress(this.request.getRemoteHost(), this.request.getRemotePort());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -231,13 +229,12 @@ public class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private class RequestBodyPublisher extends AbstractListenerReadPublisher<DataBuffer> {
|
||||
|
||||
private final ServletInputStream inputStream;
|
||||
|
||||
|
||||
public RequestBodyPublisher(ServletInputStream inputStream) {
|
||||
|
||||
this.inputStream = inputStream;
|
||||
}
|
||||
|
||||
|
@ -260,6 +257,7 @@ public class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
private class RequestBodyPublisherReadListener implements ReadListener {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -117,8 +117,12 @@ public class ServletServerHttpResponse extends AbstractListenerServerHttpRespons
|
|||
if (!httpCookie.getMaxAge().isNegative()) {
|
||||
cookie.setMaxAge((int) httpCookie.getMaxAge().getSeconds());
|
||||
}
|
||||
httpCookie.getDomain().ifPresent(cookie::setDomain);
|
||||
httpCookie.getPath().ifPresent(cookie::setPath);
|
||||
if (httpCookie.getDomain() != null) {
|
||||
cookie.setDomain(httpCookie.getDomain());
|
||||
}
|
||||
if (httpCookie.getPath() != null) {
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
}
|
||||
cookie.setSecure(httpCookie.isSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
this.response.addCookie(cookie);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -20,7 +20,6 @@ import java.io.IOException;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.undertow.connector.ByteBufferPool;
|
||||
import io.undertow.connector.PooledByteBuffer;
|
||||
|
@ -100,8 +99,8 @@ public class UndertowServerHttpRequest extends AbstractServerHttpRequest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<InetSocketAddress> getRemoteAddress() {
|
||||
return Optional.ofNullable(this.exchange.getSourceAddress());
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
return this.exchange.getSourceAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -60,7 +60,7 @@ public class UndertowServerHttpResponse extends AbstractListenerServerHttpRespon
|
|||
|
||||
public UndertowServerHttpResponse(HttpServerExchange exchange, DataBufferFactory bufferFactory) {
|
||||
super(bufferFactory);
|
||||
Assert.notNull(exchange, "HttpServerExchange is required");
|
||||
Assert.notNull(exchange, "HttpServerExchange must not be null");
|
||||
this.exchange = exchange;
|
||||
}
|
||||
|
||||
|
@ -120,8 +120,12 @@ public class UndertowServerHttpResponse extends AbstractListenerServerHttpRespon
|
|||
if (!httpCookie.getMaxAge().isNegative()) {
|
||||
cookie.setMaxAge((int) httpCookie.getMaxAge().getSeconds());
|
||||
}
|
||||
httpCookie.getDomain().ifPresent(cookie::setDomain);
|
||||
httpCookie.getPath().ifPresent(cookie::setPath);
|
||||
if (httpCookie.getDomain() != null) {
|
||||
cookie.setDomain(httpCookie.getDomain());
|
||||
}
|
||||
if (httpCookie.getPath() != null) {
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
}
|
||||
cookie.setSecure(httpCookie.isSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
this.exchange.getResponseCookies().putIfAbsent(name, cookie);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -263,9 +263,8 @@ public class WebExchangeBindException extends ServerWebInputException implements
|
|||
* Returns diagnostic information about the errors held in this object.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
public String getMessage() {
|
||||
MethodParameter parameter = getMethodParameter().get();
|
||||
MethodParameter parameter = getMethodParameter();
|
||||
StringBuilder sb = new StringBuilder("Validation failed for argument at index ")
|
||||
.append(parameter.getParameterIndex()).append(" in method: ")
|
||||
.append(parameter.getMethod().toGenericString())
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.springframework.web.server;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
|
@ -61,8 +59,8 @@ public class ServerErrorException extends ResponseStatusException {
|
|||
/**
|
||||
* Return the {@code MethodParameter} associated with this error, if any.
|
||||
*/
|
||||
public Optional<MethodParameter> getMethodParameter() {
|
||||
return Optional.ofNullable(this.parameter);
|
||||
public MethodParameter getMethodParameter() {
|
||||
return this.parameter;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -126,12 +126,10 @@ public interface ServerWebExchange {
|
|||
* status, and adding "ETag" and "Last-Modified" headers when applicable.
|
||||
* This method works with conditional GET/HEAD requests as well as with
|
||||
* conditional POST/PUT/DELETE requests.
|
||||
*
|
||||
* <p><strong>Note:</strong> The HTTP specification recommends setting both
|
||||
* ETag and Last-Modified values, but you can also use
|
||||
* {@code #checkNotModified(String)} or
|
||||
* {@link #checkNotModified(Instant)}.
|
||||
*
|
||||
* @param etag the entity tag that the application determined for the
|
||||
* underlying resource. This parameter will be padded with quotes (")
|
||||
* if necessary.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.springframework.web.server;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
|
@ -61,8 +59,8 @@ public class ServerWebInputException extends ResponseStatusException {
|
|||
/**
|
||||
* Return the {@code MethodParameter} associated with this error, if any.
|
||||
*/
|
||||
public Optional<MethodParameter> getMethodParameter() {
|
||||
return Optional.ofNullable(this.parameter);
|
||||
public MethodParameter getMethodParameter() {
|
||||
return this.parameter;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -18,7 +18,6 @@ package org.springframework.web.server;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
|
@ -57,10 +56,11 @@ public class UnsupportedMediaTypeStatusException extends ResponseStatusException
|
|||
|
||||
|
||||
/**
|
||||
* Return the request Content-Type header if it was parsed successfully.
|
||||
* Return the request Content-Type header if it was parsed successfully,
|
||||
* or {@code null} otherwise.
|
||||
*/
|
||||
public Optional<MediaType> getContentType() {
|
||||
return Optional.ofNullable(this.contentType);
|
||||
public MediaType getContentType() {
|
||||
return this.contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -29,9 +29,7 @@ import org.springframework.http.MediaType;
|
|||
import org.springframework.http.codec.json.Jackson2JsonDecoder;
|
||||
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Sebastien Deleuze
|
||||
|
@ -41,6 +39,7 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll
|
|||
private ServerSentEventHttpMessageReader messageReader =
|
||||
new ServerSentEventHttpMessageReader(new Jackson2JsonDecoder());
|
||||
|
||||
|
||||
@Test
|
||||
public void cantRead() {
|
||||
assertFalse(messageReader.canRead(ResolvableType.forClass(Object.class),
|
||||
|
@ -58,7 +57,6 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll
|
|||
|
||||
@Test
|
||||
public void readServerSentEvents() {
|
||||
|
||||
MockServerHttpRequest request = MockServerHttpRequest.post("/").body(
|
||||
"id:c42\nevent:foo\nretry:123\n:bla\n:bla bla\n:bla bla bla\ndata:bar\n\n" +
|
||||
"id:c43\nevent:bar\nretry:456\ndata:baz\n\n");
|
||||
|
@ -69,18 +67,18 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll
|
|||
|
||||
StepVerifier.create(events)
|
||||
.consumeNextWith(event -> {
|
||||
assertEquals("c42", event.id().get());
|
||||
assertEquals("foo", event.event().get());
|
||||
assertEquals(Duration.ofMillis(123), event.retry().get());
|
||||
assertEquals("bla\nbla bla\nbla bla bla", event.comment().get());
|
||||
assertEquals("bar", event.data().get());
|
||||
assertEquals("c42", event.id());
|
||||
assertEquals("foo", event.event());
|
||||
assertEquals(Duration.ofMillis(123), event.retry());
|
||||
assertEquals("bla\nbla bla\nbla bla bla", event.comment());
|
||||
assertEquals("bar", event.data());
|
||||
})
|
||||
.consumeNextWith(event -> {
|
||||
assertEquals("c43", event.id().get());
|
||||
assertEquals("bar", event.event().get());
|
||||
assertEquals(Duration.ofMillis(456), event.retry().get());
|
||||
assertFalse(event.comment().isPresent());
|
||||
assertEquals("baz", event.data().get());
|
||||
assertEquals("c43", event.id());
|
||||
assertEquals("bar", event.event());
|
||||
assertEquals(Duration.ofMillis(456), event.retry());
|
||||
assertNull(event.comment());
|
||||
assertEquals("baz", event.data());
|
||||
})
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
@ -88,7 +86,6 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll
|
|||
|
||||
@Test
|
||||
public void readServerSentEventsWithMultipleChunks() {
|
||||
|
||||
MockServerHttpRequest request = MockServerHttpRequest.post("/")
|
||||
.body(Flux.just(
|
||||
stringBuffer("id:c42\nev"),
|
||||
|
@ -101,18 +98,18 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll
|
|||
|
||||
StepVerifier.create(events)
|
||||
.consumeNextWith(event -> {
|
||||
assertEquals("c42", event.id().get());
|
||||
assertEquals("foo", event.event().get());
|
||||
assertEquals(Duration.ofMillis(123), event.retry().get());
|
||||
assertEquals("bla\nbla bla\nbla bla bla", event.comment().get());
|
||||
assertEquals("bar", event.data().get());
|
||||
assertEquals("c42", event.id());
|
||||
assertEquals("foo", event.event());
|
||||
assertEquals(Duration.ofMillis(123), event.retry());
|
||||
assertEquals("bla\nbla bla\nbla bla bla", event.comment());
|
||||
assertEquals("bar", event.data());
|
||||
})
|
||||
.consumeNextWith(event -> {
|
||||
assertEquals("c43", event.id().get());
|
||||
assertEquals("bar", event.event().get());
|
||||
assertEquals(Duration.ofMillis(456), event.retry().get());
|
||||
assertFalse(event.comment().isPresent());
|
||||
assertEquals("baz", event.data().get());
|
||||
assertEquals("c43", event.id());
|
||||
assertEquals("bar", event.event());
|
||||
assertEquals(Duration.ofMillis(456), event.retry());
|
||||
assertNull(event.comment());
|
||||
assertEquals("baz", event.data());
|
||||
})
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
@ -120,7 +117,6 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll
|
|||
|
||||
@Test
|
||||
public void readString() {
|
||||
|
||||
String body = "data:foo\ndata:bar\n\ndata:baz\n\n";
|
||||
MockServerHttpRequest request = MockServerHttpRequest.post("/").body(body);
|
||||
|
||||
|
@ -136,7 +132,6 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll
|
|||
|
||||
@Test
|
||||
public void readPojo() {
|
||||
|
||||
MockServerHttpRequest request = MockServerHttpRequest.post("/").body(
|
||||
"data:{\"foo\": \"foofoo\", \"bar\": \"barbar\"}\n\n" +
|
||||
"data:{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}\n\n");
|
||||
|
@ -157,9 +152,8 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll
|
|||
.verify();
|
||||
}
|
||||
|
||||
@Test // SPR-15331
|
||||
@Test // SPR-15331
|
||||
public void decodeFullContentAsString() {
|
||||
|
||||
String body = "data:foo\ndata:bar\n\ndata:baz\n\n";
|
||||
MockServerHttpRequest request = MockServerHttpRequest.post("/").body(body);
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.springframework.http.server.reactive;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.http.cookie.Cookie;
|
||||
|
@ -59,19 +58,20 @@ public class RxNettyServerHttpRequest extends AbstractServerHttpRequest {
|
|||
throws URISyntaxException {
|
||||
|
||||
super(initUri(request, remoteAddress), initHeaders(request));
|
||||
|
||||
Assert.notNull(dataBufferFactory, "'dataBufferFactory' must not be null");
|
||||
this.request = request;
|
||||
|
||||
Assert.notNull(dataBufferFactory, "NettyDataBufferFactory must not be null");
|
||||
this.dataBufferFactory = dataBufferFactory;
|
||||
|
||||
this.remoteAddress = remoteAddress;
|
||||
}
|
||||
|
||||
private static URI initUri(HttpServerRequest<ByteBuf> request, InetSocketAddress remoteAddress)
|
||||
throws URISyntaxException {
|
||||
|
||||
Assert.notNull(request, "'request' must not be null");
|
||||
Assert.notNull(request, "HttpServerRequest must not be null");
|
||||
String requestUri = request.getUri();
|
||||
return remoteAddress != null ? createUrl(remoteAddress, requestUri) : URI.create(requestUri);
|
||||
return (remoteAddress != null ? createUrl(remoteAddress, requestUri) : URI.create(requestUri));
|
||||
}
|
||||
|
||||
private static URI createUrl(InetSocketAddress address, String requestUri) throws URISyntaxException {
|
||||
|
@ -110,8 +110,8 @@ public class RxNettyServerHttpRequest extends AbstractServerHttpRequest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<InetSocketAddress> getRemoteAddress() {
|
||||
return Optional.ofNullable(this.remoteAddress);
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
return this.remoteAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,18 +47,18 @@ import org.springframework.util.Assert;
|
|||
*/
|
||||
public class RxNettyServerHttpResponse extends AbstractServerHttpResponse {
|
||||
|
||||
private final HttpServerResponse<ByteBuf> response;
|
||||
|
||||
private static final ByteBuf FLUSH_SIGNAL = Unpooled.buffer(0, 0);
|
||||
|
||||
// 8 Kb flush threshold to avoid blocking RxNetty when the send buffer has reached the high watermark
|
||||
private static final long FLUSH_THRESHOLD = 8192;
|
||||
|
||||
public RxNettyServerHttpResponse(HttpServerResponse<ByteBuf> response,
|
||||
NettyDataBufferFactory dataBufferFactory) {
|
||||
super(dataBufferFactory);
|
||||
Assert.notNull(response, "'response' must not be null.");
|
||||
|
||||
private final HttpServerResponse<ByteBuf> response;
|
||||
|
||||
|
||||
public RxNettyServerHttpResponse(HttpServerResponse<ByteBuf> response, NettyDataBufferFactory dataBufferFactory) {
|
||||
super(dataBufferFactory);
|
||||
Assert.notNull(response, "HttpServerResponse must not be null");
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
|
@ -113,8 +113,12 @@ public class RxNettyServerHttpResponse extends AbstractServerHttpResponse {
|
|||
if (!httpCookie.getMaxAge().isNegative()) {
|
||||
cookie.setMaxAge(httpCookie.getMaxAge().getSeconds());
|
||||
}
|
||||
httpCookie.getDomain().ifPresent(cookie::setDomain);
|
||||
httpCookie.getPath().ifPresent(cookie::setPath);
|
||||
if (httpCookie.getDomain() != null) {
|
||||
cookie.setDomain(httpCookie.getDomain());
|
||||
}
|
||||
if (httpCookie.getPath() != null) {
|
||||
cookie.setPath(httpCookie.getPath());
|
||||
}
|
||||
cookie.setSecure(httpCookie.isSecure());
|
||||
cookie.setHttpOnly(httpCookie.isHttpOnly());
|
||||
this.response.addCookie(cookie);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.http.server.reactive.test;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
@ -22,7 +23,6 @@ import java.nio.charset.Charset;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
@ -66,8 +66,7 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest {
|
|||
|
||||
private MockServerHttpRequest(HttpMethod httpMethod, URI uri, String contextPath,
|
||||
HttpHeaders headers, MultiValueMap<String, HttpCookie> cookies,
|
||||
InetSocketAddress remoteAddress,
|
||||
Publisher<? extends DataBuffer> body) {
|
||||
InetSocketAddress remoteAddress, Publisher<? extends DataBuffer> body) {
|
||||
|
||||
super(uri, headers);
|
||||
this.httpMethod = httpMethod;
|
||||
|
@ -89,8 +88,8 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<InetSocketAddress> getRemoteAddress() {
|
||||
return Optional.ofNullable(this.remoteAddress);
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
return this.remoteAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.web.reactive;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
@ -82,10 +81,10 @@ public class HandlerResult {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the value returned from the handler wrapped as {@link Optional}.
|
||||
* Return the value returned from the handler, if any.
|
||||
*/
|
||||
public Optional<Object> getReturnValue() {
|
||||
return Optional.ofNullable(this.returnValue);
|
||||
public Object getReturnValue() {
|
||||
return this.returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -86,12 +86,14 @@ public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport
|
|||
|
||||
@Override
|
||||
protected Validator getValidator() {
|
||||
return this.configurers.getValidator().orElse(super.getValidator());
|
||||
Validator validator = this.configurers.getValidator();
|
||||
return (validator != null ? validator : super.getValidator());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MessageCodesResolver getMessageCodesResolver() {
|
||||
return this.configurers.getMessageCodesResolver().orElse(super.getMessageCodesResolver());
|
||||
MessageCodesResolver messageCodesResolver = this.configurers.getMessageCodesResolver();
|
||||
return (messageCodesResolver != null ? messageCodesResolver : super.getMessageCodesResolver());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.springframework.web.reactive.config;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
|
@ -104,17 +102,16 @@ public interface WebFluxConfigurer {
|
|||
* <p>By default a validator for standard bean validation is created if
|
||||
* bean validation api is present on the classpath.
|
||||
*/
|
||||
default Optional<Validator> getValidator() {
|
||||
return Optional.empty();
|
||||
default Validator getValidator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a custom {@link MessageCodesResolver} to use for data binding
|
||||
* instead of the one created by default in
|
||||
* {@link org.springframework.validation.DataBinder}.
|
||||
* Provide a custom {@link MessageCodesResolver} to use for data binding instead
|
||||
* of the one created by default in {@link org.springframework.validation.DataBinder}.
|
||||
*/
|
||||
default Optional<MessageCodesResolver> getMessageCodesResolver() {
|
||||
return Optional.empty();
|
||||
default MessageCodesResolver getMessageCodesResolver() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -18,7 +18,6 @@ package org.springframework.web.reactive.config;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -85,12 +84,12 @@ public class WebFluxConfigurerComposite implements WebFluxConfigurer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<Validator> getValidator() {
|
||||
public Validator getValidator() {
|
||||
return createSingleBean(WebFluxConfigurer::getValidator, Validator.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<MessageCodesResolver> getMessageCodesResolver() {
|
||||
public MessageCodesResolver getMessageCodesResolver() {
|
||||
return createSingleBean(WebFluxConfigurer::getMessageCodesResolver, MessageCodesResolver.class);
|
||||
}
|
||||
|
||||
|
@ -99,14 +98,10 @@ public class WebFluxConfigurerComposite implements WebFluxConfigurer {
|
|||
this.delegates.forEach(delegate -> delegate.configureViewResolvers(registry));
|
||||
}
|
||||
|
||||
private <T> Optional<T> createSingleBean(Function<WebFluxConfigurer, Optional<T>> factory,
|
||||
Class<T> beanType) {
|
||||
|
||||
List<Optional<T>> result = this.delegates.stream()
|
||||
.map(factory).filter(Optional::isPresent).collect(Collectors.toList());
|
||||
|
||||
private <T> T createSingleBean(Function<WebFluxConfigurer, T> factory, Class<T> beanType) {
|
||||
List<T> result = this.delegates.stream().map(factory).filter(t -> t != null).collect(Collectors.toList());
|
||||
if (result.isEmpty()) {
|
||||
return Optional.empty();
|
||||
return null;
|
||||
}
|
||||
else if (result.size() == 1) {
|
||||
return result.get(0);
|
||||
|
|
|
@ -57,10 +57,11 @@ public class UnsupportedMediaTypeException extends NestedRuntimeException {
|
|||
|
||||
|
||||
/**
|
||||
* Return the request Content-Type header if it was parsed successfully.
|
||||
* Return the request Content-Type header if it was parsed successfully,
|
||||
* or {@code null} otherwise.
|
||||
*/
|
||||
public Optional<MediaType> getContentType() {
|
||||
return Optional.ofNullable(this.contentType);
|
||||
public MediaType getContentType() {
|
||||
return this.contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -57,10 +57,10 @@ import org.springframework.web.server.WebSession;
|
|||
class DefaultServerRequest implements ServerRequest {
|
||||
|
||||
private static final Function<UnsupportedMediaTypeException, UnsupportedMediaTypeStatusException> ERROR_MAPPER =
|
||||
ex -> ex.getContentType()
|
||||
.map(contentType -> new UnsupportedMediaTypeStatusException(contentType,
|
||||
ex.getSupportedMediaTypes()))
|
||||
.orElseGet(() -> new UnsupportedMediaTypeStatusException(ex.getMessage()));
|
||||
ex -> (ex.getContentType() != null ?
|
||||
new UnsupportedMediaTypeStatusException(ex.getContentType(), ex.getSupportedMediaTypes()) :
|
||||
new UnsupportedMediaTypeStatusException(ex.getMessage()));
|
||||
|
||||
|
||||
private final ServerWebExchange exchange;
|
||||
|
||||
|
@ -69,8 +69,7 @@ class DefaultServerRequest implements ServerRequest {
|
|||
private final Supplier<Stream<HttpMessageReader<?>>> messageReaders;
|
||||
|
||||
|
||||
DefaultServerRequest(ServerWebExchange exchange,
|
||||
Supplier<Stream<HttpMessageReader<?>>> messageReaders) {
|
||||
DefaultServerRequest(ServerWebExchange exchange, Supplier<Stream<HttpMessageReader<?>>> messageReaders) {
|
||||
this.exchange = exchange;
|
||||
this.messageReaders = messageReaders;
|
||||
this.headers = new DefaultHeaders();
|
||||
|
@ -106,12 +105,10 @@ class DefaultServerRequest implements ServerRequest {
|
|||
public Supplier<Stream<HttpMessageReader<?>>> messageReaders() {
|
||||
return DefaultServerRequest.this.messageReaders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ServerHttpResponse> serverResponse() {
|
||||
return Optional.of(exchange().getResponse());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> hints() {
|
||||
return hints;
|
||||
|
|
|
@ -54,14 +54,13 @@ public class ServerResponseResultHandler implements HandlerResultHandler {
|
|||
|
||||
@Override
|
||||
public boolean supports(HandlerResult result) {
|
||||
return result.getReturnValue()
|
||||
.filter(o -> o instanceof ServerResponse)
|
||||
.isPresent();
|
||||
return (result.getReturnValue() instanceof ServerResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
|
||||
ServerResponse response = (ServerResponse) result.getReturnValue().orElseThrow(IllegalStateException::new);
|
||||
ServerResponse response = (ServerResponse) result.getReturnValue();
|
||||
Assert.state(response != null, "No ServerResponse");
|
||||
return response.writeTo(exchange, this.strategies);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.springframework.web.reactive.result.method.annotation;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.support.WebBindingInitializer;
|
||||
|
@ -69,17 +68,15 @@ class InitBinderBindingContext extends BindingContext {
|
|||
private void invokeBinderMethod(WebExchangeDataBinder dataBinder,
|
||||
ServerWebExchange exchange, SyncInvocableHandlerMethod binderMethod) {
|
||||
|
||||
Optional<Object> returnValue = binderMethod
|
||||
.invokeForHandlerResult(exchange, this.binderMethodContext, dataBinder)
|
||||
Object returnValue = binderMethod.invokeForHandlerResult(exchange, this.binderMethodContext, dataBinder)
|
||||
.getReturnValue();
|
||||
|
||||
if (returnValue.isPresent()) {
|
||||
if (returnValue != null) {
|
||||
throw new IllegalStateException(
|
||||
"@InitBinder methods should return void: " + binderMethod);
|
||||
}
|
||||
|
||||
// Should not happen (no Model argument resolution) ...
|
||||
|
||||
if (!this.binderMethodContext.getModel().asMap().isEmpty()) {
|
||||
throw new IllegalStateException(
|
||||
"@InitBinder methods should not add model attributes: " + binderMethod);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.result.method.annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -36,7 +37,6 @@ import org.springframework.web.reactive.HandlerResult;
|
|||
import org.springframework.web.reactive.result.method.InvocableHandlerMethod;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
|
||||
/**
|
||||
* Package-private class to assist {@link RequestMappingHandlerAdapter} with
|
||||
* default model initialization through {@code @ModelAttribute} methods.
|
||||
|
@ -54,24 +54,16 @@ class ModelInitializer {
|
|||
}
|
||||
|
||||
|
||||
private ReactiveAdapterRegistry getAdapterRegistry() {
|
||||
return this.adapterRegistry;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the default model in the given {@code BindingContext} through
|
||||
* the {@code @ModelAttribute} methods and indicate when complete.
|
||||
*
|
||||
* <p>This will wait for {@code @ModelAttribute} methods that return
|
||||
* {@code Mono<Void>} since those may be adding attributes asynchronously.
|
||||
* However if methods return async attributes, those will be added to the
|
||||
* model as-is and without waiting for them to be resolved.
|
||||
*
|
||||
* @param bindingContext the BindingContext with the default model
|
||||
* @param attributeMethods the {@code @ModelAttribute} methods
|
||||
* @param exchange the current exchange
|
||||
*
|
||||
* @return a {@code Mono} for when the model is populated.
|
||||
*/
|
||||
@SuppressWarnings("Convert2MethodRef")
|
||||
|
@ -90,28 +82,20 @@ class ModelInitializer {
|
|||
}
|
||||
|
||||
private Mono<Void> handleResult(HandlerResult handlerResult, BindingContext bindingContext) {
|
||||
|
||||
return handlerResult.getReturnValue()
|
||||
.map(value -> {
|
||||
ResolvableType type = handlerResult.getReturnType();
|
||||
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type.getRawClass(), value);
|
||||
|
||||
Class<?> attributeType;
|
||||
if (adapter != null) {
|
||||
attributeType = adapter.isNoValue() ? Void.class : type.resolveGeneric(0);
|
||||
if (attributeType.equals(Void.class)) {
|
||||
return Mono.<Void>from(adapter.toPublisher(value));
|
||||
}
|
||||
}
|
||||
else {
|
||||
attributeType = type.resolve();
|
||||
}
|
||||
|
||||
String name = getAttributeName(handlerResult.getReturnTypeSource());
|
||||
bindingContext.getModel().asMap().putIfAbsent(name, value);
|
||||
return Mono.<Void>empty();
|
||||
})
|
||||
.orElse(Mono.empty());
|
||||
Object value = handlerResult.getReturnValue();
|
||||
if (value != null) {
|
||||
ResolvableType type = handlerResult.getReturnType();
|
||||
ReactiveAdapter adapter = this.adapterRegistry.getAdapter(type.getRawClass(), value);
|
||||
if (adapter != null) {
|
||||
Class<?> attributeType = (adapter.isNoValue() ? Void.class : type.resolveGeneric());
|
||||
if (attributeType == Void.class) {
|
||||
return Mono.from(adapter.toPublisher(value));
|
||||
}
|
||||
}
|
||||
String name = getAttributeName(handlerResult.getReturnTypeSource());
|
||||
bindingContext.getModel().asMap().putIfAbsent(name, value);
|
||||
}
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
private String getAttributeName(MethodParameter param) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -30,7 +30,6 @@ import org.springframework.web.reactive.HandlerResultHandler;
|
|||
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
|
||||
/**
|
||||
* {@code HandlerResultHandler} that handles return values from methods annotated
|
||||
* with {@code @ResponseBody} writing to the body of the request or response with
|
||||
|
@ -47,9 +46,7 @@ import org.springframework.web.server.ServerWebExchange;
|
|||
* @author Arjen Poutsma
|
||||
* @since 5.0
|
||||
*/
|
||||
public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandler
|
||||
implements HandlerResultHandler {
|
||||
|
||||
public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandler implements HandlerResultHandler {
|
||||
|
||||
/**
|
||||
* Basic constructor with a default {@link ReactiveAdapterRegistry}.
|
||||
|
@ -86,7 +83,7 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle
|
|||
|
||||
@Override
|
||||
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
|
||||
Object body = result.getReturnValue().orElse(null);
|
||||
Object body = result.getReturnValue();
|
||||
MethodParameter bodyTypeParameter = result.getReturnTypeSource();
|
||||
return writeBody(body, bodyTypeParameter, exchange);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.result.view;
|
||||
|
||||
import java.beans.PropertyEditor;
|
||||
|
@ -99,7 +100,7 @@ public class BindStatus {
|
|||
this.expression = path.substring(dotPos + 1);
|
||||
}
|
||||
|
||||
this.errors = requestContext.getErrors(beanName, false).orElse(null);
|
||||
this.errors = requestContext.getErrors(beanName, false);
|
||||
|
||||
if (this.errors != null) {
|
||||
// Usual case: A BindingResult is available as request attribute.
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.result.view;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
@ -47,13 +47,13 @@ class DefaultRendering implements Rendering {
|
|||
this.view = view;
|
||||
this.model = (model != null ? model.asMap() : Collections.emptyMap());
|
||||
this.status = status;
|
||||
this.headers = headers != null ? headers : EMPTY_HEADERS;
|
||||
this.headers = (headers != null ? headers : EMPTY_HEADERS);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Optional<Object> view() {
|
||||
return Optional.ofNullable(this.view);
|
||||
public Object view() {
|
||||
return this.view;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,8 +62,8 @@ class DefaultRendering implements Rendering {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<HttpStatus> status() {
|
||||
return Optional.ofNullable(this.status);
|
||||
public HttpStatus status() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,17 +13,16 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.result.view;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
|
||||
/**
|
||||
* Public API for HTML rendering. Supported as a return value in Spring WebFlux
|
||||
* controllers. Comparable to the use of {@code ModelAndView} as a return value
|
||||
|
@ -46,7 +45,7 @@ public interface Rendering {
|
|||
/**
|
||||
* Return the selected {@link String} view name or {@link View} object.
|
||||
*/
|
||||
Optional<Object> view();
|
||||
Object view();
|
||||
|
||||
/**
|
||||
* Return attributes to add to the model.
|
||||
|
@ -56,7 +55,7 @@ public interface Rendering {
|
|||
/**
|
||||
* Return the HTTP status to set the response to.
|
||||
*/
|
||||
Optional<HttpStatus> status();
|
||||
HttpStatus status();
|
||||
|
||||
/**
|
||||
* Return headers to add to the response.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -19,7 +19,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
|
@ -170,8 +169,8 @@ public class RequestContext {
|
|||
* Return the {@link RequestDataValueProcessor} instance to apply to in form
|
||||
* tag libraries and to redirect URLs.
|
||||
*/
|
||||
public Optional<RequestDataValueProcessor> getRequestDataValueProcessor() {
|
||||
return Optional.ofNullable(this.dataValueProcessor);
|
||||
public RequestDataValueProcessor getRequestDataValueProcessor() {
|
||||
return this.dataValueProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -346,7 +345,7 @@ public class RequestContext {
|
|||
* @param name name of the bind object
|
||||
* @return the Errors instance, or {@code null} if not found
|
||||
*/
|
||||
public Optional<Errors> getErrors(String name) {
|
||||
public Errors getErrors(String name) {
|
||||
return getErrors(name, isDefaultHtmlEscape());
|
||||
}
|
||||
|
||||
|
@ -356,34 +355,28 @@ public class RequestContext {
|
|||
* @param htmlEscape create an Errors instance with automatic HTML escaping?
|
||||
* @return the Errors instance, or {@code null} if not found
|
||||
*/
|
||||
public Optional<Errors> getErrors(String name, boolean htmlEscape) {
|
||||
public Errors getErrors(String name, boolean htmlEscape) {
|
||||
if (this.errorsMap == null) {
|
||||
this.errorsMap = new HashMap<>();
|
||||
}
|
||||
|
||||
// Since there is no Optional orElse + flatMap...
|
||||
Optional<Errors> optional = Optional.ofNullable(this.errorsMap.get(name));
|
||||
optional = optional.isPresent() ? optional : getModelObject(BindingResult.MODEL_KEY_PREFIX + name);
|
||||
Errors errors = this.errorsMap.get(name);
|
||||
if (errors == null) {
|
||||
errors = getModelObject(BindingResult.MODEL_KEY_PREFIX + name);
|
||||
}
|
||||
if (errors instanceof BindException) {
|
||||
errors = ((BindException) errors).getBindingResult();
|
||||
}
|
||||
|
||||
return optional
|
||||
.map(errors -> {
|
||||
if (errors instanceof BindException) {
|
||||
return ((BindException) errors).getBindingResult();
|
||||
}
|
||||
else {
|
||||
return errors;
|
||||
}
|
||||
})
|
||||
.map(errors -> {
|
||||
if (htmlEscape && !(errors instanceof EscapedErrors)) {
|
||||
errors = new EscapedErrors(errors);
|
||||
}
|
||||
else if (!htmlEscape && errors instanceof EscapedErrors) {
|
||||
errors = ((EscapedErrors) errors).getSource();
|
||||
}
|
||||
this.errorsMap.put(name, errors);
|
||||
return errors;
|
||||
});
|
||||
if (htmlEscape && !(errors instanceof EscapedErrors)) {
|
||||
errors = new EscapedErrors(errors);
|
||||
}
|
||||
else if (!htmlEscape && errors instanceof EscapedErrors) {
|
||||
errors = ((EscapedErrors) errors).getSource();
|
||||
}
|
||||
|
||||
this.errorsMap.put(name, errors);
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -393,10 +386,12 @@ public class RequestContext {
|
|||
* @return the model object
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> Optional<T> getModelObject(String modelName) {
|
||||
return Optional.ofNullable(this.model)
|
||||
.map(model -> Optional.ofNullable((T) model.get(modelName)))
|
||||
.orElse(this.exchange.getAttribute(modelName));
|
||||
protected <T> T getModelObject(String modelName) {
|
||||
T modelObject = (T) this.model.get(modelName);
|
||||
if (modelObject == null) {
|
||||
modelObject = (T) this.exchange.getAttribute(modelName);
|
||||
}
|
||||
return modelObject;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,9 +36,9 @@ import org.springframework.core.ReactiveAdapter;
|
|||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
|
@ -56,13 +56,13 @@ import org.springframework.web.server.support.HttpRequestPathHelper;
|
|||
* {@code HandlerResultHandler} that encapsulates the view resolution algorithm
|
||||
* supporting the following return types:
|
||||
* <ul>
|
||||
* <li>{@link Void} or no value -- default view name</li>
|
||||
* <li>{@link String} -- view name unless {@code @ModelAttribute}-annotated
|
||||
* <li>{@link View} -- View to render with
|
||||
* <li>{@link Model} -- attributes to add to the model
|
||||
* <li>{@link Map} -- attributes to add to the model
|
||||
* <li>{@link ModelAttribute @ModelAttribute} -- attribute for the model
|
||||
* <li>Non-simple value -- attribute for the model
|
||||
* <li>{@link Void} or no value -- default view name</li>
|
||||
* <li>{@link String} -- view name unless {@code @ModelAttribute}-annotated
|
||||
* <li>{@link View} -- View to render with
|
||||
* <li>{@link Model} -- attributes to add to the model
|
||||
* <li>{@link Map} -- attributes to add to the model
|
||||
* <li>{@link ModelAttribute @ModelAttribute} -- attribute for the model
|
||||
* <li>Non-simple value -- attribute for the model
|
||||
* </ul>
|
||||
*
|
||||
* <p>A String-based view name is resolved through the configured
|
||||
|
@ -150,14 +150,16 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport
|
|||
if (hasModelAnnotation(result.getReturnTypeSource())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Class<?> type = result.getReturnType().getRawClass();
|
||||
ReactiveAdapter adapter = getAdapter(result);
|
||||
if (adapter != null) {
|
||||
if (adapter.isNoValue()) {
|
||||
return true;
|
||||
}
|
||||
type = result.getReturnType().getGeneric(0).resolve(Object.class);
|
||||
type = result.getReturnType().getGeneric().resolve(Object.class);
|
||||
}
|
||||
|
||||
return (CharSequence.class.isAssignableFrom(type) || Rendering.class.isAssignableFrom(type) ||
|
||||
Model.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type) ||
|
||||
void.class.equals(type) || View.class.isAssignableFrom(type) ||
|
||||
|
@ -171,22 +173,21 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
|
||||
|
||||
Mono<Object> valueMono;
|
||||
ResolvableType valueType;
|
||||
ReactiveAdapter adapter = getAdapter(result);
|
||||
|
||||
if (adapter != null) {
|
||||
Assert.isTrue(!adapter.isMultiValue(), "Multi-value " +
|
||||
"reactive types not supported in view resolution: " + result.getReturnType());
|
||||
if (adapter.isMultiValue()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Multi-value reactive types not supported in view resolution: " + result.getReturnType());
|
||||
}
|
||||
|
||||
valueMono = result.getReturnValue()
|
||||
.map(value -> Mono.from(adapter.toPublisher(value)))
|
||||
.orElse(Mono.empty());
|
||||
valueMono = (result.getReturnValue() != null ?
|
||||
Mono.from(adapter.toPublisher(result.getReturnValue())) : Mono.empty());
|
||||
|
||||
valueType = adapter.isNoValue() ?
|
||||
ResolvableType.forClass(Void.class) :
|
||||
result.getReturnType().getGeneric(0);
|
||||
valueType = (adapter.isNoValue() ? ResolvableType.forClass(Void.class) :
|
||||
result.getReturnType().getGeneric());
|
||||
}
|
||||
else {
|
||||
valueMono = Mono.justOrEmpty(result.getReturnValue());
|
||||
|
@ -217,10 +218,16 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport
|
|||
}
|
||||
else if (Rendering.class.isAssignableFrom(clazz)) {
|
||||
Rendering render = (Rendering) returnValue;
|
||||
render.status().ifPresent(exchange.getResponse()::setStatusCode);
|
||||
HttpStatus status = render.status();
|
||||
if (status != null) {
|
||||
exchange.getResponse().setStatusCode(status);
|
||||
}
|
||||
exchange.getResponse().getHeaders().putAll(render.headers());
|
||||
model.addAllAttributes(render.modelAttributes());
|
||||
Object view = render.view().orElse(getDefaultViewName(exchange));
|
||||
Object view = render.view();
|
||||
if (view == null) {
|
||||
view = getDefaultViewName(exchange);
|
||||
}
|
||||
viewsMono = (view instanceof String ? resolveViews((String) view, locale) :
|
||||
Mono.just(Collections.singletonList((View) view)));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -13,11 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.socket;
|
||||
|
||||
import java.net.URI;
|
||||
import java.security.Principal;
|
||||
import java.util.Optional;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
|
@ -32,7 +32,6 @@ import org.springframework.util.Assert;
|
|||
* @since 5.0
|
||||
* @see WebSocketSession#getHandshakeInfo()
|
||||
*/
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public class HandshakeInfo {
|
||||
|
||||
private final URI uri;
|
||||
|
@ -41,7 +40,7 @@ public class HandshakeInfo {
|
|||
|
||||
private final HttpHeaders headers;
|
||||
|
||||
private final Optional<String> protocol;
|
||||
private final String protocol;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -49,13 +48,12 @@ public class HandshakeInfo {
|
|||
* @param uri the endpoint URL
|
||||
* @param headers request headers for server or response headers or client
|
||||
* @param principal the principal for the session
|
||||
* @param protocol the negotiated sub-protocol
|
||||
* @param protocol the negotiated sub-protocol (may be {@code null})
|
||||
*/
|
||||
public HandshakeInfo(URI uri, HttpHeaders headers, Mono<Principal> principal, Optional<String> protocol) {
|
||||
Assert.notNull(uri, "URI is required.");
|
||||
Assert.notNull(headers, "HttpHeaders are required.");
|
||||
Assert.notNull(principal, "Principal is required.");
|
||||
Assert.notNull(protocol, "Sub-protocol is required.");
|
||||
public HandshakeInfo(URI uri, HttpHeaders headers, Mono<Principal> principal, String protocol) {
|
||||
Assert.notNull(uri, "URI is required");
|
||||
Assert.notNull(headers, "HttpHeaders are required");
|
||||
Assert.notNull(principal, "Principal is required");
|
||||
this.uri = uri;
|
||||
this.headers = headers;
|
||||
this.principalMono = principal;
|
||||
|
@ -86,11 +84,11 @@ public class HandshakeInfo {
|
|||
}
|
||||
|
||||
/**
|
||||
* The sub-protocol negotiated at handshake time.
|
||||
* The sub-protocol negotiated at handshake time, or {@code null} if none.
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6455#section-1.9">
|
||||
* https://tools.ietf.org/html/rfc6455#section-1.9</a>
|
||||
* https://tools.ietf.org/html/rfc6455#section-1.9</a>
|
||||
*/
|
||||
public Optional<String> getSubProtocol() {
|
||||
public String getSubProtocol() {
|
||||
return this.protocol;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.socket;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
|
@ -27,10 +31,10 @@ public interface WebSocketHandler {
|
|||
|
||||
/**
|
||||
* Return the list of sub-protocols supported by this handler.
|
||||
* <p>By default an empty array is returned.
|
||||
* <p>By default an empty list is returned.
|
||||
*/
|
||||
default String[] getSubProtocols() {
|
||||
return new String[0];
|
||||
default List<String> getSubProtocols() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.web.reactive.socket.client;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||
|
@ -154,7 +155,7 @@ public class JettyWebSocketClient extends WebSocketClientSupport implements WebS
|
|||
MonoProcessor<Void> completionMono = MonoProcessor.create();
|
||||
return Mono.fromCallable(
|
||||
() -> {
|
||||
String[] protocols = beforeHandshake(url, headers, handler);
|
||||
List<String> protocols = beforeHandshake(url, headers, handler);
|
||||
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
|
||||
upgradeRequest.setSubProtocols(protocols);
|
||||
Object jettyHandler = createJettyHandler(url, handler, completionMono);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -16,6 +16,7 @@
|
|||
package org.springframework.web.reactive.socket.client;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
|
@ -74,13 +75,12 @@ public class ReactorNettyWebSocketClient extends WebSocketClientSupport implemen
|
|||
|
||||
@Override
|
||||
public Mono<Void> execute(URI url, HttpHeaders headers, WebSocketHandler handler) {
|
||||
|
||||
String[] protocols = beforeHandshake(url, headers, handler);
|
||||
List<String> protocols = beforeHandshake(url, headers, handler);
|
||||
|
||||
return getHttpClient()
|
||||
.ws(url.toString(),
|
||||
nettyHeaders -> setNettyHeaders(headers, nettyHeaders),
|
||||
StringUtils.arrayToCommaDelimitedString(protocols))
|
||||
StringUtils.collectionToCommaDelimitedString(protocols))
|
||||
.flatMap(response -> {
|
||||
HandshakeInfo info = afterHandshake(url, toHttpHeaders(response));
|
||||
ByteBufAllocator allocator = response.channel().alloc();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.web.reactive.socket.client;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
|
@ -94,10 +93,10 @@ public class StandardWebSocketClient extends WebSocketClientSupport implements W
|
|||
MonoProcessor<Void> completionMono = MonoProcessor.create();
|
||||
return Mono.fromCallable(
|
||||
() -> {
|
||||
String[] subProtocols = beforeHandshake(url, requestHeaders, handler);
|
||||
List<String> protocols = beforeHandshake(url, requestHeaders, handler);
|
||||
DefaultConfigurator configurator = new DefaultConfigurator(requestHeaders);
|
||||
Endpoint endpoint = createEndpoint(url, handler, completionMono, configurator);
|
||||
ClientEndpointConfig config = createEndpointConfig(configurator, subProtocols);
|
||||
ClientEndpointConfig config = createEndpointConfig(configurator, protocols);
|
||||
return this.webSocketContainer.connectToServer(endpoint, config, url);
|
||||
})
|
||||
.subscribeOn(Schedulers.elastic()) // connectToServer is blocking
|
||||
|
@ -114,10 +113,10 @@ public class StandardWebSocketClient extends WebSocketClientSupport implements W
|
|||
});
|
||||
}
|
||||
|
||||
private ClientEndpointConfig createEndpointConfig(Configurator configurator, String[] subProtocols) {
|
||||
private ClientEndpointConfig createEndpointConfig(Configurator configurator, List<String> subProtocols) {
|
||||
return ClientEndpointConfig.Builder.create()
|
||||
.configurator(configurator)
|
||||
.preferredSubprotocols(Arrays.asList(subProtocols))
|
||||
.preferredSubprotocols(subProtocols)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -128,12 +127,10 @@ public class StandardWebSocketClient extends WebSocketClientSupport implements W
|
|||
|
||||
private final HttpHeaders responseHeaders = new HttpHeaders();
|
||||
|
||||
|
||||
public DefaultConfigurator(HttpHeaders requestHeaders) {
|
||||
this.requestHeaders = requestHeaders;
|
||||
}
|
||||
|
||||
|
||||
public HttpHeaders getResponseHeaders() {
|
||||
return this.responseHeaders;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -18,7 +18,6 @@ package org.springframework.web.reactive.socket.client;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -132,18 +131,15 @@ public class UndertowWebSocketClient extends WebSocketClientSupport implements W
|
|||
return Mono.fromCallable(
|
||||
() -> {
|
||||
ConnectionBuilder builder = createConnectionBuilder(url);
|
||||
String[] protocols = beforeHandshake(url, headers, handler);
|
||||
List<String> protocols = beforeHandshake(url, headers, handler);
|
||||
DefaultNegotiation negotiation = new DefaultNegotiation(protocols, headers, builder);
|
||||
builder.setClientNegotiation(negotiation);
|
||||
|
||||
return builder.connect().addNotifier(
|
||||
new IoFuture.HandlingNotifier<WebSocketChannel, Object>() {
|
||||
|
||||
@Override
|
||||
public void handleDone(WebSocketChannel channel, Object attachment) {
|
||||
handleChannel(url, handler, completion, negotiation, channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleFailed(IOException ex, Object attachment) {
|
||||
completion.onError(new IllegalStateException("Failed to connect", ex));
|
||||
|
@ -161,11 +157,9 @@ public class UndertowWebSocketClient extends WebSocketClientSupport implements W
|
|||
* provided at construction time.
|
||||
*/
|
||||
protected ConnectionBuilder createConnectionBuilder(URI url) {
|
||||
|
||||
ConnectionBuilder builder = io.undertow.websockets.client.WebSocketClient
|
||||
.connectionBuilder(getXnioWorker(),
|
||||
new DefaultByteBufferPool(false, getPoolBufferSize()), url);
|
||||
|
||||
this.builderConsumer.accept(builder);
|
||||
return builder;
|
||||
}
|
||||
|
@ -192,11 +186,10 @@ public class UndertowWebSocketClient extends WebSocketClientSupport implements W
|
|||
|
||||
private final WebSocketClientNegotiation delegate;
|
||||
|
||||
|
||||
public DefaultNegotiation(String[] protocols, HttpHeaders requestHeaders,
|
||||
public DefaultNegotiation(List<String> protocols, HttpHeaders requestHeaders,
|
||||
ConnectionBuilder connectionBuilder) {
|
||||
|
||||
super(Arrays.asList(protocols), Collections.emptyList());
|
||||
super(protocols, Collections.emptyList());
|
||||
this.requestHeaders = requestHeaders;
|
||||
this.delegate = connectionBuilder.getClientNegotiation();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -13,10 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.socket.client;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Optional;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
@ -40,7 +41,7 @@ public class WebSocketClientSupport {
|
|||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
|
||||
protected String[] beforeHandshake(URI url, HttpHeaders requestHeaders, WebSocketHandler handler) {
|
||||
protected List<String> beforeHandshake(URI url, HttpHeaders requestHeaders, WebSocketHandler handler) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Executing handshake to " + url);
|
||||
}
|
||||
|
@ -52,7 +53,7 @@ public class WebSocketClientSupport {
|
|||
logger.debug("Handshake response: " + url + ", " + responseHeaders);
|
||||
}
|
||||
String protocol = responseHeaders.getFirst(SEC_WEBSOCKET_PROTOCOL);
|
||||
return new HandshakeInfo(url, responseHeaders, Mono.empty(), Optional.ofNullable(protocol));
|
||||
return new HandshakeInfo(url, responseHeaders, Mono.empty(), protocol);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -13,9 +13,8 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.web.reactive.socket.server;
|
||||
|
||||
import java.util.Optional;
|
||||
package org.springframework.web.reactive.socket.server;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
|
@ -46,8 +45,6 @@ public interface RequestUpgradeStrategy {
|
|||
* @return completion {@code Mono<Void>} to indicate the outcome of the
|
||||
* WebSocket session handling.
|
||||
*/
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler webSocketHandler,
|
||||
Optional<String> subProtocol);
|
||||
Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler webSocketHandler, String subProtocol);
|
||||
|
||||
}
|
||||
|
|
|
@ -13,12 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.socket.server.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
@ -93,7 +92,7 @@ public class HandshakeWebSocketService implements WebSocketService, Lifecycle {
|
|||
* @param upgradeStrategy the strategy to use
|
||||
*/
|
||||
public HandshakeWebSocketService(RequestUpgradeStrategy upgradeStrategy) {
|
||||
Assert.notNull(upgradeStrategy, "'upgradeStrategy' is required");
|
||||
Assert.notNull(upgradeStrategy, "RequestUpgradeStrategy is required");
|
||||
this.upgradeStrategy = upgradeStrategy;
|
||||
}
|
||||
|
||||
|
@ -197,7 +196,7 @@ public class HandshakeWebSocketService implements WebSocketService, Lifecycle {
|
|||
return handleBadRequest("Missing \"Sec-WebSocket-Key\" header");
|
||||
}
|
||||
|
||||
Optional<String> protocol = selectProtocol(headers, handler);
|
||||
String protocol = selectProtocol(headers, handler);
|
||||
return this.upgradeStrategy.upgrade(exchange, handler, protocol);
|
||||
}
|
||||
|
||||
|
@ -208,15 +207,17 @@ public class HandshakeWebSocketService implements WebSocketService, Lifecycle {
|
|||
return Mono.error(new ServerWebInputException(reason));
|
||||
}
|
||||
|
||||
private Optional<String> selectProtocol(HttpHeaders headers, WebSocketHandler handler) {
|
||||
private String selectProtocol(HttpHeaders headers, WebSocketHandler handler) {
|
||||
String protocolHeader = headers.getFirst(SEC_WEBSOCKET_PROTOCOL);
|
||||
if (protocolHeader == null) {
|
||||
return Optional.empty();
|
||||
if (protocolHeader != null) {
|
||||
List<String> supportedProtocols = handler.getSubProtocols();
|
||||
for (String protocol : StringUtils.commaDelimitedListToStringArray(protocolHeader)) {
|
||||
if (supportedProtocols.contains(protocol)) {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
}
|
||||
String[] protocols = handler.getSubProtocols();
|
||||
return StringUtils.commaDelimitedListToSet(protocolHeader).stream()
|
||||
.filter(protocol -> Arrays.stream(protocols).anyMatch(protocol::equals))
|
||||
.findFirst();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ package org.springframework.web.reactive.socket.server.upgrade;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.Optional;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -48,7 +47,6 @@ import org.springframework.web.server.ServerWebExchange;
|
|||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Lifecycle {
|
||||
|
||||
private static final ThreadLocal<WebSocketHandlerContainer> adapterHolder =
|
||||
|
@ -73,7 +71,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life
|
|||
this.factory = new WebSocketServerFactory(this.servletContext);
|
||||
this.factory.setCreator((request, response) -> {
|
||||
WebSocketHandlerContainer container = adapterHolder.get();
|
||||
String protocol = container.getProtocol().orElse(null);
|
||||
String protocol = container.getProtocol();
|
||||
if (protocol != null) {
|
||||
response.setAcceptedSubProtocol(protocol);
|
||||
}
|
||||
|
@ -110,9 +108,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life
|
|||
|
||||
|
||||
@Override
|
||||
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,
|
||||
Optional<String> subProtocol) {
|
||||
|
||||
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, String subProtocol) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
|
||||
|
@ -155,7 +151,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life
|
|||
return ((ServletServerHttpResponse) response).getServletResponse();
|
||||
}
|
||||
|
||||
private HandshakeInfo getHandshakeInfo(ServerWebExchange exchange, Optional<String> protocol) {
|
||||
private HandshakeInfo getHandshakeInfo(ServerWebExchange exchange, String protocol) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
Mono<Principal> principal = exchange.getPrincipal();
|
||||
return new HandshakeInfo(request.getURI(), request.getHeaders(), principal, protocol);
|
||||
|
@ -178,9 +174,9 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life
|
|||
|
||||
private final JettyWebSocketHandlerAdapter adapter;
|
||||
|
||||
private final Optional<String> protocol;
|
||||
private final String protocol;
|
||||
|
||||
public WebSocketHandlerContainer(JettyWebSocketHandlerAdapter adapter, Optional<String> protocol) {
|
||||
public WebSocketHandlerContainer(JettyWebSocketHandlerAdapter adapter, String protocol) {
|
||||
this.adapter = adapter;
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
@ -189,7 +185,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life
|
|||
return this.adapter;
|
||||
}
|
||||
|
||||
public Optional<String> getProtocol() {
|
||||
public String getProtocol() {
|
||||
return this.protocol;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -13,10 +13,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.socket.server.upgrade;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Optional;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
|
@ -35,23 +35,19 @@ import org.springframework.web.server.ServerWebExchange;
|
|||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public class ReactorNettyRequestUpgradeStrategy implements RequestUpgradeStrategy {
|
||||
|
||||
@Override
|
||||
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,
|
||||
Optional<String> subProtocol) {
|
||||
|
||||
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, String subProtocol) {
|
||||
ReactorServerHttpResponse response = (ReactorServerHttpResponse) exchange.getResponse();
|
||||
HandshakeInfo info = getHandshakeInfo(exchange, subProtocol);
|
||||
NettyDataBufferFactory bufferFactory = (NettyDataBufferFactory) response.bufferFactory();
|
||||
|
||||
return response.getReactorResponse().sendWebsocket(subProtocol.orElse(null),
|
||||
(in, out) -> handler.handle(
|
||||
new ReactorNettyWebSocketSession(in, out, info, bufferFactory)));
|
||||
return response.getReactorResponse().sendWebsocket(subProtocol,
|
||||
(in, out) -> handler.handle(new ReactorNettyWebSocketSession(in, out, info, bufferFactory)));
|
||||
}
|
||||
|
||||
private HandshakeInfo getHandshakeInfo(ServerWebExchange exchange, Optional<String> protocol) {
|
||||
private HandshakeInfo getHandshakeInfo(ServerWebExchange exchange, String protocol) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
Mono<Principal> principal = exchange.getPrincipal();
|
||||
return new HandshakeInfo(request.getURI(), request.getHeaders(), principal, protocol);
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.springframework.web.reactive.socket.server.upgrade;
|
|||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -47,14 +46,13 @@ import org.springframework.web.server.ServerWebExchange;
|
|||
* @author Violeta Georgieva
|
||||
* @since 5.0
|
||||
*/
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public class TomcatRequestUpgradeStrategy implements RequestUpgradeStrategy {
|
||||
|
||||
private static final String SERVER_CONTAINER_ATTR = "javax.websocket.server.ServerContainer";
|
||||
|
||||
|
||||
@Override
|
||||
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, Optional<String> subProtocol){
|
||||
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, String subProtocol){
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
|
||||
|
@ -70,7 +68,7 @@ public class TomcatRequestUpgradeStrategy implements RequestUpgradeStrategy {
|
|||
|
||||
String requestURI = servletRequest.getRequestURI();
|
||||
DefaultServerEndpointConfig config = new DefaultServerEndpointConfig(requestURI, endpoint);
|
||||
config.setSubprotocols(subProtocol.map(Collections::singletonList).orElse(Collections.emptyList()));
|
||||
config.setSubprotocols(subProtocol != null ? Collections.singletonList(subProtocol) : Collections.emptyList());
|
||||
|
||||
try {
|
||||
WsServerContainer container = getContainer(servletRequest);
|
||||
|
@ -93,7 +91,7 @@ public class TomcatRequestUpgradeStrategy implements RequestUpgradeStrategy {
|
|||
return ((ServletServerHttpResponse) response).getServletResponse();
|
||||
}
|
||||
|
||||
private HandshakeInfo getHandshakeInfo(ServerWebExchange exchange, Optional<String> protocol) {
|
||||
private HandshakeInfo getHandshakeInfo(ServerWebExchange exchange, String protocol) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
Mono<Principal> principal = exchange.getPrincipal();
|
||||
return new HandshakeInfo(request.getURI(), request.getHeaders(), principal, protocol);
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.net.URI;
|
|||
import java.security.Principal;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
|
@ -50,16 +49,15 @@ import org.springframework.web.server.ServerWebExchange;
|
|||
* @author Violeta Georgieva
|
||||
* @since 5.0
|
||||
*/
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public class UndertowRequestUpgradeStrategy implements RequestUpgradeStrategy {
|
||||
|
||||
@Override
|
||||
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, Optional<String> subProtocol) {
|
||||
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, String subProtocol) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
Assert.isInstanceOf(UndertowServerHttpRequest.class, request, "UndertowServerHttpRequest required");
|
||||
HttpServerExchange httpExchange = ((UndertowServerHttpRequest) request).getUndertowExchange();
|
||||
|
||||
Set<String> protocols = subProtocol.map(Collections::singleton).orElse(Collections.emptySet());
|
||||
Set<String> protocols = (subProtocol != null ? Collections.singleton(subProtocol) : Collections.emptySet());
|
||||
Hybi13Handshake handshake = new Hybi13Handshake(protocols, false);
|
||||
List<Handshake> handshakes = Collections.singletonList(handshake);
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ package org.springframework.web.reactive.config;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -37,13 +36,8 @@ import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
|
|||
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
|
||||
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.BDDMockito.any;
|
||||
import static org.mockito.BDDMockito.doAnswer;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.verify;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.BDDMockito.*;
|
||||
|
||||
/**
|
||||
* Test fixture for {@link DelegatingWebFluxConfiguration} tests.
|
||||
|
@ -72,8 +66,8 @@ public class DelegatingWebFluxConfigurationTests {
|
|||
MockitoAnnotations.initMocks(this);
|
||||
delegatingConfig = new DelegatingWebFluxConfiguration();
|
||||
delegatingConfig.setApplicationContext(new StaticApplicationContext());
|
||||
given(webFluxConfigurer.getValidator()).willReturn(Optional.empty());
|
||||
given(webFluxConfigurer.getMessageCodesResolver()).willReturn(Optional.empty());
|
||||
given(webFluxConfigurer.getValidator()).willReturn(null);
|
||||
given(webFluxConfigurer.getMessageCodesResolver()).willReturn(null);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -98,18 +98,18 @@ public class SseHandlerFunctionIntegrationTests extends AbstractRouterFunctionIn
|
|||
|
||||
StepVerifier.create(result)
|
||||
.consumeNextWith( event -> {
|
||||
assertEquals("0", event.id().get());
|
||||
assertEquals("foo", event.data().get());
|
||||
assertEquals("bar", event.comment().get());
|
||||
assertFalse(event.event().isPresent());
|
||||
assertFalse(event.retry().isPresent());
|
||||
assertEquals("0", event.id());
|
||||
assertEquals("foo", event.data());
|
||||
assertEquals("bar", event.comment());
|
||||
assertNull(event.event());
|
||||
assertNull(event.retry());
|
||||
})
|
||||
.consumeNextWith( event -> {
|
||||
assertEquals("1", event.id().get());
|
||||
assertEquals("foo", event.data().get());
|
||||
assertEquals("bar", event.comment().get());
|
||||
assertFalse(event.event().isPresent());
|
||||
assertFalse(event.retry().isPresent());
|
||||
assertEquals("1", event.id());
|
||||
assertEquals("foo", event.data());
|
||||
assertEquals("bar", event.comment());
|
||||
assertNull(event.event());
|
||||
assertNull(event.retry());
|
||||
})
|
||||
.expectComplete()
|
||||
.verify(Duration.ofSeconds(5L));
|
||||
|
|
|
@ -18,7 +18,6 @@ package org.springframework.web.reactive.result.method;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
@ -59,7 +58,6 @@ public class InvocableHandlerMethodTests {
|
|||
|
||||
@Test
|
||||
public void invokeMethodWithNoValue() throws Exception {
|
||||
|
||||
Mono<Object> resolvedValue = Mono.empty();
|
||||
Method method = on(TestController.class).mockCall(o -> o.singleArg(null)).method();
|
||||
Mono<HandlerResult> mono = invoke(new TestController(), method, resolverFor(resolvedValue));
|
||||
|
@ -69,7 +67,6 @@ public class InvocableHandlerMethodTests {
|
|||
|
||||
@Test
|
||||
public void invokeMethodWithValue() throws Exception {
|
||||
|
||||
Mono<Object> resolvedValue = Mono.just("value1");
|
||||
Method method = on(TestController.class).mockCall(o -> o.singleArg(null)).method();
|
||||
Mono<HandlerResult> mono = invoke(new TestController(), method, resolverFor(resolvedValue));
|
||||
|
@ -79,7 +76,6 @@ public class InvocableHandlerMethodTests {
|
|||
|
||||
@Test
|
||||
public void noMatchingResolver() throws Exception {
|
||||
|
||||
Method method = on(TestController.class).mockCall(o -> o.singleArg(null)).method();
|
||||
Mono<HandlerResult> mono = invoke(new TestController(), method);
|
||||
|
||||
|
@ -95,7 +91,6 @@ public class InvocableHandlerMethodTests {
|
|||
|
||||
@Test
|
||||
public void resolverThrowsException() throws Exception {
|
||||
|
||||
Mono<Object> resolvedValue = Mono.error(new UnsupportedMediaTypeStatusException("boo"));
|
||||
Method method = on(TestController.class).mockCall(o -> o.singleArg(null)).method();
|
||||
Mono<HandlerResult> mono = invoke(new TestController(), method, resolverFor(resolvedValue));
|
||||
|
@ -111,7 +106,6 @@ public class InvocableHandlerMethodTests {
|
|||
|
||||
@Test
|
||||
public void illegalArgumentExceptionIsWrappedWithInvocationDetails() throws Exception {
|
||||
|
||||
Mono<Object> resolvedValue = Mono.just(1);
|
||||
Method method = on(TestController.class).mockCall(o -> o.singleArg(null)).method();
|
||||
Mono<HandlerResult> mono = invoke(new TestController(), method, resolverFor(resolvedValue));
|
||||
|
@ -129,7 +123,6 @@ public class InvocableHandlerMethodTests {
|
|||
|
||||
@Test
|
||||
public void invocationTargetExceptionIsUnwrapped() throws Exception {
|
||||
|
||||
Method method = on(TestController.class).mockCall(TestController::exceptionMethod).method();
|
||||
Mono<HandlerResult> mono = invoke(new TestController(), method);
|
||||
|
||||
|
@ -144,7 +137,6 @@ public class InvocableHandlerMethodTests {
|
|||
|
||||
@Test
|
||||
public void invokeMethodWithResponseStatus() throws Exception {
|
||||
|
||||
Method method = on(TestController.class).annotPresent(ResponseStatus.class).resolveMethod();
|
||||
Mono<HandlerResult> mono = invoke(new TestController(), method);
|
||||
|
||||
|
@ -175,9 +167,7 @@ public class InvocableHandlerMethodTests {
|
|||
private void assertHandlerResultValue(Mono<HandlerResult> mono, String expected) {
|
||||
StepVerifier.create(mono)
|
||||
.consumeNextWith(result -> {
|
||||
Optional<?> optional = result.getReturnValue();
|
||||
assertTrue(optional.isPresent());
|
||||
assertEquals(expected, optional.get());
|
||||
assertEquals(expected, result.getReturnValue());
|
||||
})
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
|
|
@ -23,7 +23,6 @@ import java.util.Collections;
|
|||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
@ -353,10 +352,10 @@ public class RequestMappingInfoHandlerMappingTests {
|
|||
HandlerResult result = mono.block();
|
||||
assertNotNull(result);
|
||||
|
||||
Optional<Object> value = result.getReturnValue();
|
||||
assertTrue(value.isPresent());
|
||||
assertEquals(HttpHeaders.class, value.get().getClass());
|
||||
assertEquals(allowedMethods, ((HttpHeaders) value.get()).getAllow());
|
||||
Object value = result.getReturnValue();
|
||||
assertNotNull(value);
|
||||
assertEquals(HttpHeaders.class, value.getClass());
|
||||
assertEquals(allowedMethods, ((HttpHeaders) value).getAllow());
|
||||
}
|
||||
|
||||
private void testMediaTypeNotAcceptable(String url) throws Exception {
|
||||
|
@ -490,4 +489,4 @@ public class RequestMappingInfoHandlerMappingTests {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ public class ControllerAdviceTests {
|
|||
TestController controller = context.getBean(TestController.class);
|
||||
controller.setException(exception);
|
||||
|
||||
Object actual = handle(adapter, controller, "handle").getReturnValue().orElse(null);
|
||||
Object actual = handle(adapter, controller, "handle").getReturnValue();
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,12 +37,10 @@ import org.springframework.web.reactive.config.EnableWebFlux;
|
|||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.springframework.core.ResolvableType.forClassWithGenerics;
|
||||
import static org.springframework.http.MediaType.TEXT_EVENT_STREAM;
|
||||
import static org.springframework.web.reactive.function.BodyExtractors.toFlux;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.core.ResolvableType.*;
|
||||
import static org.springframework.http.MediaType.*;
|
||||
import static org.springframework.web.reactive.function.BodyExtractors.*;
|
||||
|
||||
/**
|
||||
* @author Sebastien Deleuze
|
||||
|
@ -112,18 +110,18 @@ public class SseIntegrationTests extends AbstractHttpHandlerIntegrationTests {
|
|||
|
||||
StepVerifier.create(result)
|
||||
.consumeNextWith( event -> {
|
||||
assertEquals("0", event.id().get());
|
||||
assertEquals("foo", event.data().get());
|
||||
assertEquals("bar", event.comment().get());
|
||||
assertFalse(event.event().isPresent());
|
||||
assertFalse(event.retry().isPresent());
|
||||
assertEquals("0", event.id());
|
||||
assertEquals("foo", event.data());
|
||||
assertEquals("bar", event.comment());
|
||||
assertNull(event.event());
|
||||
assertNull(event.retry());
|
||||
})
|
||||
.consumeNextWith( event -> {
|
||||
assertEquals("1", event.id().get());
|
||||
assertEquals("foo", event.data().get());
|
||||
assertEquals("bar", event.comment().get());
|
||||
assertFalse(event.event().isPresent());
|
||||
assertFalse(event.retry().isPresent());
|
||||
assertEquals("1", event.id());
|
||||
assertEquals("foo", event.data());
|
||||
assertEquals("bar", event.comment());
|
||||
assertNull(event.event());
|
||||
assertNull(event.retry());
|
||||
})
|
||||
.thenCancel()
|
||||
.verify(Duration.ofSeconds(5L));
|
||||
|
@ -140,18 +138,18 @@ public class SseIntegrationTests extends AbstractHttpHandlerIntegrationTests {
|
|||
|
||||
StepVerifier.create(result)
|
||||
.consumeNextWith( event -> {
|
||||
assertEquals("0", event.id().get());
|
||||
assertEquals("foo", event.data().get());
|
||||
assertEquals("bar", event.comment().get());
|
||||
assertFalse(event.event().isPresent());
|
||||
assertFalse(event.retry().isPresent());
|
||||
assertEquals("0", event.id());
|
||||
assertEquals("foo", event.data());
|
||||
assertEquals("bar", event.comment());
|
||||
assertNull(event.event());
|
||||
assertNull(event.retry());
|
||||
})
|
||||
.consumeNextWith( event -> {
|
||||
assertEquals("1", event.id().get());
|
||||
assertEquals("foo", event.data().get());
|
||||
assertEquals("bar", event.comment().get());
|
||||
assertFalse(event.event().isPresent());
|
||||
assertFalse(event.retry().isPresent());
|
||||
assertEquals("1", event.id());
|
||||
assertEquals("foo", event.data());
|
||||
assertEquals("bar", event.comment());
|
||||
assertNull(event.event());
|
||||
assertNull(event.retry());
|
||||
})
|
||||
.thenCancel()
|
||||
.verify(Duration.ofSeconds(5L));
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.result.view;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
@ -23,29 +23,23 @@ import java.util.Map;
|
|||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultRenderingBuilder}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class DefaultRenderingBuilderTests {
|
||||
|
||||
|
||||
@Test
|
||||
public void defaultValues() {
|
||||
Rendering rendering = Rendering.view("abc").build();
|
||||
|
||||
assertEquals("abc", rendering.view().orElse(null));
|
||||
assertEquals("abc", rendering.view());
|
||||
assertEquals(Collections.emptyMap(), rendering.modelAttributes());
|
||||
assertNull(rendering.status().orElse(null));
|
||||
assertNull(rendering.status());
|
||||
assertEquals(0, rendering.headers().size());
|
||||
}
|
||||
|
||||
|
@ -53,7 +47,7 @@ public class DefaultRenderingBuilderTests {
|
|||
public void defaultValuesForRedirect() throws Exception {
|
||||
Rendering rendering = Rendering.redirectTo("abc").build();
|
||||
|
||||
Object view = rendering.view().orElse(null);
|
||||
Object view = rendering.view();
|
||||
assertEquals(RedirectView.class, view.getClass());
|
||||
assertEquals("abc", ((RedirectView) view).getUrl());
|
||||
assertTrue(((RedirectView) view).isContextRelative());
|
||||
|
@ -64,7 +58,7 @@ public class DefaultRenderingBuilderTests {
|
|||
@Test
|
||||
public void viewName() {
|
||||
Rendering rendering = Rendering.view("foo").build();
|
||||
assertEquals("foo", rendering.view().orElse(null));
|
||||
assertEquals("foo", rendering.view());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -118,7 +112,7 @@ public class DefaultRenderingBuilderTests {
|
|||
public void redirectWithAbsoluteUrl() throws Exception {
|
||||
Rendering rendering = Rendering.redirectTo("foo").contextRelative(false).build();
|
||||
|
||||
Object view = rendering.view().orElse(null);
|
||||
Object view = rendering.view();
|
||||
assertEquals(RedirectView.class, view.getClass());
|
||||
assertFalse(((RedirectView) view).isContextRelative());
|
||||
}
|
||||
|
@ -127,7 +121,7 @@ public class DefaultRenderingBuilderTests {
|
|||
public void redirectWithPropagateQuery() throws Exception {
|
||||
Rendering rendering = Rendering.redirectTo("foo").propagateQuery(true).build();
|
||||
|
||||
Object view = rendering.view().orElse(null);
|
||||
Object view = rendering.view();
|
||||
assertEquals(RedirectView.class, view.getClass());
|
||||
assertTrue(((RedirectView) view).isPropagateQuery());
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
package org.springframework.web.reactive.socket;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
|
@ -69,19 +71,16 @@ public class WebSocketIntegrationTests extends AbstractWebSocketIntegrationTests
|
|||
|
||||
@Test
|
||||
public void subProtocol() throws Exception {
|
||||
|
||||
String protocol = "echo-v1";
|
||||
AtomicReference<HandshakeInfo> infoRef = new AtomicReference<>();
|
||||
MonoProcessor<Object> output = MonoProcessor.create();
|
||||
|
||||
client.execute(getUrl("/sub-protocol"),
|
||||
new WebSocketHandler() {
|
||||
|
||||
@Override
|
||||
public String[] getSubProtocols() {
|
||||
return new String[] {protocol};
|
||||
public List<String> getSubProtocols() {
|
||||
return Collections.singletonList(protocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(WebSocketSession session) {
|
||||
infoRef.set(session.getHandshakeInfo());
|
||||
|
@ -96,7 +95,7 @@ public class WebSocketIntegrationTests extends AbstractWebSocketIntegrationTests
|
|||
HandshakeInfo info = infoRef.get();
|
||||
assertThat(info.getHeaders().getFirst("Upgrade"), Matchers.equalToIgnoringCase("websocket"));
|
||||
assertEquals(protocol, info.getHeaders().getFirst("Sec-WebSocket-Protocol"));
|
||||
assertEquals("Wrong protocol accepted", protocol, info.getSubProtocol().orElse("none"));
|
||||
assertEquals("Wrong protocol accepted", protocol, info.getSubProtocol());
|
||||
assertEquals("Wrong protocol detected on the server side", protocol, output.block(Duration.ofMillis(5000)));
|
||||
}
|
||||
|
||||
|
@ -122,7 +121,6 @@ public class WebSocketIntegrationTests extends AbstractWebSocketIntegrationTests
|
|||
|
||||
@Bean
|
||||
public HandlerMapping handlerMapping() {
|
||||
|
||||
Map<String, WebSocketHandler> map = new HashMap<>();
|
||||
map.put("/echo", new EchoWebSocketHandler());
|
||||
map.put("/sub-protocol", new SubProtocolWebSocketHandler());
|
||||
|
@ -149,13 +147,13 @@ public class WebSocketIntegrationTests extends AbstractWebSocketIntegrationTests
|
|||
private static class SubProtocolWebSocketHandler implements WebSocketHandler {
|
||||
|
||||
@Override
|
||||
public String[] getSubProtocols() {
|
||||
return new String[] {"echo-v1"};
|
||||
public List<String> getSubProtocols() {
|
||||
return Collections.singletonList("echo-v1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(WebSocketSession session) {
|
||||
String protocol = session.getHandshakeInfo().getSubProtocol().orElse("none");
|
||||
String protocol = session.getHandshakeInfo().getSubProtocol();
|
||||
WebSocketMessage message = session.textMessage(protocol);
|
||||
return doSend(session, Mono.just(message));
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.socket.client;
|
||||
|
||||
import java.net.URI;
|
||||
|
@ -24,6 +25,7 @@ import java.util.function.Function;
|
|||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.reactivex.netty.protocol.http.HttpHandlerNames;
|
||||
import io.reactivex.netty.protocol.http.client.HttpClient;
|
||||
import io.reactivex.netty.protocol.http.client.HttpClientRequest;
|
||||
import io.reactivex.netty.protocol.http.ws.WebSocketConnection;
|
||||
|
@ -39,12 +41,11 @@ import rx.RxReactiveStreams;
|
|||
import org.springframework.core.io.buffer.NettyDataBufferFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.reactive.socket.HandshakeInfo;
|
||||
import org.springframework.web.reactive.socket.WebSocketHandler;
|
||||
import org.springframework.web.reactive.socket.adapter.RxNettyWebSocketSession;
|
||||
|
||||
import static io.reactivex.netty.protocol.http.HttpHandlerNames.WsClientDecoder;
|
||||
|
||||
/**
|
||||
* {@link WebSocketClient} implementation for use with RxNetty.
|
||||
* For internal use within the framework.
|
||||
|
@ -125,7 +126,7 @@ public class RxNettyWebSocketClient extends WebSocketClientSupport implements We
|
|||
|
||||
@SuppressWarnings("cast")
|
||||
private Observable<Void> executeInternal(URI url, HttpHeaders headers, WebSocketHandler handler) {
|
||||
String[] protocols = beforeHandshake(url, headers, handler);
|
||||
List<String> protocols = beforeHandshake(url, headers, handler);
|
||||
return createRequest(url, headers, protocols)
|
||||
.flatMap(response -> {
|
||||
Observable<WebSocketConnection> conn = response.getWebSocketConnection();
|
||||
|
@ -141,13 +142,13 @@ public class RxNettyWebSocketClient extends WebSocketClientSupport implements We
|
|||
ByteBufAllocator allocator = response.unsafeNettyChannel().alloc();
|
||||
NettyDataBufferFactory factory = new NettyDataBufferFactory(allocator);
|
||||
RxNettyWebSocketSession session = new RxNettyWebSocketSession(conn, info, factory);
|
||||
session.aggregateFrames(response.unsafeNettyChannel(), WsClientDecoder.getName());
|
||||
session.aggregateFrames(response.unsafeNettyChannel(), HttpHandlerNames.WsClientDecoder.getName());
|
||||
|
||||
return RxReactiveStreams.toObservable(handler.handle(session));
|
||||
});
|
||||
}
|
||||
|
||||
private WebSocketRequest<ByteBuf> createRequest(URI url, HttpHeaders headers, String[] protocols) {
|
||||
private WebSocketRequest<ByteBuf> createRequest(URI url, HttpHeaders headers, List<String> protocols) {
|
||||
String query = url.getRawQuery();
|
||||
String requestUrl = url.getRawPath() + (query != null ? "?" + query : "");
|
||||
HttpClientRequest<ByteBuf, ByteBuf> request = getHttpClient(url).createGet(requestUrl);
|
||||
|
@ -158,9 +159,8 @@ public class RxNettyWebSocketClient extends WebSocketClientSupport implements We
|
|||
request = request.setHeaders(map);
|
||||
}
|
||||
|
||||
return (ObjectUtils.isEmpty(protocols) ?
|
||||
request.requestWebSocketUpgrade() :
|
||||
request.requestWebSocketUpgrade().requestSubProtocols(protocols));
|
||||
return (ObjectUtils.isEmpty(protocols) ? request.requestWebSocketUpgrade() :
|
||||
request.requestWebSocketUpgrade().requestSubProtocols(StringUtils.toStringArray(protocols)));
|
||||
}
|
||||
|
||||
private HttpHeaders toHttpHeaders(WebSocketResponse<ByteBuf> response) {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.socket.server.upgrade;
|
||||
|
||||
import java.security.Principal;
|
||||
|
@ -40,14 +41,10 @@ import org.springframework.web.server.ServerWebExchange;
|
|||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public class RxNettyRequestUpgradeStrategy implements RequestUpgradeStrategy {
|
||||
|
||||
|
||||
@Override
|
||||
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,
|
||||
Optional<String> subProtocol) {
|
||||
|
||||
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, String subProtocol) {
|
||||
RxNettyServerHttpResponse response = (RxNettyServerHttpResponse) exchange.getResponse();
|
||||
HttpServerResponse<?> rxNettyResponse = response.getRxNettyResponse();
|
||||
|
||||
|
@ -62,18 +59,18 @@ public class RxNettyRequestUpgradeStrategy implements RequestUpgradeStrategy {
|
|||
return RxReactiveStreams.toObservable(handler.handle(session));
|
||||
});
|
||||
|
||||
if (subProtocol.isPresent()) {
|
||||
handshaker = handshaker.subprotocol(subProtocol.get());
|
||||
if (subProtocol != null) {
|
||||
handshaker = handshaker.subprotocol(subProtocol);
|
||||
}
|
||||
else {
|
||||
// TODO: https://github.com/reactor/reactor-netty/issues/20
|
||||
handshaker = handshaker.subprotocol(new String[0]);
|
||||
handshaker = handshaker.subprotocol();
|
||||
}
|
||||
|
||||
return Mono.from(RxReactiveStreams.toPublisher(handshaker));
|
||||
}
|
||||
|
||||
private HandshakeInfo getHandshakeInfo(ServerWebExchange exchange, Optional<String> protocol) {
|
||||
private HandshakeInfo getHandshakeInfo(ServerWebExchange exchange, String protocol) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
Mono<Principal> principal = exchange.getPrincipal();
|
||||
return new HandshakeInfo(request.getURI(), request.getHeaders(), principal, protocol);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -50,7 +51,6 @@ import org.springframework.web.context.request.async.WebAsyncUtils;
|
|||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
|
||||
|
||||
/**
|
||||
* Private helper class to assist with handling "reactive" return values types
|
||||
* that can be adapted to a Reactive Streams {@link Publisher} through the
|
||||
|
@ -70,9 +70,6 @@ class ReactiveTypeHandler {
|
|||
|
||||
private static Log logger = LogFactory.getLog(ReactiveTypeHandler.class);
|
||||
|
||||
private static final MediaType JSON_TYPE = new MediaType("application", "*+json");
|
||||
|
||||
|
||||
private final ReactiveAdapterRegistry reactiveRegistry;
|
||||
|
||||
private final TaskExecutor taskExecutor;
|
||||
|
@ -100,14 +97,13 @@ class ReactiveTypeHandler {
|
|||
* Whether the type can be adapted to a Reactive Streams {@link Publisher}.
|
||||
*/
|
||||
public boolean isReactiveType(Class<?> type) {
|
||||
return this.reactiveRegistry.hasAdapters() && this.reactiveRegistry.getAdapter(type) != null;
|
||||
return (this.reactiveRegistry.hasAdapters() && this.reactiveRegistry.getAdapter(type) != null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the given reactive return value and decide whether to adapt it
|
||||
* to a {@link ResponseBodyEmitter} or a {@link DeferredResult}.
|
||||
*
|
||||
* @return an emitter for streaming or {@code null} if handled internally
|
||||
* with a {@link DeferredResult}.
|
||||
*/
|
||||
|
@ -164,7 +160,6 @@ class ReactiveTypeHandler {
|
|||
|
||||
private ResponseBodyEmitter getEmitter(MediaType mediaType) {
|
||||
return new ResponseBodyEmitter() {
|
||||
|
||||
@Override
|
||||
protected void extendResponse(ServerHttpResponse outputMessage) {
|
||||
outputMessage.getHeaders().setContentType(mediaType);
|
||||
|
@ -191,24 +186,20 @@ class ReactiveTypeHandler {
|
|||
|
||||
private volatile boolean done;
|
||||
|
||||
|
||||
protected AbstractEmitterSubscriber(ResponseBodyEmitter emitter, TaskExecutor executor) {
|
||||
this.emitter = emitter;
|
||||
this.taskExecutor = executor;
|
||||
}
|
||||
|
||||
|
||||
public void connect(ReactiveAdapter adapter, Object returnValue) {
|
||||
Publisher<Object> publisher = adapter.toPublisher(returnValue);
|
||||
publisher.subscribe(this);
|
||||
}
|
||||
|
||||
|
||||
protected ResponseBodyEmitter getEmitter() {
|
||||
return this.emitter;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void onSubscribe(Subscription subscription) {
|
||||
this.subscription = subscription;
|
||||
|
@ -344,10 +335,18 @@ class ReactiveTypeHandler {
|
|||
|
||||
private SseEmitter.SseEventBuilder adapt(ServerSentEvent<?> event) {
|
||||
SseEmitter.SseEventBuilder builder = SseEmitter.event();
|
||||
event.id().ifPresent(builder::id);
|
||||
event.comment().ifPresent(builder::comment);
|
||||
event.data().ifPresent(builder::data);
|
||||
event.retry().ifPresent(duration -> builder.reconnectTime(duration.toMillis()));
|
||||
if (event.id() != null) {
|
||||
builder.id(event.id());
|
||||
}
|
||||
if (event.comment() != null) {
|
||||
builder.comment(event.comment());
|
||||
}
|
||||
if (event.data() != null) {
|
||||
builder.data(event.data());
|
||||
}
|
||||
if (event.retry() != null) {
|
||||
builder.reconnectTime(event.retry().toMillis());
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue