diff --git a/common/proxy/proxy.go b/common/proxy/proxy.go index 44abac14398e07ac2cbc96b799cfada7e1f0ad19..96d42eb21152e64d170f50276bbce88e1bf8db69 100644 --- a/common/proxy/proxy.go +++ b/common/proxy/proxy.go @@ -81,23 +81,31 @@ func (p *Proxy) Implement(v common.RPCService) { methodName = "$echo" } - start := 0 - end := len(in) - if in[0].Type().String() == "context.Context" { - start += 1 - } - if len(outs) == 1 { - end -= 1 - reply = in[len(in)-1] - } else { + if len(outs) == 2 { if outs[0].Kind() == reflect.Ptr { reply = reflect.New(outs[0].Elem()) } else { reply = reflect.New(outs[0]) } + } else { + reply = valueOf } - if v, ok := in[start].Interface().([]interface{}); ok && end-start == 1 { + start := 0 + end := len(in) + if end > 0 { + if in[0].Type().String() == "context.Context" { + start += 1 + } + if len(outs) == 1 && in[end-1].Type().Kind() == reflect.Ptr { + end -= 1 + reply = in[len(in)-1] + } + } + + if end-start <= 0 { + inArr = []interface{}{} + } else if v, ok := in[start].Interface().([]interface{}); ok && end-start == 1 { inArr = v } else { inArr = make([]interface{}, end-start) @@ -137,7 +145,6 @@ func (p *Proxy) Implement(v common.RPCService) { } f := valueOfElem.Field(i) if f.Kind() == reflect.Func && f.IsValid() && f.CanSet() { - inNum := t.Type.NumIn() outNum := t.Type.NumOut() if outNum != 1 && outNum != 2 { @@ -152,12 +159,6 @@ func (p *Proxy) Implement(v common.RPCService) { continue } - // reply must be Ptr when outNum == 1 - if outNum == 1 && t.Type.In(inNum-1).Kind() != reflect.Ptr { - logger.Warnf("reply type of method %q is not a pointer", t.Name) - continue - } - var funcOuts = make([]reflect.Type, outNum) for i := 0; i < outNum; i++ { funcOuts[i] = t.Type.Out(i) diff --git a/common/proxy/proxy_test.go b/common/proxy/proxy_test.go index 44bdaec4b845a3a864c8637ced16ac4493fc2b80..1cc30457c3b021ec139b57fe764d6ac6b9104dbc 100644 --- a/common/proxy/proxy_test.go +++ b/common/proxy/proxy_test.go @@ -36,9 +36,10 @@ import ( type TestService struct { MethodOne func(context.Context, int, bool, *interface{}) error - MethodTwo func([]interface{}, *interface{}) error + MethodTwo func([]interface{}) error MethodThree func(int, bool) (interface{}, error) MethodFour func(int, bool) (*interface{}, error) `dubbo:"methodFour"` + MethodFive func() error Echo func(interface{}, *interface{}) error } @@ -64,19 +65,25 @@ func TestProxy_Implement(t *testing.T) { p := NewProxy(invoker, nil, map[string]string{constant.ASYNC_KEY: "false"}) s := &TestService{} p.Implement(s) + err := p.Get().(*TestService).MethodOne(nil, 0, false, nil) assert.NoError(t, err) - err = p.Get().(*TestService).MethodTwo(nil, nil) + + err = p.Get().(*TestService).MethodTwo(nil) assert.NoError(t, err) ret, err := p.Get().(*TestService).MethodThree(0, false) assert.NoError(t, err) assert.Nil(t, ret) // ret is nil, because it doesn't be injection yet + ret2, err := p.Get().(*TestService).MethodFour(0, false) assert.NoError(t, err) assert.Equal(t, "*interface {}", reflect.TypeOf(ret2).String()) err = p.Get().(*TestService).Echo(nil, nil) assert.NoError(t, err) + err = p.Get().(*TestService).MethodFive() + assert.NoError(t, err) + // inherit & lowercase p.rpc = nil type S1 struct { @@ -108,24 +115,14 @@ func TestProxy_Implement(t *testing.T) { p.Implement(s2) assert.Nil(t, s2.MethodOne) - // reply type + // returns type p.rpc = nil type S3 struct { TestService - MethodOne func(context.Context, []interface{}, struct{}) error + MethodOne func(context.Context, []interface{}, *struct{}) interface{} } s3 := &S3{TestService: *s} p.Implement(s3) assert.Nil(t, s3.MethodOne) - // returns type - p.rpc = nil - type S4 struct { - TestService - MethodOne func(context.Context, []interface{}, *struct{}) interface{} - } - s4 := &S4{TestService: *s} - p.Implement(s4) - assert.Nil(t, s4.MethodOne) - } diff --git a/common/rpc_service.go b/common/rpc_service.go index 2aaa772765e3c76b2062326fd9c6ce35dcee11a2..0444f0c17e7e9d96d1563c72fde2fd62b81fb744 100644 --- a/common/rpc_service.go +++ b/common/rpc_service.go @@ -268,12 +268,7 @@ func suiteMethod(method reflect.Method) *MethodType { } // replyType - if outNum == 1 { - if mtype.In(inNum-1).Kind() != reflect.Ptr { - logger.Errorf("reply type of method %q is not a pointer %v", mname, replyType) - return nil - } - } else { + if outNum == 2 { replyType = mtype.Out(0) if !isExportedOrBuiltinType(replyType) { logger.Errorf("reply type of method %s not exported{%v}", mname, replyType) @@ -284,7 +279,7 @@ func suiteMethod(method reflect.Method) *MethodType { index := 1 // ctxType - if mtype.In(1).String() == "context.Context" { + if inNum > 1 && mtype.In(1).String() == "context.Context" { ctxType = mtype.In(1) index = 2 } diff --git a/common/rpc_service_test.go b/common/rpc_service_test.go index 9a1e08f718d64cc740f8c6ecd7467bf494bbab9c..ec4371da4768298fe0928ba6ef88c2be7060832e 100644 --- a/common/rpc_service_test.go +++ b/common/rpc_service_test.go @@ -30,12 +30,15 @@ import ( type TestService struct { } -func (s *TestService) MethodOne(ctx context.Context, args []interface{}, rsp *struct{}) error { +func (s *TestService) MethodOne(ctx context.Context, arg1, arg2, arg3 interface{}) error { return nil } -func (s *TestService) MethodTwo(args []interface{}) (struct{}, error) { +func (s *TestService) MethodTwo(arg1, arg2, arg3 interface{}) (interface{}, error) { return struct{}{}, nil } +func (s *TestService) MethodThree() error { + return nil +} func (s *TestService) Service() string { return "com.test.Path" } @@ -54,15 +57,12 @@ type testService struct { func (s *testService) Method1(ctx context.Context, args testService, rsp *struct{}) error { return nil } -func (s *testService) Method2(ctx context.Context, args []interface{}, rsp struct{}) error { - return nil -} -func (s *testService) Method3(ctx context.Context, args []interface{}) (testService, error) { +func (s *testService) Method2(ctx context.Context, args []interface{}) (testService, error) { return testService{}, nil } -func (s *testService) Method4(ctx context.Context, args []interface{}, rsp *struct{}) { +func (s *testService) Method3(ctx context.Context, args []interface{}, rsp *struct{}) { } -func (s *testService) Method5(ctx context.Context, args []interface{}, rsp *struct{}) *testService { +func (s *testService) Method4(ctx context.Context, args []interface{}, rsp *struct{}) *testService { return nil } func (s *testService) Service() string { @@ -92,7 +92,7 @@ func TestServiceMap_Register(t *testing.T) { s := &TestService{} methods, err = ServiceMap.Register("testporotocol", s) assert.NoError(t, err) - assert.Equal(t, "MethodOne,methodTwo", methods) + assert.Equal(t, "MethodOne,MethodThree,methodTwo", methods) // repeat methods, err = ServiceMap.Register("testporotocol", s) @@ -144,10 +144,11 @@ func TestSuiteMethod(t *testing.T) { assert.True(t, ok) methodType := suiteMethod(method) method = methodType.Method() - assert.Equal(t, "func(*common.TestService, context.Context, []interface {}, *struct {}) error", method.Type.String()) + assert.Equal(t, "func(*common.TestService, context.Context, interface {}, interface {}, interface {}) error", method.Type.String()) at := methodType.ArgsType() - assert.Equal(t, "[]interface {}", at[0].String()) - assert.Equal(t, "*struct {}", at[1].String()) + assert.Equal(t, "interface {}", at[0].String()) + assert.Equal(t, "interface {}", at[1].String()) + assert.Equal(t, "interface {}", at[2].String()) ct := methodType.CtxType() assert.Equal(t, "context.Context", ct.String()) rt := methodType.ReplyType() @@ -157,12 +158,25 @@ func TestSuiteMethod(t *testing.T) { assert.True(t, ok) methodType = suiteMethod(method) method = methodType.Method() - assert.Equal(t, "func(*common.TestService, []interface {}) (struct {}, error)", method.Type.String()) + assert.Equal(t, "func(*common.TestService, interface {}, interface {}, interface {}) (interface {}, error)", method.Type.String()) + at = methodType.ArgsType() + assert.Equal(t, "interface {}", at[0].String()) + assert.Equal(t, "interface {}", at[1].String()) + assert.Equal(t, "interface {}", at[2].String()) + assert.Nil(t, methodType.CtxType()) + rt = methodType.ReplyType() + assert.Equal(t, "interface {}", rt.String()) + + method, ok = reflect.TypeOf(s).MethodByName("MethodThree") + assert.True(t, ok) + methodType = suiteMethod(method) + method = methodType.Method() + assert.Equal(t, "func(*common.TestService) error", method.Type.String()) at = methodType.ArgsType() - assert.Equal(t, "[]interface {}", at[0].String()) + assert.Equal(t, 0, len(at)) assert.Nil(t, methodType.CtxType()) rt = methodType.ReplyType() - assert.Equal(t, "struct {}", rt.String()) + assert.Nil(t, rt) // wrong number of in return s1 := &testService{} @@ -177,26 +191,20 @@ func TestSuiteMethod(t *testing.T) { methodType = suiteMethod(method) assert.Nil(t, methodType) - // replyType != Ptr - method, ok = reflect.TypeOf(s1).MethodByName("Method2") - assert.True(t, ok) - methodType = suiteMethod(method) - assert.Nil(t, methodType) - // Reply not exported - method, ok = reflect.TypeOf(s1).MethodByName("Method3") + method, ok = reflect.TypeOf(s1).MethodByName("Method2") assert.True(t, ok) methodType = suiteMethod(method) assert.Nil(t, methodType) // no return - method, ok = reflect.TypeOf(s1).MethodByName("Method4") + method, ok = reflect.TypeOf(s1).MethodByName("Method3") assert.True(t, ok) methodType = suiteMethod(method) assert.Nil(t, methodType) // return value is not error - method, ok = reflect.TypeOf(s1).MethodByName("Method5") + method, ok = reflect.TypeOf(s1).MethodByName("Method4") assert.True(t, ok) methodType = suiteMethod(method) assert.Nil(t, methodType) diff --git a/examples/dubbo/go-client/app/client.go b/examples/dubbo/go-client/app/client.go index 954717d1687055ca601fd64f63031a9841f217b8..8fea06a05b18012a0aa00ce3f0d227d8bfac97e5 100644 --- a/examples/dubbo/go-client/app/client.go +++ b/examples/dubbo/go-client/app/client.go @@ -102,6 +102,13 @@ func main() { } println("response result: %v", user) + println("\n\n\nstart to test dubbo - GetUser3") + err = userProvider.GetUser3() + if err != nil { + panic(err) + } + println("succ!") + println("\n\n\nstart to test dubbo - getErr") user = &User{} err = userProvider.GetErr(context.TODO(), []interface{}{"A003"}, user) diff --git a/examples/dubbo/go-client/app/user.go b/examples/dubbo/go-client/app/user.go index 2fd29803c8d2b1262838a4dca34a0a38cacb5884..d491c3633384ad9ee6acdb2786d383e420f26db3 100644 --- a/examples/dubbo/go-client/app/user.go +++ b/examples/dubbo/go-client/app/user.go @@ -103,7 +103,8 @@ type UserProvider struct { GetUser func(ctx context.Context, req []interface{}, rsp *User) error GetUser0 func(id string, name string) (User, error) GetUser1 func(ctx context.Context, req []interface{}, rsp *User) error - GetUser2 func(ctx context.Context, req []interface{}, rsp *User) error `dubbo:"getUser"` + GetUser2 func(ctx context.Context, req []interface{}, rsp *User) error `dubbo:"getUser"` + GetUser3 func() error Echo func(ctx context.Context, req interface{}) (interface{}, error) // Echo represent EchoFilter will be used } diff --git a/examples/dubbo/go-server/app/user.go b/examples/dubbo/go-server/app/user.go index 953c38bca2b44abe9c0c43aae4e6ce291f23ea7c..fcd9ea7b8677add705127b817799bcb4beb6dabb 100644 --- a/examples/dubbo/go-server/app/user.go +++ b/examples/dubbo/go-server/app/user.go @@ -25,12 +25,12 @@ import ( ) import ( + "github.com/dubbogo/hessian2" perrors "github.com/pkg/errors" ) import ( "github.com/apache/dubbo-go/config" - hessian "github.com/dubbogo/hessian2" ) type Gender hessian.JavaEnum @@ -130,14 +130,6 @@ func (u *UserProvider) getUser(userId string) (*User, error) { return nil, fmt.Errorf("invalid user id:%s", userId) } -func (u *UserProvider) GetUser2(ctx context.Context, req []interface{}, rsp *User) error { - var err error - - println("req:%#v", req) - rsp.Id = strconv.Itoa(int(req[0].(int32))) - return err -} - func (u *UserProvider) GetUser(ctx context.Context, req []interface{}, rsp *User) error { var ( err error @@ -153,10 +145,6 @@ func (u *UserProvider) GetUser(ctx context.Context, req []interface{}, rsp *User return err } -func (u *UserProvider) GetErr(ctx context.Context, req []interface{}, rsp *User) error { - return hessian.NewThrowable("exception") -} - func (u *UserProvider) GetUser0(id string, name string) (User, error) { var err error @@ -171,6 +159,22 @@ func (u *UserProvider) GetUser0(id string, name string) (User, error) { return *user, err } +func (u *UserProvider) GetUser2(ctx context.Context, req []interface{}, rsp *User) error { + var err error + + println("req:%#v", req) + rsp.Id = strconv.Itoa(int(req[0].(int32))) + return err +} + +func (u *UserProvider) GetUser3() error { + return nil +} + +func (u *UserProvider) GetErr(ctx context.Context, req []interface{}, rsp *User) error { + return hessian.NewThrowable("exception") +} + func (u *UserProvider) GetUsers(req []interface{}) ([]interface{}, error) { var err error diff --git a/examples/dubbo/java-client/src/main/java/com/ikurento/user/Consumer.java b/examples/dubbo/java-client/src/main/java/com/ikurento/user/Consumer.java index 98fa6bdc216ca3cc36a9a3ba63d301b3bab951a4..edf4c0d2b20a08c17241132cd03bf16a51b2fbb8 100644 --- a/examples/dubbo/java-client/src/main/java/com/ikurento/user/Consumer.java +++ b/examples/dubbo/java-client/src/main/java/com/ikurento/user/Consumer.java @@ -55,6 +55,8 @@ public class Consumer { System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] " + " UserInfo, Id:" + user3.getId() + ", name:" + user3.getName() + ", sex:" + user3.getSex().toString() + ", age:" + user3.getAge() + ", time:" + user3.getTime().toString()); + userProvider.GetUser3(); + System.out.println("GetUser3 succ"); User user9 = userProvider.GetUser1("A003"); } catch (Exception e) { diff --git a/examples/dubbo/java-client/src/main/java/com/ikurento/user/UserProvider.java b/examples/dubbo/java-client/src/main/java/com/ikurento/user/UserProvider.java index c7cca9229906111e269de9cd4cd972dc059d7e85..ed765d4c0c6b6b9b382666b29d90c9dd25206f8d 100644 --- a/examples/dubbo/java-client/src/main/java/com/ikurento/user/UserProvider.java +++ b/examples/dubbo/java-client/src/main/java/com/ikurento/user/UserProvider.java @@ -23,7 +23,7 @@ public interface UserProvider { User GetErr(String userId) throws Exception; User GetUser1(String userId); User getUser(int usercode); - + void GetUser3(); List<User> GetUsers(List<String> userIdList); User GetUser0(String userId, String name); } diff --git a/examples/dubbo/java-server/src/main/java/com/ikurento/user/UserProvider.java b/examples/dubbo/java-server/src/main/java/com/ikurento/user/UserProvider.java index bb1d9a9d42444b1782d919c6a62ac2fc60e509b1..24567d23be662312a4750f07b605c685a8dfa5fe 100644 --- a/examples/dubbo/java-server/src/main/java/com/ikurento/user/UserProvider.java +++ b/examples/dubbo/java-server/src/main/java/com/ikurento/user/UserProvider.java @@ -12,6 +12,8 @@ public interface UserProvider { List<User> GetUsers(List<String> userIdList); + void GetUser3(); + User GetUser0(String userId, String name); User GetErr(String userId) throws Exception; diff --git a/examples/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java b/examples/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java index 9eaf989a8204be5a7b0065b23dfec88eff837854..d600545c5084a40f1318e47a6a1c20bfcd6d36bc 100644 --- a/examples/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java +++ b/examples/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java @@ -35,6 +35,8 @@ public class UserProviderAnotherImpl implements UserProvider { public User GetUser0(String userId, String name) { return new User(userId, name, 48); } + public void GetUser3() { + } public User GetErr(String userId) throws Exception { throw new Exception("exception"); } diff --git a/examples/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java b/examples/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java index f8875651096ef719182eb0eeffb779de16425702..47a4e2d9732aa8d8d9279d47af5bb4fb3db37195 100644 --- a/examples/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java +++ b/examples/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java @@ -56,6 +56,9 @@ public class UserProviderImpl implements UserProvider { return userList; } + public void GetUser3() { + } + public Map<String, User> GetUserMap(List<String> userIdList) { Iterator it = userIdList.iterator(); Map<String, User> map = new HashMap<String, User>(); diff --git a/examples/jsonrpc/go-client/app/client.go b/examples/jsonrpc/go-client/app/client.go index ec8bc6dd62ed77d9daf1ecb0b1a18e79ce4916c1..4c7b5146f9682867e50549d6dfa419f430c5c558 100644 --- a/examples/jsonrpc/go-client/app/client.go +++ b/examples/jsonrpc/go-client/app/client.go @@ -94,6 +94,13 @@ func main() { } println("response result: %v", user) + println("\n\n\nstart to test jsonrpc - GetUser3") + err = userProvider.GetUser3() + if err != nil { + panic(err) + } + println("succ!") + println("\n\n\nstart to test jsonrpc illegal method") err = userProvider.GetUser1(context.TODO(), []interface{}{"A003"}, user) if err != nil { diff --git a/examples/jsonrpc/go-client/app/user.go b/examples/jsonrpc/go-client/app/user.go index b6c1a2feaccaca027ed57eb0f0a934fac0d560f6..ca98b1af0b3c1379c73623162546db9fb4fc95d6 100644 --- a/examples/jsonrpc/go-client/app/user.go +++ b/examples/jsonrpc/go-client/app/user.go @@ -54,7 +54,8 @@ type UserProvider struct { GetUser0 func(id string, name string) (JsonRPCUser, error) GetUser1 func(ctx context.Context, req []interface{}, rsp *JsonRPCUser) error GetUser2 func(ctx context.Context, req []interface{}, rsp *JsonRPCUser) error `dubbo:"getUser"` - Echo func(ctx context.Context, req interface{}) (interface{}, error) // Echo represent EchoFilter will be used + GetUser3 func() error + Echo func(ctx context.Context, req interface{}) (interface{}, error) // Echo represent EchoFilter will be used } func (u *UserProvider) Service() string { diff --git a/examples/jsonrpc/go-server/app/user.go b/examples/jsonrpc/go-server/app/user.go index c0beb31d17f12185b687b073b2db8d831ad93edc..e86d915417cc54b05faa25ebaa06dae2c5fb6dd1 100644 --- a/examples/jsonrpc/go-server/app/user.go +++ b/examples/jsonrpc/go-server/app/user.go @@ -137,6 +137,10 @@ func (u *UserProvider) GetUser2(ctx context.Context, req []interface{}, rsp *Use return err } +func (u *UserProvider) GetUser3() error { + return nil +} + func (u *UserProvider) GetUsers(req []interface{}) ([]User, error) { var err error diff --git a/examples/jsonrpc/java-client/src/main/java/com/ikurento/user/Consumer.java b/examples/jsonrpc/java-client/src/main/java/com/ikurento/user/Consumer.java index f8847fe0287e0ce24a7d70b83c646c6df92fdd2f..ddf899aa10979d65f9c88bc0b79ccbb065812417 100644 --- a/examples/jsonrpc/java-client/src/main/java/com/ikurento/user/Consumer.java +++ b/examples/jsonrpc/java-client/src/main/java/com/ikurento/user/Consumer.java @@ -59,6 +59,9 @@ public class Consumer { System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] " + " UserInfo, Id:" + user3.getId() + ", name:" + user3.getName() + ", sex:" + user3.getSex().toString() + ", age:" + user3.getAge() + ", time:" + user3.getTime().toString()); + + userProvider.GetUser3(); + System.out.println("GetUser3 succ"); } catch (Exception e) { e.printStackTrace(); } diff --git a/examples/jsonrpc/java-client/src/main/java/com/ikurento/user/UserProvider.java b/examples/jsonrpc/java-client/src/main/java/com/ikurento/user/UserProvider.java index 255283cadb99717b8571fdd3776c1414ed5232df..93e7aadf02a869163f41a8f3dda84d2ebf18a475 100644 --- a/examples/jsonrpc/java-client/src/main/java/com/ikurento/user/UserProvider.java +++ b/examples/jsonrpc/java-client/src/main/java/com/ikurento/user/UserProvider.java @@ -21,7 +21,7 @@ import java.util.List; public interface UserProvider { User GetUser(String userId); User getUser(int usercode); - + void GetUser3(); List<User> GetUsers(List<String> userIdList); User GetUser0(String userId, String name); } diff --git a/examples/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProvider.java b/examples/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProvider.java index b75740bbcd26a6438d22f7d3bf08fa5e316f7aa7..a74b2222018988e13b29f5d3b74cee00815ec40e 100644 --- a/examples/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProvider.java +++ b/examples/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProvider.java @@ -14,6 +14,8 @@ public interface UserProvider { User GetUser0(String userId, String name); + void GetUser3(); + Map<String, User> GetUserMap(List<String> userIdList); User getUser(int usercode); diff --git a/examples/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java b/examples/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java index 157253575b9e5e75dadaaeaffa1e256374fefa5d..753a6f89a5f60e0f4884711d4c3b79e52ed2f094 100644 --- a/examples/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java +++ b/examples/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java @@ -32,9 +32,12 @@ public class UserProviderAnotherImpl implements UserProvider { return new User(userId, "Joe", 48); } - public User GetUser0(String userId, String name) { - return new User(userId, name, 48); - } + public User GetUser0(String userId, String name) { + return new User(userId, name, 48); + } + + public void GetUser3() { + } public List<User> GetUsers(ArrayList<String> userIdList) { Iterator it = userIdList.iterator(); diff --git a/examples/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java b/examples/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java index 25e97dd1c4482f2ff6ae7acb1ecb01a5ed66b328..960c678cf76cf4bafb3de9d5ce2a587b61aa1bac 100644 --- a/examples/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java +++ b/examples/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java @@ -78,7 +78,8 @@ public class UserProviderImpl implements UserProvider { public Map<String, User> queryAll() { return userMap; } - + public void GetUser3() { + } public User getUser(int userCode) { return new User(String.valueOf(userCode), "userCode get", 48); diff --git a/protocol/dubbo/client_test.go b/protocol/dubbo/client_test.go index 14982c6f123101ea9581542790c74bfc999437b5..4c36c44904a77085d31af1c2c9c6b8d7a4083120 100644 --- a/protocol/dubbo/client_test.go +++ b/protocol/dubbo/client_test.go @@ -36,17 +36,6 @@ import ( "github.com/apache/dubbo-go/protocol" ) -type ( - User struct { - Id string `json:"id"` - Name string `json:"name"` - } - - UserProvider struct { - user map[string]User - } -) - func TestClient_CallOneway(t *testing.T) { proto, url := InitTest(t) @@ -74,7 +63,7 @@ func TestClient_Call(t *testing.T) { c.pool = newGettyRPCClientConnPool(c, clientConf.PoolSize, time.Duration(int(time.Second)*clientConf.PoolTTL)) user := &User{} - err := c.Call("127.0.0.1:20000", url, "GetBigPkg", []interface{}{}, user) + err := c.Call("127.0.0.1:20000", url, "GetBigPkg", []interface{}{nil}, user) assert.NoError(t, err) assert.NotEqual(t, "", user.Id) assert.NotEqual(t, "", user.Name) @@ -85,30 +74,42 @@ func TestClient_Call(t *testing.T) { assert.Equal(t, User{Id: "1", Name: "username"}, *user) user = &User{} - err = c.Call("127.0.0.1:20000", url, "GetUser0", []interface{}{"1", "username"}, user) + err = c.Call("127.0.0.1:20000", url, "GetUser0", []interface{}{"1", nil, "username"}, user) assert.NoError(t, err) assert.Equal(t, User{Id: "1", Name: "username"}, *user) - user = &User{} - err = c.Call("127.0.0.1:20000", url, "GetUser1", []interface{}{"1", "username"}, user) + err = c.Call("127.0.0.1:20000", url, "GetUser1", []interface{}{}, user) + assert.NoError(t, err) + + err = c.Call("127.0.0.1:20000", url, "GetUser2", []interface{}{}, user) assert.EqualError(t, err, "got exception: error") user2 := []interface{}{} - err = c.Call("127.0.0.1:20000", url, "GetUser2", []interface{}{"1", "username"}, &user2) + err = c.Call("127.0.0.1:20000", url, "GetUser3", []interface{}{}, &user2) assert.NoError(t, err) assert.Equal(t, &User{Id: "1", Name: "username"}, user2[0]) user2 = []interface{}{} - err = c.Call("127.0.0.1:20000", url, "GetUser3", []interface{}{[]interface{}{"1", "username"}}, &user2) + err = c.Call("127.0.0.1:20000", url, "GetUser4", []interface{}{[]interface{}{"1", "username"}}, &user2) assert.NoError(t, err) assert.Equal(t, &User{Id: "1", Name: "username"}, user2[0]) user3 := map[interface{}]interface{}{} - err = c.Call("127.0.0.1:20000", url, "GetUser4", []interface{}{map[interface{}]interface{}{"id": "1", "name": "username"}}, &user3) + err = c.Call("127.0.0.1:20000", url, "GetUser5", []interface{}{map[interface{}]interface{}{"id": "1", "name": "username"}}, &user3) assert.NoError(t, err) assert.NotNil(t, user3) assert.Equal(t, &User{Id: "1", Name: "username"}, user3["key"]) + user = &User{} + err = c.Call("127.0.0.1:20000", url, "GetUser6", []interface{}{0}, user) + assert.NoError(t, err) + assert.Equal(t, User{Id: "", Name: ""}, *user) + + user = &User{} + err = c.Call("127.0.0.1:20000", url, "GetUser6", []interface{}{1}, user) + assert.NoError(t, err) + assert.Equal(t, User{Id: "1", Name: ""}, *user) + // destroy proto.Destroy() } @@ -144,7 +145,7 @@ func InitTest(t *testing.T) (protocol.Protocol, common.URL) { methods, err := common.ServiceMap.Register("dubbo", &UserProvider{}) assert.NoError(t, err) - assert.Equal(t, "GetBigPkg,GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4", methods) + assert.Equal(t, "GetBigPkg,GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4,GetUser5,GetUser6", methods) // config SetClientConf(ClientConfig{ @@ -207,6 +208,21 @@ func InitTest(t *testing.T) (protocol.Protocol, common.URL) { return proto, url } +////////////////////////////////// +// provider +////////////////////////////////// + +type ( + User struct { + Id string `json:"id"` + Name string `json:"name"` + } + + UserProvider struct { + user map[string]User + } +) + // size:4801228 func (u *UserProvider) GetBigPkg(ctx context.Context, req []interface{}, rsp *User) error { argBuf := new(bytes.Buffer) @@ -225,28 +241,39 @@ func (u *UserProvider) GetUser(ctx context.Context, req []interface{}, rsp *User return nil } -func (u *UserProvider) GetUser0(id string, name string) (User, error) { +func (u *UserProvider) GetUser0(id string, k *User, name string) (User, error) { return User{Id: id, Name: name}, nil } -func (u *UserProvider) GetUser1(ctx context.Context, req []interface{}, rsp *User) error { +func (u *UserProvider) GetUser1() error { + return nil +} + +func (u *UserProvider) GetUser2() error { return perrors.New("error") } -func (u *UserProvider) GetUser2(ctx context.Context, req []interface{}, rsp *[]interface{}) error { - *rsp = append(*rsp, User{Id: req[0].(string), Name: req[1].(string)}) +func (u *UserProvider) GetUser3(rsp *[]interface{}) error { + *rsp = append(*rsp, User{Id: "1", Name: "username"}) return nil } -func (u *UserProvider) GetUser3(ctx context.Context, req []interface{}) ([]interface{}, error) { +func (u *UserProvider) GetUser4(ctx context.Context, req []interface{}) ([]interface{}, error) { return []interface{}{User{Id: req[0].([]interface{})[0].(string), Name: req[0].([]interface{})[1].(string)}}, nil } -func (u *UserProvider) GetUser4(ctx context.Context, req []interface{}) (map[interface{}]interface{}, error) { +func (u *UserProvider) GetUser5(ctx context.Context, req []interface{}) (map[interface{}]interface{}, error) { return map[interface{}]interface{}{"key": User{Id: req[0].(map[interface{}]interface{})["id"].(string), Name: req[0].(map[interface{}]interface{})["name"].(string)}}, nil } +func (u *UserProvider) GetUser6(id int64) (*User, error) { + if id == 0 { + return nil, nil + } + return &User{Id: "1"}, nil +} + func (u *UserProvider) Service() string { return "com.ikurento.user.UserProvider" } diff --git a/protocol/dubbo/listener.go b/protocol/dubbo/listener.go index b2ac981c19365d0b300b219d1377b83286da241b..e1bfc699163171f5f3e1c51d3eb0e283a9e7922c 100644 --- a/protocol/dubbo/listener.go +++ b/protocol/dubbo/listener.go @@ -268,7 +268,7 @@ func (h *RpcServerHandler) callService(req *DubboPackage, ctx context.Context) { if e := recover(); e != nil { req.Header.ResponseStatus = hessian.Response_SERVER_ERROR if err, ok := e.(error); ok { - logger.Errorf("callService panic: %+v", err) + logger.Errorf("callService panic: %+v", perrors.WithStack(err)) req.Body = perrors.WithStack(err) } else if err, ok := e.(string); ok { logger.Errorf("callService panic: %+v", perrors.New(err)) @@ -307,13 +307,21 @@ func (h *RpcServerHandler) callService(req *DubboPackage, ctx context.Context) { in = append(in, reflect.ValueOf(argv)) } else { for i := 0; i < len(argv.([]interface{})); i++ { - in = append(in, reflect.ValueOf(argv.([]interface{})[i])) + t := reflect.ValueOf(argv.([]interface{})[i]) + if !t.IsValid() { + at := method.ArgsType()[i] + if at.Kind() == reflect.Ptr { + at = at.Elem() + } + t = reflect.New(at) + } + in = append(in, t) } } // prepare replyv var replyv reflect.Value - if method.ReplyType() == nil { + if method.ReplyType() == nil && len(method.ArgsType()) > 0 { replyv = reflect.New(method.ArgsType()[len(method.ArgsType())-1].Elem()) in = append(in, replyv) } @@ -331,7 +339,11 @@ func (h *RpcServerHandler) callService(req *DubboPackage, ctx context.Context) { req.Header.ResponseStatus = hessian.Response_OK req.Body = retErr } else { - req.Body = replyv.Interface() + if replyv.IsValid() && (replyv.Kind() != reflect.Ptr || replyv.Kind() == reflect.Ptr && replyv.Elem().IsValid()) { + req.Body = replyv.Interface() + } else { + req.Body = nil + } } } diff --git a/protocol/jsonrpc/http_test.go b/protocol/jsonrpc/http_test.go index 3f6f983702360b9c3036c943b0651e5c935376e3..f05f47b8c1b571846335852503bb2c3a5a8c5a8d 100644 --- a/protocol/jsonrpc/http_test.go +++ b/protocol/jsonrpc/http_test.go @@ -50,7 +50,7 @@ func TestHTTPClient_Call(t *testing.T) { methods, err := common.ServiceMap.Register("jsonrpc", &UserProvider{}) assert.NoError(t, err) - assert.Equal(t, "GetUser,GetUser0,GetUser1,GetUser2,GetUser3", methods) + assert.Equal(t, "GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4", methods) // Export proto := GetProtocol() @@ -82,9 +82,9 @@ func TestHTTPClient_Call(t *testing.T) { ctx = context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{ "X-Proxy-Id": "dubbogo", "X-Services": url.Path, - "X-Method": "GetUser", + "X-Method": "GetUser0", }) - req = client.NewRequest(url, "GetUser0", []interface{}{"1", "username"}) + req = client.NewRequest(url, "GetUser0", []interface{}{"1", nil, "username"}) reply = &User{} err = client.Call(ctx, url, req, reply) assert.NoError(t, err) @@ -97,7 +97,7 @@ func TestHTTPClient_Call(t *testing.T) { "X-Services": url.Path, "X-Method": "GetUser1", }) - req = client.NewRequest(url, "GetUser1", []interface{}{""}) + req = client.NewRequest(url, "GetUser1", []interface{}{}) reply = &User{} err = client.Call(ctx, url, req, reply) assert.True(t, strings.Contains(err.Error(), "500 Internal Server Error")) @@ -107,7 +107,7 @@ func TestHTTPClient_Call(t *testing.T) { ctx = context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{ "X-Proxy-Id": "dubbogo", "X-Services": url.Path, - "X-Method": "GetUser", + "X-Method": "GetUser2", }) req = client.NewRequest(url, "GetUser2", []interface{}{"1", "username"}) reply1 := []User{} @@ -119,7 +119,7 @@ func TestHTTPClient_Call(t *testing.T) { ctx = context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{ "X-Proxy-Id": "dubbogo", "X-Services": url.Path, - "X-Method": "GetUser", + "X-Method": "GetUser3", }) req = client.NewRequest(url, "GetUser3", []interface{}{"1", "username"}) reply1 = []User{} @@ -127,6 +127,29 @@ func TestHTTPClient_Call(t *testing.T) { assert.NoError(t, err) assert.Equal(t, User{Id: "1", Name: "username"}, reply1[0]) + // call GetUser4 + ctx = context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{ + "X-Proxy-Id": "dubbogo", + "X-Services": url.Path, + "X-Method": "GetUser4", + }) + req = client.NewRequest(url, "GetUser4", []interface{}{0}) + reply = &User{} + err = client.Call(ctx, url, req, reply) + assert.NoError(t, err) + assert.Equal(t, &User{Id: "", Name: ""}, reply) + + ctx = context.WithValue(context.Background(), constant.DUBBOGO_CTX_KEY, map[string]string{ + "X-Proxy-Id": "dubbogo", + "X-Services": url.Path, + "X-Method": "GetUser4", + }) + req = client.NewRequest(url, "GetUser4", []interface{}{1}) + reply = &User{} + err = client.Call(ctx, url, req, reply) + assert.NoError(t, err) + assert.Equal(t, &User{Id: "1", Name: ""}, reply) + // destroy proto.Destroy() @@ -138,11 +161,11 @@ func (u *UserProvider) GetUser(ctx context.Context, req []interface{}, rsp *User return nil } -func (u *UserProvider) GetUser0(id string, name string) (User, error) { +func (u *UserProvider) GetUser0(id string, k *User, name string) (User, error) { return User{Id: id, Name: name}, nil } -func (u *UserProvider) GetUser1(ctx context.Context, req []interface{}, rsp *User) error { +func (u *UserProvider) GetUser1() error { return perrors.New("error") } @@ -155,6 +178,13 @@ func (u *UserProvider) GetUser3(ctx context.Context, req []interface{}) ([]User, return []User{{Id: req[0].(string), Name: req[1].(string)}}, nil } +func (u *UserProvider) GetUser4(id float64) (*User, error) { + if id == 0 { + return nil, nil + } + return &User{Id: "1"}, nil +} + func (u *UserProvider) Service() string { return "com.ikurento.user.UserProvider" } diff --git a/protocol/jsonrpc/json.go b/protocol/jsonrpc/json.go index c147f9add85041b3dfaf1c9463813c560f9238d0..7ee454e8ad16d2ee96ed08e7e5f55b2209a81054 100644 --- a/protocol/jsonrpc/json.go +++ b/protocol/jsonrpc/json.go @@ -192,6 +192,9 @@ func (c *jsonClientCodec) Read(streamBytes []byte, x interface{}) error { return perrors.New(c.rsp.Error.Error()) } + if c.rsp.Result == nil { + return nil + } return perrors.WithStack(json.Unmarshal(*c.rsp.Result, x)) } diff --git a/protocol/jsonrpc/jsonrpc_invoker_test.go b/protocol/jsonrpc/jsonrpc_invoker_test.go index 9641fb532148bc78562755ea4c55696142278951..0dd427eb69127317d646c599506dc476f2859a3f 100644 --- a/protocol/jsonrpc/jsonrpc_invoker_test.go +++ b/protocol/jsonrpc/jsonrpc_invoker_test.go @@ -37,7 +37,7 @@ func TestJsonrpcInvoker_Invoke(t *testing.T) { methods, err := common.ServiceMap.Register("jsonrpc", &UserProvider{}) assert.NoError(t, err) - assert.Equal(t, "GetUser,GetUser0,GetUser1,GetUser2,GetUser3", methods) + assert.Equal(t, "GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4", methods) // Export proto := GetProtocol() diff --git a/protocol/jsonrpc/server.go b/protocol/jsonrpc/server.go index a7643dc215e8ae1ef5f7e5b02236f881b0f963c9..c5083a61fdb4b1d4026acb2f8af12ade4f9310e3 100644 --- a/protocol/jsonrpc/server.go +++ b/protocol/jsonrpc/server.go @@ -317,7 +317,7 @@ func serveRequest(ctx context.Context, } // read body - var args interface{} + var args []interface{} if err = codec.ReadBody(&args); err != nil { return perrors.WithStack(err) } @@ -326,7 +326,7 @@ func serveRequest(ctx context.Context, // exporter invoke invoker := exporter.GetInvoker() if invoker != nil { - result := invoker.Invoke(invocation.NewRPCInvocationForProvider(methodName, args.([]interface{}), map[string]string{ + result := invoker.Invoke(invocation.NewRPCInvocationForProvider(methodName, args, map[string]string{ //attachments[constant.PATH_KEY] = url.Path //attachments[constant.GROUP_KEY] = url.GetParam(constant.GROUP_KEY, "") //attachments[constant.INTERFACE_KEY] = url.GetParam(constant.INTERFACE_KEY, "") @@ -371,14 +371,22 @@ func serveRequest(ctx context.Context, if (len(method.ArgsType()) == 1 || len(method.ArgsType()) == 2 && method.ReplyType() == nil) && method.ArgsType()[0].String() == "[]interface {}" { in = append(in, reflect.ValueOf(args)) } else { - for i := 0; i < len(args.([]interface{})); i++ { - in = append(in, reflect.ValueOf(args.([]interface{})[i])) + for i := 0; i < len(args); i++ { + t := reflect.ValueOf(args[i]) + if !t.IsValid() { + at := method.ArgsType()[i] + if at.Kind() == reflect.Ptr { + at = at.Elem() + } + t = reflect.New(at) + } + in = append(in, t) } } // prepare replyv var replyv reflect.Value - if method.ReplyType() == nil { + if method.ReplyType() == nil && len(method.ArgsType()) > 0 { replyv = reflect.New(method.ArgsType()[len(method.ArgsType())-1].Elem()) in = append(in, replyv) } @@ -401,7 +409,10 @@ func serveRequest(ctx context.Context, // write response code := 200 - rspReply := replyv.Interface() + var rspReply interface{} + if replyv.IsValid() && (replyv.Kind() != reflect.Ptr || replyv.Kind() == reflect.Ptr && replyv.Elem().IsValid()) { + rspReply = replyv.Interface() + } if len(errMsg) != 0 { code = 500 rspReply = invalidRequest