Skip to content

Commit c4366b5

Browse files
committed
feat: abstract class method obtains the name of the calling class
1 parent 84fed02 commit c4366b5

File tree

4 files changed

+44
-12
lines changed

4 files changed

+44
-12
lines changed

arex-instrumentation/dynamic/arex-dynamic-common/src/main/java/io/arex/inst/dynamic/common/DynamicClassExtractor.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import java.lang.reflect.Array;
2626
import java.lang.reflect.Method;
27+
import java.lang.reflect.Modifier;
2728
import java.util.Collection;
2829
import java.util.Map;
2930
import java.util.Objects;
@@ -74,7 +75,7 @@ public DynamicClassExtractor(Method method, Object[] args, String keyExpression,
7475
this.requestType = buildRequestType(method);
7576
}
7677

77-
public DynamicClassExtractor(Method method, Object[] args) {
78+
public DynamicClassExtractor(Method method, Object[] args, Object target) {
7879
int proceedingJoinPointIndex = proceedingJoinPointIndex(method.getParameterTypes());
7980
if (proceedingJoinPointIndex != -1) {
8081
ProceedingJoinPoint proceedingJoinPoint = (ProceedingJoinPoint) args[proceedingJoinPointIndex];
@@ -84,7 +85,7 @@ public DynamicClassExtractor(Method method, Object[] args) {
8485
this.args = proceedingJoinPoint.getArgs();
8586
this.requestType = ArrayUtils.toString(this.args, o -> o.getClass().getTypeName());
8687
} else {
87-
this.clazzName = normalizeClassName(method.getDeclaringClass().getName());
88+
this.clazzName = normalizeClassName(getCallerClassName(method.getDeclaringClass(), target));
8889
this.methodName = method.getName();
8990
this.args = args;
9091
this.requestType = ArrayUtils.toString(method.getParameterTypes(), obj -> ((Class<?>)obj).getTypeName());
@@ -402,6 +403,17 @@ private int buildNoArgMethodSignatureHash(boolean isNeedResult) {
402403
return StringUtil.encodeAndHash(String.format("%s_%s_%s", this.clazzName, this.methodName, null));
403404
}
404405

406+
private String getCallerClassName(Class<?> clazz, Object target) {
407+
if (isAbstractOrInterface(clazz) && target != null) {
408+
return target.getClass().getName();
409+
}
410+
return clazz.getName();
411+
}
412+
413+
private boolean isAbstractOrInterface(Class<?> clazz) {
414+
return clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers());
415+
}
416+
405417
String normalizeClassName(String className) {
406418
// ex: com.xxx.xxx.client$$EnhancerBySpringCGLIB$$1e3f5g
407419
if (StringUtil.isNotEmpty(className) && className.contains("CGLIB$$")) {

arex-instrumentation/dynamic/arex-dynamic-common/src/test/java/io/arex/inst/dynamic/common/DynamicClassExtractorTest.java

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ void record(Runnable mocker, Object[] args, Object result, Predicate<Object> pre
9696
return null;
9797
});
9898
Method testWithArexMock = getMethod(result);
99-
DynamicClassExtractor extractor = new DynamicClassExtractor(testWithArexMock, args);
99+
DynamicClassExtractor extractor = new DynamicClassExtractor(testWithArexMock, args, null);
100100
extractor.recordResponse(result);
101101

102102
assertTrue(predicate.test(result));
@@ -125,7 +125,7 @@ void resetMonoResponse() {
125125
Method testWithArexMock = DynamicClassExtractorTest.class.getDeclaredMethod("testWithArexMock",
126126
String.class);
127127
final Object[] args = {"errorSerialize"};
128-
final DynamicClassExtractor extractor = new DynamicClassExtractor(testWithArexMock, args);
128+
final DynamicClassExtractor extractor = new DynamicClassExtractor(testWithArexMock, args, null);
129129
final Predicate<Object> nonNull = Objects::nonNull;
130130

131131
// exception
@@ -427,10 +427,10 @@ void invalidOperation() throws Throwable {
427427
final Object[] args = {"errorSerialize"};
428428
ConfigBuilder.create("invalid-operation").enableDebug(true).build();
429429
Mockito.when(Serializer.serializeWithException(any(), anyString())).thenThrow(new RuntimeException("errorSerialize"));
430-
DynamicClassExtractor extractor = new DynamicClassExtractor(testWithArexMock, args);
430+
DynamicClassExtractor extractor = new DynamicClassExtractor(testWithArexMock, args, null);
431431
extractor.recordResponse("errorSerialize");
432432
// invalid operation return empty
433-
DynamicClassExtractor extractor2 = new DynamicClassExtractor(testWithArexMock, args);
433+
DynamicClassExtractor extractor2 = new DynamicClassExtractor(testWithArexMock, args, null);
434434
final Field methodKey = DynamicClassExtractor.class.getDeclaredField("methodKey");
435435
methodKey.setAccessible(true);
436436
assertNull(methodKey.get(extractor2));
@@ -442,14 +442,14 @@ void invalidOperation() throws Throwable {
442442

443443
// test getSerializedResult serialize
444444
Mockito.when(agentSizeOf.checkMemorySizeLimit(any(), any(long.class))).thenReturn(true);
445-
extractor = new DynamicClassExtractor(testWithArexMock, args);
445+
extractor = new DynamicClassExtractor(testWithArexMock, args, null);
446446
assertNull(extractor.getSerializedResult());
447447
}
448448

449449
@Test
450450
void emptyMethodKeyAndExceedSize() throws NoSuchMethodException {
451451
Method testEmptyArgs = DynamicClassExtractorTest.class.getDeclaredMethod("invalidOperation");
452-
DynamicClassExtractor extractor = new DynamicClassExtractor(testEmptyArgs, new Object[0]);
452+
DynamicClassExtractor extractor = new DynamicClassExtractor(testEmptyArgs, new Object[0], null);
453453
assertDoesNotThrow(() -> extractor.recordResponse(new int[1001]));
454454
}
455455

@@ -566,12 +566,31 @@ void testProceedingJointPoint() throws Throwable {
566566
Mockito.when(joinPoint.getSignature()).thenReturn(signature);
567567
String arg1 = "arg1";
568568
Mockito.when(joinPoint.getArgs()).thenReturn(new Object[]{arg1});
569-
DynamicClassExtractor extractor = new DynamicClassExtractor(testProceedingJointPoint, new Object[]{joinPoint});
569+
DynamicClassExtractor extractor = new DynamicClassExtractor(testProceedingJointPoint, new Object[]{joinPoint}, null);
570570
Field requestType = DynamicClassExtractor.class.getDeclaredField("requestType");
571571
requestType.setAccessible(true);
572572
assertEquals("[\"java.lang.String\"]", requestType.get(extractor));
573573
}
574574

575575
public void testProceedingJointPoint(ProceedingJoinPoint joinPoint) {
576576
}
577+
578+
@Test
579+
void testRecordWithAbstractClassMethod() throws Exception {
580+
CacheClass cacheClass = new CacheClass();
581+
Method abstractMethod = AbstractClass.class.getDeclaredMethod("abstractMethod", String.class);
582+
Field clazzName = DynamicClassExtractor.class.getDeclaredField("clazzName");
583+
clazzName.setAccessible(true);
584+
DynamicClassExtractor extractor = new DynamicClassExtractor(abstractMethod, new Object[]{"arg"}, cacheClass);
585+
assertEquals(CacheClass.class.getName(), clazzName.get(extractor));
586+
}
587+
588+
static abstract class AbstractClass {
589+
public String abstractMethod(String arg) {
590+
return arg;
591+
}
592+
}
593+
594+
static class CacheClass extends AbstractClass {
595+
}
577596
}

arex-instrumentation/dynamic/arex-dynamic/src/main/java/io/arex/inst/dynamic/DynamicClassInstrumentation.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ public static final class MethodAdvice {
143143

144144
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class, suppress = Throwable.class)
145145
public static boolean onEnter(@Advice.Origin Method method,
146+
@Advice.This(optional = true) Object target,
146147
@Advice.AllArguments Object[] args,
147148
@Advice.Local("extractor") DynamicClassExtractor extractor,
148149
@Advice.Local("mockResult") MockResult mockResult) {
@@ -153,7 +154,7 @@ public static boolean onEnter(@Advice.Origin Method method,
153154
if (void.class.isAssignableFrom(method.getReturnType())) {
154155
return ContextManager.needReplay();
155156
}
156-
extractor = new DynamicClassExtractor(method, args);
157+
extractor = new DynamicClassExtractor(method, args, target);
157158
}
158159
if (ContextManager.needReplay()) {
159160
mockResult = extractor.replay();

arex-instrumentation/dynamic/arex-dynamic/src/test/java/io/arex/inst/dynamic/DynamicClassInstrumentationTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,13 @@ void onEnter() throws NoSuchMethodException {
179179
Mockito.when(ContextManager.needRecordOrReplay()).thenReturn(true);
180180
Mockito.when(ContextManager.needRecord()).thenReturn(true);
181181
DynamicClassExtractor extractor = new DynamicClassExtractor(test1, new Object[]{"mock"}, "#val", null);
182-
boolean actualResult = DynamicClassInstrumentation.MethodAdvice.onEnter(test1, new Object[]{ "name", 18 }, extractor, null);
182+
boolean actualResult = DynamicClassInstrumentation.MethodAdvice.onEnter(test1, null, new Object[]{ "name", 18 }, extractor, null);
183183
assertFalse(actualResult);
184184

185185
// replay
186186
Mockito.when(ContextManager.needRecord()).thenReturn(false);
187187
Mockito.when(ContextManager.needReplay()).thenReturn(true);
188-
actualResult = DynamicClassInstrumentation.MethodAdvice.onEnter(test1, new Object[]{ "name", 18 }, extractor, null);
188+
actualResult = DynamicClassInstrumentation.MethodAdvice.onEnter(test1, null, new Object[]{ "name", 18 }, extractor, null);
189189
assertTrue(actualResult);
190190
}
191191
}

0 commit comments

Comments
 (0)