diff --git a/spring-core/src/main/java/org/springframework/core/ReactiveAdapter.java b/spring-core/src/main/java/org/springframework/core/ReactiveAdapter.java
new file mode 100644
index 0000000000..bb0b7ad72a
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/core/ReactiveAdapter.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2002-2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.core;
+
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+/**
+ * Contract for adapting to and from {@link Flux} and {@link Mono}.
+ *
+ *
An adapter supports a specific adaptee type whose stream semantics can be
+ * checked via {@link #getDescriptor()}.
+ *
+ *
Use the {@link ReactiveAdapterRegistry} to obtain an adapter for a
+ * supported adaptee type or to register additional adapters.
+ *
+ * @author Rossen Stoyanchev
+ * @since 5.0
+ */
+public interface ReactiveAdapter {
+
+ /**
+ * Return a descriptor with further information about the adaptee.
+ */
+ Descriptor getDescriptor();
+
+ /**
+ * Adapt the given Object to a {@link Mono}
+ * @param source the source object to adapt
+ * @return the resulting {@link Mono} possibly empty
+ */
+ Mono toMono(Object source);
+
+ /**
+ * Adapt the given Object to a {@link Flux}.
+ * @param source the source object to adapt
+ * @return the resulting {@link Flux} possibly empty
+ */
+ Flux toFlux(Object source);
+
+ /**
+ * Adapt the given Object to a Publisher.
+ * @param source the source object to adapt
+ * @return the resulting {@link Mono} or {@link Flux} possibly empty
+ */
+ Publisher toPublisher(Object source);
+
+ /**
+ * Adapt the given Publisher to the target adaptee.
+ * @param publisher the publisher to adapt
+ * @return the resulting adaptee
+ */
+ Object fromPublisher(Publisher> publisher);
+
+
+ /**
+ * A descriptor with information about the adaptee stream semantics.
+ */
+ class Descriptor {
+
+ private final boolean isMultiValue;
+
+ private final boolean supportsEmpty;
+
+ private final boolean isNoValue;
+
+
+ public Descriptor(boolean isMultiValue, boolean canBeEmpty, boolean isNoValue) {
+ this.isMultiValue = isMultiValue;
+ this.supportsEmpty = canBeEmpty;
+ this.isNoValue = isNoValue;
+ }
+
+
+ /**
+ * Return {@code true} if the adaptee implies 0..N values can be produced
+ * and is therefore a good fit to adapt to {@link Flux}. A {@code false}
+ * return value implies the adaptee will produce 1 value at most and is
+ * therefore a good fit for {@link Mono}.
+ */
+ public boolean isMultiValue() {
+ return this.isMultiValue;
+ }
+
+ /**
+ * Return {@code true} if the adaptee can complete without values.
+ */
+ public boolean supportsEmpty() {
+ return this.supportsEmpty;
+ }
+
+ /**
+ * Return {@code true} if the adaptee implies no values will be produced,
+ * i.e. providing only completion or error signal.
+ */
+ public boolean isNoValue() {
+ return this.isNoValue;
+ }
+
+ }
+
+}
diff --git a/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java b/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java
new file mode 100644
index 0000000000..921dae625f
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2002-2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.core;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import org.reactivestreams.Publisher;
+import reactor.adapter.RxJava1Adapter;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import rx.Completable;
+import rx.Observable;
+import rx.Single;
+
+import org.springframework.core.ReactiveAdapter.Descriptor;
+import org.springframework.util.ClassUtils;
+
+/**
+ * A registry of adapters to adapt to {@link Flux} and {@link Mono}.
+ *
+ * By default there are adapters for {@link CompletableFuture}, RxJava 1, and
+ * also for a any Reactive Streams {@link Publisher}. Additional adapters can be
+ * registered via {@link #registerFluxAdapter) and {@link #registerMonoAdapter}.
+ *
+ * @author Rossen Stoyanchev
+ * @since 5.0
+ */
+public class ReactiveAdapterRegistry {
+
+ private static final boolean rxJava1Present =
+ ClassUtils.isPresent("rx.Observable", ReactiveAdapterRegistry.class.getClassLoader());
+
+
+ private final Map, ReactiveAdapter> adapterMap = new LinkedHashMap<>();
+
+
+ /**
+ * Create a registry and auto-register default adapters.
+ */
+ public ReactiveAdapterRegistry() {
+
+ // Flux and Mono ahead of Publisher...
+ registerMonoAdapter(Mono.class,
+ source -> (Mono>) source, source -> source, new Descriptor(false, true, false));
+
+ registerFluxAdapter(
+ Flux.class, source -> (Flux>) source, source -> source);
+
+ registerFluxAdapter(
+ Publisher.class, source -> Flux.from((Publisher>) source), source -> source);
+
+ registerMonoAdapter(CompletableFuture.class,
+ source -> Mono.fromFuture((CompletableFuture>) source),
+ source -> Mono.from((Publisher>) source).toFuture(),
+ new Descriptor(false, true, false)
+ );
+
+ if (rxJava1Present) {
+ new RxJava1AdapterRegistrar().register(this);
+ }
+ }
+
+
+ /**
+ * Register an adapter for adapting to and from a {@link Mono}. The provided
+ * functions can assume that input will never be {@code null} and also that
+ * any {@link Optional} wrapper is unwrapped.
+ */
+ public void registerMonoAdapter(Class> adapteeType,
+ Function> toAdapter, Function, Object> fromAdapter,
+ Descriptor descriptor) {
+
+ this.adapterMap.put(adapteeType, new MonoReactiveAdapter(toAdapter, fromAdapter, descriptor));
+ }
+
+ /**
+ * Register an adapter for adapting to and from a {@link Flux}. The provided
+ * functions can assume that input will never be {@code null} and also that
+ * any {@link Optional} wrapper is unwrapped.
+ */
+ public void registerFluxAdapter(Class> adapteeType,
+ Function> toAdapter, Function, Object> fromAdapter) {
+
+ this.adapterMap.put(adapteeType, new FluxReactiveAdapter(toAdapter, fromAdapter));
+ }
+
+
+ /**
+ * Get the adapter for the given adaptee type to adapt from.
+ */
+ public ReactiveAdapter getAdapterFrom(Class> adapteeType) {
+ return getAdapterFrom(adapteeType, null);
+ }
+
+ /**
+ * Get the adapter for the given adaptee type to adapt from.
+ * If the instance is not {@code null} its actual type is used to check.
+ */
+ public ReactiveAdapter getAdapterFrom(Class> adapteeType, Object adaptee) {
+ Class> actualType = getActualType(adapteeType, adaptee);
+ return getAdapterInternal(supportedType -> supportedType.isAssignableFrom(actualType));
+ }
+
+ /**
+ * Get the adapter for the given adaptee type to adapt to.
+ */
+ public ReactiveAdapter getAdapterTo(Class> adapteeType) {
+ return getAdapterTo(adapteeType, null);
+ }
+
+ /**
+ * Get the adapter for the given adaptee type to adapt to.
+ * If the instance is not {@code null} its actual type is used to check.
+ */
+ public ReactiveAdapter getAdapterTo(Class> adapteeType, Object adaptee) {
+ Class> actualType = getActualType(adapteeType, adaptee);
+ return getAdapterInternal(supportedType -> supportedType.equals(actualType));
+ }
+
+
+ private static Class> getActualType(Class> adapteeType, Object adaptee) {
+ adaptee = unwrapOptional(adaptee);
+ return (adaptee != null ? adaptee.getClass() : adapteeType);
+ }
+
+ private static Object unwrapOptional(Object value) {
+ if (value != null && value instanceof Optional) {
+ value = ((Optional>) value).orElse(null);
+ }
+ return value;
+ }
+
+ private ReactiveAdapter getAdapterInternal(Predicate> adapteeTypePredicate) {
+ return this.adapterMap.keySet().stream()
+ .filter(adapteeTypePredicate)
+ .map(this.adapterMap::get)
+ .findFirst()
+ .orElse(null);
+ }
+
+
+ @SuppressWarnings("unchecked")
+ private static class MonoReactiveAdapter implements ReactiveAdapter {
+
+ private final Function> toAdapter;
+
+ private final Function, Object> fromAdapter;
+
+ private final Descriptor descriptor;
+
+
+ MonoReactiveAdapter(Function> to, Function, Object> from, Descriptor descriptor) {
+ this.toAdapter = to;
+ this.fromAdapter = from;
+ this.descriptor = descriptor;
+ }
+
+ @Override
+ public Descriptor getDescriptor() {
+ return this.descriptor;
+ }
+
+ @Override
+ public Mono toMono(Object source) {
+ source = unwrapOptional(source);
+ if (source == null) {
+ return Mono.empty();
+ }
+ return (Mono) this.toAdapter.apply(source);
+ }
+
+ @Override
+ public Flux toFlux(Object source) {
+ source = unwrapOptional(source);
+ if (source == null) {
+ return Flux.empty();
+ }
+ return (Flux) this.toMono(source).flux();
+ }
+
+ @Override
+ public Publisher toPublisher(Object source) {
+ return toMono(source);
+ }
+
+ @Override
+ public Object fromPublisher(Publisher> source) {
+ return (source != null ? this.fromAdapter.apply((Mono>) source) : null);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static class FluxReactiveAdapter implements ReactiveAdapter {
+
+ private final Function> toAdapter;
+
+ private final Function, Object> fromAdapter;
+
+ private final Descriptor descriptor = new Descriptor(true, true, false);
+
+
+ FluxReactiveAdapter(Function> to, Function, Object> from) {
+ this.toAdapter = to;
+ this.fromAdapter = from;
+ }
+
+ @Override
+ public Descriptor getDescriptor() {
+ return this.descriptor;
+ }
+
+ @Override
+ public Mono toMono(Object source) {
+ source = unwrapOptional(source);
+ if (source == null) {
+ return Mono.empty();
+ }
+ return (Mono) this.toAdapter.apply(source).next();
+ }
+
+ @Override
+ public Flux toFlux(Object source) {
+ source = unwrapOptional(source);
+ if (source == null) {
+ return Flux.empty();
+ }
+ return (Flux) this.toAdapter.apply(source);
+ }
+
+ @Override
+ public Publisher toPublisher(Object source) {
+ return toFlux(source);
+ }
+
+ @Override
+ public Object fromPublisher(Publisher> source) {
+ return (source != null ? this.fromAdapter.apply((Flux>) source) : null);
+ }
+ }
+
+ private static class RxJava1AdapterRegistrar {
+
+ public void register(ReactiveAdapterRegistry registry) {
+
+ registry.registerFluxAdapter(Observable.class,
+ source -> RxJava1Adapter.observableToFlux((Observable>) source),
+ RxJava1Adapter::publisherToObservable
+ );
+
+ registry.registerMonoAdapter(Single.class,
+ source -> RxJava1Adapter.singleToMono((Single>) source),
+ RxJava1Adapter::publisherToSingle,
+ new Descriptor(false, false, false)
+ );
+
+ registry.registerMonoAdapter(Completable.class,
+ source -> RxJava1Adapter.completableToMono((Completable) source),
+ RxJava1Adapter::publisherToCompletable,
+ new Descriptor(false, true, true)
+ );
+ }
+ }
+
+}
diff --git a/spring-core/src/main/java/org/springframework/core/convert/support/MonoToCompletableFutureConverter.java b/spring-core/src/main/java/org/springframework/core/convert/support/MonoToCompletableFutureConverter.java
deleted file mode 100644
index 7917fa2617..0000000000
--- a/spring-core/src/main/java/org/springframework/core/convert/support/MonoToCompletableFutureConverter.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2002-2015 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.core.convert.support;
-
-import java.util.LinkedHashSet;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-
-import org.reactivestreams.Publisher;
-import reactor.core.publisher.Mono;
-
-import org.springframework.core.convert.TypeDescriptor;
-import org.springframework.core.convert.converter.GenericConverter;
-
-/**
- * Converter to adapt {@link CompletableFuture} to Reactive Streams and
- * Reactor {@link Mono}.
- *
- * @author Sebastien Deleuze
- * @since 5.0
- */
-public class MonoToCompletableFutureConverter implements GenericConverter {
-
-
- @Override
- public Set getConvertibleTypes() {
- Set pairs = new LinkedHashSet<>(2);
- pairs.add(new GenericConverter.ConvertiblePair(Mono.class, CompletableFuture.class));
- pairs.add(new GenericConverter.ConvertiblePair(CompletableFuture.class, Mono.class));
- return pairs;
- }
-
-
- @Override
- public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
- if (source == null) {
- return null;
- }
- else if (CompletableFuture.class.isAssignableFrom(sourceType.getType())) {
- return Mono.fromFuture((CompletableFuture>) source);
- }
- else if (CompletableFuture.class.isAssignableFrom(targetType.getType())) {
- return Mono.from((Publisher>) source).toFuture();
- }
- return null;
- }
-
-}
diff --git a/spring-core/src/main/java/org/springframework/core/convert/support/ReactorToRxJava1Converter.java b/spring-core/src/main/java/org/springframework/core/convert/support/ReactorToRxJava1Converter.java
deleted file mode 100644
index d25b4f9c86..0000000000
--- a/spring-core/src/main/java/org/springframework/core/convert/support/ReactorToRxJava1Converter.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2002-2015 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.core.convert.support;
-
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import org.reactivestreams.Publisher;
-import reactor.adapter.RxJava1Adapter;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-import rx.Completable;
-import rx.Observable;
-import rx.Single;
-
-import org.springframework.core.convert.TypeDescriptor;
-import org.springframework.core.convert.converter.GenericConverter;
-
-/**
- * Converter to adapt RxJava1 {@link Observable}, {@link Single}, and
- * {@link Completable} to Reactive Streams and Reactor types.
- *
- * @author Stephane Maldini
- * @author Sebastien Deleuze
- * @since 5.0
- */
-public final class ReactorToRxJava1Converter implements GenericConverter {
-
- @Override
- public Set getConvertibleTypes() {
- Set pairs = new LinkedHashSet<>(6);
- pairs.add(new GenericConverter.ConvertiblePair(Flux.class, Observable.class));
- pairs.add(new GenericConverter.ConvertiblePair(Observable.class, Flux.class));
- pairs.add(new GenericConverter.ConvertiblePair(Mono.class, Single.class));
- pairs.add(new GenericConverter.ConvertiblePair(Single.class, Mono.class));
- pairs.add(new GenericConverter.ConvertiblePair(Mono.class, Completable.class));
- pairs.add(new GenericConverter.ConvertiblePair(Completable.class, Mono.class));
- return pairs;
- }
-
- @Override
- public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
- if (source == null) {
- return null;
- }
- if (Observable.class.isAssignableFrom(sourceType.getType())) {
- return RxJava1Adapter.observableToFlux((Observable>) source);
- }
- else if (Observable.class.isAssignableFrom(targetType.getType())) {
- return RxJava1Adapter.publisherToObservable((Publisher>) source);
- }
- else if (Single.class.isAssignableFrom(sourceType.getType())) {
- return RxJava1Adapter.singleToMono((Single>) source);
- }
- else if (Single.class.isAssignableFrom(targetType.getType())) {
- return RxJava1Adapter.publisherToSingle((Publisher>) source);
- }
- else if (Completable.class.isAssignableFrom(sourceType.getType())) {
- return RxJava1Adapter.completableToMono((Completable) source);
- }
- else if (Completable.class.isAssignableFrom(targetType.getType())) {
- return RxJava1Adapter.publisherToCompletable((Publisher>) source);
- }
- return null;
- }
-
-}
diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/MonoToCompletableFutureConverterTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/MonoToCompletableFutureConverterTests.java
deleted file mode 100644
index 64b33cc9b8..0000000000
--- a/spring-core/src/test/java/org/springframework/core/convert/support/MonoToCompletableFutureConverterTests.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2002-2016 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.core.convert.support;
-
-import java.util.concurrent.CompletableFuture;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.reactivestreams.Publisher;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-/**
- * Unit tests for {@link ReactorToRxJava1Converter}.
- * @author Rossen Stoyanchev
- */
-public class MonoToCompletableFutureConverterTests {
-
- private GenericConversionService conversionService;
-
-
- @Before
- public void setUp() throws Exception {
- this.conversionService = new GenericConversionService();
- this.conversionService.addConverter(new MonoToCompletableFutureConverter());
- }
-
- @Test
- public void canConvert() throws Exception {
- assertTrue(this.conversionService.canConvert(Mono.class, CompletableFuture.class));
- assertTrue(this.conversionService.canConvert(CompletableFuture.class, Mono.class));
-
- assertFalse(this.conversionService.canConvert(Flux.class, CompletableFuture.class));
- assertFalse(this.conversionService.canConvert(CompletableFuture.class, Flux.class));
-
- assertFalse(this.conversionService.canConvert(Publisher.class, CompletableFuture.class));
- assertFalse(this.conversionService.canConvert(CompletableFuture.class, Publisher.class));
- }
-
-}
diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/ReactiveAdapterRegistryTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/ReactiveAdapterRegistryTests.java
new file mode 100644
index 0000000000..7bc2464433
--- /dev/null
+++ b/spring-core/src/test/java/org/springframework/core/convert/support/ReactiveAdapterRegistryTests.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2002-2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.core.convert.support;
+
+import java.util.concurrent.CompletableFuture;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import rx.Completable;
+import rx.Observable;
+import rx.Single;
+
+import org.springframework.core.ReactiveAdapter;
+import org.springframework.core.ReactiveAdapterRegistry;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Unit tests for {@link ReactiveAdapterRegistry}.
+ * @author Rossen Stoyanchev
+ */
+public class ReactiveAdapterRegistryTests {
+
+ private ReactiveAdapterRegistry adapterRegistry;
+
+ @Before
+ public void setUp() throws Exception {
+ this.adapterRegistry = new ReactiveAdapterRegistry();
+ }
+
+ @Test
+ public void getDefaultAdapters() throws Exception {
+ testMonoAdapter(Mono.class);
+ testFluxAdapter(Flux.class);
+ testFluxAdapter(Publisher.class);
+ testMonoAdapter(CompletableFuture.class);
+ testFluxAdapter(Observable.class);
+ testMonoAdapter(Single.class);
+ testMonoAdapter(Completable.class);
+ }
+
+ private void testFluxAdapter(Class> adapteeType) {
+ ReactiveAdapter adapter = this.adapterRegistry.getAdapterFrom(adapteeType);
+ assertNotNull(adapter);
+ assertTrue(adapter.getDescriptor().isMultiValue());
+
+ adapter = this.adapterRegistry.getAdapterTo(adapteeType);
+ assertNotNull(adapter);
+ assertTrue(adapter.getDescriptor().isMultiValue());
+ }
+
+ private void testMonoAdapter(Class> adapteeType) {
+ ReactiveAdapter adapter = this.adapterRegistry.getAdapterFrom(adapteeType);
+ assertNotNull(adapter);
+ assertFalse(adapter.getDescriptor().isMultiValue());
+
+ adapter = this.adapterRegistry.getAdapterTo(adapteeType);
+ assertNotNull(adapter);
+ assertFalse(adapter.getDescriptor().isMultiValue());
+ }
+
+}
diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/ReactorToRxJava1ConverterTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/ReactorToRxJava1ConverterTests.java
deleted file mode 100644
index 427e9be4ef..0000000000
--- a/spring-core/src/test/java/org/springframework/core/convert/support/ReactorToRxJava1ConverterTests.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2002-2016 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.core.convert.support;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.reactivestreams.Publisher;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-import rx.Completable;
-import rx.Observable;
-import rx.Single;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-/**
- * Unit tests for {@link ReactorToRxJava1Converter}.
- * @author Rossen Stoyanchev
- */
-public class ReactorToRxJava1ConverterTests {
-
- private GenericConversionService conversionService;
-
-
- @Before
- public void setUp() throws Exception {
- this.conversionService = new GenericConversionService();
- this.conversionService.addConverter(new ReactorToRxJava1Converter());
- }
-
- @Test
- public void canConvert() throws Exception {
- assertTrue(this.conversionService.canConvert(Flux.class, Observable.class));
- assertTrue(this.conversionService.canConvert(Observable.class, Flux.class));
-
- assertTrue(this.conversionService.canConvert(Mono.class, Single.class));
- assertTrue(this.conversionService.canConvert(Single.class, Mono.class));
-
- assertTrue(this.conversionService.canConvert(Mono.class, Completable.class));
- assertTrue(this.conversionService.canConvert(Completable.class, Mono.class));
-
- assertFalse(this.conversionService.canConvert(Flux.class, Single.class));
- assertFalse(this.conversionService.canConvert(Single.class, Flux.class));
-
- assertFalse(this.conversionService.canConvert(Flux.class, Completable.class));
- assertFalse(this.conversionService.canConvert(Completable.class, Flux.class));
-
- assertFalse(this.conversionService.canConvert(Mono.class, Observable.class));
- assertFalse(this.conversionService.canConvert(Observable.class, Mono.class));
-
- assertFalse(this.conversionService.canConvert(Publisher.class, Observable.class));
- assertFalse(this.conversionService.canConvert(Observable.class, Publisher.class));
- }
-
-}
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java
index 6244967dc4..d8bc0dcc96 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java
@@ -34,8 +34,6 @@ import org.springframework.core.codec.ResourceDecoder;
import org.springframework.core.codec.StringDecoder;
import org.springframework.core.codec.StringEncoder;
import org.springframework.core.convert.converter.Converter;
-import org.springframework.core.convert.support.MonoToCompletableFutureConverter;
-import org.springframework.core.convert.support.ReactorToRxJava1Converter;
import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.support.DefaultFormattingConversionService;
@@ -274,17 +272,8 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
/**
* Override to add custom {@link Converter}s and {@link Formatter}s.
- * By default this method method registers:
- *
- * {@link MonoToCompletableFutureConverter}
- * {@link ReactorToRxJava1Converter}
- *
*/
protected void addFormatters(FormatterRegistry registry) {
- registry.addConverter(new MonoToCompletableFutureConverter());
- if (rxJava1Present) {
- registry.addConverter(new ReactorToRxJava1Converter());
- }
}
/**
@@ -334,19 +323,17 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
@Bean
public SimpleResultHandler simpleResultHandler() {
- return new SimpleResultHandler(mvcConversionService());
+ return new SimpleResultHandler();
}
@Bean
public ResponseEntityResultHandler responseEntityResultHandler() {
- return new ResponseEntityResultHandler(getMessageWriters(), mvcConversionService(),
- mvcContentTypeResolver());
+ return new ResponseEntityResultHandler(getMessageWriters(), mvcContentTypeResolver());
}
@Bean
public ResponseBodyResultHandler responseBodyResultHandler() {
- return new ResponseBodyResultHandler(getMessageWriters(), mvcConversionService(),
- mvcContentTypeResolver());
+ return new ResponseBodyResultHandler(getMessageWriters(), mvcContentTypeResolver());
}
/**
@@ -405,7 +392,7 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
ViewResolverRegistry registry = new ViewResolverRegistry(getApplicationContext());
configureViewResolvers(registry);
List resolvers = registry.getViewResolvers();
- ViewResolutionResultHandler handler = new ViewResolutionResultHandler(resolvers, mvcConversionService());
+ ViewResolutionResultHandler handler = new ViewResolutionResultHandler(resolvers, mvcContentTypeResolver());
handler.setDefaultViews(registry.getDefaultViews());
handler.setOrder(registry.getOrder());
return handler;
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/ContentNegotiatingResultHandlerSupport.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/ContentNegotiatingResultHandlerSupport.java
index abab1545ac..43f4b35a94 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/ContentNegotiatingResultHandlerSupport.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/ContentNegotiatingResultHandlerSupport.java
@@ -24,7 +24,7 @@ import java.util.Optional;
import java.util.Set;
import org.springframework.core.Ordered;
-import org.springframework.core.convert.ConversionService;
+import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.reactive.HandlerMapping;
@@ -43,28 +43,32 @@ public abstract class ContentNegotiatingResultHandlerSupport implements Ordered
private static final MediaType MEDIA_TYPE_APPLICATION_ALL = new MediaType("application");
- private final ConversionService conversionService;
-
private final RequestedContentTypeResolver contentTypeResolver;
+ private final ReactiveAdapterRegistry adapterRegistry;
+
private int order = LOWEST_PRECEDENCE;
- protected ContentNegotiatingResultHandlerSupport(ConversionService conversionService,
- RequestedContentTypeResolver contentTypeResolver) {
+ protected ContentNegotiatingResultHandlerSupport(RequestedContentTypeResolver contentTypeResolver) {
+ this(contentTypeResolver, new ReactiveAdapterRegistry());
+ }
+
+ protected ContentNegotiatingResultHandlerSupport(RequestedContentTypeResolver contentTypeResolver,
+ ReactiveAdapterRegistry adapterRegistry) {
- Assert.notNull(conversionService, "'conversionService' is required.");
Assert.notNull(contentTypeResolver, "'contentTypeResolver' is required.");
- this.conversionService = conversionService;
+ Assert.notNull(adapterRegistry, "'adapterRegistry' is required.");
this.contentTypeResolver = contentTypeResolver;
+ this.adapterRegistry = adapterRegistry;
}
/**
- * Return the configured {@link ConversionService}.
+ * Return the configured {@link ReactiveAdapterRegistry}.
*/
- public ConversionService getConversionService() {
- return this.conversionService;
+ public ReactiveAdapterRegistry getReactiveAdapterRegistry() {
+ return this.adapterRegistry;
}
/**
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/SimpleResultHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/SimpleResultHandler.java
index f64d11e143..39d795d6f2 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/SimpleResultHandler.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/SimpleResultHandler.java
@@ -18,14 +18,12 @@ package org.springframework.web.reactive.result;
import java.util.Optional;
-import org.reactivestreams.Publisher;
-import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.Ordered;
+import org.springframework.core.ReactiveAdapter;
+import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.core.convert.TypeDescriptor;
import org.springframework.util.Assert;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.HandlerResultHandler;
@@ -45,27 +43,26 @@ import org.springframework.web.server.ServerWebExchange;
*/
public class SimpleResultHandler implements Ordered, HandlerResultHandler {
- protected static final TypeDescriptor MONO_TYPE = TypeDescriptor.valueOf(Mono.class);
-
- protected static final TypeDescriptor FLUX_TYPE = TypeDescriptor.valueOf(Flux.class);
-
-
- private ConversionService conversionService;
+ private ReactiveAdapterRegistry adapterRegistry;
private int order = Ordered.LOWEST_PRECEDENCE;
- public SimpleResultHandler(ConversionService conversionService) {
- Assert.notNull(conversionService, "'conversionService' is required.");
- this.conversionService = conversionService;
+ public SimpleResultHandler() {
+ this.adapterRegistry = new ReactiveAdapterRegistry();
+ }
+
+ public SimpleResultHandler(ReactiveAdapterRegistry adapterRegistry) {
+ Assert.notNull(adapterRegistry, "'adapterRegistry' is required.");
+ this.adapterRegistry = adapterRegistry;
}
/**
- * Return the configured {@link ConversionService}.
+ * Return the configured {@link ReactiveAdapterRegistry}.
*/
- public ConversionService getConversionService() {
- return this.conversionService;
+ public ReactiveAdapterRegistry getAdapterRegistry() {
+ return this.adapterRegistry;
}
/**
@@ -88,37 +85,28 @@ public class SimpleResultHandler implements Ordered, HandlerResultHandler {
@Override
public boolean supports(HandlerResult result) {
ResolvableType type = result.getReturnType();
- if (Void.TYPE.equals(type.getRawClass())) {
+ Class> rawClass = type.getRawClass();
+ if (Void.TYPE.equals(rawClass)) {
return true;
}
- TypeDescriptor source = new TypeDescriptor(result.getReturnTypeSource());
- if (Publisher.class.isAssignableFrom(type.getRawClass()) ||
- canConvert(source, MONO_TYPE) || canConvert(source, FLUX_TYPE)) {
- Class> clazz = result.getReturnType().getGeneric(0).getRawClass();
+ ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(rawClass, result.getReturnValue());
+ if (adapter != null) {
+ Class> clazz = type.getGeneric(0).getRawClass();
return Void.class.equals(clazz);
}
return false;
}
- private boolean canConvert(TypeDescriptor source, TypeDescriptor target) {
- return getConversionService().canConvert(source, target);
- }
-
@SuppressWarnings("unchecked")
@Override
public Mono handleResult(ServerWebExchange exchange, HandlerResult result) {
- Optional optional = result.getReturnValue();
- if (!optional.isPresent()) {
+ Optional optionalValue = result.getReturnValue();
+ if (!optionalValue.isPresent()) {
return Mono.empty();
}
- Object value = optional.get();
- if (Publisher.class.isAssignableFrom(result.getReturnType().getRawClass())) {
- return Mono.from((Publisher>) value).then();
- }
- TypeDescriptor source = new TypeDescriptor(result.getReturnTypeSource());
- return canConvert(source, MONO_TYPE) ?
- ((Mono) getConversionService().convert(value, source, MONO_TYPE)) :
- ((Flux) getConversionService().convert(value, source, FLUX_TYPE)).single();
+ Class> returnType = result.getReturnType().getRawClass();
+ ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(returnType, optionalValue);
+ return adapter.toMono(optionalValue);
}
}
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java
index 499c8f6b93..eca6310ab3 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java
@@ -25,10 +25,10 @@ import reactor.core.publisher.Mono;
import org.springframework.core.Conventions;
import org.springframework.core.MethodParameter;
+import org.springframework.core.ReactiveAdapter;
+import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.core.convert.TypeDescriptor;
import org.springframework.http.MediaType;
import org.springframework.http.converter.reactive.HttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
@@ -57,34 +57,39 @@ import org.springframework.web.server.UnsupportedMediaTypeStatusException;
*/
public abstract class AbstractMessageReaderArgumentResolver {
- private static final TypeDescriptor MONO_TYPE = TypeDescriptor.valueOf(Mono.class);
-
- private static final TypeDescriptor FLUX_TYPE = TypeDescriptor.valueOf(Flux.class);
-
-
private final List> messageReaders;
- private final ConversionService conversionService;
-
private final Validator validator;
+ private final ReactiveAdapterRegistry adapterRegistry;
+
private final List supportedMediaTypes;
/**
- * Constructor with message converters and a ConversionService.
- * @param messageReaders readers to convert from the request body
- * @param service for converting to other reactive types from Flux and Mono
+ * Constructor with {@link HttpMessageReader}'s and a {@link Validator}.
+ * @param readers readers to convert from the request body
* @param validator validator to validate decoded objects with
*/
- protected AbstractMessageReaderArgumentResolver(List> messageReaders,
- ConversionService service, Validator validator) {
+ protected AbstractMessageReaderArgumentResolver(List> readers, Validator validator) {
- Assert.notEmpty(messageReaders, "At least one message reader is required.");
- Assert.notNull(service, "'conversionService' is required.");
+ this(readers, validator, new ReactiveAdapterRegistry());
+ }
+
+ /**
+ * Constructor that also accepts a {@link ReactiveAdapterRegistry}.
+ * @param messageReaders readers to convert from the request body
+ * @param validator validator to validate decoded objects with
+ * @param adapterRegistry for adapting to other reactive types from Flux and Mono
+ */
+ protected AbstractMessageReaderArgumentResolver(List> messageReaders,
+ Validator validator, ReactiveAdapterRegistry adapterRegistry) {
+
+ Assert.notEmpty(messageReaders, "At least one HttpMessageReader is required.");
+ Assert.notNull(adapterRegistry, "'adapterRegistry' is required");
this.messageReaders = messageReaders;
- this.conversionService = service;
this.validator = validator;
+ this.adapterRegistry = adapterRegistry;
this.supportedMediaTypes = messageReaders.stream()
.flatMap(converter -> converter.getReadableMediaTypes().stream())
.collect(Collectors.toList());
@@ -99,22 +104,21 @@ public abstract class AbstractMessageReaderArgumentResolver {
}
/**
- * Return the configured {@link ConversionService}.
+ * Return the configured {@link ReactiveAdapterRegistry}.
*/
- public ConversionService getConversionService() {
- return this.conversionService;
+ public ReactiveAdapterRegistry getReactiveAdapterRegistry() {
+ return this.adapterRegistry;
}
protected Mono readBody(MethodParameter bodyParameter, boolean isBodyRequired,
ServerWebExchange exchange) {
- TypeDescriptor typeDescriptor = new TypeDescriptor(bodyParameter);
- boolean convertFromMono = getConversionService().canConvert(MONO_TYPE, typeDescriptor);
- boolean convertFromFlux = getConversionService().canConvert(FLUX_TYPE, typeDescriptor);
+ Class> bodyType = ResolvableType.forMethodParameter(bodyParameter).resolve();
+ ReactiveAdapter adapter = getReactiveAdapterRegistry().getAdapterTo(bodyType);
ResolvableType elementType = ResolvableType.forMethodParameter(bodyParameter);
- if (convertFromMono || convertFromFlux) {
+ if (adapter != null) {
elementType = elementType.getGeneric(0);
}
@@ -126,28 +130,28 @@ public abstract class AbstractMessageReaderArgumentResolver {
for (HttpMessageReader> reader : getMessageReaders()) {
if (reader.canRead(elementType, mediaType)) {
- if (convertFromFlux) {
+ if (adapter != null && adapter.getDescriptor().isMultiValue()) {
Flux> flux = reader.read(elementType, request)
.onErrorResumeWith(ex -> Flux.error(getReadError(ex, bodyParameter)));
- if (checkRequired(bodyParameter, isBodyRequired)) {
+ if (checkRequired(adapter, isBodyRequired)) {
flux = flux.switchIfEmpty(Flux.error(getRequiredBodyError(bodyParameter)));
}
if (this.validator != null) {
flux = flux.map(applyValidationIfApplicable(bodyParameter));
}
- return Mono.just(getConversionService().convert(flux, FLUX_TYPE, typeDescriptor));
+ return Mono.just(adapter.fromPublisher(flux));
}
else {
Mono> mono = reader.readMono(elementType, request)
.otherwise(ex -> Mono.error(getReadError(ex, bodyParameter)));
- if (checkRequired(bodyParameter, isBodyRequired)) {
+ if (checkRequired(adapter, isBodyRequired)) {
mono = mono.otherwiseIfEmpty(Mono.error(getRequiredBodyError(bodyParameter)));
}
if (this.validator != null) {
mono = mono.map(applyValidationIfApplicable(bodyParameter));
}
- if (convertFromMono) {
- return Mono.just(getConversionService().convert(mono, MONO_TYPE, typeDescriptor));
+ if (adapter != null) {
+ return Mono.just(adapter.fromPublisher(mono));
}
else {
return Mono.from(mono);
@@ -159,11 +163,8 @@ public abstract class AbstractMessageReaderArgumentResolver {
return Mono.error(new UnsupportedMediaTypeStatusException(mediaType, this.supportedMediaTypes));
}
- protected boolean checkRequired(MethodParameter bodyParameter, boolean isBodyRequired) {
- if ("rx.Single".equals(bodyParameter.getNestedParameterType().getName())) {
- return true;
- }
- return isBodyRequired;
+ protected boolean checkRequired(ReactiveAdapter adapter, boolean isBodyRequired) {
+ return adapter != null && !adapter.getDescriptor().supportsEmpty() || isBodyRequired;
}
protected ServerWebInputException getReadError(Throwable ex, MethodParameter parameter) {
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java
index c42034efca..e82af46631 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java
@@ -19,13 +19,12 @@ import java.util.List;
import java.util.stream.Collectors;
import org.reactivestreams.Publisher;
-import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
+import org.springframework.core.ReactiveAdapter;
+import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.core.convert.TypeDescriptor;
import org.springframework.http.MediaType;
import org.springframework.http.converter.reactive.HttpMessageWriter;
import org.springframework.http.server.reactive.ServerHttpResponse;
@@ -44,31 +43,42 @@ import org.springframework.web.server.ServerWebExchange;
*/
public abstract class AbstractMessageWriterResultHandler extends ContentNegotiatingResultHandlerSupport {
- protected static final TypeDescriptor MONO_TYPE = TypeDescriptor.valueOf(Mono.class);
-
- protected static final TypeDescriptor FLUX_TYPE = TypeDescriptor.valueOf(Flux.class);
-
-
private final List> messageWriters;
/**
- * Constructor with message converters, a {@code ConversionService}, and a
+ * Constructor with {@link HttpMessageWriter}s and a
* {@code RequestedContentTypeResolver}.
*
* @param messageWriters for serializing Objects to the response body stream
- * @param conversionService for converting other reactive types (e.g.
- * rx.Observable, rx.Single, etc.) to Flux or Mono
* @param contentTypeResolver for resolving the requested content type
*/
protected AbstractMessageWriterResultHandler(List> messageWriters,
- ConversionService conversionService, RequestedContentTypeResolver contentTypeResolver) {
+ RequestedContentTypeResolver contentTypeResolver) {
- super(conversionService, contentTypeResolver);
+ super(contentTypeResolver);
Assert.notEmpty(messageWriters, "At least one message writer is required.");
this.messageWriters = messageWriters;
}
+ /**
+ * Constructor with an additional {@link ReactiveAdapterRegistry}.
+ *
+ * @param messageWriters for serializing Objects to the response body stream
+ * @param contentTypeResolver for resolving the requested content type
+ * @param adapterRegistry for adapting other reactive types (e.g. rx.Observable,
+ * rx.Single, etc.) to Flux or Mono
+ */
+ protected AbstractMessageWriterResultHandler(List> messageWriters,
+ RequestedContentTypeResolver contentTypeResolver,
+ ReactiveAdapterRegistry adapterRegistry) {
+
+ super(contentTypeResolver, adapterRegistry);
+ Assert.notEmpty(messageWriters, "At least one message writer is required.");
+ this.messageWriters = messageWriters;
+ }
+
+
/**
* Return the configured message converters.
*/
@@ -78,31 +88,20 @@ public abstract class AbstractMessageWriterResultHandler extends ContentNegotiat
@SuppressWarnings("unchecked")
- protected Mono writeBody(ServerWebExchange exchange, Object body,
- ResolvableType bodyType, MethodParameter bodyTypeParameter) {
+ protected Mono writeBody(Object body, MethodParameter bodyType, ServerWebExchange exchange) {
- Publisher> publisher = null;
+ Class> bodyClass = bodyType.getParameterType();
+ ReactiveAdapter adapter = getReactiveAdapterRegistry().getAdapterFrom(bodyClass, body);
+
+ Publisher> publisher;
ResolvableType elementType;
-
- if (Publisher.class.isAssignableFrom(bodyType.getRawClass())) {
- publisher = (Publisher>) body;
+ if (adapter != null) {
+ publisher = adapter.toPublisher(body);
+ elementType = ResolvableType.forMethodParameter(bodyType).getGeneric(0);
}
else {
- TypeDescriptor descriptor = new TypeDescriptor(bodyTypeParameter);
- if (getConversionService().canConvert(descriptor, MONO_TYPE)) {
- publisher = (Publisher>) getConversionService().convert(body, descriptor, MONO_TYPE);
- }
- else if (getConversionService().canConvert(descriptor, FLUX_TYPE)) {
- publisher = (Publisher>) getConversionService().convert(body, descriptor, FLUX_TYPE);
- }
- }
-
- if (publisher != null) {
- elementType = bodyType.getGeneric(0);
- }
- else {
- elementType = bodyType;
publisher = Mono.justOrEmpty(body);
+ elementType = ResolvableType.forMethodParameter(bodyType);
}
if (void.class == elementType.getRawClass() || Void.class == elementType.getRawClass()) {
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java
index b737a54099..625460c8f9 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java
@@ -20,8 +20,8 @@ import java.util.List;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
+import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
-import org.springframework.core.convert.ConversionService;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.RequestEntity;
@@ -45,26 +45,24 @@ public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentRes
/**
- * Constructor with message converters and a ConversionService.
- * @param messageReaders readers for de-serializing the request body with
- * @param service for converting to other reactive types from Flux and Mono
+ * Constructor with {@link HttpMessageReader}'s and a {@link Validator}.
+ * @param readers readers for de-serializing the request body with
+ * @param validator validator to validate decoded objects with
*/
- public HttpEntityArgumentResolver(List> messageReaders,
- ConversionService service) {
-
- this(messageReaders, service, null);
+ public HttpEntityArgumentResolver(List> readers, Validator validator) {
+ super(readers, validator);
}
/**
- * Constructor with message converters and a ConversionService.
- * @param messageReaders readers for de-serializing the request body with
- * @param service for converting to other reactive types from Flux and Mono
+ * Constructor that also accepts a {@link ReactiveAdapterRegistry}.
+ * @param readers readers for de-serializing the request body with
* @param validator validator to validate decoded objects with
+ * @param adapterRegistry for adapting to other reactive types from Flux and Mono
*/
- public HttpEntityArgumentResolver(List> messageReaders,
- ConversionService service, Validator validator) {
+ public HttpEntityArgumentResolver(List> readers, Validator validator,
+ ReactiveAdapterRegistry adapterRegistry) {
- super(messageReaders, service, validator);
+ super(readers, validator, adapterRegistry);
}
@@ -77,20 +75,9 @@ public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentRes
@Override
public Mono resolveArgument(MethodParameter param, ModelMap model, ServerWebExchange exchange) {
- ResolvableType entityType;
- MethodParameter bodyParameter;
-
- if (getConversionService().canConvert(Mono.class, param.getParameterType())) {
- entityType = ResolvableType.forMethodParameter(param).getGeneric(0);
- bodyParameter = new MethodParameter(param);
- bodyParameter.increaseNestingLevel();
- bodyParameter.increaseNestingLevel();
- }
- else {
- entityType = ResolvableType.forMethodParameter(param);
- bodyParameter = new MethodParameter(param);
- bodyParameter.increaseNestingLevel();
- }
+ ResolvableType entityType = ResolvableType.forMethodParameter(param);
+ MethodParameter bodyParameter = new MethodParameter(param);
+ bodyParameter.increaseNestingLevel();
return readBody(bodyParameter, false, exchange)
.map(body -> createHttpEntity(body, entityType, exchange))
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java
index 39eba423a4..3bca0935c8 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java
@@ -21,7 +21,7 @@ import java.util.List;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
-import org.springframework.core.convert.ConversionService;
+import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.converter.reactive.HttpMessageReader;
import org.springframework.ui.ModelMap;
import org.springframework.validation.Validator;
@@ -49,26 +49,24 @@ public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentRe
/**
- * Constructor with message converters and a ConversionService.
- * @param messageReaders readers for de-serializing the request body with
- * @param service for converting to other reactive types from Flux and Mono
+ * Constructor with {@link HttpMessageReader}'s and a {@link Validator}.
+ * @param readers readers for de-serializing the request body with
+ * @param validator validator to validate decoded objects with
*/
- public RequestBodyArgumentResolver(List> messageReaders,
- ConversionService service) {
-
- this(messageReaders, service, null);
+ public RequestBodyArgumentResolver(List> readers, Validator validator) {
+ super(readers, validator);
}
/**
- * Constructor with message converters and a ConversionService.
- * @param messageReaders readers for de-serializing the request body with
- * @param service for converting to other reactive types from Flux and Mono
+ * Constructor that also accepts a {@link ReactiveAdapterRegistry}.
+ * @param readers readers for de-serializing the request body with
* @param validator validator to validate decoded objects with
+ * @param adapterRegistry for adapting to other reactive types from Flux and Mono
*/
- public RequestBodyArgumentResolver(List> messageReaders,
- ConversionService service, Validator validator) {
+ public RequestBodyArgumentResolver(List> readers, Validator validator,
+ ReactiveAdapterRegistry adapterRegistry) {
- super(messageReaders, service, validator);
+ super(readers, validator, adapterRegistry);
}
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java
index b550ea0ba4..cae25da552 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java
@@ -31,6 +31,7 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.codec.ByteBufferDecoder;
import org.springframework.core.codec.StringDecoder;
import org.springframework.core.convert.ConversionService;
@@ -66,6 +67,8 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
private final List> messageReaders = new ArrayList<>(10);
+ private ReactiveAdapterRegistry reactiveAdapters = new ReactiveAdapterRegistry();
+
private ConversionService conversionService = new DefaultFormattingConversionService();
private Validator validator;
@@ -126,6 +129,14 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
return this.messageReaders;
}
+ public void setReactiveAdapterRegistry(ReactiveAdapterRegistry registry) {
+ this.reactiveAdapters = registry;
+ }
+
+ public ReactiveAdapterRegistry getReactiveAdapterRegistry() {
+ return this.reactiveAdapters;
+ }
+
/**
* Configure a ConversionService for type conversion of controller method
* arguments as well as for converting from different async types to
@@ -187,13 +198,15 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
protected List initArgumentResolvers() {
List resolvers = new ArrayList<>();
- // Annotation-based argument resolution
ConversionService cs = getConversionService();
+ ReactiveAdapterRegistry adapterRegistry = getReactiveAdapterRegistry();
+
+ // Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(cs, getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver(cs, getBeanFactory()));
resolvers.add(new PathVariableMapMethodArgumentResolver());
- resolvers.add(new RequestBodyArgumentResolver(getMessageReaders(), cs, getValidator()));
+ resolvers.add(new RequestBodyArgumentResolver(getMessageReaders(), getValidator(), adapterRegistry));
resolvers.add(new RequestHeaderMethodArgumentResolver(cs, getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new CookieValueMethodArgumentResolver(cs, getBeanFactory()));
@@ -202,6 +215,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
resolvers.add(new RequestAttributeMethodArgumentResolver(cs , getBeanFactory()));
// Type-based argument resolution
+ resolvers.add(new HttpEntityArgumentResolver(getMessageReaders(), getValidator(), adapterRegistry));
resolvers.add(new ModelArgumentResolver());
// Custom resolvers
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java
index 4812c9978f..7a39aeafab 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java
@@ -21,15 +21,14 @@ import java.util.List;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
+import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.core.convert.ConversionService;
import org.springframework.http.HttpEntity;
import org.springframework.http.converter.reactive.HttpMessageWriter;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.HandlerResultHandler;
-import org.springframework.web.reactive.accept.HeaderContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.server.ServerWebExchange;
@@ -53,42 +52,41 @@ import org.springframework.web.server.ServerWebExchange;
public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandler
implements HandlerResultHandler {
- /**
- * Constructor with message converters and a {@code ConversionService} only
- * and creating a {@link HeaderContentTypeResolver}, i.e. using Accept header
- * to determine the requested content type.
- *
- * @param messageWriters writers for serializing to the response body stream
- * @param conversionService for converting to Flux and Mono from other reactive types
- */
- public ResponseBodyResultHandler(List> messageWriters,
- ConversionService conversionService) {
-
- this(messageWriters, conversionService, new HeaderContentTypeResolver());
- }
/**
- * Constructor with message converters, a {@code ConversionService}, and a
+ * Constructor with {@link HttpMessageWriter}s and a
* {@code RequestedContentTypeResolver}.
*
* @param messageWriters writers for serializing to the response body stream
- * @param conversionService for converting other reactive types (e.g.
- * rx.Observable, rx.Single, etc.) to Flux or Mono
* @param contentTypeResolver for resolving the requested content type
*/
public ResponseBodyResultHandler(List> messageWriters,
- ConversionService conversionService, RequestedContentTypeResolver contentTypeResolver) {
+ RequestedContentTypeResolver contentTypeResolver) {
- super(messageWriters, conversionService, contentTypeResolver);
+ this(messageWriters, contentTypeResolver, new ReactiveAdapterRegistry());
+ }
+
+ /**
+ * Constructor with an additional {@link ReactiveAdapterRegistry}.
+ *
+ * @param messageWriters writers for serializing to the response body stream
+ * @param contentTypeResolver for resolving the requested content type
+ * @param adapterRegistry for adapting other reactive types (e.g. rx.Observable,
+ * rx.Single, etc.) to Flux or Mono
+ */
+ public ResponseBodyResultHandler(List> messageWriters,
+ RequestedContentTypeResolver contentTypeResolver,
+ ReactiveAdapterRegistry adapterRegistry) {
+
+ super(messageWriters, contentTypeResolver, adapterRegistry);
setOrder(100);
}
@Override
public boolean supports(HandlerResult result) {
- ResolvableType returnType = result.getReturnType();
MethodParameter parameter = result.getReturnTypeSource();
- return hasResponseBodyAnnotation(parameter) && !isHttpEntityType(returnType);
+ return hasResponseBodyAnnotation(parameter) && !isHttpEntityType(result);
}
private boolean hasResponseBodyAnnotation(MethodParameter parameter) {
@@ -97,26 +95,27 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle
parameter.getMethodAnnotation(ResponseBody.class) != null);
}
- private boolean isHttpEntityType(ResolvableType returnType) {
- if (HttpEntity.class.isAssignableFrom(returnType.getRawClass())) {
+ private boolean isHttpEntityType(HandlerResult result) {
+ Class> rawClass = result.getReturnType().getRawClass();
+ if (HttpEntity.class.isAssignableFrom(rawClass)) {
return true;
}
- else if (getConversionService().canConvert(returnType.getRawClass(), Mono.class)) {
- ResolvableType genericType = returnType.getGeneric(0);
- if (HttpEntity.class.isAssignableFrom(genericType.getRawClass())) {
- return true;
+ else {
+ if (getReactiveAdapterRegistry().getAdapterFrom(rawClass, result.getReturnValue()) != null) {
+ ResolvableType genericType = result.getReturnType().getGeneric(0);
+ if (HttpEntity.class.isAssignableFrom(genericType.getRawClass())) {
+ return true;
+ }
}
}
return false;
}
-
@Override
public Mono handleResult(ServerWebExchange exchange, HandlerResult result) {
Object body = result.getReturnValue().orElse(null);
- ResolvableType bodyType = result.getReturnType();
MethodParameter bodyTypeParameter = result.getReturnTypeSource();
- return writeBody(exchange, body, bodyType, bodyTypeParameter);
+ return writeBody(body, bodyTypeParameter, exchange);
}
}
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandler.java
index fd28d33fae..3f8264a256 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandler.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandler.java
@@ -21,8 +21,9 @@ import java.util.Optional;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
+import org.springframework.core.ReactiveAdapter;
+import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
-import org.springframework.core.convert.ConversionService;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.RequestEntity;
@@ -31,7 +32,6 @@ import org.springframework.http.converter.reactive.HttpMessageWriter;
import org.springframework.util.Assert;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.HandlerResultHandler;
-import org.springframework.web.reactive.accept.HeaderContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.server.ServerWebExchange;
@@ -47,52 +47,55 @@ import org.springframework.web.server.ServerWebExchange;
public class ResponseEntityResultHandler extends AbstractMessageWriterResultHandler
implements HandlerResultHandler {
- /**
- * Constructor with message converters and a {@code ConversionService} only
- * and creating a {@link HeaderContentTypeResolver}, i.e. using Accept header
- * to determine the requested content type.
- *
- * @param messageWriters writers for serializing to the response body stream
- * @param conversionService for converting to Flux and Mono from other reactive types
- */
- public ResponseEntityResultHandler(List> messageWriters,
- ConversionService conversionService) {
-
- this(messageWriters, conversionService, new HeaderContentTypeResolver());
- }
/**
- * Constructor with message converters, a {@code ConversionService}, and a
+ * Constructor with {@link HttpMessageWriter}s and a
* {@code RequestedContentTypeResolver}.
*
* @param messageWriters writers for serializing to the response body stream
- * @param conversionService for converting other reactive types (e.g.
- * rx.Observable, rx.Single, etc.) to Flux or Mono
* @param contentTypeResolver for resolving the requested content type
*/
public ResponseEntityResultHandler(List> messageWriters,
- ConversionService conversionService, RequestedContentTypeResolver contentTypeResolver) {
+ RequestedContentTypeResolver contentTypeResolver) {
- super(messageWriters, conversionService, contentTypeResolver);
+ this(messageWriters, contentTypeResolver, new ReactiveAdapterRegistry());
+ }
+
+ /**
+ * Constructor with an additional {@link ReactiveAdapterRegistry}.
+ *
+ * @param messageWriters writers for serializing to the response body stream
+ * @param contentTypeResolver for resolving the requested content type
+ * @param adapterRegistry for adapting other reactive types (e.g. rx.Observable,
+ * rx.Single, etc.) to Flux or Mono
+ */
+ public ResponseEntityResultHandler(List> messageWriters,
+ RequestedContentTypeResolver contentTypeResolver,
+ ReactiveAdapterRegistry adapterRegistry) {
+
+ super(messageWriters, contentTypeResolver, adapterRegistry);
setOrder(0);
}
@Override
public boolean supports(HandlerResult result) {
- ResolvableType returnType = result.getReturnType();
+ Class> returnType = result.getReturnType().getRawClass();
if (isSupportedType(returnType)) {
return true;
}
- else if (getConversionService().canConvert(returnType.getRawClass(), Mono.class)) {
- ResolvableType genericType = result.getReturnType().getGeneric(0);
- return isSupportedType(genericType);
+ else {
+ Optional returnValue = result.getReturnValue();
+ ReactiveAdapter adapter = getReactiveAdapterRegistry().getAdapterFrom(returnType, returnValue);
+ if (adapter != null && !adapter.getDescriptor().isMultiValue()) {
+ ResolvableType genericType = result.getReturnType().getGeneric(0);
+ return isSupportedType(genericType.getRawClass());
+ }
}
return false;
}
- private boolean isSupportedType(ResolvableType returnType) {
- Class> clazz = returnType.getRawClass();
+ private boolean isSupportedType(Class> clazz) {
return (HttpEntity.class.isAssignableFrom(clazz) && !RequestEntity.class.isAssignableFrom(clazz));
}
@@ -101,25 +104,24 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
public Mono handleResult(ServerWebExchange exchange, HandlerResult result) {
ResolvableType returnType = result.getReturnType();
-
- ResolvableType bodyType;
- MethodParameter bodyTypeParameter;
+ MethodParameter bodyType;
Mono> returnValueMono;
- Optional optional = result.getReturnValue();
+ Optional optionalValue = result.getReturnValue();
- if (optional.isPresent() && getConversionService().canConvert(returnType.getRawClass(), Mono.class)) {
- returnValueMono = getConversionService().convert(optional.get(), Mono.class);
- bodyType = returnType.getGeneric(0, 0);
- bodyTypeParameter = new MethodParameter(result.getReturnTypeSource());
- bodyTypeParameter.increaseNestingLevel();
- bodyTypeParameter.increaseNestingLevel();
+ Class> rawClass = returnType.getRawClass();
+ ReactiveAdapter adapter = getReactiveAdapterRegistry().getAdapterFrom(rawClass, optionalValue);
+
+ if (adapter != null) {
+ returnValueMono = adapter.toMono(optionalValue);
+ bodyType = new MethodParameter(result.getReturnTypeSource());
+ bodyType.increaseNestingLevel();
+ bodyType.increaseNestingLevel();
}
else {
- returnValueMono = Mono.justOrEmpty(optional);
- bodyType = returnType.getGeneric(0);
- bodyTypeParameter = new MethodParameter(result.getReturnTypeSource());
- bodyTypeParameter.increaseNestingLevel();
+ returnValueMono = Mono.justOrEmpty(optionalValue);
+ bodyType = new MethodParameter(result.getReturnTypeSource());
+ bodyType.increaseNestingLevel();
}
return returnValueMono.then(returnValue -> {
@@ -141,7 +143,7 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
.forEach(entry -> responseHeaders.put(entry.getKey(), entry.getValue()));
}
- return writeBody(exchange, httpEntity.getBody(), bodyType, bodyTypeParameter);
+ return writeBody(httpEntity.getBody(), bodyType, exchange);
});
}
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java
index 650f5f9804..d1a146c205 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java
@@ -31,16 +31,16 @@ import org.springframework.core.Conventions;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered;
+import org.springframework.core.ReactiveAdapter;
+import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
-import org.springframework.core.convert.ConversionService;
import org.springframework.http.MediaType;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.HandlerResultHandler;
-import org.springframework.web.reactive.accept.HeaderContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.result.ContentNegotiatingResultHandlerSupport;
import org.springframework.web.server.NotAcceptableStatusException;
@@ -84,26 +84,28 @@ public class ViewResolutionResultHandler extends ContentNegotiatingResultHandler
/**
- * Constructor with {@code ViewResolver}s and a {@code ConversionService} only
- * and creating a {@link HeaderContentTypeResolver}, i.e. using Accept header
- * to determine the requested content type.
+ * Constructor with {@link ViewResolver}s and a {@link RequestedContentTypeResolver}.
* @param resolvers the resolver to use
- * @param conversionService for converting other reactive types (e.g. rx.Single) to Mono
+ * @param contentTypeResolver for resolving the requested content type
*/
- public ViewResolutionResultHandler(List resolvers, ConversionService conversionService) {
- this(resolvers, conversionService, new HeaderContentTypeResolver());
+ public ViewResolutionResultHandler(List resolvers,
+ RequestedContentTypeResolver contentTypeResolver) {
+
+ this(resolvers, contentTypeResolver, new ReactiveAdapterRegistry());
}
/**
* Constructor with {@code ViewResolver}s tand a {@code ConversionService}.
* @param resolvers the resolver to use
- * @param conversionService for converting other reactive types (e.g. rx.Single) to Mono
* @param contentTypeResolver for resolving the requested content type
+ * @param adapterRegistry for adapting from other reactive types (e.g.
+ * rx.Single) to Mono
*/
- public ViewResolutionResultHandler(List resolvers, ConversionService conversionService,
- RequestedContentTypeResolver contentTypeResolver) {
+ public ViewResolutionResultHandler(List resolvers,
+ RequestedContentTypeResolver contentTypeResolver,
+ ReactiveAdapterRegistry adapterRegistry) {
- super(conversionService, contentTypeResolver);
+ super(contentTypeResolver, adapterRegistry);
this.viewResolvers.addAll(resolvers);
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
@@ -143,7 +145,7 @@ public class ViewResolutionResultHandler extends ContentNegotiatingResultHandler
if (isSupportedType(clazz)) {
return true;
}
- if (getConversionService().canConvert(clazz, Mono.class)) {
+ if (getReactiveAdapterRegistry().getAdapterFrom(clazz, result.getReturnValue()) != null) {
clazz = result.getReturnType().getGeneric(0).getRawClass();
return isSupportedType(clazz);
}
@@ -168,10 +170,12 @@ public class ViewResolutionResultHandler extends ContentNegotiatingResultHandler
ResolvableType elementType;
ResolvableType returnType = result.getReturnType();
- if (getConversionService().canConvert(returnType.getRawClass(), Mono.class)) {
- Optional optionalValue = result.getReturnValue();
+ Class> rawClass = returnType.getRawClass();
+ Optional optionalValue = result.getReturnValue();
+ ReactiveAdapter adapter = getReactiveAdapterRegistry().getAdapterFrom(rawClass, optionalValue);
+ if (adapter != null) {
if (optionalValue.isPresent()) {
- Mono> converted = getConversionService().convert(optionalValue.get(), Mono.class);
+ Mono> converted = adapter.toMono(optionalValue);
valueMono = converted.map(o -> o);
}
else {
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/DispatcherHandlerErrorTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/DispatcherHandlerErrorTests.java
index 5a3b39ae1a..91a1bc2e23 100644
--- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/DispatcherHandlerErrorTests.java
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/DispatcherHandlerErrorTests.java
@@ -30,7 +30,6 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.codec.StringEncoder;
-import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpMethod;
@@ -43,6 +42,7 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.reactive.accept.HeaderContentTypeResolver;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler;
@@ -198,7 +198,7 @@ public class DispatcherHandlerErrorTests {
public ResponseBodyResultHandler resultHandler() {
return new ResponseBodyResultHandler(
Collections.singletonList(new EncoderHttpMessageWriter<>(new StringEncoder())),
- new DefaultConversionService());
+ new HeaderContentTypeResolver());
}
@Bean
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/ContentNegotiatingResultHandlerSupportTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/ContentNegotiatingResultHandlerSupportTests.java
index 08bc361585..131d039a4c 100644
--- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/ContentNegotiatingResultHandlerSupportTests.java
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/ContentNegotiatingResultHandlerSupportTests.java
@@ -24,7 +24,6 @@ import java.util.Set;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.MockServerHttpRequest;
@@ -125,7 +124,7 @@ public class ContentNegotiatingResultHandlerSupportTests {
}
public TestResultHandler(RequestedContentTypeResolver contentTypeResolver) {
- super(new GenericConversionService(), contentTypeResolver);
+ super(contentTypeResolver);
}
}
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/SimpleResultHandlerTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/SimpleResultHandlerTests.java
index 646956d4ef..af660ebdfb 100644
--- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/SimpleResultHandlerTests.java
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/SimpleResultHandlerTests.java
@@ -27,10 +27,6 @@ import rx.Observable;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
-import org.springframework.core.convert.support.MonoToCompletableFutureConverter;
-import org.springframework.core.convert.support.ReactorToRxJava1Converter;
-import org.springframework.format.support.DefaultFormattingConversionService;
-import org.springframework.format.support.FormattingConversionService;
import org.springframework.web.reactive.HandlerResult;
import static org.junit.Assert.assertEquals;
@@ -47,10 +43,7 @@ public class SimpleResultHandlerTests {
@Before
public void setUp() throws Exception {
- FormattingConversionService service = new DefaultFormattingConversionService();
- service.addConverter(new MonoToCompletableFutureConverter());
- service.addConverter(new ReactorToRxJava1Converter());
- this.resultHandler = new SimpleResultHandler(service);
+ this.resultHandler = new SimpleResultHandler();
}
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/SimpleUrlHandlerMappingIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/SimpleUrlHandlerMappingIntegrationTests.java
index 5b1c273038..76142d278e 100644
--- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/SimpleUrlHandlerMappingIntegrationTests.java
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/SimpleUrlHandlerMappingIntegrationTests.java
@@ -28,7 +28,6 @@ import reactor.core.publisher.Mono;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
@@ -147,7 +146,7 @@ public class SimpleUrlHandlerMappingIntegrationTests extends AbstractHttpHandler
@Bean
public SimpleResultHandler resultHandler() {
- return new SimpleResultHandler(new DefaultConversionService());
+ return new SimpleResultHandler();
}
}
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java
index 922d08e6d5..40de5da683 100644
--- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java
@@ -35,12 +35,8 @@ import rx.Single;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.StringDecoder;
-import org.springframework.core.convert.support.MonoToCompletableFutureConverter;
-import org.springframework.core.convert.support.ReactorToRxJava1Converter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
-import org.springframework.format.support.DefaultFormattingConversionService;
-import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
@@ -50,14 +46,20 @@ import org.springframework.http.converter.reactive.HttpMessageReader;
import org.springframework.http.server.reactive.MockServerHttpRequest;
import org.springframework.http.server.reactive.MockServerHttpResponse;
import org.springframework.ui.ExtendedModelMap;
+import org.springframework.validation.Validator;
import org.springframework.web.reactive.result.ResolvableMethod;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.session.MockWebSessionManager;
-import static org.junit.Assert.*;
-import static org.springframework.core.ResolvableType.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.springframework.core.ResolvableType.forClassWithGenerics;
/**
* Unit tests for {@link HttpEntityArgumentResolver}.When adding a test also
@@ -87,12 +89,7 @@ public class HttpEntityArgumentResolverTests {
private HttpEntityArgumentResolver createResolver() {
List> readers = new ArrayList<>();
readers.add(new DecoderHttpMessageReader<>(new StringDecoder()));
-
- FormattingConversionService service = new DefaultFormattingConversionService();
- service.addConverter(new MonoToCompletableFutureConverter());
- service.addConverter(new ReactorToRxJava1Converter());
-
- return new HttpEntityArgumentResolver(readers, service);
+ return new HttpEntityArgumentResolver(readers, mock(Validator.class));
}
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java
index 71c6789154..539c3490ae 100644
--- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java
@@ -42,12 +42,8 @@ import rx.Single;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.Decoder;
-import org.springframework.core.convert.support.MonoToCompletableFutureConverter;
-import org.springframework.core.convert.support.ReactorToRxJava1Converter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
-import org.springframework.format.support.DefaultFormattingConversionService;
-import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.codec.json.JacksonJsonDecoder;
@@ -66,8 +62,12 @@ import org.springframework.web.server.UnsupportedMediaTypeStatusException;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.session.MockWebSessionManager;
-import static org.junit.Assert.*;
-import static org.springframework.core.ResolvableType.*;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.springframework.core.ResolvableType.forClass;
+import static org.springframework.core.ResolvableType.forClassWithGenerics;
/**
* Unit tests for {@link AbstractMessageReaderArgumentResolver}.
@@ -275,15 +275,9 @@ public class MessageReaderArgumentResolverTests {
@SuppressWarnings("Convert2MethodRef")
private AbstractMessageReaderArgumentResolver resolver(Decoder>... decoders) {
-
List> readers = new ArrayList<>();
Arrays.asList(decoders).forEach(decoder -> readers.add(new DecoderHttpMessageReader<>(decoder)));
-
- FormattingConversionService service = new DefaultFormattingConversionService();
- service.addConverter(new MonoToCompletableFutureConverter());
- service.addConverter(new ReactorToRxJava1Converter());
-
- return new AbstractMessageReaderArgumentResolver(readers, service, new TestBeanValidator()) {};
+ return new AbstractMessageReaderArgumentResolver(readers, new TestBeanValidator()) {};
}
private DataBuffer dataBuffer(String body) {
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageWriterResultHandlerTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageWriterResultHandlerTests.java
index 2fac801f30..f01b6b51e0 100644
--- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageWriterResultHandlerTests.java
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageWriterResultHandlerTests.java
@@ -41,9 +41,6 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.ByteBufferEncoder;
import org.springframework.core.codec.StringEncoder;
-import org.springframework.core.convert.support.GenericConversionService;
-import org.springframework.core.convert.support.MonoToCompletableFutureConverter;
-import org.springframework.core.convert.support.ReactorToRxJava1Converter;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.buffer.support.DataBufferTestUtils;
@@ -64,9 +61,11 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.session.MockWebSessionManager;
-import static org.junit.Assert.*;
-import static org.springframework.http.MediaType.*;
-import static org.springframework.web.reactive.HandlerMapping.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.springframework.http.MediaType.APPLICATION_JSON;
+import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8;
+import static org.springframework.web.reactive.HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE;
/**
* Unit tests for {@link AbstractMessageWriterResultHandler}.
@@ -93,7 +92,7 @@ public class MessageWriterResultHandlerTests {
public void useDefaultContentType() throws Exception {
Resource body = new ClassPathResource("logo.png", getClass());
ResolvableType type = ResolvableType.forType(Resource.class);
- this.resultHandler.writeBody(this.exchange, body, type, returnType(type)).block(Duration.ofSeconds(5));
+ this.resultHandler.writeBody(body, returnType(type), this.exchange).block(Duration.ofSeconds(5));
assertEquals("image/x-png", this.response.getHeaders().getFirst("Content-Type"));
}
@@ -105,7 +104,7 @@ public class MessageWriterResultHandlerTests {
String body = "foo";
ResolvableType type = ResolvableType.forType(String.class);
- this.resultHandler.writeBody(this.exchange, body, type, returnType(type)).block(Duration.ofSeconds(5));
+ this.resultHandler.writeBody(body, returnType(type), this.exchange).block(Duration.ofSeconds(5));
assertEquals(APPLICATION_JSON_UTF8, this.response.getHeaders().getContentType());
}
@@ -119,7 +118,7 @@ public class MessageWriterResultHandlerTests {
}
private void testVoidReturnType(Object body, ResolvableType type) {
- this.resultHandler.writeBody(this.exchange, body, type, returnType(type)).block(Duration.ofSeconds(5));
+ this.resultHandler.writeBody(body, returnType(type), this.exchange).block(Duration.ofSeconds(5));
assertNull(this.response.getHeaders().get("Content-Type"));
assertNull(this.response.getBody());
@@ -131,7 +130,7 @@ public class MessageWriterResultHandlerTests {
ResolvableType type = ResolvableType.forType(OutputStream.class);
HttpMessageWriter> writer = new EncoderHttpMessageWriter<>(new ByteBufferEncoder());
- Mono mono = createResultHandler(writer).writeBody(this.exchange, body, type, returnType(type));
+ Mono mono = createResultHandler(writer).writeBody(body, returnType(type), this.exchange);
TestSubscriber.subscribe(mono).assertError(IllegalStateException.class);
}
@@ -140,7 +139,7 @@ public class MessageWriterResultHandlerTests {
public void jacksonTypeOfListElement() throws Exception {
List body = Arrays.asList(new Foo("foo"), new Bar("bar"));
ResolvableType type = ResolvableType.forClassWithGenerics(List.class, ParentClass.class);
- this.resultHandler.writeBody(this.exchange, body, type, returnType(type)).block(Duration.ofSeconds(5));
+ this.resultHandler.writeBody(body, returnType(type), this.exchange).block(Duration.ofSeconds(5));
assertEquals(APPLICATION_JSON_UTF8, this.response.getHeaders().getContentType());
assertResponseBody("[{\"type\":\"foo\",\"parentProperty\":\"foo\"}," +
@@ -151,7 +150,7 @@ public class MessageWriterResultHandlerTests {
public void jacksonTypeWithSubType() throws Exception {
SimpleBean body = new SimpleBean(123L, "foo");
ResolvableType type = ResolvableType.forClass(Identifiable.class);
- this.resultHandler.writeBody(this.exchange, body, type, returnType(type)).block(Duration.ofSeconds(5));
+ this.resultHandler.writeBody(body, returnType(type), this.exchange).block(Duration.ofSeconds(5));
assertEquals(APPLICATION_JSON_UTF8, this.response.getHeaders().getContentType());
assertResponseBody("{\"id\":123,\"name\":\"foo\"}");
@@ -161,7 +160,7 @@ public class MessageWriterResultHandlerTests {
public void jacksonTypeWithSubTypeOfListElement() throws Exception {
List body = Arrays.asList(new SimpleBean(123L, "foo"), new SimpleBean(456L, "bar"));
ResolvableType type = ResolvableType.forClassWithGenerics(List.class, Identifiable.class);
- this.resultHandler.writeBody(this.exchange, body, type, returnType(type)).block(Duration.ofSeconds(5));
+ this.resultHandler.writeBody(body, returnType(type), this.exchange).block(Duration.ofSeconds(5));
assertEquals(APPLICATION_JSON_UTF8, this.response.getHeaders().getContentType());
assertResponseBody("[{\"id\":123,\"name\":\"foo\"},{\"id\":456,\"name\":\"bar\"}]");
@@ -185,14 +184,8 @@ public class MessageWriterResultHandlerTests {
else {
writerList = Arrays.asList(writers);
}
-
- GenericConversionService service = new GenericConversionService();
- service.addConverter(new MonoToCompletableFutureConverter());
- service.addConverter(new ReactorToRxJava1Converter());
-
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
-
- return new AbstractMessageWriterResultHandler(writerList, service, resolver) {};
+ return new AbstractMessageWriterResultHandler(writerList, resolver) {};
}
private void assertResponseBody(String responseBody) {
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolverTests.java
index 3ce8f43ba9..1fd74451f9 100644
--- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolverTests.java
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolverTests.java
@@ -18,7 +18,6 @@ package org.springframework.web.reactive.result.method.annotation;
import java.net.URI;
import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
@@ -38,18 +37,15 @@ import rx.Single;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.StringDecoder;
-import org.springframework.core.convert.support.MonoToCompletableFutureConverter;
-import org.springframework.core.convert.support.ReactorToRxJava1Converter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
-import org.springframework.format.support.DefaultFormattingConversionService;
-import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.HttpMethod;
import org.springframework.http.converter.reactive.DecoderHttpMessageReader;
import org.springframework.http.converter.reactive.HttpMessageReader;
import org.springframework.http.server.reactive.MockServerHttpRequest;
import org.springframework.http.server.reactive.MockServerHttpResponse;
import org.springframework.ui.ExtendedModelMap;
+import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.reactive.result.ResolvableMethod;
import org.springframework.web.server.ServerWebExchange;
@@ -62,6 +58,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
import static org.springframework.core.ResolvableType.forClass;
import static org.springframework.core.ResolvableType.forClassWithGenerics;
@@ -93,12 +90,7 @@ public class RequestBodyArgumentResolverTests {
private RequestBodyArgumentResolver resolver() {
List> readers = new ArrayList<>();
readers.add(new DecoderHttpMessageReader<>(new StringDecoder()));
-
- FormattingConversionService service = new DefaultFormattingConversionService();
- service.addConverter(new MonoToCompletableFutureConverter());
- service.addConverter(new ReactorToRxJava1Converter());
-
- return new RequestBodyArgumentResolver(readers, service);
+ return new RequestBodyArgumentResolver(readers, mock(Validator.class));
}
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java
index 52ce511667..32abc9d5dd 100644
--- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java
@@ -27,11 +27,6 @@ import reactor.core.publisher.Mono;
import org.springframework.core.codec.ByteBufferEncoder;
import org.springframework.core.codec.StringEncoder;
-import org.springframework.core.convert.support.DefaultConversionService;
-import org.springframework.core.convert.support.MonoToCompletableFutureConverter;
-import org.springframework.core.convert.support.ReactorToRxJava1Converter;
-import org.springframework.format.support.DefaultFormattingConversionService;
-import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.json.JacksonJsonEncoder;
@@ -99,12 +94,8 @@ public class ResponseBodyResultHandlerTests {
else {
writerList = Arrays.asList(writers);
}
- FormattingConversionService service = new DefaultFormattingConversionService();
- service.addConverter(new MonoToCompletableFutureConverter());
- service.addConverter(new ReactorToRxJava1Converter());
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
-
- return new ResponseBodyResultHandler(writerList, new DefaultConversionService(), resolver);
+ return new ResponseBodyResultHandler(writerList, resolver);
}
@Test
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandlerTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandlerTests.java
index a62d9a3f4b..0034b3050c 100644
--- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandlerTests.java
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandlerTests.java
@@ -34,11 +34,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.ByteBufferEncoder;
import org.springframework.core.codec.StringEncoder;
-import org.springframework.core.convert.support.MonoToCompletableFutureConverter;
-import org.springframework.core.convert.support.ReactorToRxJava1Converter;
import org.springframework.core.io.buffer.support.DataBufferTestUtils;
-import org.springframework.format.support.DefaultFormattingConversionService;
-import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -59,8 +55,11 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.session.MockWebSessionManager;
-import static org.junit.Assert.*;
-import static org.springframework.core.ResolvableType.*;
+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.springframework.core.ResolvableType.forClassWithGenerics;
/**
* Unit tests for {@link ResponseEntityResultHandler}. When adding a test also
@@ -100,14 +99,8 @@ public class ResponseEntityResultHandlerTests {
else {
writerList = Arrays.asList(writers);
}
- FormattingConversionService service = new DefaultFormattingConversionService();
- service.addConverter(new MonoToCompletableFutureConverter());
- service.addConverter(new ReactorToRxJava1Converter());
-
-
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
-
- return new ResponseEntityResultHandler(writerList, service, resolver);
+ return new ResponseEntityResultHandler(writerList, resolver);
}
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandlerTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandlerTests.java
index ad5d15b838..4b86da852e 100644
--- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandlerTests.java
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandlerTests.java
@@ -38,13 +38,9 @@ import rx.Single;
import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
-import org.springframework.core.convert.support.MonoToCompletableFutureConverter;
-import org.springframework.core.convert.support.ReactorToRxJava1Converter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.core.io.buffer.support.DataBufferTestUtils;
-import org.springframework.format.support.DefaultFormattingConversionService;
-import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.MockServerHttpRequest;
@@ -55,6 +51,8 @@ import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.reactive.HandlerResult;
+import org.springframework.web.reactive.accept.HeaderContentTypeResolver;
+import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.result.ResolvableMethod;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
@@ -62,9 +60,10 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.session.DefaultWebSessionManager;
import org.springframework.web.server.session.WebSessionManager;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.*;
-import static org.springframework.http.MediaType.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.springframework.http.MediaType.APPLICATION_JSON;
/**
* Unit tests for {@link ViewResolutionResultHandler}.
@@ -247,12 +246,9 @@ public class ViewResolutionResultHandlerTests {
}
private ViewResolutionResultHandler createResultHandler(List defaultViews, ViewResolver... resolvers) {
- FormattingConversionService service = new DefaultFormattingConversionService();
- service.addConverter(new MonoToCompletableFutureConverter());
- service.addConverter(new ReactorToRxJava1Converter());
List resolverList = Arrays.asList(resolvers);
-
- ViewResolutionResultHandler handler = new ViewResolutionResultHandler(resolverList, service);
+ RequestedContentTypeResolver contentTypeResolver = new HeaderContentTypeResolver();
+ ViewResolutionResultHandler handler = new ViewResolutionResultHandler(resolverList, contentTypeResolver);
handler.setDefaultViews(defaultViews);
return handler;
}