From eb16e853b16022c88f2fb8a4d593875ca46d6cb7 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 8 May 2019 14:01:12 +0200 Subject: [PATCH] Fix JDK 9+ generics compilation problem in TransactionAspectSupport Includes consistent mentioning of ReactiveTransactionManager in javadoc. Closes gh-22923 --- .../interceptor/TransactionAspectSupport.java | 96 +++++++++---------- .../interceptor/TransactionInterceptor.java | 5 +- 2 files changed, 49 insertions(+), 52 deletions(-) diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java index 2175a92da18..712f470c10e 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java @@ -57,13 +57,14 @@ import org.springframework.util.StringUtils; * *

Subclasses are responsible for calling methods in this class in the correct order. * - *

If no transaction name has been specified in the {@code TransactionAttribute}, + *

If no transaction name has been specified in the {@link TransactionAttribute}, * the exposed name will be the {@code fully-qualified class name + "." + method name} * (by default). * - *

Uses the Strategy design pattern. A {@code PlatformTransactionManager} - * implementation will perform the actual transaction management, and a - * {@code TransactionAttributeSource} is used for determining transaction definitions. + *

Uses the Strategy design pattern. A {@link PlatformTransactionManager} or + * {@link ReactiveTransactionManager} implementation will perform the actual transaction + * management, and a {@link TransactionAttributeSource} (e.g. annotation-based) is used + * for determining transaction definitions for a particular class or method. * *

