use of io.micronaut.aop.kotlin.KotlinInterceptedMethod in project micronaut-data by micronaut-projects.
the class TransactionalInterceptor method interceptKotlinSuspended.
private Object interceptKotlinSuspended(MethodInvocationContext<Object, Object> context, InterceptedMethod interceptedMethod, TransactionInvocation<?> transactionInvocation, TransactionAttribute definition) {
KotlinInterceptedMethod kotlinInterceptedMethod = (KotlinInterceptedMethod) interceptedMethod;
TransactionSynchronizationManager.TransactionSynchronizationState state = Objects.requireNonNull(coroutineTxHelper).setupTxState(kotlinInterceptedMethod);
return TransactionSynchronizationManager.withState(state, () -> {
final SynchronousTransactionManager<?> transactionManager = transactionInvocation.transactionManager;
TransactionInfo<Object> transactionInfo = (TransactionInfo<Object>) createTransactionIfNecessary(transactionManager, definition, context.getExecutableMethod());
CompletionStage<?> result;
try {
result = interceptedMethod.interceptResultAsCompletionStage();
} catch (Exception e) {
CompletableFuture<?> r = new CompletableFuture<>();
r.completeExceptionally(e);
result = r;
}
CompletableFuture<Object> newResult = new CompletableFuture<>();
// Last step to complete the TX, we need to use `withState` to properly setup thread-locals for the TX manager
result.whenComplete((o, throwable) -> TransactionSynchronizationManager.withState(state, () -> {
if (throwable == null) {
commitTransactionAfterReturning(transactionInfo);
newResult.complete(o);
} else {
try {
completeTransactionAfterThrowing(transactionInfo, throwable);
} catch (Exception e) {
// Ignore rethrow
}
newResult.completeExceptionally(throwable);
}
cleanupTransactionInfo(transactionInfo);
return null;
}));
return interceptedMethod.handleResult(newResult);
});
}
use of io.micronaut.aop.kotlin.KotlinInterceptedMethod in project micronaut-data by micronaut-projects.
the class TransactionalInterceptor method intercept.
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
InterceptedMethod interceptedMethod = InterceptedMethod.of(context);
boolean isKotlinSuspended = interceptedMethod instanceof KotlinInterceptedMethod;
try {
boolean isReactive = interceptedMethod.resultType() == InterceptedMethod.ResultType.PUBLISHER;
boolean isAsync = interceptedMethod.resultType() == InterceptedMethod.ResultType.COMPLETION_STAGE;
final TransactionInvocation<?> transactionInvocation = transactionInvocationMap.computeIfAbsent(context.getExecutableMethod(), executableMethod -> {
final String qualifier = executableMethod.stringValue(TransactionalAdvice.class).orElse(null);
ReactiveTransactionOperations<?> reactiveTransactionOperations = beanLocator.findBean(ReactiveTransactionOperations.class, qualifier != null ? Qualifiers.byName(qualifier) : null).orElse(null);
if ((isReactive || isAsync) && !(isKotlinSuspended && reactiveTransactionOperations == null)) {
if (isReactive && reactiveTransactionOperations == null) {
throw new ConfigurationException("No reactive transaction management has been configured. Ensure you have correctly configured a reactive capable transaction manager");
} else {
final TransactionAttribute transactionAttribute = resolveTransactionDefinition(executableMethod);
return new TransactionInvocation(null, reactiveTransactionOperations, transactionAttribute);
}
} else {
SynchronousTransactionManager<?> transactionManager = beanLocator.getBean(SynchronousTransactionManager.class, qualifier != null ? Qualifiers.byName(qualifier) : null);
final TransactionAttribute transactionAttribute = resolveTransactionDefinition(executableMethod);
return new TransactionInvocation<>(transactionManager, null, transactionAttribute);
}
});
final TransactionAttribute definition = transactionInvocation.definition;
switch(interceptedMethod.resultType()) {
case PUBLISHER:
return interceptedMethod.handleResult(transactionInvocation.reactiveTransactionOperations.withTransaction(definition, (status) -> {
context.setAttribute(ReactiveTransactionStatus.STATUS, status);
context.setAttribute(ReactiveTransactionStatus.ATTRIBUTE, definition);
return Publishers.convertPublisher(context.proceed(), Publisher.class);
}));
case COMPLETION_STAGE:
if (transactionInvocation.reactiveTransactionOperations != null) {
return interceptedMethod.handleResult(interceptedMethod.interceptResult());
} else {
if (isKotlinSuspended) {
return interceptKotlinSuspended(context, interceptedMethod, transactionInvocation, definition);
} else {
throw new ConfigurationException("Async return type doesn't support transactional execution.");
}
}
case SYNCHRONOUS:
final SynchronousTransactionManager<?> transactionManager = transactionInvocation.transactionManager;
final TransactionInfo transactionInfo = createTransactionIfNecessary(transactionManager, definition, context.getExecutableMethod());
Object retVal;
try {
retVal = context.proceed();
} catch (Throwable ex) {
completeTransactionAfterThrowing(transactionInfo, ex);
throw ex;
} finally {
cleanupTransactionInfo(transactionInfo);
}
commitTransactionAfterReturning(transactionInfo);
return retVal;
default:
return interceptedMethod.unsupported();
}
} catch (Exception e) {
return interceptedMethod.handleException(e);
}
}
Aggregations