Closed wsky closed 11 years ago
remoting sink design is necessarily in next version, channel property passing some protocol info that making something special for different language
about MethodReturn.Exception
public class MethodReturn implements Message {
public Object ReturnValue;
public Throwable Exception;
}
exception not friendly for cross-language,
java have it's own format:
{"Exception":{"@type":"com.taobao.top.link.LinkException","cause":{"@type":"java.lang.NullPointerException","stackTrace":[{"className":"com.taobao.top.link.remoting.JsonSerializerTest","fileName":"JsonSerializerTest.java","lineNumber":46,"methodName":"methodReturn_test","nativeMethod":false},{"className":"sun.reflect.NativeMethodAccessorImpl","lineNumber":-2,"methodName":"invoke0","nativeMethod":true},{"className":"sun.reflect.NativeMethodAccessorImpl","lineNumber":-1,"methodName":"invoke","nativeMethod":false},{"className":"sun.reflect.DelegatingMethodAccessorImpl","lineNumber":-1,"methodName":"invoke","nativeMethod":false},{"className":"java.lang.reflect.Method","lineNumber":-1,"methodName":"invoke","nativeMethod":false},{"className":"org.junit.runners.model.FrameworkMethod$1","fileName":"FrameworkMethod.java","lineNumber":44,"methodName":"runReflectiveCall","nativeMethod":false},{"className":"org.junit.internal.runners.model.ReflectiveCallable","fileName":"ReflectiveCallable.java","lineNumber":15,"methodName":"run","nativeMethod":false},{"className":"org.junit.runners.model.FrameworkMethod","fileName":"FrameworkMethod.java","lineNumber":41,"methodName":"invokeExplosively","nativeMethod":false},{"className":"org.junit.internal.runners.statements.InvokeMethod","fileName":"InvokeMethod.java","lineNumber":20,"methodName":"evaluate","nativeMethod":false},{"className":"org.junit.runners.BlockJUnit4ClassRunner","fileName":"BlockJUnit4ClassRunner.java","lineNumber":79,"methodName":"runNotIgnored","nativeMethod":false},{"className":"org.junit.runners.BlockJUnit4ClassRunner","fileName":"BlockJUnit4ClassRunner.java","lineNumber":71,"methodName":"runChild","nativeMethod":false},{"className":"org.junit.runners.BlockJUnit4ClassRunner","fileName":"BlockJUnit4ClassRunner.java","lineNumber":49,"methodName":"runChild","nativeMethod":false},{"className":"org.junit.runners.ParentRunner$3","fileName":"ParentRunner.java","lineNumber":193,"methodName":"run","nativeMethod":false},{"className":"org.junit.runners.ParentRunner$1","fileName":"ParentRunner.java","lineNumber":52,"methodName":"schedule","nativeMethod":false},{"className":"org.junit.runners.ParentRunner","fileName":"ParentRunner.java","lineNumber":191,"methodName":"runChildren","nativeMethod":false},{"className":"org.junit.runners.ParentRunner","fileName":"ParentRunner.java","lineNumber":42,"methodName":"access$000","nativeMethod":false},{"className":"org.junit.runners.ParentRunner$2","fileName":"ParentRunner.java","lineNumber":184,"methodName":"evaluate","nativeMethod":false},{"className":"org.junit.runners.ParentRunner","fileName":"ParentRunner.java","lineNumber":236,"methodName":"run","nativeMethod":false},{"className":"org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference","fileName":"JUnit4TestReference.java","lineNumber":50,"methodName":"run","nativeMethod":false},{"className":"org.eclipse.jdt.internal.junit.runner.TestExecution","fileName":"TestExecution.java","lineNumber":38,"methodName":"run","nativeMethod":false},{"className":"org.eclipse.jdt.internal.junit.runner.RemoteTestRunner","fileName":"RemoteTestRunner.java","lineNumber":467,"methodName":"runTests","nativeMethod":false},{"className":"org.eclipse.jdt.internal.junit.runner.RemoteTestRunner","fileName":"RemoteTestRunner.java","lineNumber":683,"methodName":"runTests","nativeMethod":false},{"className":"org.eclipse.jdt.internal.junit.runner.RemoteTestRunner","fileName":"RemoteTestRunner.java","lineNumber":390,"methodName":"run","nativeMethod":false},{"className":"org.eclipse.jdt.internal.junit.runner.RemoteTestRunner","fileName":"RemoteTestRunner.java","lineNumber":197,"methodName":"main","nativeMethod":false}]},"errorCode":0,"localizedMessage":"error","message":"error","stackTrace":[{"className":"com.taobao.top.link.remoting.JsonSerializerTest","fileName":"JsonSerializerTest.java","lineNumber":46,"methodName":"methodReturn_test","nativeMethod":false},{"className":"sun.reflect.NativeMethodAccessorImpl","lineNumber":-2,"methodName":"invoke0","nativeMethod":true},{"className":"sun.reflect.NativeMethodAccessorImpl","lineNumber":-1,"methodName":"invoke","nativeMethod":false},{"className":"sun.reflect.DelegatingMethodAccessorImpl","lineNumber":-1,"methodName":"invoke","nativeMethod":false},{"className":"java.lang.reflect.Method","lineNumber":-1,"methodName":"invoke","nativeMethod":false},{"className":"org.junit.runners.model.FrameworkMethod$1","fileName":"FrameworkMethod.java","lineNumber":44,"methodName":"runReflectiveCall","nativeMethod":false},{"className":"org.junit.internal.runners.model.ReflectiveCallable","fileName":"ReflectiveCallable.java","lineNumber":15,"methodName":"run","nativeMethod":false},{"className":"org.junit.runners.model.FrameworkMethod","fileName":"FrameworkMethod.java","lineNumber":41,"methodName":"invokeExplosively","nativeMethod":false},{"className":"org.junit.internal.runners.statements.InvokeMethod","fileName":"InvokeMethod.java","lineNumber":20,"methodName":"evaluate","nativeMethod":false},{"className":"org.junit.runners.BlockJUnit4ClassRunner","fileName":"BlockJUnit4ClassRunner.java","lineNumber":79,"methodName":"runNotIgnored","nativeMethod":false},{"className":"org.junit.runners.BlockJUnit4ClassRunner","fileName":"BlockJUnit4ClassRunner.java","lineNumber":71,"methodName":"runChild","nativeMethod":false},{"className":"org.junit.runners.BlockJUnit4ClassRunner","fileName":"BlockJUnit4ClassRunner.java","lineNumber":49,"methodName":"runChild","nativeMethod":false},{"className":"org.junit.runners.ParentRunner$3","fileName":"ParentRunner.java","lineNumber":193,"methodName":"run","nativeMethod":false},{"className":"org.junit.runners.ParentRunner$1","fileName":"ParentRunner.java","lineNumber":52,"methodName":"schedule","nativeMethod":false},{"className":"org.junit.runners.ParentRunner","fileName":"ParentRunner.java","lineNumber":191,"methodName":"runChildren","nativeMethod":false},{"className":"org.junit.runners.ParentRunner","fileName":"ParentRunner.java","lineNumber":42,"methodName":"access$000","nativeMethod":false},{"className":"org.junit.runners.ParentRunner$2","fileName":"ParentRunner.java","lineNumber":184,"methodName":"evaluate","nativeMethod":false},{"className":"org.junit.runners.ParentRunner","fileName":"ParentRunner.java","lineNumber":236,"methodName":"run","nativeMethod":false},{"className":"org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference","fileName":"JUnit4TestReference.java","lineNumber":50,"methodName":"run","nativeMethod":false},{"className":"org.eclipse.jdt.internal.junit.runner.TestExecution","fileName":"TestExecution.java","lineNumber":38,"methodName":"run","nativeMethod":false},{"className":"org.eclipse.jdt.internal.junit.runner.RemoteTestRunner","fileName":"RemoteTestRunner.java","lineNumber":467,"methodName":"runTests","nativeMethod":false},{"className":"org.eclipse.jdt.internal.junit.runner.RemoteTestRunner","fileName":"RemoteTestRunner.java","lineNumber":683,"methodName":"runTests","nativeMethod":false},{"className":"org.eclipse.jdt.internal.junit.runner.RemoteTestRunner","fileName":"RemoteTestRunner.java","lineNumber":390,"methodName":"run","nativeMethod":false},{"className":"org.eclipse.jdt.internal.junit.runner.RemoteTestRunner","fileName":"RemoteTestRunner.java","lineNumber":197,"methodName":"main","nativeMethod":false}]},"ReturnType":"com.taobao.top.link.remoting.MethodReturn","ReturnValue":"{\"ReturnValue\":\"abc\"}"}
but in .net or other not, so just pass error stack string, and typeless exception
following impl just works in java, maybe can hack by protocol special language, like .NET/Java
@Override
public byte[] serializeMethodReturn(MethodReturn methodReturn) throws FormatterException {
MethodReturnWrapper wrapper = new MethodReturnWrapper();
if (methodReturn.ReturnValue != null) {
wrapper.ReturnValue = JSON.toJSONString(methodReturn.ReturnValue);
wrapper.ReturnType = methodReturn.ReturnValue.getClass().getName();
}
if (methodReturn.Exception != null) {
wrapper.Exception = JSON.toJSONString(methodReturn.Exception);
wrapper.ExceptionType = methodReturn.Exception.getClass().getName();
}
return JSON.toJSONBytes(wrapper);
}
@Override
public MethodReturn deserializeMethodReturn(byte[] input) throws FormatterException {
MethodReturnWrapper wrapper = JSON.parseObject(input, MethodReturnWrapper.class);
MethodReturn methodReturn = new MethodReturn();
if (wrapper.ReturnValue != null && wrapper.ReturnType != null) {
try {
methodReturn.ReturnValue = JSON.parseObject(wrapper.ReturnValue,
Class.forName(wrapper.ReturnType, false, this.getClass().getClassLoader()));
} catch (ClassNotFoundException e) {
throw new FormatterException("parse ReturnValue error", e);
}
}
if (wrapper.Exception != null && wrapper.ExceptionType != null) {
try {
methodReturn.Exception = (Throwable) JSON.parseObject(wrapper.Exception,
Class.forName(wrapper.ExceptionType, false, this.getClass().getClassLoader()));
} catch (ClassNotFoundException e) {
throw new FormatterException("parse Exception error", e);
}
}
return methodReturn;
}
base type like int/long/... should be given a common name for cross-language, special type need thought about
private String parseTypeName(Class<?> type) {
if (String.class.equals(type))
return "string";
if (Byte.class.equals(type))
return "byte";
if (Double.class.equals(type))
return "double";
if (Float.class.equals(type))
return "float";
if (Integer.class.equals(type))
return "int";
if (Long.class.equals(type))
return "long";
if (Short.class.equals(type))
return "short";
if (Date.class.equals(type))
return "date";
if (Map.class.equals(type) || Map.class.isAssignableFrom(type))
return "map";
return type.getName();
}
private Class<?> parseType(String typeName) throws ClassNotFoundException {
if ("string".equalsIgnoreCase(typeName))
return String.class;
if ("byte".equalsIgnoreCase(typeName))
return Byte.class;
if ("double".equalsIgnoreCase(typeName))
return Double.class;
if ("float".equalsIgnoreCase(typeName))
return Float.class;
if ("int".equalsIgnoreCase(typeName))
return Integer.class;
if ("long".equalsIgnoreCase(typeName))
return Long.class;
if ("short".equalsIgnoreCase(typeName))
return Short.class;
if ("date".equalsIgnoreCase(typeName))
return Date.class;
if ("map".equalsIgnoreCase(typeName))
return HashMap.class;
return Class.forName(typeName, false, this.getClass().getClassLoader());
}
{"Args":["abc",1,1.1,1.2,1,1,1,1369015078327,{"k":"k"},{"array":["abc"],"long":0,"map":{"k":"k"},"string":"string"},["abc"]],"MethodName":"echo","MethodSignature":["","b","d","f","i","l","s","t","m","com.taobao.top.link.remoting.Entity","["],"TypeName":"serviceType","Uri":"uri"}
private String parseTypeName(Class<?> type) {
if (String.class.equals(type))
return "";
if (Byte.class.equals(type) || byte.class.equals(type))
return "b";
if (Double.class.equals(type) || double.class.equals(type))
return "d";
if (Float.class.equals(type) || float.class.equals(type))
return "f";
if (Integer.class.equals(type) || int.class.equals(type))
return "i";
if (Long.class.equals(type) || long.class.equals(type))
return "l";
if (Short.class.equals(type) || short.class.equals(type))
return "s";
if (Date.class.equals(type))
return "t";
if (Map.class.equals(type) || Map.class.isAssignableFrom(type))
return "m";
if (type.isArray())
return String.format("[%s", this.parseTypeName(type.getComponentType()));
return type.getName();
}
fastjson deserialize "null" field https://github.com/alibaba/fastjson/issues/39
impl cross-language serialization
hessian serialization also works http://hessian.caucho.com/doc/hessian-serialization.html
said, java generics was not real type, so HashMap.class did not work for json deserialize, and HashMap<Object, Object>.class was wrong
if (methodCall.MethodSignature[i].equals(HashMap.class))
methodCall.Args[i] = JSON.parseObject(
args.getJSONObject(i).toJSONString(),
new TypeReference<HashMap<Object, Object>>() {
});
else
methodCall.Args[i] = args.getObject(i, methodCall.MethodSignature[i]);
server can support deserialize HashMap<Object,Object>
c# DateTime serilize should be same as java, convert to long
need support multilanguage