Merge branch '5.1.x'

This commit is contained in:
Juergen Hoeller
2019-04-26 16:56:04 +02:00
28 changed files with 189 additions and 201 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -254,13 +254,12 @@ public class SimpleJndiBeanFactory extends JndiLocatorSupport implements BeanFac
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T> T doGetSingleton(String name, @Nullable Class<T> requiredType) throws NamingException { private <T> T doGetSingleton(String name, @Nullable Class<T> requiredType) throws NamingException {
synchronized (this.singletonObjects) { synchronized (this.singletonObjects) {
if (this.singletonObjects.containsKey(name)) { Object singleton = this.singletonObjects.get(name);
Object jndiObject = this.singletonObjects.get(name); if (singleton != null) {
if (requiredType != null && !requiredType.isInstance(jndiObject)) { if (requiredType != null && !requiredType.isInstance(singleton)) {
throw new TypeMismatchNamingException( throw new TypeMismatchNamingException(convertJndiName(name), requiredType, singleton.getClass());
convertJndiName(name), requiredType, (jndiObject != null ? jndiObject.getClass() : null));
} }
return (T) jndiObject; return (T) singleton;
} }
T jndiObject = lookup(name, requiredType); T jndiObject = lookup(name, requiredType);
this.singletonObjects.put(name, jndiObject); this.singletonObjects.put(name, jndiObject);
@@ -274,14 +273,12 @@ public class SimpleJndiBeanFactory extends JndiLocatorSupport implements BeanFac
} }
else { else {
synchronized (this.resourceTypes) { synchronized (this.resourceTypes) {
if (this.resourceTypes.containsKey(name)) { Class<?> type = this.resourceTypes.get(name);
return this.resourceTypes.get(name); if (type == null) {
} type = lookup(name, null).getClass();
else {
Class<?> type = lookup(name, null).getClass();
this.resourceTypes.put(name, type); this.resourceTypes.put(name, type);
return type;
} }
return type;
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -118,13 +118,10 @@ public final class Conventions {
} }
else { else {
valueClass = parameter.getParameterType(); valueClass = parameter.getParameterType();
ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(valueClass);
if (reactiveAdapterRegistry.hasAdapters()) { if (adapter != null && !adapter.getDescriptor().isNoValue()) {
ReactiveAdapter adapter = reactiveAdapterRegistry.getAdapter(valueClass); reactiveSuffix = ClassUtils.getShortName(valueClass);
if (adapter != null && !adapter.getDescriptor().isNoValue()) { valueClass = parameter.nested().getNestedParameterType();
reactiveSuffix = ClassUtils.getShortName(valueClass);
valueClass = parameter.nested().getNestedParameterType();
}
} }
} }
@@ -207,13 +204,10 @@ public final class Conventions {
} }
else { else {
valueClass = resolvedType; valueClass = resolvedType;
ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(valueClass);
if (reactiveAdapterRegistry.hasAdapters()) { if (adapter != null && !adapter.getDescriptor().isNoValue()) {
ReactiveAdapter adapter = reactiveAdapterRegistry.getAdapter(valueClass); reactiveSuffix = ClassUtils.getShortName(valueClass);
if (adapter != null && !adapter.getDescriptor().isNoValue()) { valueClass = ResolvableType.forMethodReturnType(method).getGeneric().toClass();
reactiveSuffix = ClassUtils.getShortName(valueClass);
valueClass = ResolvableType.forMethodReturnType(method).getGeneric().toClass();
}
} }
} }

View File

@@ -59,7 +59,7 @@ public class ReactiveAdapterRegistry {
private final boolean reactorPresent; private final boolean reactorPresent;
private final List<ReactiveAdapter> adapters = new ArrayList<>(32); private final List<ReactiveAdapter> adapters = new ArrayList<>();
/** /**
@@ -67,7 +67,6 @@ public class ReactiveAdapterRegistry {
* @see #getSharedInstance() * @see #getSharedInstance()
*/ */
public ReactiveAdapterRegistry() { public ReactiveAdapterRegistry() {
ClassLoader classLoader = ReactiveAdapterRegistry.class.getClassLoader(); ClassLoader classLoader = ReactiveAdapterRegistry.class.getClassLoader();
// Reactor // Reactor
@@ -118,8 +117,8 @@ public class ReactiveAdapterRegistry {
/** /**
* Register a reactive type along with functions to adapt to and from a * Register a reactive type along with functions to adapt to and from a
* Reactive Streams {@link Publisher}. The functions can assume their * Reactive Streams {@link Publisher}. The function arguments assume that
* input is never be {@code null} nor {@link Optional}. * their input is neither {@code null} nor {@link Optional}.
*/ */
public void registerReactiveType(ReactiveTypeDescriptor descriptor, public void registerReactiveType(ReactiveTypeDescriptor descriptor,
Function<Object, Publisher<?>> toAdapter, Function<Publisher<?>, Object> fromAdapter) { Function<Object, Publisher<?>> toAdapter, Function<Publisher<?>, Object> fromAdapter) {
@@ -134,6 +133,7 @@ public class ReactiveAdapterRegistry {
/** /**
* Get the adapter for the given reactive type. * Get the adapter for the given reactive type.
* @return the corresponding adapter, or {@code null} if none available
*/ */
@Nullable @Nullable
public ReactiveAdapter getAdapter(Class<?> reactiveType) { public ReactiveAdapter getAdapter(Class<?> reactiveType) {
@@ -147,20 +147,25 @@ public class ReactiveAdapterRegistry {
* (may be {@code null} if a concrete source object is given) * (may be {@code null} if a concrete source object is given)
* @param source an instance of the reactive type * @param source an instance of the reactive type
* (i.e. to adapt from; may be {@code null} if the reactive type is specified) * (i.e. to adapt from; may be {@code null} if the reactive type is specified)
* @return the corresponding adapter, or {@code null} if none available
*/ */
@Nullable @Nullable
public ReactiveAdapter getAdapter(@Nullable Class<?> reactiveType, @Nullable Object source) { public ReactiveAdapter getAdapter(@Nullable Class<?> reactiveType, @Nullable Object source) {
if (this.adapters.isEmpty()) {
return null;
}
Object sourceToUse = (source instanceof Optional ? ((Optional<?>) source).orElse(null) : source); Object sourceToUse = (source instanceof Optional ? ((Optional<?>) source).orElse(null) : source);
Class<?> clazz = (sourceToUse != null ? sourceToUse.getClass() : reactiveType); Class<?> clazz = (sourceToUse != null ? sourceToUse.getClass() : reactiveType);
if (clazz == null) { if (clazz == null) {
return null; return null;
} }
for(ReactiveAdapter adapter : this.adapters) { for (ReactiveAdapter adapter : this.adapters) {
if (adapter.getReactiveType() == clazz) { if (adapter.getReactiveType() == clazz) {
return adapter; return adapter;
} }
} }
for(ReactiveAdapter adapter : this.adapters) { for (ReactiveAdapter adapter : this.adapters) {
if (adapter.getReactiveType().isAssignableFrom(clazz)) { if (adapter.getReactiveType().isAssignableFrom(clazz)) {
return adapter; return adapter;
} }
@@ -170,13 +175,13 @@ public class ReactiveAdapterRegistry {
/** /**
* Return a shared default {@code ReactiveAdapterRegistry} instance, lazily * Return a shared default {@code ReactiveAdapterRegistry} instance,
* building it once needed. * lazily building it once needed.
* <p><b>NOTE:</b> We highly recommend passing a long-lived, pre-configured * <p><b>NOTE:</b> We highly recommend passing a long-lived, pre-configured
* {@code ReactiveAdapterRegistry} instance for customization purposes. * {@code ReactiveAdapterRegistry} instance for customization purposes.
* This accessor is only meant as a fallback for code paths that want to * This accessor is only meant as a fallback for code paths that want to
* fall back on a default instance if one isn't provided. * fall back on a default instance if one isn't provided.
* @return the shared {@code ReactiveAdapterRegistry} instance (never {@code null}) * @return the shared {@code ReactiveAdapterRegistry} instance
* @since 5.0.2 * @since 5.0.2
*/ */
public static ReactiveAdapterRegistry getSharedInstance() { public static ReactiveAdapterRegistry getSharedInstance() {

View File

@@ -40,10 +40,10 @@ import org.springframework.util.MimeType;
*/ */
public abstract class AbstractDecoder<T> implements Decoder<T> { public abstract class AbstractDecoder<T> implements Decoder<T> {
protected Log logger = LogFactory.getLog(getClass());
private final List<MimeType> decodableMimeTypes; private final List<MimeType> decodableMimeTypes;
protected Log logger = LogFactory.getLog(getClass());
protected AbstractDecoder(MimeType... supportedMimeTypes) { protected AbstractDecoder(MimeType... supportedMimeTypes) {
this.decodableMimeTypes = Arrays.asList(supportedMimeTypes); this.decodableMimeTypes = Arrays.asList(supportedMimeTypes);

View File

@@ -36,10 +36,10 @@ import org.springframework.util.MimeType;
*/ */
public abstract class AbstractEncoder<T> implements Encoder<T> { public abstract class AbstractEncoder<T> implements Encoder<T> {
protected Log logger = LogFactory.getLog(getClass());
private final List<MimeType> encodableMimeTypes; private final List<MimeType> encodableMimeTypes;
protected Log logger = LogFactory.getLog(getClass());
protected AbstractEncoder(MimeType... supportedMimeTypes) { protected AbstractEncoder(MimeType... supportedMimeTypes) {
this.encodableMimeTypes = Arrays.asList(supportedMimeTypes); this.encodableMimeTypes = Arrays.asList(supportedMimeTypes);

View File

@@ -74,32 +74,32 @@ final class CompositeLog implements Log {
@Override @Override
public boolean isFatalEnabled() { public boolean isFatalEnabled() {
return this.fatalLogger != NO_OP_LOG; return (this.fatalLogger != NO_OP_LOG);
} }
@Override @Override
public boolean isErrorEnabled() { public boolean isErrorEnabled() {
return this.errorLogger != NO_OP_LOG; return (this.errorLogger != NO_OP_LOG);
} }
@Override @Override
public boolean isWarnEnabled() { public boolean isWarnEnabled() {
return this.warnLogger != NO_OP_LOG; return (this.warnLogger != NO_OP_LOG);
} }
@Override @Override
public boolean isInfoEnabled() { public boolean isInfoEnabled() {
return this.infoLogger != NO_OP_LOG; return (this.infoLogger != NO_OP_LOG);
} }
@Override @Override
public boolean isDebugEnabled() { public boolean isDebugEnabled() {
return this.debugLogger != NO_OP_LOG; return (this.debugLogger != NO_OP_LOG);
} }
@Override @Override
public boolean isTraceEnabled() { public boolean isTraceEnabled() {
return this.traceLogger != NO_OP_LOG; return (this.traceLogger != NO_OP_LOG);
} }
@Override @Override

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -58,8 +58,6 @@ public class HandlerMethod {
public static final Log defaultLogger = LogFactory.getLog(HandlerMethod.class); public static final Log defaultLogger = LogFactory.getLog(HandlerMethod.class);
protected Log logger = defaultLogger;
private final Object bean; private final Object bean;
@Nullable @Nullable
@@ -76,6 +74,8 @@ public class HandlerMethod {
@Nullable @Nullable
private HandlerMethod resolvedFromHandlerMethod; private HandlerMethod resolvedFromHandlerMethod;
protected Log logger = defaultLogger;
/** /**
* Create an instance from a bean instance and a method. * Create an instance from a bean instance and a method.

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -43,8 +43,8 @@ public interface AsyncHandlerMethodReturnValueHandler extends HandlerMethodRetur
* {@link #supportsReturnType(org.springframework.core.MethodParameter)} * {@link #supportsReturnType(org.springframework.core.MethodParameter)}
* is called and it returns {@code true}. * is called and it returns {@code true}.
* @param returnValue the value returned from the handler method * @param returnValue the value returned from the handler method
* @param returnType the type of the return value. * @param returnType the type of the return value
* @return true if the return value type represents an async value. * @return {@code true} if the return value type represents an async value
*/ */
boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType); boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType);
@@ -58,9 +58,9 @@ public interface AsyncHandlerMethodReturnValueHandler extends HandlerMethodRetur
* {@link #supportsReturnType(org.springframework.core.MethodParameter)} * {@link #supportsReturnType(org.springframework.core.MethodParameter)}
* is called and it returns {@code true}. * is called and it returns {@code true}.
* @param returnValue the value returned from the handler method * @param returnValue the value returned from the handler method
* @param returnType the type of the return value. * @param returnType the type of the return value
* @return the resulting ListenableFuture or {@code null} in which case no * @return the resulting ListenableFuture, or {@code null} in which case
* further handling will be performed. * no further handling will be performed
*/ */
@Nullable @Nullable
ListenableFuture<?> toListenableFuture(Object returnValue, MethodParameter returnType); ListenableFuture<?> toListenableFuture(Object returnValue, MethodParameter returnType);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@ public class ReactiveReturnValueHandler extends AbstractAsyncReturnValueHandler
@Override @Override
public boolean supportsReturnType(MethodParameter returnType) { public boolean supportsReturnType(MethodParameter returnType) {
return this.adapterRegistry.getAdapter(returnType.getParameterType()) != null; return (this.adapterRegistry.getAdapter(returnType.getParameterType()) != null);
} }
@Override @Override

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -42,10 +42,10 @@ public abstract class AbstractMessageChannel implements MessageChannel, Intercep
protected Log logger = LogFactory.getLog(getClass()); protected Log logger = LogFactory.getLog(getClass());
private final List<ChannelInterceptor> interceptors = new ArrayList<>(5);
private String beanName; private String beanName;
private final List<ChannelInterceptor> interceptors = new ArrayList<>(5);
public AbstractMessageChannel() { public AbstractMessageChannel() {
this.beanName = getClass().getSimpleName() + "@" + ObjectUtils.getIdentityHexString(this); this.beanName = getClass().getSimpleName() + "@" + ObjectUtils.getIdentityHexString(this);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -70,8 +70,6 @@ public class ReactorNettyTcpClient<P> implements TcpOperations<P> {
private static final int PUBLISH_ON_BUFFER_SIZE = 16; private static final int PUBLISH_ON_BUFFER_SIZE = 16;
private Log logger = LogFactory.getLog(ReactorNettyTcpClient.class);
private final TcpClient tcpClient; private final TcpClient tcpClient;
@@ -81,13 +79,15 @@ public class ReactorNettyTcpClient<P> implements TcpOperations<P> {
private final ChannelGroup channelGroup; private final ChannelGroup channelGroup;
@Nullable @Nullable
private LoopResources loopResources; private final LoopResources loopResources;
@Nullable @Nullable
private ConnectionProvider poolResources; private final ConnectionProvider poolResources;
private final Scheduler scheduler = Schedulers.newParallel("tcp-client-scheduler"); private final Scheduler scheduler = Schedulers.newParallel("tcp-client-scheduler");
private Log logger = LogFactory.getLog(ReactorNettyTcpClient.class);
private volatile boolean stopping = false; private volatile boolean stopping = false;

View File

@@ -415,7 +415,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
} }
/** /**
* Indicates whether DTD parsing should be supported. * Indicate whether DTD parsing should be supported.
* <p>Default is {@code false} meaning that DTD is disabled. * <p>Default is {@code false} meaning that DTD is disabled.
*/ */
public void setSupportDtd(boolean supportDtd) { public void setSupportDtd(boolean supportDtd) {
@@ -423,14 +423,14 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
} }
/** /**
* Whether DTD parsing is supported. * Return whether DTD parsing is supported.
*/ */
public boolean isSupportDtd() { public boolean isSupportDtd() {
return this.supportDtd; return this.supportDtd;
} }
/** /**
* Indicates whether external XML entities are processed when unmarshalling. * Indicate whether external XML entities are processed when unmarshalling.
* <p>Default is {@code false}, meaning that external entities are not resolved. * <p>Default is {@code false}, meaning that external entities are not resolved.
* Note that processing of external entities will only be enabled/disabled when the * Note that processing of external entities will only be enabled/disabled when the
* {@code Source} passed to {@link #unmarshal(Source)} is a {@link SAXSource} or * {@code Source} passed to {@link #unmarshal(Source)} is a {@link SAXSource} or
@@ -442,12 +442,12 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
public void setProcessExternalEntities(boolean processExternalEntities) { public void setProcessExternalEntities(boolean processExternalEntities) {
this.processExternalEntities = processExternalEntities; this.processExternalEntities = processExternalEntities;
if (processExternalEntities) { if (processExternalEntities) {
setSupportDtd(true); this.supportDtd = true;
} }
} }
/** /**
* Returns the configured value for whether XML external entities are allowed. * Return whether XML external entities are allowed.
*/ */
public boolean isProcessExternalEntities() { public boolean isProcessExternalEntities() {
return this.processExternalEntities; return this.processExternalEntities;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -86,7 +86,7 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
/** /**
* Indicates whether DTD parsing should be supported. * Indicate whether DTD parsing should be supported.
* <p>Default is {@code false} meaning that DTD is disabled. * <p>Default is {@code false} meaning that DTD is disabled.
*/ */
public void setSupportDtd(boolean supportDtd) { public void setSupportDtd(boolean supportDtd) {
@@ -94,14 +94,14 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
} }
/** /**
* Whether DTD parsing is supported. * Return whether DTD parsing is supported.
*/ */
public boolean isSupportDtd() { public boolean isSupportDtd() {
return this.supportDtd; return this.supportDtd;
} }
/** /**
* Indicates whether external XML entities are processed when unmarshalling. * Indicate whether external XML entities are processed when unmarshalling.
* <p>Default is {@code false}, meaning that external entities are not resolved. * <p>Default is {@code false}, meaning that external entities are not resolved.
* Note that processing of external entities will only be enabled/disabled when the * Note that processing of external entities will only be enabled/disabled when the
* {@code Source} passed to {@link #unmarshal(Source)} is a {@link SAXSource} or * {@code Source} passed to {@link #unmarshal(Source)} is a {@link SAXSource} or
@@ -113,12 +113,12 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
public void setProcessExternalEntities(boolean processExternalEntities) { public void setProcessExternalEntities(boolean processExternalEntities) {
this.processExternalEntities = processExternalEntities; this.processExternalEntities = processExternalEntities;
if (processExternalEntities) { if (processExternalEntities) {
setSupportDtd(true); this.supportDtd = true;
} }
} }
/** /**
* Returns the configured value for whether XML external entities are allowed. * Return whether XML external entities are allowed.
* @see #createXmlReader() * @see #createXmlReader()
*/ */
public boolean isProcessExternalEntities() { public boolean isProcessExternalEntities() {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -26,15 +26,11 @@ import org.junit.rules.ExpectedException;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpRequest;
import static junit.framework.TestCase.assertFalse; import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue; import static org.springframework.http.HttpMethod.*;
import static org.springframework.http.HttpMethod.GET; import static org.springframework.test.web.client.ExpectedCount.*;
import static org.springframework.http.HttpMethod.POST; import static org.springframework.test.web.client.match.MockRestRequestMatchers.*;
import static org.springframework.test.web.client.ExpectedCount.once; import static org.springframework.test.web.client.response.MockRestResponseCreators.*;
import static org.springframework.test.web.client.ExpectedCount.twice;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
/** /**
* Unit tests for {@link DefaultRequestExpectation}. * Unit tests for {@link DefaultRequestExpectation}.
@@ -86,7 +82,6 @@ public class DefaultRequestExpectationTests {
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private ClientHttpRequest createRequest(HttpMethod method, String url) { private ClientHttpRequest createRequest(HttpMethod method, String url) {
try { try {

View File

@@ -126,7 +126,7 @@ public class MockRestServiceServerTests {
try { try {
this.restTemplate.getForEntity("/some-service/some-endpoint", String.class); this.restTemplate.getForEntity("/some-service/some-endpoint", String.class);
fail("Expected exception to be thrown."); fail("Expected exception");
} }
catch (Exception ex) { catch (Exception ex) {
this.restTemplate.postForEntity("/reporting-service/report-error", ex.toString(), String.class); this.restTemplate.postForEntity("/reporting-service/report-error", ex.toString(), String.class);
@@ -135,7 +135,7 @@ public class MockRestServiceServerTests {
server.verify(); server.verify();
} }
@Test // gh-21799 @Test // gh-21799
public void verifyShouldFailIfRequestsFailed() { public void verifyShouldFailIfRequestsFailed() {
MockRestServiceServer server = MockRestServiceServer.bindTo(this.restTemplate).build(); MockRestServiceServer server = MockRestServiceServer.bindTo(this.restTemplate).build();
server.expect(once(), requestTo("/remoteurl")).andRespond(withSuccess()); server.expect(once(), requestTo("/remoteurl")).andRespond(withSuccess());
@@ -143,7 +143,7 @@ public class MockRestServiceServerTests {
this.restTemplate.postForEntity("/remoteurl", null, String.class); this.restTemplate.postForEntity("/remoteurl", null, String.class);
try { try {
this.restTemplate.postForEntity("/remoteurl", null, String.class); this.restTemplate.postForEntity("/remoteurl", null, String.class);
fail("Expected error to be thrown."); fail("Expected assertion error");
} }
catch (AssertionError error) { catch (AssertionError error) {
assertThat(error.getMessage()).startsWith("No further requests expected"); assertThat(error.getMessage()).startsWith("No further requests expected");
@@ -157,4 +157,5 @@ public class MockRestServiceServerTests {
assertThat(error.getMessage()).startsWith("Some requests did not execute successfully"); assertThat(error.getMessage()).startsWith("Some requests did not execute successfully");
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -50,7 +50,7 @@ public interface HttpMessageWriter<T> {
/** /**
* Whether the given object type is supported by this writer. * Whether the given object type is supported by this writer.
* @param elementType the type of object to check * @param elementType the type of object to check
* @param mediaType the media type for the write, possibly {@code null} * @param mediaType the media type for the write (possibly {@code null})
* @return {@code true} if writable, {@code false} otherwise * @return {@code true} if writable, {@code false} otherwise
*/ */
boolean canWrite(ResolvableType elementType, @Nullable MediaType mediaType); boolean canWrite(ResolvableType elementType, @Nullable MediaType mediaType);
@@ -60,8 +60,8 @@ public interface HttpMessageWriter<T> {
* @param inputStream the objects to write * @param inputStream the objects to write
* @param elementType the type of objects in the stream which must have been * @param elementType the type of objects in the stream which must have been
* previously checked via {@link #canWrite(ResolvableType, MediaType)} * previously checked via {@link #canWrite(ResolvableType, MediaType)}
* @param mediaType the content type for the write, possibly {@code null} to * @param mediaType the content type for the write (possibly {@code null} to
* indicate that the default content type of the writer must be used. * indicate that the default content type of the writer must be used)
* @param message the message to write to * @param message the message to write to
* @param hints additional information about how to encode and write * @param hints additional information about how to encode and write
* @return indicates completion or error * @return indicates completion or error
@@ -77,8 +77,8 @@ public interface HttpMessageWriter<T> {
* value; for annotated controllers, the {@link MethodParameter} can be * value; for annotated controllers, the {@link MethodParameter} can be
* accessed via {@link ResolvableType#getSource()}. * accessed via {@link ResolvableType#getSource()}.
* @param elementType the type of Objects in the input stream * @param elementType the type of Objects in the input stream
* @param mediaType the content type to use, possibly {@code null} indicating * @param mediaType the content type to use (possibly {@code null} indicating
* the default content type of the writer should be used. * the default content type of the writer should be used)
* @param request the current request * @param request the current request
* @param response the current response * @param response the current response
* @return a {@link Mono} that indicates completion of writing or error * @return a {@link Mono} that indicates completion of writing or error

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -68,7 +68,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
/** /**
* Indicates whether DTD parsing should be supported. * Indicate whether DTD parsing should be supported.
* <p>Default is {@code false} meaning that DTD is disabled. * <p>Default is {@code false} meaning that DTD is disabled.
*/ */
public void setSupportDtd(boolean supportDtd) { public void setSupportDtd(boolean supportDtd) {
@@ -76,14 +76,14 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
} }
/** /**
* Whether DTD parsing is supported. * Return whether DTD parsing is supported.
*/ */
public boolean isSupportDtd() { public boolean isSupportDtd() {
return this.supportDtd; return this.supportDtd;
} }
/** /**
* Indicates whether external XML entities are processed when converting to a Source. * Indicate whether external XML entities are processed when converting to a Source.
* <p>Default is {@code false}, meaning that external entities are not resolved. * <p>Default is {@code false}, meaning that external entities are not resolved.
* <p><strong>Note:</strong> setting this option to {@code true} also * <p><strong>Note:</strong> setting this option to {@code true} also
* automatically sets {@link #setSupportDtd} to {@code true}. * automatically sets {@link #setSupportDtd} to {@code true}.
@@ -91,12 +91,12 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
public void setProcessExternalEntities(boolean processExternalEntities) { public void setProcessExternalEntities(boolean processExternalEntities) {
this.processExternalEntities = processExternalEntities; this.processExternalEntities = processExternalEntities;
if (processExternalEntities) { if (processExternalEntities) {
setSupportDtd(true); this.supportDtd = true;
} }
} }
/** /**
* Returns the configured value for whether XML external entities are allowed. * Return whether XML external entities are allowed.
*/ */
public boolean isProcessExternalEntities() { public boolean isProcessExternalEntities() {
return this.processExternalEntities; return this.processExternalEntities;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -100,7 +100,7 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
/** /**
* Indicates whether DTD parsing should be supported. * Indicate whether DTD parsing should be supported.
* <p>Default is {@code false} meaning that DTD is disabled. * <p>Default is {@code false} meaning that DTD is disabled.
*/ */
public void setSupportDtd(boolean supportDtd) { public void setSupportDtd(boolean supportDtd) {
@@ -108,14 +108,14 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
} }
/** /**
* Whether DTD parsing is supported. * Return whether DTD parsing is supported.
*/ */
public boolean isSupportDtd() { public boolean isSupportDtd() {
return this.supportDtd; return this.supportDtd;
} }
/** /**
* Indicates whether external XML entities are processed when converting to a Source. * Indicate whether external XML entities are processed when converting to a Source.
* <p>Default is {@code false}, meaning that external entities are not resolved. * <p>Default is {@code false}, meaning that external entities are not resolved.
* <p><strong>Note:</strong> setting this option to {@code true} also * <p><strong>Note:</strong> setting this option to {@code true} also
* automatically sets {@link #setSupportDtd} to {@code true}. * automatically sets {@link #setSupportDtd} to {@code true}.
@@ -123,12 +123,12 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
public void setProcessExternalEntities(boolean processExternalEntities) { public void setProcessExternalEntities(boolean processExternalEntities) {
this.processExternalEntities = processExternalEntities; this.processExternalEntities = processExternalEntities;
if (processExternalEntities) { if (processExternalEntities) {
setSupportDtd(true); this.supportDtd = true;
} }
} }
/** /**
* Returns the configured value for whether XML external entities are allowed. * Return whether XML external entities are allowed.
*/ */
public boolean isProcessExternalEntities() { public boolean isProcessExternalEntities() {
return this.processExternalEntities; return this.processExternalEntities;

View File

@@ -950,9 +950,9 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
return; return;
} }
} }
String message = "No HttpMessageConverter for [" + requestBodyClass.getName() + "]"; String message = "No HttpMessageConverter for " + requestBodyClass.getName();
if (requestContentType != null) { if (requestContentType != null) {
message += " and content type [" + requestContentType + "]"; message += " and content type \"" + requestContentType + "\"";
} }
throw new RestClientException(message); throw new RestClientException(message);
} }
@@ -964,8 +964,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
logger.debug("Writing [" + body + "] as \"" + mediaType + "\""); logger.debug("Writing [" + body + "] as \"" + mediaType + "\"");
} }
else { else {
String classname = converter.getClass().getName(); logger.debug("Writing [" + body + "] with " + converter.getClass().getName());
logger.debug("Writing [" + body + "] with " + classname);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -38,9 +38,9 @@ public interface AsyncHandlerMethodReturnValueHandler extends HandlerMethodRetur
/** /**
* Whether the given return value represents asynchronous computation. * Whether the given return value represents asynchronous computation.
* @param returnValue the return value * @param returnValue the value returned from the handler method
* @param returnType the return type * @param returnType the return type
* @return {@code true} if the return value is asynchronous * @return {@code true} if the return value type represents an async value
*/ */
boolean isAsyncReturnValue(@Nullable Object returnValue, MethodParameter returnType); boolean isAsyncReturnValue(@Nullable Object returnValue, MethodParameter returnType);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -43,10 +43,10 @@ public class NotAcceptableStatusException extends ResponseStatusException {
} }
/** /**
* Constructor for when requested Content-Type is not supported. * Constructor for when the requested Content-Type is not supported.
*/ */
public NotAcceptableStatusException(List<MediaType> supportedMediaTypes) { public NotAcceptableStatusException(List<MediaType> supportedMediaTypes) {
super(HttpStatus.NOT_ACCEPTABLE, "Could not find acceptable representation", null); super(HttpStatus.NOT_ACCEPTABLE, "Could not find acceptable representation");
this.supportedMediaTypes = Collections.unmodifiableList(supportedMediaTypes); this.supportedMediaTypes = Collections.unmodifiableList(supportedMediaTypes);
} }

View File

@@ -117,8 +117,8 @@ public abstract class HandlerResultHandlerSupport implements Ordered {
* @return the selected media type, or {@code null} if none * @return the selected media type, or {@code null} if none
*/ */
@Nullable @Nullable
protected MediaType selectMediaType(ServerWebExchange exchange, protected MediaType selectMediaType(
Supplier<List<MediaType>> producibleTypesSupplier) { ServerWebExchange exchange, Supplier<List<MediaType>> producibleTypesSupplier) {
MediaType contentType = exchange.getResponse().getHeaders().getContentType(); MediaType contentType = exchange.getResponse().getHeaders().getContentType();
if (contentType != null && contentType.isConcrete()) { if (contentType != null && contentType.isConcrete()) {
@@ -157,8 +157,8 @@ public abstract class HandlerResultHandlerSupport implements Ordered {
if (selected != null) { if (selected != null) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Using '" + selected + "' given " + logger.debug("Using '" + selected + "' given " + acceptableTypes +
acceptableTypes + " and supported " + producibleTypes); " and supported " + producibleTypes);
} }
} }
else if (logger.isDebugEnabled()) { else if (logger.isDebugEnabled()) {
@@ -173,9 +173,8 @@ public abstract class HandlerResultHandlerSupport implements Ordered {
return getContentTypeResolver().resolveMediaTypes(exchange); return getContentTypeResolver().resolveMediaTypes(exchange);
} }
@SuppressWarnings("unchecked") private List<MediaType> getProducibleTypes(
private List<MediaType> getProducibleTypes(ServerWebExchange exchange, ServerWebExchange exchange, Supplier<List<MediaType>> producibleTypesSupplier) {
Supplier<List<MediaType>> producibleTypesSupplier) {
Set<MediaType> mediaTypes = exchange.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); Set<MediaType> mediaTypes = exchange.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
return (mediaTypes != null ? new ArrayList<>(mediaTypes) : producibleTypesSupplier.get()); return (mediaTypes != null ? new ArrayList<>(mediaTypes) : producibleTypesSupplier.get());

View File

@@ -33,8 +33,6 @@ import org.springframework.core.ResolvableType;
import org.springframework.core.codec.Hints; import org.springframework.core.codec.Hints;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver; import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
@@ -145,10 +143,7 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
return Mono.from((Publisher<Void>) publisher); return Mono.from((Publisher<Void>) publisher);
} }
ServerHttpRequest request = exchange.getRequest(); MediaType bestMediaType = selectMediaType(exchange, () -> getMediaTypesFor(elementType));
ServerHttpResponse response = exchange.getResponse();
List<MediaType> writableMediaTypes = getMediaTypesFor(elementType);
MediaType bestMediaType = selectMediaType(exchange, () -> writableMediaTypes);
if (bestMediaType != null) { if (bestMediaType != null) {
String logPrefix = exchange.getLogPrefix(); String logPrefix = exchange.getLogPrefix();
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
@@ -157,18 +152,18 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
} }
for (HttpMessageWriter<?> writer : getMessageWriters()) { for (HttpMessageWriter<?> writer : getMessageWriters()) {
if (writer.canWrite(elementType, bestMediaType)) { if (writer.canWrite(elementType, bestMediaType)) {
return writer.write((Publisher) publisher, actualType, elementType, bestMediaType, return writer.write((Publisher) publisher, actualType, elementType,
request, response, Hints.from(Hints.LOG_PREFIX_HINT, logPrefix)); bestMediaType, exchange.getRequest(), exchange.getResponse(),
Hints.from(Hints.LOG_PREFIX_HINT, logPrefix));
} }
} }
} }
else {
if (writableMediaTypes.isEmpty()) {
return Mono.error(new IllegalStateException("No writer for : " + elementType));
}
}
return Mono.error(new NotAcceptableStatusException(writableMediaTypes)); List<MediaType> mediaTypes = getMediaTypesFor(elementType);
if (bestMediaType == null && mediaTypes.isEmpty()) {
return Mono.error(new IllegalStateException("No HttpMessageWriter for " + elementType));
}
return Mono.error(new NotAcceptableStatusException(mediaTypes));
} }
private ResolvableType getElementType(ReactiveAdapter adapter, ResolvableType genericType) { private ResolvableType getElementType(ReactiveAdapter adapter, ResolvableType genericType) {
@@ -193,6 +188,7 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
return writableMediaTypes; return writableMediaTypes;
} }
/** /**
* Inner class to avoid a hard dependency on Kotlin at runtime. * Inner class to avoid a hard dependency on Kotlin at runtime.
*/ */

View File

@@ -113,56 +113,56 @@ class ControllerMethodResolver {
private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64); private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64);
ControllerMethodResolver(ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry reactiveRegistry, ControllerMethodResolver(ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry adapterRegistry,
ConfigurableApplicationContext context, List<HttpMessageReader<?>> readers) { ConfigurableApplicationContext context, List<HttpMessageReader<?>> readers) {
Assert.notNull(customResolvers, "ArgumentResolverConfigurer is required"); Assert.notNull(customResolvers, "ArgumentResolverConfigurer is required");
Assert.notNull(readers, "'messageReaders' is required"); Assert.notNull(adapterRegistry, "ReactiveAdapterRegistry is required");
Assert.notNull(reactiveRegistry, "ReactiveAdapterRegistry is required");
Assert.notNull(context, "ApplicationContext is required"); Assert.notNull(context, "ApplicationContext is required");
Assert.notNull(readers, "HttpMessageReader List is required");
this.initBinderResolvers = initBinderResolvers(customResolvers, reactiveRegistry, context); this.initBinderResolvers = initBinderResolvers(customResolvers, adapterRegistry, context);
this.modelAttributeResolvers = modelMethodResolvers(customResolvers, reactiveRegistry, context); this.modelAttributeResolvers = modelMethodResolvers(customResolvers, adapterRegistry, context);
this.requestMappingResolvers = requestMappingResolvers(customResolvers, reactiveRegistry, context, readers); this.requestMappingResolvers = requestMappingResolvers(customResolvers, adapterRegistry, context, readers);
this.exceptionHandlerResolvers = exceptionHandlerResolvers(customResolvers, reactiveRegistry, context); this.exceptionHandlerResolvers = exceptionHandlerResolvers(customResolvers, adapterRegistry, context);
this.reactiveAdapterRegistry = reactiveRegistry; this.reactiveAdapterRegistry = adapterRegistry;
initControllerAdviceCaches(context); initControllerAdviceCaches(context);
} }
private List<SyncHandlerMethodArgumentResolver> initBinderResolvers( private List<SyncHandlerMethodArgumentResolver> initBinderResolvers(
ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry reactiveRegistry, ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry adapterRegistry,
ConfigurableApplicationContext context) { ConfigurableApplicationContext context) {
return initResolvers(customResolvers, reactiveRegistry, context, false, Collections.emptyList()).stream() return initResolvers(customResolvers, adapterRegistry, context, false, Collections.emptyList()).stream()
.filter(resolver -> resolver instanceof SyncHandlerMethodArgumentResolver) .filter(resolver -> resolver instanceof SyncHandlerMethodArgumentResolver)
.map(resolver -> (SyncHandlerMethodArgumentResolver) resolver) .map(resolver -> (SyncHandlerMethodArgumentResolver) resolver)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
private static List<HandlerMethodArgumentResolver> modelMethodResolvers( private static List<HandlerMethodArgumentResolver> modelMethodResolvers(
ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry reactiveRegistry, ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry adapterRegistry,
ConfigurableApplicationContext context) { ConfigurableApplicationContext context) {
return initResolvers(customResolvers, reactiveRegistry, context, true, Collections.emptyList()); return initResolvers(customResolvers, adapterRegistry, context, true, Collections.emptyList());
} }
private static List<HandlerMethodArgumentResolver> requestMappingResolvers( private static List<HandlerMethodArgumentResolver> requestMappingResolvers(
ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry reactiveRegistry, ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry adapterRegistry,
ConfigurableApplicationContext context, List<HttpMessageReader<?>> readers) { ConfigurableApplicationContext context, List<HttpMessageReader<?>> readers) {
return initResolvers(customResolvers, reactiveRegistry, context, true, readers); return initResolvers(customResolvers, adapterRegistry, context, true, readers);
} }
private static List<HandlerMethodArgumentResolver> exceptionHandlerResolvers( private static List<HandlerMethodArgumentResolver> exceptionHandlerResolvers(
ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry reactiveRegistry, ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry adapterRegistry,
ConfigurableApplicationContext context) { ConfigurableApplicationContext context) {
return initResolvers(customResolvers, reactiveRegistry, context, false, Collections.emptyList()); return initResolvers(customResolvers, adapterRegistry, context, false, Collections.emptyList());
} }
private static List<HandlerMethodArgumentResolver> initResolvers(ArgumentResolverConfigurer customResolvers, private static List<HandlerMethodArgumentResolver> initResolvers(ArgumentResolverConfigurer customResolvers,
ReactiveAdapterRegistry reactiveRegistry, ConfigurableApplicationContext context, ReactiveAdapterRegistry adapterRegistry, ConfigurableApplicationContext context,
boolean supportDataBinding, List<HttpMessageReader<?>> readers) { boolean supportDataBinding, List<HttpMessageReader<?>> readers) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
@@ -170,51 +170,51 @@ class ControllerMethodResolver {
// Annotation-based... // Annotation-based...
List<HandlerMethodArgumentResolver> result = new ArrayList<>(); List<HandlerMethodArgumentResolver> result = new ArrayList<>();
result.add(new RequestParamMethodArgumentResolver(beanFactory, reactiveRegistry, false)); result.add(new RequestParamMethodArgumentResolver(beanFactory, adapterRegistry, false));
result.add(new RequestParamMapMethodArgumentResolver(reactiveRegistry)); result.add(new RequestParamMapMethodArgumentResolver(adapterRegistry));
result.add(new PathVariableMethodArgumentResolver(beanFactory, reactiveRegistry)); result.add(new PathVariableMethodArgumentResolver(beanFactory, adapterRegistry));
result.add(new PathVariableMapMethodArgumentResolver(reactiveRegistry)); result.add(new PathVariableMapMethodArgumentResolver(adapterRegistry));
result.add(new MatrixVariableMethodArgumentResolver(beanFactory, reactiveRegistry)); result.add(new MatrixVariableMethodArgumentResolver(beanFactory, adapterRegistry));
result.add(new MatrixVariableMapMethodArgumentResolver(reactiveRegistry)); result.add(new MatrixVariableMapMethodArgumentResolver(adapterRegistry));
if (!readers.isEmpty()) { if (!readers.isEmpty()) {
result.add(new RequestBodyArgumentResolver(readers, reactiveRegistry)); result.add(new RequestBodyArgumentResolver(readers, adapterRegistry));
result.add(new RequestPartMethodArgumentResolver(readers, reactiveRegistry)); result.add(new RequestPartMethodArgumentResolver(readers, adapterRegistry));
} }
if (supportDataBinding) { if (supportDataBinding) {
result.add(new ModelAttributeMethodArgumentResolver(reactiveRegistry, false)); result.add(new ModelAttributeMethodArgumentResolver(adapterRegistry, false));
} }
result.add(new RequestHeaderMethodArgumentResolver(beanFactory, reactiveRegistry)); result.add(new RequestHeaderMethodArgumentResolver(beanFactory, adapterRegistry));
result.add(new RequestHeaderMapMethodArgumentResolver(reactiveRegistry)); result.add(new RequestHeaderMapMethodArgumentResolver(adapterRegistry));
result.add(new CookieValueMethodArgumentResolver(beanFactory, reactiveRegistry)); result.add(new CookieValueMethodArgumentResolver(beanFactory, adapterRegistry));
result.add(new ExpressionValueMethodArgumentResolver(beanFactory, reactiveRegistry)); result.add(new ExpressionValueMethodArgumentResolver(beanFactory, adapterRegistry));
result.add(new SessionAttributeMethodArgumentResolver(beanFactory, reactiveRegistry)); result.add(new SessionAttributeMethodArgumentResolver(beanFactory, adapterRegistry));
result.add(new RequestAttributeMethodArgumentResolver(beanFactory, reactiveRegistry)); result.add(new RequestAttributeMethodArgumentResolver(beanFactory, adapterRegistry));
// Type-based... // Type-based...
if (KotlinDetector.isKotlinPresent()) { if (KotlinDetector.isKotlinPresent()) {
result.add(new ContinuationHandlerMethodArgumentResolver()); result.add(new ContinuationHandlerMethodArgumentResolver());
} }
if (!readers.isEmpty()) { if (!readers.isEmpty()) {
result.add(new HttpEntityArgumentResolver(readers, reactiveRegistry)); result.add(new HttpEntityArgumentResolver(readers, adapterRegistry));
} }
result.add(new ModelArgumentResolver(reactiveRegistry)); result.add(new ModelArgumentResolver(adapterRegistry));
if (supportDataBinding) { if (supportDataBinding) {
result.add(new ErrorsMethodArgumentResolver(reactiveRegistry)); result.add(new ErrorsMethodArgumentResolver(adapterRegistry));
} }
result.add(new ServerWebExchangeArgumentResolver(reactiveRegistry)); result.add(new ServerWebExchangeArgumentResolver(adapterRegistry));
result.add(new PrincipalArgumentResolver(reactiveRegistry)); result.add(new PrincipalArgumentResolver(adapterRegistry));
if (requestMappingMethod) { if (requestMappingMethod) {
result.add(new SessionStatusMethodArgumentResolver()); result.add(new SessionStatusMethodArgumentResolver());
} }
result.add(new WebSessionArgumentResolver(reactiveRegistry)); result.add(new WebSessionArgumentResolver(adapterRegistry));
// Custom... // Custom...
result.addAll(customResolvers.getCustomResolvers()); result.addAll(customResolvers.getCustomResolvers());
// Catch-all... // Catch-all...
result.add(new RequestParamMethodArgumentResolver(beanFactory, reactiveRegistry, true)); result.add(new RequestParamMethodArgumentResolver(beanFactory, adapterRegistry, true));
if (supportDataBinding) { if (supportDataBinding) {
result.add(new ModelAttributeMethodArgumentResolver(reactiveRegistry, true)); result.add(new ModelAttributeMethodArgumentResolver(adapterRegistry, true));
} }
return result; return result;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -160,10 +160,10 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
return createAttribute(attributeName, attributeType.toClass(), context, exchange); return createAttribute(attributeName, attributeType.toClass(), context, exchange);
} }
ReactiveAdapter adapterFrom = getAdapterRegistry().getAdapter(null, attribute); ReactiveAdapter adapter = getAdapterRegistry().getAdapter(null, attribute);
if (adapterFrom != null) { if (adapter != null) {
Assert.isTrue(!adapterFrom.isMultiValue(), "Data binding only supports single-value async types"); Assert.isTrue(!adapter.isMultiValue(), "Data binding only supports single-value async types");
return Mono.from(adapterFrom.toPublisher(attribute)); return Mono.from(adapter.toPublisher(attribute));
} }
else { else {
return Mono.justOrEmpty(attribute); return Mono.justOrEmpty(attribute);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@ public abstract class AbstractView implements View, BeanNameAware, ApplicationCo
private static final Object NO_VALUE = new Object(); private static final Object NO_VALUE = new Object();
private final ReactiveAdapterRegistry reactiveAdapterRegistry; private final ReactiveAdapterRegistry adapterRegistry;
private final List<MediaType> mediaTypes = new ArrayList<>(4); private final List<MediaType> mediaTypes = new ArrayList<>(4);
@@ -78,7 +78,7 @@ public abstract class AbstractView implements View, BeanNameAware, ApplicationCo
} }
public AbstractView(ReactiveAdapterRegistry reactiveAdapterRegistry) { public AbstractView(ReactiveAdapterRegistry reactiveAdapterRegistry) {
this.reactiveAdapterRegistry = reactiveAdapterRegistry; this.adapterRegistry = reactiveAdapterRegistry;
this.mediaTypes.add(ViewResolverSupport.DEFAULT_CONTENT_TYPE); this.mediaTypes.add(ViewResolverSupport.DEFAULT_CONTENT_TYPE);
} }
@@ -240,7 +240,7 @@ public abstract class AbstractView implements View, BeanNameAware, ApplicationCo
if (value == null) { if (value == null) {
continue; continue;
} }
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(null, value); ReactiveAdapter adapter = this.adapterRegistry.getAdapter(null, value);
if (adapter != null) { if (adapter != null) {
names.add(entry.getKey()); names.add(entry.getKey());
if (adapter.isMultiValue()) { if (adapter.isMultiValue()) {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -76,14 +76,14 @@ class ReactiveTypeHandler {
private static Log logger = LogFactory.getLog(ReactiveTypeHandler.class); private static Log logger = LogFactory.getLog(ReactiveTypeHandler.class);
private final ReactiveAdapterRegistry reactiveRegistry; private final ReactiveAdapterRegistry adapterRegistry;
private final TaskExecutor taskExecutor; private final TaskExecutor taskExecutor;
private Boolean taskExecutorWarning;
private final ContentNegotiationManager contentNegotiationManager; private final ContentNegotiationManager contentNegotiationManager;
private boolean taskExecutorWarning;
public ReactiveTypeHandler() { public ReactiveTypeHandler() {
this(ReactiveAdapterRegistry.getSharedInstance(), new SyncTaskExecutor(), new ContentNegotiationManager()); this(ReactiveAdapterRegistry.getSharedInstance(), new SyncTaskExecutor(), new ContentNegotiationManager());
@@ -93,10 +93,12 @@ class ReactiveTypeHandler {
Assert.notNull(registry, "ReactiveAdapterRegistry is required"); Assert.notNull(registry, "ReactiveAdapterRegistry is required");
Assert.notNull(executor, "TaskExecutor is required"); Assert.notNull(executor, "TaskExecutor is required");
Assert.notNull(manager, "ContentNegotiationManager is required"); Assert.notNull(manager, "ContentNegotiationManager is required");
this.reactiveRegistry = registry; this.adapterRegistry = registry;
this.taskExecutor = executor; this.taskExecutor = executor;
this.taskExecutorWarning = executor instanceof SimpleAsyncTaskExecutor || executor instanceof SyncTaskExecutor;
this.contentNegotiationManager = manager; this.contentNegotiationManager = manager;
this.taskExecutorWarning =
(executor instanceof SimpleAsyncTaskExecutor || executor instanceof SyncTaskExecutor);
} }
@@ -104,7 +106,7 @@ class ReactiveTypeHandler {
* Whether the type can be adapted to a Reactive Streams {@link Publisher}. * Whether the type can be adapted to a Reactive Streams {@link Publisher}.
*/ */
public boolean isReactiveType(Class<?> type) { public boolean isReactiveType(Class<?> type) {
return (this.reactiveRegistry.hasAdapters() && this.reactiveRegistry.getAdapter(type) != null); return (this.adapterRegistry.getAdapter(type) != null);
} }
@@ -119,7 +121,7 @@ class ReactiveTypeHandler {
ModelAndViewContainer mav, NativeWebRequest request) throws Exception { ModelAndViewContainer mav, NativeWebRequest request) throws Exception {
Assert.notNull(returnValue, "Expected return value"); Assert.notNull(returnValue, "Expected return value");
ReactiveAdapter adapter = this.reactiveRegistry.getAdapter(returnValue.getClass()); ReactiveAdapter adapter = this.adapterRegistry.getAdapter(returnValue.getClass());
Assert.state(adapter != null, () -> "Unexpected return value: " + returnValue); Assert.state(adapter != null, () -> "Unexpected return value: " + returnValue);
ResolvableType elementType = ResolvableType.forMethodParameter(returnType).getGeneric(); ResolvableType elementType = ResolvableType.forMethodParameter(returnType).getGeneric();

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -77,17 +77,17 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur
/** /**
* Complete constructor with pluggable "reactive" type support. * Complete constructor with pluggable "reactive" type support.
* @param messageConverters converters to write emitted objects with * @param messageConverters converters to write emitted objects with
* @param reactiveRegistry for reactive return value type support * @param registry for reactive return value type support
* @param executor for blocking I/O writes of items emitted from reactive types * @param executor for blocking I/O writes of items emitted from reactive types
* @param manager for detecting streaming media types * @param manager for detecting streaming media types
* @since 5.0 * @since 5.0
*/ */
public ResponseBodyEmitterReturnValueHandler(List<HttpMessageConverter<?>> messageConverters, public ResponseBodyEmitterReturnValueHandler(List<HttpMessageConverter<?>> messageConverters,
ReactiveAdapterRegistry reactiveRegistry, TaskExecutor executor, ContentNegotiationManager manager) { ReactiveAdapterRegistry registry, TaskExecutor executor, ContentNegotiationManager manager) {
Assert.notEmpty(messageConverters, "HttpMessageConverter List must not be empty"); Assert.notEmpty(messageConverters, "HttpMessageConverter List must not be empty");
this.messageConverters = messageConverters; this.messageConverters = messageConverters;
this.reactiveHandler = new ReactiveTypeHandler(reactiveRegistry, executor, manager); this.reactiveHandler = new ReactiveTypeHandler(registry, executor, manager);
} }