Fix dubbo get wrong return type when generic impl invoke (#10891)

This commit is contained in:
Albumen Kevin 2022-11-08 11:34:05 +08:00 committed by GitHub
parent dce55071c7
commit 305d290e5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 125 additions and 11 deletions

View File

@ -78,10 +78,22 @@ public class RpcUtils {
&& invocation.getInvoker().getUrl() != null
&& invocation.getInvoker().getInterface() != GenericService.class
&& !invocation.getMethodName().startsWith("$")) {
Type[] returnTypes = null;
if (invocation instanceof RpcInvocation) {
returnTypes = ((RpcInvocation) invocation).getReturnTypes();
if (returnTypes != null) {
return returnTypes;
}
}
String service = invocation.getInvoker().getUrl().getServiceInterface();
if (StringUtils.isNotEmpty(service)) {
Method method = getMethodByService(invocation, service);
return ReflectUtils.getReturnTypes(method);
if (method != null) {
returnTypes = ReflectUtils.getReturnTypes(method);
}
}
if (returnTypes != null) {
return returnTypes;
}
}
} catch (Throwable t) {

View File

@ -35,6 +35,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.$INVOKE;
import static org.apache.dubbo.rpc.Constants.AUTO_ATTACH_INVOCATIONID_KEY;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -153,7 +154,7 @@ public class RpcUtilsTest {
}
@Test
public void testGetReturnTypes() throws Exception {
public void testGetReturnTypesUseCache() throws Exception {
Class<?> demoServiceClass = DemoService.class;
String serviceName = demoServiceClass.getName();
Invoker invoker = mock(Invoker.class);
@ -216,6 +217,114 @@ public class RpcUtilsTest {
Assertions.assertArrayEquals(types5, inv5.getReturnTypes());
}
@Test
public void testGetReturnTypesWithoutCache() throws Exception {
Class<?> demoServiceClass = DemoService.class;
String serviceName = demoServiceClass.getName();
Invoker invoker = mock(Invoker.class);
given(invoker.getUrl()).willReturn(URL.valueOf(
"test://127.0.0.1:1/org.apache.dubbo.rpc.support.DemoService?interface=org.apache.dubbo.rpc.support.DemoService"));
RpcInvocation inv = new RpcInvocation("testReturnType", serviceName, "", new Class<?>[] {String.class}, null, null, invoker, null);
inv.setReturnTypes(null);
Type[] types = RpcUtils.getReturnTypes(inv);
Assertions.assertNotNull(types);
Assertions.assertEquals(2, types.length);
Assertions.assertEquals(String.class, types[0]);
Assertions.assertEquals(String.class, types[1]);
RpcInvocation inv1 =
new RpcInvocation("testReturnType1", serviceName, "", new Class<?>[] {String.class}, null, null, invoker, null);
inv1.setReturnTypes(null);
java.lang.reflect.Type[] types1 = RpcUtils.getReturnTypes(inv1);
Assertions.assertNotNull(types1);
Assertions.assertEquals(2, types1.length);
Assertions.assertEquals(List.class, types1[0]);
Assertions.assertEquals(demoServiceClass.getMethod("testReturnType1", String.class).getGenericReturnType(), types1[1]);
RpcInvocation inv2 =
new RpcInvocation("testReturnType2", serviceName, "", new Class<?>[] {String.class}, null, null, invoker, null);
inv2.setReturnTypes(null);
java.lang.reflect.Type[] types2 = RpcUtils.getReturnTypes(inv2);
Assertions.assertNotNull(types2);
Assertions.assertEquals(2, types2.length);
Assertions.assertEquals(String.class, types2[0]);
Assertions.assertEquals(String.class, types2[1]);
RpcInvocation inv3 =
new RpcInvocation("testReturnType3", serviceName, "", new Class<?>[] {String.class}, null, null, invoker, null);
inv3.setReturnTypes(null);
java.lang.reflect.Type[] types3 = RpcUtils.getReturnTypes(inv3);
Assertions.assertNotNull(types3);
Assertions.assertEquals(2, types3.length);
Assertions.assertEquals(List.class, types3[0]);
java.lang.reflect.Type genericReturnType3 = demoServiceClass.getMethod("testReturnType3", String.class).getGenericReturnType();
Assertions.assertEquals(((ParameterizedType) genericReturnType3).getActualTypeArguments()[0], types3[1]);
RpcInvocation inv4 =
new RpcInvocation("testReturnType4", serviceName, "", new Class<?>[] {String.class}, null, null, invoker, null);
inv4.setReturnTypes(null);
java.lang.reflect.Type[] types4 = RpcUtils.getReturnTypes(inv4);
Assertions.assertNotNull(types4);
Assertions.assertEquals(2, types4.length);
Assertions.assertNull(types4[0]);
Assertions.assertNull(types4[1]);
RpcInvocation inv5 =
new RpcInvocation("testReturnType5", serviceName, "", new Class<?>[] {String.class}, null, null, invoker, null);
inv5.setReturnTypes(null);
java.lang.reflect.Type[] types5 = RpcUtils.getReturnTypes(inv5);
Assertions.assertNotNull(types5);
Assertions.assertEquals(2, types5.length);
Assertions.assertEquals(Map.class, types5[0]);
java.lang.reflect.Type genericReturnType5 = demoServiceClass.getMethod("testReturnType5", String.class).getGenericReturnType();
Assertions.assertEquals(((ParameterizedType) genericReturnType5).getActualTypeArguments()[0], types5[1]);
}
@Test
public void testGetReturnTypesWhenGeneric() throws Exception {
Class<?> demoServiceClass = DemoService.class;
String serviceName = demoServiceClass.getName();
Invoker invoker = mock(Invoker.class);
given(invoker.getUrl()).willReturn(URL.valueOf(
"test://127.0.0.1:1/org.apache.dubbo.rpc.support.DemoService?interface=org.apache.dubbo.rpc.support.DemoService"));
RpcInvocation inv = new RpcInvocation("testReturnType", serviceName, "", new Class<?>[] {String.class}, null, null, invoker, null);
inv.setMethodName($INVOKE);
Type[] types = RpcUtils.getReturnTypes(inv);
Assertions.assertNull(types);
RpcInvocation inv1 =
new RpcInvocation("testReturnType1", serviceName, "", new Class<?>[] {String.class}, null, null, invoker, null);
inv1.setMethodName($INVOKE);
java.lang.reflect.Type[] types1 = RpcUtils.getReturnTypes(inv1);
Assertions.assertNull(types1);
RpcInvocation inv2 =
new RpcInvocation("testReturnType2", serviceName, "", new Class<?>[] {String.class}, null, null, invoker, null);
inv2.setMethodName($INVOKE);
java.lang.reflect.Type[] types2 = RpcUtils.getReturnTypes(inv2);
Assertions.assertNull(types2);
RpcInvocation inv3 =
new RpcInvocation("testReturnType3", serviceName, "", new Class<?>[] {String.class}, null, null, invoker, null);
inv3.setMethodName($INVOKE);
java.lang.reflect.Type[] types3 = RpcUtils.getReturnTypes(inv3);
Assertions.assertNull(types3);
RpcInvocation inv4 =
new RpcInvocation("testReturnType4", serviceName, "", new Class<?>[] {String.class}, null, null, invoker, null);
inv4.setMethodName($INVOKE);
java.lang.reflect.Type[] types4 = RpcUtils.getReturnTypes(inv4);
Assertions.assertNull(types4);
RpcInvocation inv5 =
new RpcInvocation("testReturnType5", serviceName, "", new Class<?>[] {String.class}, null, null, invoker, null);
inv5.setMethodName($INVOKE);
java.lang.reflect.Type[] types5 = RpcUtils.getReturnTypes(inv5);
Assertions.assertNull(types5);
}
@Test
public void testGetParameterTypes() {
Class<?> demoServiceClass = DemoService.class;

View File

@ -32,7 +32,6 @@ import org.apache.dubbo.remoting.exchange.Response;
import org.apache.dubbo.remoting.transport.CodecSupport;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.support.RpcUtils;
import java.io.IOException;
@ -151,15 +150,10 @@ public class DecodeableRpcResult extends AppResponse implements Codec, Decodeabl
private void handleValue(ObjectInput in) throws IOException {
try {
Type[] returnTypes;
if (invocation instanceof RpcInvocation) {
returnTypes = ((RpcInvocation) invocation).getReturnTypes();
} else {
returnTypes = RpcUtils.getReturnTypes(invocation);
}
Type[] returnTypes = RpcUtils.getReturnTypes(invocation);
Object value;
if (ArrayUtils.isEmpty(returnTypes)) {
// This almost never happens?
// happens when generic invoke or void return
value = in.readObject();
} else if (returnTypes.length == 1) {
value = in.readObject((Class<?>) returnTypes[0]);

View File

@ -32,7 +32,6 @@ public interface ObjectInput extends DataInput {
* @throws IOException if an I/O error occurs
* @throws ClassNotFoundException if an ClassNotFoundException occurs
*/
@Deprecated
Object readObject() throws IOException, ClassNotFoundException;
/**