Avoid java.util.Optional signatures for simple field access

Issue: SPR-15576
This commit is contained in:
Juergen Hoeller
2017-05-23 22:05:15 +02:00
parent ce5e2b94c4
commit db69a082d9
62 changed files with 467 additions and 549 deletions

View File

@@ -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;
}
/**

View File

@@ -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

View File

@@ -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;
}
/**

View File

@@ -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);

View File

@@ -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;
}
/**

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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;
}
/**

View File

@@ -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)));
}

View File

@@ -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;
}

View File

@@ -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();
}
/**

View File

@@ -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);

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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));

View File

@@ -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();

View File

@@ -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 {
}
}
}
}

View File

@@ -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);
}

View File

@@ -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));

View File

@@ -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());
}

View File

@@ -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));
}

View File

@@ -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) {

View File

@@ -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);