A transaction aspect is serializable if its {@code PlatformTransactionManager} * and {@code TransactionAttributeSource} are serializable. @@ -72,7 +73,10 @@ import org.springframework.util.StringUtils; * @author Juergen Hoeller * @author Stéphane Nicoll * @author Sam Brannen + * @author Mark Paluch * @since 1.1 + * @see PlatformTransactionManager + * @see ReactiveTransactionManager * @see #setTransactionManager * @see #setTransactionAttributes * @see #setTransactionAttributeSource @@ -450,7 +454,8 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init else { PlatformTransactionManager defaultTransactionManager = asPlatformTransactionManager(getTransactionManager()); if (defaultTransactionManager == null) { - defaultTransactionManager = asPlatformTransactionManager(this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY)); + defaultTransactionManager = asPlatformTransactionManager( + this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY)); if (defaultTransactionManager == null) { defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class); this.transactionManagerCache.putIfAbsent( @@ -817,7 +822,6 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init this.adapter = adapter; } - @SuppressWarnings({ "unchecked", "rawtypes" }) public Object invokeWithinTransaction(Method method, @Nullable Class targetClass, InvocationCallback invocation) { // If the transaction attribute is null, the method is non-transactional. TransactionAttributeSource tas = getTransactionAttributeSource(); @@ -827,62 +831,53 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init // Optimize for Mono if (Mono.class.isAssignableFrom(method.getReturnType())) { - return TransactionContextManager.currentContext().flatMap(context -> { - // Standard transaction demarcation with getTransaction and commit/rollback calls. - Mono txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); - return txInfo.flatMap(it -> { + return TransactionContextManager.currentContext().flatMap(context -> + createTransactionIfNecessary(tm, txAttr, joinpointIdentification).flatMap(it -> { + try { + // This is an around advice: Invoke the next interceptor in the chain. + // 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.usingWhen(Mono.just(it), txInfo -> { + try { + return (Mono) invocation.proceedWithInvocation(); + } + catch (Throwable throwable) { + return Mono.error(throwable); + } + }, this::commitTransactionAfterReturning, txInfo -> Mono.empty()) + .onErrorResume(ex -> completeTransactionAfterThrowing(it, ex).then(Mono.error(ex))); + } + catch (Throwable ex) { + // target invocation exception + return completeTransactionAfterThrowing(it, ex).then(Mono.error(ex)); + } + })).subscriberContext(TransactionContextManager.getOrCreateContext()) + .subscriberContext(TransactionContextManager.getOrCreateContextHolder()); + } + + return TransactionContextManager.currentContext().flatMapMany(context -> + createTransactionIfNecessary(tm, txAttr, joinpointIdentification).flatMapMany(it -> { try { // This is an around advice: Invoke the next interceptor in the chain. // 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.usingWhen(Mono.just(it), s -> { + return Flux.usingWhen(Mono.just(it), txInfo -> { try { - return (Mono) invocation.proceedWithInvocation(); + return this.adapter.toPublisher(invocation.proceedWithInvocation()); } catch (Throwable throwable) { return Mono.error(throwable); } - }, this::commitTransactionAfterReturning, s -> Mono.empty()) - .onErrorResume(ex -> completeTransactionAfterThrowing(it, ex) - .then(Mono.error(ex))); + }, this::commitTransactionAfterReturning, txInfo -> Mono.empty()) + .onErrorResume(ex -> completeTransactionAfterThrowing(it, ex).then(Mono.error(ex))); } catch (Throwable ex) { // target invocation exception return completeTransactionAfterThrowing(it, ex).then(Mono.error(ex)); } - }); - }).subscriberContext(TransactionContextManager.getOrCreateContext()) - .subscriberContext(TransactionContextManager.getOrCreateContextHolder()); - } - - return TransactionContextManager.currentContext().flatMapMany(context -> { - // Standard transaction demarcation with getTransaction and commit/rollback calls. - Mono txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); - return txInfo.flatMapMany(it -> { - try { - // This is an around advice: Invoke the next interceptor in the chain. - // 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), s -> { - try { - return this.adapter.toPublisher( - invocation.proceedWithInvocation()); - } - catch (Throwable throwable) { - return Mono.error(throwable); - } - }, this::commitTransactionAfterReturning, s -> Mono.empty()) - .onErrorResume(ex -> completeTransactionAfterThrowing(it, ex) - .then(Mono.error(ex))); - } - catch (Throwable ex) { - // target invocation exception - return completeTransactionAfterThrowing(it, ex).then(Mono.error(ex)); - } - }); - }).subscriberContext(TransactionContextManager.getOrCreateContext()) + })).subscriberContext(TransactionContextManager.getOrCreateContext()) .subscriberContext(TransactionContextManager.getOrCreateContextHolder()); } @@ -903,7 +898,8 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init else { ReactiveTransactionManager defaultTransactionManager = asReactiveTransactionManager(getTransactionManager()); if (defaultTransactionManager == null) { - defaultTransactionManager = asReactiveTransactionManager(transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY)); + defaultTransactionManager = asReactiveTransactionManager( + transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY)); if (defaultTransactionManager == null) { defaultTransactionManager = beanFactory.getBean(ReactiveTransactionManager.class); transactionManagerCache.putIfAbsent( @@ -963,8 +959,8 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init } } - return tx.map(it -> prepareTransactionInfo(tm, attrToUse, joinpointIdentification, it)) - .switchIfEmpty(Mono.defer(() -> Mono.just(prepareTransactionInfo(tm, attrToUse, joinpointIdentification, null)))); + return tx.map(it -> prepareTransactionInfo(tm, attrToUse, joinpointIdentification, it)).switchIfEmpty( + Mono.defer(() -> Mono.just(prepareTransactionInfo(tm, attrToUse, joinpointIdentification, null)))); } private ReactiveTransactionInfo prepareTransactionInfo(@Nullable ReactiveTransactionManager tm, diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionInterceptor.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionInterceptor.java index c7a93c1af0e..c0e0649d8e3 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionInterceptor.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,8 @@ import org.springframework.transaction.PlatformTransactionManager; /** * AOP Alliance MethodInterceptor for declarative transaction * management using the common Spring transaction infrastructure - * ({@link org.springframework.transaction.PlatformTransactionManager}). + * ({@link org.springframework.transaction.PlatformTransactionManager}/ + * {@link org.springframework.transaction.ReactiveTransactionManager}). * *

Derives from the {@link TransactionAspectSupport} class which * contains the integration with Spring's underlying transaction API.