Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bugfix: fix the failure of @BusinessActionContextParamete annotation … #6475

Open
wants to merge 7 commits into
base: 2.x
Choose a base branch
from
2 changes: 2 additions & 0 deletions changes/en-us/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#6385](https://github.com/apache/incubator-seata/pull/6385)] fix the bug where Role.participant does not execute hooks but clears them.
- [[#6465](https://github.com/apache/incubator-seata/pull/6465)] fix(6257): fix saga mode replay context lost start in 2.x
- [[#6469](https://github.com/apache/incubator-seata/pull/6469)] fix Error in insert sql of [lock_table] data table to sqlserver database
- [[#6475](https://github.com/apache/incubator-seata/pull/6475)] fix the failure of @BusinessActionContextParamete annotation to set parameters into io.seata.rm.tcc.api.BusinessActionContext at TCC mode.


### optimize:
- [[#6031](https://github.com/apache/incubator-seata/pull/6031)] add a check for the existence of the undolog table
Expand Down
1 change: 1 addition & 0 deletions changes/zh-cn/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
- [[#6385](https://github.com/apache/incubator-seata/pull/6385)] 修复Role.Participant不执行hook但会清理的问题
- [[#6465](https://github.com/apache/incubator-seata/pull/6465)] 修复2.0下saga模式的context replay丢失start问题
- [[#6469](https://github.com/apache/incubator-seata/pull/6469)] 修复在sqlserver数据库下[lock_table]数据表的插入操作sql中存在的错误
- [[#6475](https://github.com/apache/incubator-seata/pull/6475)] 修复TCC模式@BusinessActionContextParamete注解无法将参数设置到BusinessActionContext的问题


### optimize:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.apache.seata.spring.tcc;
funky-eyes marked this conversation as resolved.
Show resolved Hide resolved

import org.aopalliance.intercept.MethodInvocation;
import org.apache.seata.integration.tx.api.interceptor.InvocationWrapper;
import org.apache.seata.rm.tcc.api.BusinessActionContext;
import org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction;
import org.apache.seata.rm.tcc.interceptor.TccActionInterceptorHandler;
import org.apache.seata.spring.annotation.AdapterInvocationWrapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;
import java.util.HashSet;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;


class TccActionInterceptorHandlerTest {

protected TccActionInterceptorHandler tccActionInterceptorHandler = new TccActionInterceptorHandler(
null,
new HashSet<String>() {{
add("prepare");
}}
);

/**
* Test method "parseAnnotation" of TccActionInterceptorHandler
*
* @throws Throwable
*/
@Test
void testParseAnnotation() throws Throwable {
// mock MethodInvocation
NormalTccActionImpl tccAction = new NormalTccActionImpl();
Method classMethod = NormalTccActionImpl.class.getMethod("prepare", BusinessActionContext.class);
MethodInvocation mockInvocation = mock(MethodInvocation.class);
when(mockInvocation.getMethod()).thenReturn(classMethod);
when(mockInvocation.getArguments()).thenReturn(new Object[]{new BusinessActionContext()});
when(mockInvocation.proceed()).thenAnswer(invocation -> classMethod.invoke(tccAction, mockInvocation.getArguments()));

// mock AdapterInvocationWrapper
AdapterInvocationWrapper invocationWrapper = new AdapterInvocationWrapper(mockInvocation);
when(invocationWrapper.getTarget()).thenReturn(tccAction);

// invoke private method "parseAnnotation" of TccActionInterceptorHandler
Method method = TccActionInterceptorHandler.class.getDeclaredMethod("parseAnnotation", InvocationWrapper.class);
method.setAccessible(true);
Object[] results = (Object[]) method.invoke(tccActionInterceptorHandler, invocationWrapper);
System.out.println(results);

// test results
Method interfaceMethod = NormalTccAction.class.getMethod("prepare", BusinessActionContext.class);
Assertions.assertEquals(interfaceMethod, results[0]);
Assertions.assertEquals(true, results[1] instanceof TwoPhaseBusinessAction);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
import org.apache.seata.integration.tx.api.interceptor.TwoPhaseBusinessActionParam;
import org.apache.seata.integration.tx.api.interceptor.handler.AbstractProxyInvocationHandler;
import org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;


Expand All @@ -46,6 +48,8 @@

public class TccActionInterceptorHandler extends AbstractProxyInvocationHandler {

private static final Logger LOGGER = LoggerFactory.getLogger(TccActionInterceptorHandler.class);

private static final int ORDER_NUM = ConfigurationFactory.getInstance().getInt(TCC_ACTION_INTERCEPTOR_ORDER,
DefaultValues.TCC_ACTION_INTERCEPTOR_ORDER);

Expand All @@ -54,7 +58,7 @@ public class TccActionInterceptorHandler extends AbstractProxyInvocationHandler
private Set<String> methodsToProxy;
protected Object targetBean;

protected Map<Method, Annotation> parseAnnotationCache = new ConcurrentHashMap<>();
protected Map<Method, Object[]> parseAnnotationCache = new ConcurrentHashMap<>();

public TccActionInterceptorHandler(Object targetBean, Set<String> methodsToProxy) {
this.targetBean = targetBean;
Expand All @@ -67,8 +71,10 @@ protected Object doInvoke(InvocationWrapper invocation) throws Throwable {
//not in transaction, or this interceptor is disabled
return invocation.proceed();
}
Method method = invocation.getMethod();
Annotation businessAction = parseAnnotation(method);

Object[] methodAndAnnotation = parseAnnotation(invocation);
Method method = (Method) methodAndAnnotation[0];
Annotation businessAction = (Annotation) methodAndAnnotation[1];

//try method
if (businessAction != null) {
Expand Down Expand Up @@ -99,30 +105,41 @@ protected Object doInvoke(InvocationWrapper invocation) throws Throwable {
return invocation.proceed();
}

private Annotation parseAnnotation(Method methodKey) throws NoSuchMethodException {
Annotation result = parseAnnotationCache.computeIfAbsent(methodKey, method -> {
/**
* Get try method and the corresponding annotation of TCC mode.
*
* @param invocation
* @return
*/
private Object[] parseAnnotation(InvocationWrapper invocation) {
Object[] results = parseAnnotationCache.computeIfAbsent(invocation.getMethod(), method -> {
Annotation twoPhaseBusinessAction = method.getAnnotation(getAnnotationClass());
if (twoPhaseBusinessAction == null && targetBean.getClass() != null) {
Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(targetBean.getClass());
Method tryMethod = method;
if (twoPhaseBusinessAction == null && invocation.getTarget() != null) {
Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(invocation.getTarget().getClass());
if (interfaceClasses != null) {
for (Class<?> interClass : interfaceClasses) {
try {
Method m = interClass.getMethod(method.getName(), method.getParameterTypes());
twoPhaseBusinessAction = m.getAnnotation(getAnnotationClass());
if (twoPhaseBusinessAction != null) {
// init common fence clean task if enable useTccFence
initCommonFenceCleanTask(twoPhaseBusinessAction);
tryMethod = m;
break;
}
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
LOGGER.debug(method.getName() + ", no such method found", e);
}
}
}
}
return twoPhaseBusinessAction;
if (twoPhaseBusinessAction == null) {
throw new RuntimeException("No such method with annotation" + getAnnotationClass());
}
// init common fence clean task if enable useTccFence
initCommonFenceCleanTask(twoPhaseBusinessAction);
return new Object[] {tryMethod, twoPhaseBusinessAction};
});
return result;
return results;
}

protected TwoPhaseBusinessActionParam createTwoPhaseBusinessActionParam(Annotation annotation) {
Expand Down
Loading