Skip to content

Commit

Permalink
fix(codec-jackson): fix json response error when response type is gen…
Browse files Browse the repository at this point in the history
…eric type. (sofastack#921)

* fix(codec-jackson): fix json response error when response type is generic type.

* fix(style): format code

Co-authored-by: wenxiang.jin <[email protected]>
  • Loading branch information
jwx0925 and wenxiang.jin authored May 21, 2020
1 parent f8aae68 commit ed9a2fc
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class JacksonHelper {
/**
* Response service and method cache {service+method:class}
*/
private ConcurrentHashMap<String, Class> responseClassCache = new ConcurrentHashMap<String, Class>();
private ConcurrentHashMap<String, JavaType> responseClassCache = new ConcurrentHashMap<String, JavaType>();

/**
* Fetch request class for cache according service and method
Expand Down Expand Up @@ -71,10 +71,10 @@ public JavaType[] getReqClass(String service, String methodName) {
* @param methodName method name
* @return response class
*/
public Class getResClass(String service, String methodName) {
public JavaType getResClass(String service, String methodName) {
String key = service + "#" + methodName;
Class reqClass = responseClassCache.get(key);
if (reqClass == null) {
JavaType reqType = responseClassCache.get(key);
if (reqType == null) {
// 读取接口里的方法参数和返回值
String interfaceClass = ConfigUniqueNameGenerator.getInterfaceName(service);
Class clazz = ClassUtils.forName(interfaceClass, true);
Expand Down Expand Up @@ -102,30 +102,34 @@ private String buildMethodKey(String serviceName, String methodName) {
* @param methodName method name
*/
private void loadClassToCache(String key, Class clazz, String methodName) {
Method pbMethod = null;
Method jsonMethod = null;
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (methodName.equals(method.getName())) {
pbMethod = method;
jsonMethod = method;
break;
}
}
if (pbMethod == null) {
if (jsonMethod == null) {
throw new SofaRpcRuntimeException(LogCodes.getLog(LogCodes.ERROR_METHOD_NOT_FOUND, clazz.getName(),
methodName));
}
Type[] parameterTypes = pbMethod.getGenericParameterTypes();

// parse request types
Type[] parameterTypes = jsonMethod.getGenericParameterTypes();
JavaType[] javaTypes = new JavaType[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
JavaType javaType = mapper.getTypeFactory().constructType(parameterTypes[i]);
javaTypes[i] = javaType;
}

requestClassCache.put(key, javaTypes);
Class resClass = pbMethod.getReturnType();
if (resClass == void.class) {

// parse response types
Type resType = jsonMethod.getGenericReturnType();
if (resType == void.class) {
throw new SofaRpcRuntimeException(LogCodes.getLog(LogCodes.ERROR_VOID_RETURN, "jackson", clazz.getName()));
}
responseClassCache.put(key, resClass);
JavaType resJavaType = mapper.getTypeFactory().constructType(resType);
responseClassCache.put(key, resJavaType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,14 @@ private void decodeSofaResponse(AbstractByteBuf data, SofaResponse sofaResponse,
sofaResponse.setErrorMsg(errorMessage);
} else {
// according interface and method name to find paramter types
Class responseClass = jacksonHelper.getResClass(targetService, methodName);
Object pbRes = decode(data, responseClass, head);
sofaResponse.setAppResponse(pbRes);
JavaType respType = jacksonHelper.getResClass(targetService, methodName);
Object result;
try {
result = mapper.readValue(data.array(), respType);
} catch (IOException e) {
throw buildDeserializeError(e.getMessage());
}
sofaResponse.setAppResponse(result);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,33 @@ public void testSofaResponse() throws Exception {
Assert.assertEquals(response.getErrorMsg(), newResponse.getErrorMsg());
}

@Test
public void testListResponse() {
// success response
Map<String, String> head = new HashMap<String, String>();
head.put(RemotingConstants.HEAD_TARGET_SERVICE, DemoService.class.getCanonicalName() + ":1.0");
head.put(RemotingConstants.HEAD_METHOD_NAME, "say3");
head.put(RemotingConstants.HEAD_TARGET_APP, "targetApp");
head.put(RemotingConstants.RPC_TRACE_NAME + ".a", "xxx");
head.put(RemotingConstants.RPC_TRACE_NAME + ".b", "yyy");
SofaResponse response = new SofaResponse();
final DemoResponse response1 = new DemoResponse();
response1.setWord("result");

List<DemoResponse> listResponse = new ArrayList<DemoResponse>();
listResponse.add(response1);

response.setAppResponse(listResponse);

AbstractByteBuf data = serializer.encode(response, null);
SofaResponse newResponse = new SofaResponse();
serializer.decode(data, newResponse, head);
Assert.assertFalse(newResponse.isError());
Assert.assertEquals(response.getAppResponse(), newResponse.getAppResponse());
Assert.assertEquals("result", ((List<DemoResponse>) newResponse.getAppResponse()).get(0).getWord());

}

@Test
public void testMoreParameters() throws NoSuchMethodException {
SofaRequest request = buildSay2Request();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ public interface DemoService {

public DemoResponse say2(DemoRequest demoRequest, Map<String, String> ctx, int id);

public DemoResponse say3(List<DemoRequest> list);
public List<DemoResponse> say3(List<DemoRequest> list);

}

0 comments on commit ed9a2fc

Please sign in to comment.