Further refactoring of ReactiveAdapter/Registry
Simplify getAdapterFrom/To into a single getAdapter method that looks for an exact match by type first and then isAssignableFrom. Also expose shortcut methods in ReactiveAdapter to minimize the need for access to the ReactiveTypeDescriptor. Issue: SPR-14902
This commit is contained in:
parent
adb80f4099
commit
5651c2180e
|
|
@ -70,6 +70,35 @@ public class ReactiveAdapter {
|
||||||
return this.descriptor;
|
return this.descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A shortcut for {@code getDescriptor().getReactiveType()}.
|
||||||
|
*/
|
||||||
|
public Class<?> getReactiveType() {
|
||||||
|
return getDescriptor().getReactiveType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A shortcut for {@code getDescriptor().isMultiValue()}.
|
||||||
|
*/
|
||||||
|
public boolean isMultiValue() {
|
||||||
|
return getDescriptor().isMultiValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A shortcut for {@code getDescriptor().supportsEmpty()}.
|
||||||
|
*/
|
||||||
|
public boolean supportsEmpty() {
|
||||||
|
return getDescriptor().supportsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A shortcut for {@code getDescriptor().isNoValue()}.
|
||||||
|
*/
|
||||||
|
public boolean isNoValue() {
|
||||||
|
return getDescriptor().isNoValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapt the given instance to a Reactive Streams Publisher.
|
* Adapt the given instance to a Reactive Streams Publisher.
|
||||||
* @param source the source object to adapt from
|
* @param source the source object to adapt from
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
import io.reactivex.BackpressureStrategy;
|
import io.reactivex.BackpressureStrategy;
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
|
|
@ -101,34 +100,31 @@ public class ReactiveAdapterRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the adapter to use to adapt from the given reactive type.
|
* Get the adapter for the given reactive type.
|
||||||
*/
|
*/
|
||||||
public ReactiveAdapter getAdapterFrom(Class<?> reactiveType) {
|
public ReactiveAdapter getAdapter(Class<?> reactiveType) {
|
||||||
return getAdapterFrom(reactiveType, null);
|
return getAdapter(reactiveType, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the adapter to use to adapt from the given reactive type. Or if the
|
* Get the adapter for the given reactive type. Or if a "source" object is
|
||||||
* "source" object is not {@code null} its actual type is used instead.
|
* provided, its actual type is used instead.
|
||||||
|
* @param reactiveType the reactive type
|
||||||
|
* @param source an instance of the reactive type (i.e. to adapt from)
|
||||||
*/
|
*/
|
||||||
public ReactiveAdapter getAdapterFrom(Class<?> reactiveType, Object source) {
|
public ReactiveAdapter getAdapter(Class<?> reactiveType, Object source) {
|
||||||
|
|
||||||
source = (source instanceof Optional ? ((Optional<?>) source).orElse(null) : source);
|
source = (source instanceof Optional ? ((Optional<?>) source).orElse(null) : source);
|
||||||
Class<?> clazz = (source != null ? source.getClass() : reactiveType);
|
Class<?> clazz = (source != null ? source.getClass() : reactiveType);
|
||||||
return getAdapter(type -> type.isAssignableFrom(clazz));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the adapter for the given reactive type to adapt to.
|
|
||||||
*/
|
|
||||||
public ReactiveAdapter getAdapterTo(Class<?> reactiveType) {
|
|
||||||
return getAdapter(reactiveType::equals);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ReactiveAdapter getAdapter(Predicate<Class<?>> predicate) {
|
|
||||||
return this.adapters.stream()
|
return this.adapters.stream()
|
||||||
.filter(adapter -> predicate.test(adapter.getDescriptor().getReactiveType()))
|
.filter(adapter -> adapter.getReactiveType().equals(clazz))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElseGet(() ->
|
||||||
|
this.adapters.stream()
|
||||||
|
.filter(adapter -> adapter.getReactiveType().isAssignableFrom(clazz))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -233,7 +229,7 @@ public class ReactiveAdapterRegistry {
|
||||||
@Override
|
@Override
|
||||||
public <T> Publisher<T> toPublisher(Object source) {
|
public <T> Publisher<T> toPublisher(Object source) {
|
||||||
Publisher<T> publisher = super.toPublisher(source);
|
Publisher<T> publisher = super.toPublisher(source);
|
||||||
return (getDescriptor().isMultiValue() ? Flux.from(publisher) : Mono.from(publisher));
|
return (isMultiValue() ? Flux.from(publisher) : Mono.from(publisher));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.FluxProcessor;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import rx.Completable;
|
import rx.Completable;
|
||||||
import rx.Observable;
|
import rx.Observable;
|
||||||
|
|
@ -32,10 +33,13 @@ import rx.Single;
|
||||||
|
|
||||||
import org.springframework.core.ReactiveAdapter;
|
import org.springframework.core.ReactiveAdapter;
|
||||||
import org.springframework.core.ReactiveAdapterRegistry;
|
import org.springframework.core.ReactiveAdapterRegistry;
|
||||||
|
import org.springframework.core.ReactiveTypeDescriptor;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNotSame;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -55,33 +59,55 @@ public class ReactiveAdapterRegistryTests {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getDefaultAdapters() throws Exception {
|
public void defaultAdapterRegistrations() throws Exception {
|
||||||
|
|
||||||
// Reactor
|
// Reactor
|
||||||
assertNotNull(getAdapterTo(Mono.class));
|
assertNotNull(getAdapter(Mono.class));
|
||||||
assertNotNull(getAdapterTo(Flux.class));
|
assertNotNull(getAdapter(Flux.class));
|
||||||
|
|
||||||
assertNotNull(getAdapterTo(Publisher.class));
|
// Publisher
|
||||||
assertNotNull(getAdapterTo(CompletableFuture.class));
|
assertNotNull(getAdapter(Publisher.class));
|
||||||
|
|
||||||
|
// Completable
|
||||||
|
assertNotNull(getAdapter(CompletableFuture.class));
|
||||||
|
|
||||||
// RxJava 1
|
// RxJava 1
|
||||||
assertNotNull(getAdapterTo(Observable.class));
|
assertNotNull(getAdapter(Observable.class));
|
||||||
assertNotNull(getAdapterTo(Single.class));
|
assertNotNull(getAdapter(Single.class));
|
||||||
assertNotNull(getAdapterTo(Completable.class));
|
assertNotNull(getAdapter(Completable.class));
|
||||||
|
|
||||||
// RxJava 2
|
// RxJava 2
|
||||||
assertNotNull(getAdapterTo(Flowable.class));
|
assertNotNull(getAdapter(Flowable.class));
|
||||||
assertNotNull(getAdapterTo(io.reactivex.Observable.class));
|
assertNotNull(getAdapter(io.reactivex.Observable.class));
|
||||||
assertNotNull(getAdapterTo(io.reactivex.Single.class));
|
assertNotNull(getAdapter(io.reactivex.Single.class));
|
||||||
assertNotNull(getAdapterTo(Maybe.class));
|
assertNotNull(getAdapter(Maybe.class));
|
||||||
assertNotNull(getAdapterTo(io.reactivex.Completable.class));
|
assertNotNull(getAdapter(io.reactivex.Completable.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAdapterForReactiveSubType() throws Exception {
|
||||||
|
|
||||||
|
ReactiveAdapter adapter1 = getAdapter(Flux.class);
|
||||||
|
ReactiveAdapter adapter2 = getAdapter(FluxProcessor.class);
|
||||||
|
|
||||||
|
assertSame(adapter1, adapter2);
|
||||||
|
|
||||||
|
this.registry.registerReactiveType(
|
||||||
|
ReactiveTypeDescriptor.multiValue(FluxProcessor.class, FluxProcessor::empty),
|
||||||
|
o -> (FluxProcessor<?, ?>) o,
|
||||||
|
FluxProcessor::from);
|
||||||
|
|
||||||
|
ReactiveAdapter adapter3 = getAdapter(FluxProcessor.class);
|
||||||
|
|
||||||
|
assertNotNull(adapter3);
|
||||||
|
assertNotSame(adapter1, adapter3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void publisherToFlux() throws Exception {
|
public void publisherToFlux() throws Exception {
|
||||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||||
Publisher<Integer> source = Flowable.fromIterable(sequence);
|
Publisher<Integer> source = Flowable.fromIterable(sequence);
|
||||||
Object target = getAdapterTo(Flux.class).fromPublisher(source);
|
Object target = getAdapter(Flux.class).fromPublisher(source);
|
||||||
assertTrue(target instanceof Flux);
|
assertTrue(target instanceof Flux);
|
||||||
assertEquals(sequence, ((Flux<Integer>) target).collectList().blockMillis(1000));
|
assertEquals(sequence, ((Flux<Integer>) target).collectList().blockMillis(1000));
|
||||||
}
|
}
|
||||||
|
|
@ -91,7 +117,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
@Test
|
@Test
|
||||||
public void publisherToMono() throws Exception {
|
public void publisherToMono() throws Exception {
|
||||||
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
|
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
|
||||||
Object target = getAdapterTo(Mono.class).fromPublisher(source);
|
Object target = getAdapter(Mono.class).fromPublisher(source);
|
||||||
assertTrue(target instanceof Mono);
|
assertTrue(target instanceof Mono);
|
||||||
assertEquals(new Integer(1), ((Mono<Integer>) target).blockMillis(1000));
|
assertEquals(new Integer(1), ((Mono<Integer>) target).blockMillis(1000));
|
||||||
}
|
}
|
||||||
|
|
@ -99,7 +125,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
@Test
|
@Test
|
||||||
public void publisherToCompletableFuture() throws Exception {
|
public void publisherToCompletableFuture() throws Exception {
|
||||||
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
|
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
|
||||||
Object target = getAdapterTo(CompletableFuture.class).fromPublisher(source);
|
Object target = getAdapter(CompletableFuture.class).fromPublisher(source);
|
||||||
assertTrue(target instanceof CompletableFuture);
|
assertTrue(target instanceof CompletableFuture);
|
||||||
assertEquals(new Integer(1), ((CompletableFuture<Integer>) target).get());
|
assertEquals(new Integer(1), ((CompletableFuture<Integer>) target).get());
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +134,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
public void publisherToRxObservable() throws Exception {
|
public void publisherToRxObservable() throws Exception {
|
||||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||||
Publisher<Integer> source = Flowable.fromIterable(sequence);
|
Publisher<Integer> source = Flowable.fromIterable(sequence);
|
||||||
Object target = getAdapterTo(rx.Observable.class).fromPublisher(source);
|
Object target = getAdapter(rx.Observable.class).fromPublisher(source);
|
||||||
assertTrue(target instanceof rx.Observable);
|
assertTrue(target instanceof rx.Observable);
|
||||||
assertEquals(sequence, ((rx.Observable) target).toList().toBlocking().first());
|
assertEquals(sequence, ((rx.Observable) target).toList().toBlocking().first());
|
||||||
}
|
}
|
||||||
|
|
@ -116,7 +142,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
@Test
|
@Test
|
||||||
public void publisherToRxSingle() throws Exception {
|
public void publisherToRxSingle() throws Exception {
|
||||||
Publisher<Integer> source = Flowable.fromArray(1);
|
Publisher<Integer> source = Flowable.fromArray(1);
|
||||||
Object target = getAdapterTo(rx.Single.class).fromPublisher(source);
|
Object target = getAdapter(rx.Single.class).fromPublisher(source);
|
||||||
assertTrue(target instanceof rx.Single);
|
assertTrue(target instanceof rx.Single);
|
||||||
assertEquals(new Integer(1), ((rx.Single<Integer>) target).toBlocking().value());
|
assertEquals(new Integer(1), ((rx.Single<Integer>) target).toBlocking().value());
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +150,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
@Test
|
@Test
|
||||||
public void publisherToRxCompletable() throws Exception {
|
public void publisherToRxCompletable() throws Exception {
|
||||||
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
|
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
|
||||||
Object target = getAdapterTo(rx.Completable.class).fromPublisher(source);
|
Object target = getAdapter(rx.Completable.class).fromPublisher(source);
|
||||||
assertTrue(target instanceof rx.Completable);
|
assertTrue(target instanceof rx.Completable);
|
||||||
assertNull(((rx.Completable) target).get());
|
assertNull(((rx.Completable) target).get());
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +159,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
public void publisherToReactivexFlowable() throws Exception {
|
public void publisherToReactivexFlowable() throws Exception {
|
||||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||||
Publisher<Integer> source = Flux.fromIterable(sequence);
|
Publisher<Integer> source = Flux.fromIterable(sequence);
|
||||||
Object target = getAdapterTo(io.reactivex.Flowable.class).fromPublisher(source);
|
Object target = getAdapter(io.reactivex.Flowable.class).fromPublisher(source);
|
||||||
assertTrue(target instanceof io.reactivex.Flowable);
|
assertTrue(target instanceof io.reactivex.Flowable);
|
||||||
assertEquals(sequence, ((io.reactivex.Flowable) target).toList().blockingGet());
|
assertEquals(sequence, ((io.reactivex.Flowable) target).toList().blockingGet());
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +168,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
public void publisherToReactivexObservable() throws Exception {
|
public void publisherToReactivexObservable() throws Exception {
|
||||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||||
Publisher<Integer> source = Flowable.fromIterable(sequence);
|
Publisher<Integer> source = Flowable.fromIterable(sequence);
|
||||||
Object target = getAdapterTo(io.reactivex.Observable.class).fromPublisher(source);
|
Object target = getAdapter(io.reactivex.Observable.class).fromPublisher(source);
|
||||||
assertTrue(target instanceof io.reactivex.Observable);
|
assertTrue(target instanceof io.reactivex.Observable);
|
||||||
assertEquals(sequence, ((io.reactivex.Observable) target).toList().blockingGet());
|
assertEquals(sequence, ((io.reactivex.Observable) target).toList().blockingGet());
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +176,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
@Test
|
@Test
|
||||||
public void publisherToReactivexSingle() throws Exception {
|
public void publisherToReactivexSingle() throws Exception {
|
||||||
Publisher<Integer> source = Flowable.fromArray(1);
|
Publisher<Integer> source = Flowable.fromArray(1);
|
||||||
Object target = getAdapterTo(io.reactivex.Single.class).fromPublisher(source);
|
Object target = getAdapter(io.reactivex.Single.class).fromPublisher(source);
|
||||||
assertTrue(target instanceof io.reactivex.Single);
|
assertTrue(target instanceof io.reactivex.Single);
|
||||||
assertEquals(new Integer(1), ((io.reactivex.Single<Integer>) target).blockingGet());
|
assertEquals(new Integer(1), ((io.reactivex.Single<Integer>) target).blockingGet());
|
||||||
}
|
}
|
||||||
|
|
@ -158,7 +184,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
@Test
|
@Test
|
||||||
public void publisherToReactivexCompletable() throws Exception {
|
public void publisherToReactivexCompletable() throws Exception {
|
||||||
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
|
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
|
||||||
Object target = getAdapterTo(io.reactivex.Completable.class).fromPublisher(source);
|
Object target = getAdapter(io.reactivex.Completable.class).fromPublisher(source);
|
||||||
assertTrue(target instanceof io.reactivex.Completable);
|
assertTrue(target instanceof io.reactivex.Completable);
|
||||||
assertNull(((io.reactivex.Completable) target).blockingGet());
|
assertNull(((io.reactivex.Completable) target).blockingGet());
|
||||||
}
|
}
|
||||||
|
|
@ -167,7 +193,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
public void rxObservableToPublisher() throws Exception {
|
public void rxObservableToPublisher() throws Exception {
|
||||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||||
Object source = rx.Observable.from(sequence);
|
Object source = rx.Observable.from(sequence);
|
||||||
Object target = getAdapterFrom(rx.Observable.class).toPublisher(source);
|
Object target = getAdapter(rx.Observable.class).toPublisher(source);
|
||||||
assertTrue("Expected Flux Publisher: " + target.getClass().getName(), target instanceof Flux);
|
assertTrue("Expected Flux Publisher: " + target.getClass().getName(), target instanceof Flux);
|
||||||
assertEquals(sequence, ((Flux<Integer>) target).collectList().blockMillis(1000));
|
assertEquals(sequence, ((Flux<Integer>) target).collectList().blockMillis(1000));
|
||||||
}
|
}
|
||||||
|
|
@ -175,7 +201,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
@Test
|
@Test
|
||||||
public void rxSingleToPublisher() throws Exception {
|
public void rxSingleToPublisher() throws Exception {
|
||||||
Object source = rx.Single.just(1);
|
Object source = rx.Single.just(1);
|
||||||
Object target = getAdapterFrom(rx.Single.class).toPublisher(source);
|
Object target = getAdapter(rx.Single.class).toPublisher(source);
|
||||||
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
||||||
assertEquals(new Integer(1), ((Mono<Integer>) target).blockMillis(1000));
|
assertEquals(new Integer(1), ((Mono<Integer>) target).blockMillis(1000));
|
||||||
}
|
}
|
||||||
|
|
@ -183,7 +209,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
@Test
|
@Test
|
||||||
public void rxCompletableToPublisher() throws Exception {
|
public void rxCompletableToPublisher() throws Exception {
|
||||||
Object source = rx.Completable.complete();
|
Object source = rx.Completable.complete();
|
||||||
Object target = getAdapterFrom(rx.Completable.class).toPublisher(source);
|
Object target = getAdapter(rx.Completable.class).toPublisher(source);
|
||||||
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
||||||
((Mono<Void>) target).blockMillis(1000);
|
((Mono<Void>) target).blockMillis(1000);
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +218,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
public void reactivexFlowableToPublisher() throws Exception {
|
public void reactivexFlowableToPublisher() throws Exception {
|
||||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||||
Object source = io.reactivex.Flowable.fromIterable(sequence);
|
Object source = io.reactivex.Flowable.fromIterable(sequence);
|
||||||
Object target = getAdapterFrom(io.reactivex.Flowable.class).toPublisher(source);
|
Object target = getAdapter(io.reactivex.Flowable.class).toPublisher(source);
|
||||||
assertTrue("Expected Flux Publisher: " + target.getClass().getName(), target instanceof Flux);
|
assertTrue("Expected Flux Publisher: " + target.getClass().getName(), target instanceof Flux);
|
||||||
assertEquals(sequence, ((Flux<Integer>) target).collectList().blockMillis(1000));
|
assertEquals(sequence, ((Flux<Integer>) target).collectList().blockMillis(1000));
|
||||||
}
|
}
|
||||||
|
|
@ -201,7 +227,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
public void reactivexObservableToPublisher() throws Exception {
|
public void reactivexObservableToPublisher() throws Exception {
|
||||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||||
Object source = io.reactivex.Observable.fromIterable(sequence);
|
Object source = io.reactivex.Observable.fromIterable(sequence);
|
||||||
Object target = getAdapterFrom(io.reactivex.Observable.class).toPublisher(source);
|
Object target = getAdapter(io.reactivex.Observable.class).toPublisher(source);
|
||||||
assertTrue("Expected Flux Publisher: " + target.getClass().getName(), target instanceof Flux);
|
assertTrue("Expected Flux Publisher: " + target.getClass().getName(), target instanceof Flux);
|
||||||
assertEquals(sequence, ((Flux<Integer>) target).collectList().blockMillis(1000));
|
assertEquals(sequence, ((Flux<Integer>) target).collectList().blockMillis(1000));
|
||||||
}
|
}
|
||||||
|
|
@ -209,7 +235,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
@Test
|
@Test
|
||||||
public void reactivexSingleToPublisher() throws Exception {
|
public void reactivexSingleToPublisher() throws Exception {
|
||||||
Object source = io.reactivex.Single.just(1);
|
Object source = io.reactivex.Single.just(1);
|
||||||
Object target = getAdapterFrom(io.reactivex.Single.class).toPublisher(source);
|
Object target = getAdapter(io.reactivex.Single.class).toPublisher(source);
|
||||||
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
||||||
assertEquals(new Integer(1), ((Mono<Integer>) target).blockMillis(1000));
|
assertEquals(new Integer(1), ((Mono<Integer>) target).blockMillis(1000));
|
||||||
}
|
}
|
||||||
|
|
@ -217,7 +243,7 @@ public class ReactiveAdapterRegistryTests {
|
||||||
@Test
|
@Test
|
||||||
public void reactivexCompletableToPublisher() throws Exception {
|
public void reactivexCompletableToPublisher() throws Exception {
|
||||||
Object source = io.reactivex.Completable.complete();
|
Object source = io.reactivex.Completable.complete();
|
||||||
Object target = getAdapterFrom(io.reactivex.Completable.class).toPublisher(source);
|
Object target = getAdapter(io.reactivex.Completable.class).toPublisher(source);
|
||||||
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
||||||
((Mono<Void>) target).blockMillis(1000);
|
((Mono<Void>) target).blockMillis(1000);
|
||||||
}
|
}
|
||||||
|
|
@ -226,18 +252,14 @@ public class ReactiveAdapterRegistryTests {
|
||||||
public void CompletableFutureToPublisher() throws Exception {
|
public void CompletableFutureToPublisher() throws Exception {
|
||||||
CompletableFuture<Integer> future = new CompletableFuture();
|
CompletableFuture<Integer> future = new CompletableFuture();
|
||||||
future.complete(1);
|
future.complete(1);
|
||||||
Object target = getAdapterFrom(CompletableFuture.class).toPublisher(future);
|
Object target = getAdapter(CompletableFuture.class).toPublisher(future);
|
||||||
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
||||||
assertEquals(new Integer(1), ((Mono<Integer>) target).blockMillis(1000));
|
assertEquals(new Integer(1), ((Mono<Integer>) target).blockMillis(1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private ReactiveAdapter getAdapterTo(Class<?> reactiveType) {
|
private ReactiveAdapter getAdapter(Class<?> reactiveType) {
|
||||||
return this.registry.getAdapterTo(reactiveType);
|
return this.registry.getAdapter(reactiveType);
|
||||||
}
|
|
||||||
|
|
||||||
private ReactiveAdapter getAdapterFrom(Class<?> reactiveType) {
|
|
||||||
return this.registry.getAdapterFrom(reactiveType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ public abstract class AbstractMessageReaderArgumentResolver {
|
||||||
BindingContext bindingContext, ServerWebExchange exchange) {
|
BindingContext bindingContext, ServerWebExchange exchange) {
|
||||||
|
|
||||||
ResolvableType bodyType = ResolvableType.forMethodParameter(bodyParameter);
|
ResolvableType bodyType = ResolvableType.forMethodParameter(bodyParameter);
|
||||||
ReactiveAdapter adapter = getAdapterRegistry().getAdapterTo(bodyType.resolve());
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(bodyType.resolve());
|
||||||
|
|
||||||
ResolvableType elementType = ResolvableType.forMethodParameter(bodyParameter);
|
ResolvableType elementType = ResolvableType.forMethodParameter(bodyParameter);
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
|
|
@ -130,7 +130,7 @@ public abstract class AbstractMessageReaderArgumentResolver {
|
||||||
|
|
||||||
if (reader.canRead(elementType, mediaType)) {
|
if (reader.canRead(elementType, mediaType)) {
|
||||||
Map<String, Object> readHints = Collections.emptyMap();
|
Map<String, Object> readHints = Collections.emptyMap();
|
||||||
if (adapter != null && adapter.getDescriptor().isMultiValue()) {
|
if (adapter != null && adapter.isMultiValue()) {
|
||||||
Flux<?> flux;
|
Flux<?> flux;
|
||||||
if (reader instanceof ServerHttpMessageReader) {
|
if (reader instanceof ServerHttpMessageReader) {
|
||||||
ServerHttpMessageReader<?> serverReader = ((ServerHttpMessageReader<?>) reader);
|
ServerHttpMessageReader<?> serverReader = ((ServerHttpMessageReader<?>) reader);
|
||||||
|
|
@ -186,7 +186,7 @@ public abstract class AbstractMessageReaderArgumentResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean checkRequired(ReactiveAdapter adapter, boolean isBodyRequired) {
|
protected boolean checkRequired(ReactiveAdapter adapter, boolean isBodyRequired) {
|
||||||
return adapter != null && !adapter.getDescriptor().supportsEmpty() || isBodyRequired;
|
return adapter != null && !adapter.supportsEmpty() || isBodyRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ServerWebInputException getRequiredBodyError(MethodParameter parameter) {
|
protected ServerWebInputException getRequiredBodyError(MethodParameter parameter) {
|
||||||
|
|
|
||||||
|
|
@ -95,19 +95,19 @@ public abstract class AbstractMessageWriterResultHandler extends AbstractHandler
|
||||||
|
|
||||||
ResolvableType valueType = ResolvableType.forMethodParameter(bodyParameter);
|
ResolvableType valueType = ResolvableType.forMethodParameter(bodyParameter);
|
||||||
Class<?> valueClass = valueType.resolve();
|
Class<?> valueClass = valueType.resolve();
|
||||||
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(valueClass, body);
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(valueClass, body);
|
||||||
|
|
||||||
Publisher<?> publisher;
|
Publisher<?> publisher;
|
||||||
ResolvableType elementType;
|
ResolvableType elementType;
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
publisher = adapter.toPublisher(body);
|
publisher = adapter.toPublisher(body);
|
||||||
elementType = adapter.getDescriptor().isNoValue() ?
|
elementType = adapter.isNoValue() ?
|
||||||
ResolvableType.forClass(Void.class) :
|
ResolvableType.forClass(Void.class) : valueType.getGeneric(0);
|
||||||
valueType.getGeneric(0);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
publisher = Mono.justOrEmpty(body);
|
publisher = Mono.justOrEmpty(body);
|
||||||
elementType = (valueClass == null && body != null ? ResolvableType.forInstance(body) : valueType);
|
elementType = (valueClass == null && body != null ?
|
||||||
|
ResolvableType.forInstance(body) : valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (void.class == elementType.getRawClass() || Void.class == elementType.getRawClass()) {
|
if (void.class == elementType.getRawClass() || Void.class == elementType.getRawClass()) {
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ class BindingContextFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvableType type = result.getReturnType();
|
ResolvableType type = result.getReturnType();
|
||||||
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(type.getRawClass(), value);
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type.getRawClass(), value);
|
||||||
Class<?> valueType = (adapter != null ? type.resolveGeneric(0) : type.resolve());
|
Class<?> valueType = (adapter != null ? type.resolveGeneric(0) : type.resolve());
|
||||||
|
|
||||||
if (Void.class.equals(valueType) || void.class.equals(valueType)) {
|
if (Void.class.equals(valueType) || void.class.equals(valueType)) {
|
||||||
|
|
|
||||||
|
|
@ -102,9 +102,9 @@ public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolv
|
||||||
Class<?> attributeType = attributeParam.getParameterType();
|
Class<?> attributeType = attributeParam.getParameterType();
|
||||||
|
|
||||||
ResolvableType type = ResolvableType.forMethodParameter(attributeParam);
|
ResolvableType type = ResolvableType.forMethodParameter(attributeParam);
|
||||||
ReactiveAdapter adapterTo = getAdapterRegistry().getAdapterTo(type.resolve());
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type.resolve());
|
||||||
|
|
||||||
Assert.isNull(adapterTo, "Errors/BindingResult cannot be used with an async model attribute. " +
|
Assert.isNull(adapter, "Errors/BindingResult cannot be used with an async model attribute. " +
|
||||||
"Either declare the model attribute without the async wrapper type " +
|
"Either declare the model attribute without the async wrapper type " +
|
||||||
"or handle WebExchangeBindException through the async type.");
|
"or handle WebExchangeBindException through the async type.");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,10 +105,9 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
|
||||||
}
|
}
|
||||||
if (this.useDefaultResolution) {
|
if (this.useDefaultResolution) {
|
||||||
Class<?> clazz = parameter.getParameterType();
|
Class<?> clazz = parameter.getParameterType();
|
||||||
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(clazz);
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(clazz);
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
ReactiveTypeDescriptor descriptor = adapter.getDescriptor();
|
if (adapter.isNoValue() || adapter.isMultiValue()) {
|
||||||
if (descriptor.isNoValue() || descriptor.isMultiValue()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
clazz = ResolvableType.forMethodParameter(parameter).getGeneric(0).getRawClass();
|
clazz = ResolvableType.forMethodParameter(parameter).getGeneric(0).getRawClass();
|
||||||
|
|
@ -123,8 +122,8 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
|
||||||
ServerWebExchange exchange) {
|
ServerWebExchange exchange) {
|
||||||
|
|
||||||
ResolvableType type = ResolvableType.forMethodParameter(parameter);
|
ResolvableType type = ResolvableType.forMethodParameter(parameter);
|
||||||
ReactiveAdapter adapterTo = getAdapterRegistry().getAdapterTo(type.resolve());
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type.resolve());
|
||||||
Class<?> valueType = (adapterTo != null ? type.resolveGeneric(0) : parameter.getParameterType());
|
Class<?> valueType = (adapter != null ? type.resolveGeneric(0) : parameter.getParameterType());
|
||||||
String name = getAttributeName(valueType, parameter);
|
String name = getAttributeName(valueType, parameter);
|
||||||
Mono<?> valueMono = getAttributeMono(name, valueType, parameter, context, exchange);
|
Mono<?> valueMono = getAttributeMono(name, valueType, parameter, context, exchange);
|
||||||
|
|
||||||
|
|
@ -145,8 +144,8 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
|
||||||
})
|
})
|
||||||
.then(Mono.fromCallable(() -> {
|
.then(Mono.fromCallable(() -> {
|
||||||
BindingResult errors = binder.getBindingResult();
|
BindingResult errors = binder.getBindingResult();
|
||||||
if (adapterTo != null) {
|
if (adapter != null) {
|
||||||
return adapterTo.fromPublisher(errors.hasErrors() ?
|
return adapter.fromPublisher(errors.hasErrors() ?
|
||||||
Mono.error(new WebExchangeBindException(parameter, errors)) :
|
Mono.error(new WebExchangeBindException(parameter, errors)) :
|
||||||
Mono.just(value));
|
Mono.just(value));
|
||||||
}
|
}
|
||||||
|
|
@ -177,10 +176,9 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
|
||||||
attribute = createAttribute(attributeName, attributeType, param, context, exchange);
|
attribute = createAttribute(attributeName, attributeType, param, context, exchange);
|
||||||
}
|
}
|
||||||
if (attribute != null) {
|
if (attribute != null) {
|
||||||
ReactiveAdapter adapterFrom = getAdapterRegistry().getAdapterFrom(null, attribute);
|
ReactiveAdapter adapterFrom = getAdapterRegistry().getAdapter(null, attribute);
|
||||||
if (adapterFrom != null) {
|
if (adapterFrom != null) {
|
||||||
ReactiveTypeDescriptor descriptor = adapterFrom.getDescriptor();
|
Assert.isTrue(!adapterFrom.isMultiValue(), "Data binding supports single-value async types.");
|
||||||
Assert.isTrue(!descriptor.isMultiValue(), "Data binding supports single-value async types.");
|
|
||||||
return Mono.from(adapterFrom.toPublisher(attribute));
|
return Mono.from(adapterFrom.toPublisher(attribute));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package org.springframework.web.reactive.result.method.annotation;
|
package org.springframework.web.reactive.result.method.annotation;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
|
@ -103,8 +102,8 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(rawClass, result.getReturnValue());
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(rawClass, result.getReturnValue());
|
||||||
if (adapter != null && !adapter.getDescriptor().isNoValue()) {
|
if (adapter != null && !adapter.isNoValue()) {
|
||||||
ResolvableType genericType = result.getReturnType().getGeneric(0);
|
ResolvableType genericType = result.getReturnType().getGeneric(0);
|
||||||
if (HttpEntity.class.isAssignableFrom(genericType.getRawClass())) {
|
if (HttpEntity.class.isAssignableFrom(genericType.getRawClass())) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import reactor.core.publisher.Mono;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.ReactiveAdapter;
|
import org.springframework.core.ReactiveAdapter;
|
||||||
import org.springframework.core.ReactiveAdapterRegistry;
|
import org.springframework.core.ReactiveAdapterRegistry;
|
||||||
import org.springframework.core.ReactiveTypeDescriptor;
|
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpEntity;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
|
|
@ -91,11 +90,8 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(returnType, result.getReturnValue());
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(returnType, result.getReturnValue());
|
||||||
if (adapter != null &&
|
if (adapter != null && !adapter.isMultiValue() && !adapter.isNoValue()) {
|
||||||
!adapter.getDescriptor().isMultiValue() &&
|
|
||||||
!adapter.getDescriptor().isNoValue()) {
|
|
||||||
|
|
||||||
ResolvableType genericType = result.getReturnType().getGeneric(0);
|
ResolvableType genericType = result.getReturnType().getGeneric(0);
|
||||||
return isSupportedType(genericType.getRawClass());
|
return isSupportedType(genericType.getRawClass());
|
||||||
}
|
}
|
||||||
|
|
@ -118,11 +114,10 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
|
||||||
Optional<Object> optionalValue = result.getReturnValue();
|
Optional<Object> optionalValue = result.getReturnValue();
|
||||||
|
|
||||||
Class<?> rawClass = returnType.getRawClass();
|
Class<?> rawClass = returnType.getRawClass();
|
||||||
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(rawClass, optionalValue);
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(rawClass, optionalValue);
|
||||||
|
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
ReactiveTypeDescriptor descriptor = adapter.getDescriptor();
|
Assert.isTrue(!adapter.isMultiValue(), "Only a single ResponseEntity supported.");
|
||||||
Assert.isTrue(!descriptor.isMultiValue(), "Only a single ResponseEntity supported.");
|
|
||||||
returnValueMono = Mono.from(adapter.toPublisher(optionalValue));
|
returnValueMono = Mono.from(adapter.toPublisher(optionalValue));
|
||||||
bodyType = new MethodParameter(result.getReturnTypeSource());
|
bodyType = new MethodParameter(result.getReturnTypeSource());
|
||||||
bodyType.increaseNestingLevel();
|
bodyType.increaseNestingLevel();
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.ReactiveAdapter;
|
import org.springframework.core.ReactiveAdapter;
|
||||||
import org.springframework.core.ReactiveAdapterRegistry;
|
import org.springframework.core.ReactiveAdapterRegistry;
|
||||||
import org.springframework.core.ReactiveTypeDescriptor;
|
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
|
@ -154,9 +153,9 @@ public class ViewResolutionResultHandler extends AbstractHandlerResultHandler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Optional<Object> optional = result.getReturnValue();
|
Optional<Object> optional = result.getReturnValue();
|
||||||
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(clazz, optional);
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(clazz, optional);
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
if (adapter.getDescriptor().isNoValue()) {
|
if (adapter.isNoValue()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -190,15 +189,14 @@ public class ViewResolutionResultHandler extends AbstractHandlerResultHandler
|
||||||
ResolvableType parameterType = result.getReturnType();
|
ResolvableType parameterType = result.getReturnType();
|
||||||
|
|
||||||
Optional<Object> optional = result.getReturnValue();
|
Optional<Object> optional = result.getReturnValue();
|
||||||
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(parameterType.getRawClass(), optional);
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(parameterType.getRawClass(), optional);
|
||||||
|
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
ReactiveTypeDescriptor descriptor = adapter.getDescriptor();
|
Assert.isTrue(!adapter.isMultiValue(), "Only single-value async return type supported.");
|
||||||
Assert.isTrue(!descriptor.isMultiValue(), "Only single-value async return type supported.");
|
|
||||||
returnValueMono = optional
|
returnValueMono = optional
|
||||||
.map(value -> Mono.from(adapter.toPublisher(value)))
|
.map(value -> Mono.from(adapter.toPublisher(value)))
|
||||||
.orElse(Mono.empty());
|
.orElse(Mono.empty());
|
||||||
elementType = !adapter.getDescriptor().isNoValue() ?
|
elementType = !adapter.isNoValue() ?
|
||||||
parameterType.getGeneric(0) : ResolvableType.forClass(Void.class);
|
parameterType.getGeneric(0) : ResolvableType.forClass(Void.class);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -301,10 +299,10 @@ public class ViewResolutionResultHandler extends AbstractHandlerResultHandler
|
||||||
List<Mono<?>> valueMonos = new ArrayList<>();
|
List<Mono<?>> valueMonos = new ArrayList<>();
|
||||||
|
|
||||||
for (Map.Entry<String, ?> entry : model.entrySet()) {
|
for (Map.Entry<String, ?> entry : model.entrySet()) {
|
||||||
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(null, entry.getValue());
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(null, entry.getValue());
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
names.add(entry.getKey());
|
names.add(entry.getKey());
|
||||||
if (adapter.getDescriptor().isMultiValue()) {
|
if (adapter.isMultiValue()) {
|
||||||
Flux<Object> value = Flux.from(adapter.toPublisher(entry.getValue()));
|
Flux<Object> value = Flux.from(adapter.toPublisher(entry.getValue()));
|
||||||
valueMonos.add(value.collectList().defaultIfEmpty(Collections.emptyList()));
|
valueMonos.add(value.collectList().defaultIfEmpty(Collections.emptyList()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue