Skip to content

Commit 0626b50

Browse files
authored
feat: record dubbo request param type (#167)
1 parent 39bf9fe commit 0626b50

11 files changed

+145
-22
lines changed

arex-instrumentation/dubbo/arex-dubbo/src/main/java/io/arex/inst/dubbo/DubboAdapter.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.HashSet;
2222
import java.util.Map;
2323
import java.util.Set;
24+
import java.util.function.Function;
2425

2526
import static io.arex.inst.runtime.model.ArexConstants.DUBBO_STREAM_NAME;
2627
import static io.arex.inst.runtime.model.ArexConstants.DUBBO_STREAM_PROTOCOL;
@@ -59,11 +60,24 @@ public String getServiceOperation() {
5960
return getPath() + "." + getOperationName();
6061
}
6162
public String getRequest() {
62-
Object request = null;
63-
if (invocation.getArguments() != null && invocation.getArguments().length > 0) {
64-
request = invocation.getArguments()[0];
63+
return parseRequest(invocation.getArguments(), Serializer::serialize);
64+
}
65+
public String getRequestParamType() {
66+
Class<?>[] parameterTypes = invocation.getParameterTypes();
67+
if (parameterTypes != null && parameterTypes.length > 0) {
68+
return parameterTypes[0].getName();
69+
}
70+
return parseRequest(invocation.getArguments(), TypeUtil::getName);
71+
}
72+
public static String parseRequest(Object request, Function<Object, String> parser) {
73+
if (request instanceof Object[]) {
74+
Object[] requests = (Object[]) request;
75+
if (requests.length > 0) {
76+
// take only the first request parameter, and in most cases will be packed as one object
77+
return parser.apply(requests[0]);
78+
}
6579
}
66-
return Serializer.serialize(request);
80+
return parser.apply(request);
6781
}
6882
public String getReturnType() {
6983
Type returnType = null;

arex-instrumentation/dubbo/arex-dubbo/src/main/java/io/arex/inst/dubbo/DubboConsumerExtractor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public Result record(Result result) {
2121
private Mocker makeMocker() {
2222
Mocker mocker = MockUtils.createDubboConsumer(adapter.getServiceOperation());
2323
mocker.getTargetRequest().setBody(adapter.getRequest());
24+
mocker.getTargetRequest().setType(adapter.getRequestParamType());
2425
mocker.getTargetResponse().setType(adapter.getReturnType());
2526
return mocker;
2627
}

arex-instrumentation/dubbo/arex-dubbo/src/main/java/io/arex/inst/dubbo/DubboProviderExtractor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ private static Mocker makeMocker(DubboAdapter adapter) {
7070
headerMap.put("protocol", adapter.getProtocol());
7171
mocker.getTargetRequest().setAttributes(Collections.singletonMap("Headers", Serializer.serialize(headerMap)));
7272
mocker.getTargetRequest().setBody(adapter.getRequest());
73+
mocker.getTargetRequest().setType(adapter.getRequestParamType());
7374
String responseHeader = Serializer.serialize(RpcContext.getServerAttachment().getObjectAttachments());
7475
mocker.getTargetResponse().setAttributes(Collections.singletonMap("Headers", responseHeader));
7576
return mocker;

arex-instrumentation/dubbo/arex-dubbo/src/main/java/io/arex/inst/dubbo/stream/DubboStreamAdapter.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
import io.arex.agent.bootstrap.model.MockResult;
44
import io.arex.agent.bootstrap.model.MockStrategyEnum;
55
import io.arex.agent.bootstrap.model.Mocker;
6+
import io.arex.inst.dubbo.DubboAdapter;
67
import io.arex.inst.runtime.config.Config;
78
import io.arex.inst.runtime.context.ContextManager;
89
import io.arex.inst.runtime.serializer.Serializer;
910
import io.arex.inst.runtime.util.MockUtils;
11+
import io.arex.inst.runtime.util.TypeUtil;
1012
import org.apache.dubbo.rpc.model.MethodDescriptor;
1113
import org.apache.dubbo.rpc.protocol.tri.stream.Stream;
1214

15+
import java.lang.reflect.ParameterizedType;
16+
import java.lang.reflect.Type;
1317
import java.util.ArrayList;
1418
import java.util.List;
1519

@@ -18,16 +22,18 @@
1822
*/
1923
public class DubboStreamAdapter {
2024
private String streamId;
21-
private DubboStreamAdapter(String streamId) {
25+
private MethodDescriptor methodDescriptor;
26+
private DubboStreamAdapter(String streamId, MethodDescriptor methodDescriptor) {
2227
this.streamId = streamId;
28+
this.methodDescriptor = methodDescriptor;
2329
}
2430

25-
public static DubboStreamAdapter of(String streamId) {
26-
return new DubboStreamAdapter(streamId);
31+
public static DubboStreamAdapter of(String streamId, MethodDescriptor methodDescriptor) {
32+
return new DubboStreamAdapter(streamId, methodDescriptor);
2733
}
2834

29-
public static DubboStreamAdapter of(Stream stream) {
30-
return of(generateStreamId(stream));
35+
public static DubboStreamAdapter of(Stream stream, MethodDescriptor methodDescriptor) {
36+
return of(generateStreamId(stream), methodDescriptor);
3137
}
3238

3339
public void saveRequest(byte[] message) {
@@ -78,4 +84,26 @@ public void clearRequest() {
7884
public static String generateStreamId(Stream stream) {
7985
return Integer.toHexString(System.identityHashCode(stream));
8086
}
87+
88+
public String getRequest(Object request) {
89+
return DubboAdapter.parseRequest(request, Serializer::serialize);
90+
}
91+
92+
public String getRequestParamType(Object request) {
93+
if (methodDescriptor.getMethod() == null) {
94+
return DubboAdapter.parseRequest(request, TypeUtil::getName);
95+
}
96+
Type[] genericParameters = methodDescriptor.getMethod().getGenericParameterTypes();
97+
if (genericParameters.length <= 0) {
98+
return DubboAdapter.parseRequest(request, TypeUtil::getName);
99+
}
100+
Type genericType = genericParameters[0];
101+
if (genericType instanceof ParameterizedType) {
102+
Type[] actualTypes = ((ParameterizedType) genericType).getActualTypeArguments();
103+
if (actualTypes != null && actualTypes.length > 0) {
104+
return actualTypes[0].getTypeName();
105+
}
106+
}
107+
return DubboAdapter.parseRequest(request, TypeUtil::getName);
108+
}
81109
}

arex-instrumentation/dubbo/arex-dubbo/src/main/java/io/arex/inst/dubbo/stream/DubboStreamConsumerExtractor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ public void record(RequestMetadata requestMetadata, byte[] message, Throwable th
6767
StreamModel.DataModel requestModel = getUnRecordRequest(dataModels);
6868
if (requestModel.getData() != null) {
6969
Object request = requestMetadata.packableMethod.parseRequest(requestModel.getData());
70-
mocker.getTargetRequest().setBody(Serializer.serialize(request));
70+
mocker.getTargetRequest().setBody(adapter.getRequest(request));
71+
mocker.getTargetRequest().setType(adapter.getRequestParamType(request));
7172
}
7273
if (throwable != null) {
7374
mocker.getTargetResponse().setBody(Serializer.serialize(throwable));

arex-instrumentation/dubbo/arex-dubbo/src/main/java/io/arex/inst/dubbo/stream/DubboStreamConsumerInstrumentation.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public static boolean onEnter(@Advice.Argument(0) Object message,
7070
@Advice.Local("mockResult") List<MockResult> mockResults) {
7171
if (ContextManager.needRecordOrReplay()) {
7272
RepeatedCollectManager.enter();
73-
extractor = new DubboStreamConsumerExtractor(DubboStreamAdapter.of(stream));
73+
extractor = new DubboStreamConsumerExtractor(DubboStreamAdapter.of(stream, requestMetadata.method));
7474
if (ContextManager.needReplay()) {
7575
mockResults = extractor.replay(message, requestMetadata);
7676
}
@@ -113,7 +113,8 @@ public static void onExit(@Advice.Argument(0) byte[] message,
113113
@Advice.FieldValue("stream") ClientStream stream,
114114
@Advice.FieldValue("requestMetadata") RequestMetadata requestMetadata) {
115115
if (ContextManager.needRecord()) {
116-
DubboStreamConsumerExtractor extractor = new DubboStreamConsumerExtractor(DubboStreamAdapter.of(stream));
116+
DubboStreamConsumerExtractor extractor = new DubboStreamConsumerExtractor(
117+
DubboStreamAdapter.of(stream, requestMetadata.method));
117118
extractor.record(requestMetadata, message, null);
118119
}
119120
}
@@ -125,7 +126,8 @@ public static void onEnter(@Advice.Argument(0) TriRpcStatus status,
125126
@Advice.FieldValue("stream") ClientStream stream,
126127
@Advice.FieldValue("requestMetadata") RequestMetadata requestMetadata) {
127128
if (ContextManager.needRecord()) {
128-
DubboStreamConsumerExtractor extractor = new DubboStreamConsumerExtractor(DubboStreamAdapter.of(stream));
129+
DubboStreamConsumerExtractor extractor = new DubboStreamConsumerExtractor(
130+
DubboStreamAdapter.of(stream, requestMetadata.method));
129131
extractor.complete(status, requestMetadata);
130132
}
131133
}

arex-instrumentation/dubbo/arex-dubbo/src/main/java/io/arex/inst/dubbo/stream/DubboStreamProviderExtractor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ public void record(Map<String, Object> requestHeader, Object response, String se
126126
StreamModel.DataModel dataModel = requestsList.get(i);
127127
if (dataModel.getData() != null) {
128128
Object request = packableMethod.parseRequest(dataModel.getData());
129-
mocker.getTargetRequest().setBody(Serializer.serialize(request));
129+
mocker.getTargetRequest().setBody(adapter.getRequest(request));
130+
mocker.getTargetRequest().setType(adapter.getRequestParamType(request));
130131
}
131132
// The result is recorded for the last time, the previous requests are all compensate record
132133
if (i == (requestTimes - 1)) {

arex-instrumentation/dubbo/arex-dubbo/src/main/java/io/arex/inst/dubbo/stream/DubboStreamProviderInstrumentation.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ public static void onExit(@Advice.Argument(0) Object message,
7676
@Advice.FieldValue("stream") ServerStream stream,
7777
@Advice.FieldValue("packableMethod") PackableMethod packableMethod) {
7878
if (ContextManager.needRecord()) {
79-
DubboStreamProviderExtractor extractor = new DubboStreamProviderExtractor(DubboStreamAdapter.of(stream));
79+
DubboStreamProviderExtractor extractor = new DubboStreamProviderExtractor(
80+
DubboStreamAdapter.of(stream, methodDescriptor));
8081
extractor.record(requestMetadata, message, serviceName, methodDescriptor, packableMethod);
8182
}
8283
}
@@ -90,7 +91,8 @@ public static void onEnter(@Advice.Argument(0) byte[] message,
9091
@Advice.FieldValue("methodDescriptor") MethodDescriptor methodDescriptor,
9192
@Advice.FieldValue("packableMethod") PackableMethod packableMethod) {
9293
if (ContextManager.needRecordOrReplay()) {
93-
DubboStreamProviderExtractor extractor = new DubboStreamProviderExtractor(DubboStreamAdapter.of(stream));
94+
DubboStreamProviderExtractor extractor = new DubboStreamProviderExtractor(
95+
DubboStreamAdapter.of(stream, methodDescriptor));
9496
if (ContextManager.needReplay()) {
9597
extractor.replay(message, serviceName, methodDescriptor, packableMethod);
9698
}
@@ -110,7 +112,8 @@ public static void onEnter(@Advice.Argument(0) TriRpcStatus status,
110112
@Advice.FieldValue("stream") ServerStream stream,
111113
@Advice.FieldValue("packableMethod") PackableMethod packableMethod) {
112114
if (ContextManager.needRecord()) {
113-
DubboStreamProviderExtractor extractor = new DubboStreamProviderExtractor(DubboStreamAdapter.of(stream));
115+
DubboStreamProviderExtractor extractor = new DubboStreamProviderExtractor(
116+
DubboStreamAdapter.of(stream, methodDescriptor));
114117
extractor.complete(status, requestMetadata, serviceName, methodDescriptor, packableMethod);
115118
}
116119
}

arex-instrumentation/dubbo/arex-dubbo/src/test/java/io/arex/inst/dubbo/DubboAdapterTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ void getRequest() {
8383
assertNull(adapter.getRequest());
8484
}
8585

86+
@Test
87+
void getRequestParamType() {
88+
Mockito.when(invocation.getParameterTypes()).thenReturn(new Class<?>[]{String.class});
89+
assertNotNull(adapter.getRequestParamType());
90+
Mockito.when(invocation.getParameterTypes()).thenReturn(new Class<?>[]{});
91+
Mockito.when(invocation.getArguments()).thenReturn(new Object[]{});
92+
assertNotNull(adapter.getRequestParamType());
93+
}
94+
8695
@Test
8796
void getReturnType() {
8897
Type type1 = Mockito.mock(Type.class);

arex-instrumentation/dubbo/arex-dubbo/src/test/java/io/arex/inst/dubbo/stream/DubboStreamAdapterTest.java

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.mockito.Mockito;
2121
import org.mockito.junit.jupiter.MockitoExtension;
2222

23+
import java.lang.reflect.Method;
2324
import java.util.List;
2425
import java.util.Objects;
2526
import java.util.function.Predicate;
@@ -32,10 +33,12 @@
3233
class DubboStreamAdapterTest {
3334
static DubboStreamAdapter adapter;
3435
static MockedStatic<DubboStreamCache> dubboStreamCacheMocker;
36+
static MethodDescriptor methodDescriptor;
3537

3638
@BeforeAll
37-
static void setUp() {
38-
adapter = DubboStreamAdapter.of(Mockito.mock(Stream.class));
39+
static void setUp() throws NoSuchMethodException {
40+
methodDescriptor = Mockito.mock(MethodDescriptor.class);
41+
adapter = DubboStreamAdapter.of(Mockito.mock(Stream.class), methodDescriptor);
3942
dubboStreamCacheMocker = Mockito.mockStatic(DubboStreamCache.class);
4043
Mockito.mockStatic(ContextManager.class);
4144
Mockito.mockStatic(MockUtils.class);
@@ -93,4 +96,62 @@ void clearRequest() {
9396
adapter.clearRequest();
9497
dubboStreamCacheMocker.verify(() -> DubboStreamCache.remove(any()));
9598
}
99+
100+
@Test
101+
void getRequest() {
102+
assertNull(adapter.getRequest(new Object[]{"mock"}));
103+
}
104+
105+
@ParameterizedTest
106+
@MethodSource("getRequestParamTypeCase")
107+
void getRequestParamType(Runnable mocker, Predicate<String> predicate) {
108+
mocker.run();
109+
String result = adapter.getRequestParamType(new Object[]{"mock"});
110+
assertTrue(predicate.test(result));
111+
}
112+
113+
static java.util.stream.Stream<Arguments> getRequestParamTypeCase() {
114+
Runnable emptyMocker = () -> {};
115+
Runnable mocker1 = () -> {
116+
Method method = null;
117+
try {
118+
method = DubboStreamAdapterTest.class.getDeclaredMethod(
119+
"testWithoutParameter");
120+
} catch (NoSuchMethodException e) {}
121+
Mockito.when(methodDescriptor.getMethod()).thenReturn(method);
122+
};
123+
Runnable mocker2 = () -> {
124+
Method method = null;
125+
try {
126+
method = DubboStreamAdapterTest.class.getDeclaredMethod(
127+
"testWithGenericParameter", List.class);
128+
} catch (NoSuchMethodException e) {}
129+
Mockito.when(methodDescriptor.getMethod()).thenReturn(method);
130+
};
131+
Runnable mocker3 = () -> {
132+
Method method = null;
133+
try {
134+
method = DubboStreamAdapterTest.class.getDeclaredMethod(
135+
"testWithGenericParameter", String.class, List.class);
136+
} catch (NoSuchMethodException e) {}
137+
Mockito.when(methodDescriptor.getMethod()).thenReturn(method);
138+
};
139+
Predicate<String> predicate1 = Objects::nonNull;
140+
return java.util.stream.Stream.of(
141+
arguments(emptyMocker, predicate1),
142+
arguments(mocker1, predicate1),
143+
arguments(mocker2, predicate1),
144+
arguments(mocker3, predicate1)
145+
);
146+
}
147+
148+
String testWithoutParameter() {
149+
return "mock";
150+
}
151+
String testWithGenericParameter(List<String> list) {
152+
return "mock";
153+
}
154+
String testWithGenericParameter(String param, List<String> list) {
155+
return "mock";
156+
}
96157
}

0 commit comments

Comments
 (0)