Browse Source

Consistently support CompletionStage in ReactiveAdapterRegistry

Aligns ReactiveAdapterRegistry with MVC/messaging handler methods in terms of recognizing CompletionStage as well as CompletableFuture. Includes consistent use of ReactiveAdapter for reactive transactions.

Closes gh-23011
pull/23013/head
Juergen Hoeller 7 years ago
parent
commit
ff838fd011
  1. 22
      spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java
  2. 23
      spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java

22
spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java

@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.List; 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.concurrent.CompletionStage;
import java.util.function.Function; import java.util.function.Function;
import io.reactivex.BackpressureStrategy; import io.reactivex.BackpressureStrategy;
@ -221,12 +222,8 @@ public class ReactiveAdapterRegistry {
source -> source); source -> source);
registry.registerReactiveType( registry.registerReactiveType(
ReactiveTypeDescriptor.singleOptionalValue(CompletableFuture.class, () -> { ReactiveTypeDescriptor.singleOptionalValue(CompletionStage.class, EmptyCompletableFuture::new),
CompletableFuture<?> empty = new CompletableFuture<>(); source -> Mono.fromCompletionStage((CompletionStage<?>) source),
empty.complete(null);
return empty;
}),
source -> Mono.fromFuture((CompletableFuture<?>) source),
source -> Mono.from(source).toFuture() source -> Mono.from(source).toFuture()
); );
} }
@ -338,17 +335,28 @@ public class ReactiveAdapterRegistry {
} }
} }
private static class EmptyCompletableFuture<T> extends CompletableFuture<T> {
EmptyCompletableFuture() {
complete(null);
}
}
private static class CoroutinesRegistrar { private static class CoroutinesRegistrar {
@SuppressWarnings("KotlinInternalInJava") @SuppressWarnings("KotlinInternalInJava")
void registerAdapters(ReactiveAdapterRegistry registry) { void registerAdapters(ReactiveAdapterRegistry registry) {
registry.registerReactiveType( registry.registerReactiveType(
ReactiveTypeDescriptor.singleOptionalValue(Deferred.class, () -> CompletableDeferredKt.CompletableDeferred(null)), ReactiveTypeDescriptor.singleOptionalValue(Deferred.class,
() -> CompletableDeferredKt.CompletableDeferred(null)),
source -> CoroutinesUtils.deferredToMono((Deferred<?>) source), source -> CoroutinesUtils.deferredToMono((Deferred<?>) source),
source -> CoroutinesUtils.monoToDeferred(Mono.from(source))); source -> CoroutinesUtils.monoToDeferred(Mono.from(source)));
} }
} }
private static class CoroutinesFlowRegistrar { private static class CoroutinesFlowRegistrar {
void registerAdapters(ReactiveAdapterRegistry registry) { void registerAdapters(ReactiveAdapterRegistry registry) {

23
spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java

@ -834,16 +834,13 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
return TransactionContextManager.currentContext().flatMap(context -> return TransactionContextManager.currentContext().flatMap(context ->
createTransactionIfNecessary(tm, txAttr, joinpointIdentification).flatMap(it -> { createTransactionIfNecessary(tm, txAttr, joinpointIdentification).flatMap(it -> {
try { try {
// This is an around advice: Invoke the next interceptor in the chain. // Need re-wrapping until we get hold of the exception through usingWhen.
// This will normally result in a target object being invoked.
// Need re-wrapping of ReactiveTransaction until we get hold of the exception
// through usingWhen.
return Mono.<Object, ReactiveTransactionInfo>usingWhen(Mono.just(it), txInfo -> { return Mono.<Object, ReactiveTransactionInfo>usingWhen(Mono.just(it), txInfo -> {
try { try {
return (Mono<?>) invocation.proceedWithInvocation(); return (Mono<?>) invocation.proceedWithInvocation();
} }
catch (Throwable throwable) { catch (Throwable ex) {
return Mono.error(throwable); return Mono.error(ex);
} }
}, this::commitTransactionAfterReturning, txInfo -> Mono.empty()) }, this::commitTransactionAfterReturning, txInfo -> Mono.empty())
.onErrorResume(ex -> completeTransactionAfterThrowing(it, ex).then(Mono.error(ex))); .onErrorResume(ex -> completeTransactionAfterThrowing(it, ex).then(Mono.error(ex)));
@ -856,19 +853,17 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
.subscriberContext(TransactionContextManager.getOrCreateContextHolder()); .subscriberContext(TransactionContextManager.getOrCreateContextHolder());
} }
return TransactionContextManager.currentContext().flatMapMany(context -> // Any other reactive type, typically a Flux
return this.adapter.fromPublisher(TransactionContextManager.currentContext().flatMapMany(context ->
createTransactionIfNecessary(tm, txAttr, joinpointIdentification).flatMapMany(it -> { createTransactionIfNecessary(tm, txAttr, joinpointIdentification).flatMapMany(it -> {
try { try {
// This is an around advice: Invoke the next interceptor in the chain. // Need re-wrapping until we get hold of the exception through usingWhen.
// This will normally result in a target object being invoked.
// Need re-wrapping of ReactiveTransaction until we get hold of the exception
// through usingWhen.
return Flux.usingWhen(Mono.just(it), txInfo -> { return Flux.usingWhen(Mono.just(it), txInfo -> {
try { try {
return this.adapter.toPublisher(invocation.proceedWithInvocation()); return this.adapter.toPublisher(invocation.proceedWithInvocation());
} }
catch (Throwable throwable) { catch (Throwable ex) {
return Mono.error(throwable); return Mono.error(ex);
} }
}, this::commitTransactionAfterReturning, txInfo -> Mono.empty()) }, this::commitTransactionAfterReturning, txInfo -> Mono.empty())
.onErrorResume(ex -> completeTransactionAfterThrowing(it, ex).then(Mono.error(ex))); .onErrorResume(ex -> completeTransactionAfterThrowing(it, ex).then(Mono.error(ex)));
@ -878,7 +873,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
return completeTransactionAfterThrowing(it, ex).then(Mono.error(ex)); return completeTransactionAfterThrowing(it, ex).then(Mono.error(ex));
} }
})).subscriberContext(TransactionContextManager.getOrCreateContext()) })).subscriberContext(TransactionContextManager.getOrCreateContext())
.subscriberContext(TransactionContextManager.getOrCreateContextHolder()); .subscriberContext(TransactionContextManager.getOrCreateContextHolder()));
} }
@Nullable @Nullable

Loading…
Cancel
Save