diff --git a/common/proxy/proxy.go b/common/proxy/proxy.go index 6c42dab8fd7173f3ba1919ca8721201d690002df..2304b1ebcea1e95fcd07b1b0927b6c4980710e19 100644 --- a/common/proxy/proxy.go +++ b/common/proxy/proxy.go @@ -54,28 +54,59 @@ func (p *Proxy) Implement(v common.RPCService) { makeDubboCallProxy := func(methodName string, outs []reflect.Type) func(in []reflect.Value) []reflect.Value { return func(in []reflect.Value) []reflect.Value { var ( - err error - inv *invocation_impl.RPCInvocation + err error + inv *invocation_impl.RPCInvocation + inArr []interface{} + reply reflect.Value ) if methodName == "Echo" { methodName = "$echo" } - if len(in) == 2 { - inv = invocation_impl.NewRPCInvocationForConsumer(methodName, nil, in[0].Interface().([]interface{}), in[1].Interface(), p.callBack, common.URL{}, nil) + + 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 outs[0].Kind() == reflect.Ptr { + reply = reflect.New(outs[0].Elem()) + } else { + reply = reflect.New(outs[0]) + } } - if len(in) == 3 { - inv = invocation_impl.NewRPCInvocationForConsumer(methodName, nil, in[1].Interface().([]interface{}), in[2].Interface(), p.callBack, common.URL{}, nil) + + if v, ok := in[start].Interface().([]interface{}); ok && end-start == 1 { + inArr = v + } else { + inArr = make([]interface{}, end-start) + index := 0 + for i := start; i < end; i++ { + inArr[index] = in[i].Interface() + index++ + } } - for k, v := range p.attachments { - inv.SetAttachments(k, v) + inv = invocation_impl.NewRPCInvocationForConsumer(methodName, nil, inArr, reply.Interface(), p.callBack, common.URL{}, nil) + + for k, value := range p.attachments { + inv.SetAttachments(k, value) } result := p.invoke.Invoke(inv) err = result.Error() - log.Info("[makeDubboCallProxy] err: %v", err) - return []reflect.Value{reflect.ValueOf(&err).Elem()} + log.Info("[makeDubboCallProxy] result: %v, err: %v", result.Result(), err) + if len(outs) == 1 { + return []reflect.Value{reflect.ValueOf(&err).Elem()} + } + if len(outs) == 2 && outs[0].Kind() != reflect.Ptr { + return []reflect.Value{reply.Elem(), reflect.ValueOf(&err).Elem()} + } + return []reflect.Value{reply, reflect.ValueOf(&err).Elem()} } } @@ -88,35 +119,31 @@ func (p *Proxy) Implement(v common.RPCService) { } f := valueOfElem.Field(i) if f.Kind() == reflect.Func && f.IsValid() && f.CanSet() { - if t.Type.NumIn() != 2 && t.Type.NumIn() != 3 { - log.Warn("method %s of mtype %v has wrong number of in parameters %d; needs exactly 3/4", - t.Name, t.Type.String(), t.Type.NumIn()) - continue - } + inNum := t.Type.NumIn() + outNum := t.Type.NumOut() - if t.Type.NumIn() == 2 && t.Type.In(1).Kind() != reflect.Ptr { - log.Warn("reply type of method %q is not a pointer %v", t.Name, t.Type.In(1)) + if outNum != 1 && outNum != 2 { + log.Warn("method %s of mtype %v has wrong number of in out parameters %d; needs exactly 1/2", + t.Name, t.Type.String(), outNum) continue } - if t.Type.NumIn() == 3 && t.Type.In(2).Kind() != reflect.Ptr { - log.Warn("reply type of method %q is not a pointer %v", t.Name, t.Type.In(2)) + // The latest return type of the method must be error. + if returnType := t.Type.Out(outNum - 1); returnType != typError { + log.Warn("the latest return type %s of method %q is not error", returnType, t.Name) continue } - // Method needs one out. - if t.Type.NumOut() != 1 { - log.Warn("method %q has %d out parameters; needs exactly 1", t.Name, t.Type.NumOut()) - continue - } - // The return type of the method must be error. - if returnType := t.Type.Out(0); returnType != typError { - log.Warn("return type %s of method %q is not error", returnType, t.Name) + // reply must be Ptr when outNum == 1 + if outNum == 1 && t.Type.In(inNum-1).Kind() != reflect.Ptr { + log.Warn("reply type of method %q is not a pointer or interface", t.Name) continue } - var funcOuts = make([]reflect.Type, t.Type.NumOut()) - funcOuts[0] = t.Type.Out(0) + var funcOuts = make([]reflect.Type, outNum) + for i := 0; i < outNum; i++ { + funcOuts[i] = t.Type.Out(i) + } // do method proxy here: f.Set(reflect.MakeFunc(f.Type(), makeDubboCallProxy(methodName, funcOuts))) diff --git a/common/proxy/proxy_test.go b/common/proxy/proxy_test.go index 8720298aa6372108f8b6ebbb6dbef707db38fecc..617502ee657d307067586e7f83e7099fca7bafcd 100644 --- a/common/proxy/proxy_test.go +++ b/common/proxy/proxy_test.go @@ -3,6 +3,7 @@ package proxy import ( "context" "errors" + "reflect" "testing" ) @@ -17,10 +18,11 @@ import ( ) type TestService struct { - MethodOne func(context.Context, []interface{}, *struct{}) error - MethodTwo func([]interface{}, *struct{}) error - MethodThree func([]interface{}, *struct{}) error `dubbo:"methodThree"` - Echo func([]interface{}, *struct{}) error + MethodOne func(context.Context, int, bool, *interface{}) error + MethodTwo func([]interface{}, *interface{}) error + MethodThree func(int, bool) (interface{}, error) + MethodFour func(int, bool) (*interface{}, error) `dubbo:"methodFour"` + Echo func(interface{}, *interface{}) error } func (s *TestService) Service() string { @@ -45,12 +47,16 @@ 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, nil, nil) + err := p.Get().(*TestService).MethodOne(nil, 0, false, nil) assert.NoError(t, err) err = p.Get().(*TestService).MethodTwo(nil, nil) assert.NoError(t, err) - err = p.Get().(*TestService).MethodThree(nil, nil) + 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) @@ -58,13 +64,13 @@ func TestProxy_Implement(t *testing.T) { p.rpc = nil type S1 struct { TestService - methodOne func(context.Context, []interface{}, *struct{}) error + methodOne func(context.Context, interface{}, *struct{}) error } - s1 := &S1{TestService: *s, methodOne: func(i context.Context, i2 []interface{}, i3 *struct{}) error { + s1 := &S1{TestService: *s, methodOne: func(i context.Context, i2 interface{}, i3 *struct{}) error { return errors.New("errors") }} p.Implement(s1) - err = s1.MethodOne(nil, nil, nil) + err = s1.MethodOne(nil, 0, false, nil) assert.NoError(t, err) err = s1.methodOne(nil, nil, nil) assert.EqualError(t, err, "errors") @@ -75,21 +81,21 @@ func TestProxy_Implement(t *testing.T) { p.Implement(&it) assert.Nil(t, p.rpc) - // args number + // return number p.rpc = nil type S2 struct { TestService - MethodOne func([]interface{}) error + MethodOne func([]interface{}) (*struct{}, int, error) } s2 := &S2{TestService: *s} p.Implement(s2) assert.Nil(t, s2.MethodOne) - // returns number + // reply type p.rpc = nil type S3 struct { TestService - MethodOne func(context.Context, []interface{}, *struct{}) (interface{}, error) + MethodOne func(context.Context, []interface{}, struct{}) error } s3 := &S3{TestService: *s} p.Implement(s3) @@ -105,23 +111,4 @@ func TestProxy_Implement(t *testing.T) { p.Implement(s4) assert.Nil(t, s4.MethodOne) - // reply type for number 3 - p.rpc = nil - type S5 struct { - TestService - MethodOne func(context.Context, []interface{}, interface{}) error - } - s5 := &S5{TestService: *s} - p.Implement(s5) - assert.Nil(t, s5.MethodOne) - - // reply type for number 2 - p.rpc = nil - type S6 struct { - TestService - MethodOne func([]interface{}, interface{}) error - } - s6 := &S6{TestService: *s} - p.Implement(s6) - assert.Nil(t, s5.MethodOne) } diff --git a/examples/dubbo/go-client/app/client.go b/examples/dubbo/go-client/app/client.go index 3632a0e723a5bf2eb2912f604f4ed6893c37a889..35f25ae9b625986b4134c4cea797c0a02640dff2 100644 --- a/examples/dubbo/go-client/app/client.go +++ b/examples/dubbo/go-client/app/client.go @@ -52,8 +52,7 @@ func main() { initProfiling() gxlog.CInfo("\n\n\necho") - res := "" - err := conMap["com.ikurento.user.UserProvider"].GetRPCService().(*UserProvider).Echo(context.TODO(), []interface{}{"OK"}, &res) + res, err := conMap["com.ikurento.user.UserProvider"].GetRPCService().(*UserProvider).Echo(context.TODO(), "OK") if err != nil { panic(err) } @@ -69,13 +68,21 @@ func main() { } gxlog.CInfo("response result: %v", user) + gxlog.CInfo("\n\n\nstart to test dubbo - GetUser0") + ret, err := conMap["com.ikurento.user.UserProvider"].GetRPCService().(*UserProvider).GetUser0(context.TODO(), "A003") + if err != nil { + panic(err) + } + gxlog.CInfo("response result: %v", ret) + gxlog.CInfo("\n\n\nstart to test dubbo - getUser") user = &User{} err = conMap["com.ikurento.user.UserProvider"].GetRPCService().(*UserProvider).GetUser2(context.TODO(), []interface{}{1}, user) if err != nil { fmt.Println("getUser - error: ", err) + } else { + gxlog.CInfo("response result: %v", user) } - gxlog.CInfo("response result: %v", user) gxlog.CInfo("\n\n\nstart to test dubbo illegal method") err = conMap["com.ikurento.user.UserProvider"].GetRPCService().(*UserProvider).GetUser1(context.TODO(), []interface{}{"A003"}, user) diff --git a/examples/dubbo/go-client/app/user.go b/examples/dubbo/go-client/app/user.go index 1dd100ce436becc03e55abf6981b5b92136b354b..be5dde2829e2722c6bf34ca567c7e7918084a625 100644 --- a/examples/dubbo/go-client/app/user.go +++ b/examples/dubbo/go-client/app/user.go @@ -77,9 +77,10 @@ func (User) JavaClassName() string { type UserProvider struct { GetUser func(ctx context.Context, req []interface{}, rsp *User) error + GetUser0 func(ctx context.Context, req interface{}) (User, error) `dubbo:"GetUser"` GetUser1 func(ctx context.Context, req []interface{}, rsp *User) error GetUser2 func(ctx context.Context, req []interface{}, rsp *User) error `dubbo:"getUser"` - Echo func(ctx context.Context, req []interface{}, rsp *string) error // Echo represent EchoFilter will be used + 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-client/app/client.go b/examples/jsonrpc/go-client/app/client.go index 5eb6babb2dd276e1bd8dc3b476a49dbf9aa3fdfc..c87fb5e79a626d2108054e9cb342ae11398f91b9 100644 --- a/examples/jsonrpc/go-client/app/client.go +++ b/examples/jsonrpc/go-client/app/client.go @@ -47,12 +47,12 @@ func main() { initProfiling() gxlog.CInfo("\n\n\necho") - res := "" - err := conMap["com.ikurento.user.UserProvider"].GetRPCService().(*UserProvider).Echo(context.TODO(), []interface{}{"OK"}, &res) + res, err := conMap["com.ikurento.user.UserProvider"].GetRPCService().(*UserProvider).Echo(context.TODO(), "OK") if err != nil { fmt.Println("echo - error: ", err) + } else { + gxlog.CInfo("res: %s", res) } - gxlog.CInfo("res: %s", res) time.Sleep(3e9) @@ -64,13 +64,21 @@ func main() { } gxlog.CInfo("response result: %v", user) + gxlog.CInfo("\n\n\nstart to test dubbo - GetUser0") + ret, err := conMap["com.ikurento.user.UserProvider"].GetRPCService().(*UserProvider).GetUser0(context.TODO(), "A003") + if err != nil { + panic(err) + } + gxlog.CInfo("response result: %v", ret) + gxlog.CInfo("\n\n\nstart to test jsonrpc - getUser") user = &JsonRPCUser{} err = conMap["com.ikurento.user.UserProvider"].GetRPCService().(*UserProvider).GetUser2(context.TODO(), []interface{}{1}, user) if err != nil { fmt.Println("getUser - error: ", err) + } else { + gxlog.CInfo("response result: %v", user) } - gxlog.CInfo("response result: %v", user) gxlog.CInfo("\n\n\nstart to test jsonrpc illegal method") err = conMap["com.ikurento.user.UserProvider"].GetRPCService().(*UserProvider).GetUser1(context.TODO(), []interface{}{"A003"}, user) diff --git a/examples/jsonrpc/go-client/app/user.go b/examples/jsonrpc/go-client/app/user.go index 20a62a010638c5813157a09a9d8186c0d81c0281..a453a06d2f76b3f54fc1139c6f3921039f5cad4f 100644 --- a/examples/jsonrpc/go-client/app/user.go +++ b/examples/jsonrpc/go-client/app/user.go @@ -31,9 +31,10 @@ func (u JsonRPCUser) String() string { type UserProvider struct { GetUser func(ctx context.Context, req []interface{}, rsp *JsonRPCUser) error + GetUser0 func(ctx context.Context, req interface{}) (*JsonRPCUser, error) `dubbo:"GetUser"` 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{}, rsp *string) error // Echo represent EchoFilter will be used + 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/java-client/src/main/java/com/ikurento/user/Consumer.java b/examples/jsonrpc/java-client/src/main/java/com/ikurento/user/Consumer.java index a9e5aaa51fe0a4bb5a3ee31b36cfb46cac5a6122..fec1597240ee351e6b53a3cb6a43a18ca33eef6e 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 @@ -47,9 +47,6 @@ public class Consumer { e.printStackTrace(); } try { - EchoService echoService = (EchoService)userProvider; - Object status = echoService.$echo("OK"); - System.out.println("echo: "+status); User user1 = userProvider.GetUser("A003"); System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] " + " UserInfo, Id:" + user1.getId() + ", name:" + user1.getName() + ", sex:" + user1.getSex().toString() diff --git a/filter/impl/echo_filter.go b/filter/impl/echo_filter.go index 3608cefd23a9c4412292ee8aadaedbbaa3a0026f..82d48701383c5c3b91b69aec780d2bc5e071d640 100644 --- a/filter/impl/echo_filter.go +++ b/filter/impl/echo_filter.go @@ -19,7 +19,7 @@ func init() { // RPCService need a Echo method in consumer, if you want to use EchoFilter // eg: -// Echo func(ctx context.Context, args []interface{}, rsp *Xxx) error +// Echo func(ctx context.Context, arg interface{}, rsp *Xxx) error type EchoFilter struct { } diff --git a/protocol/dubbo/listener.go b/protocol/dubbo/listener.go index f180ca63196ce707d4ce7f864621acf1d07511aa..21b19c0742c5a52196af40d01aa1f2cde55d66a2 100644 --- a/protocol/dubbo/listener.go +++ b/protocol/dubbo/listener.go @@ -279,30 +279,18 @@ func (h *RpcServerHandler) callService(req *DubboPackage, ctx context.Context) { } // prepare argv - var argv reflect.Value - argIsValue := false // if true, need to indirect before calling. - if method.ArgType().Kind() == reflect.Ptr { - argv = reflect.New(method.ArgType().Elem()) - } else { - argv = reflect.New(method.ArgType()) - argIsValue = true - } - argvTmp := argv.Interface() - argvTmp = req.Body.(map[string]interface{})["args"] // type is []interface - if argIsValue { - argv = argv.Elem() - } + argv := req.Body.(map[string]interface{})["args"] // type is []interface // prepare replyv replyv := reflect.New(method.ReplyType().Elem()) var returnValues []reflect.Value if method.CtxType() == nil { - returnValues = method.Method().Func.Call([]reflect.Value{svc.Rcvr(), reflect.ValueOf(argvTmp), reflect.ValueOf(replyv.Interface())}) + returnValues = method.Method().Func.Call([]reflect.Value{svc.Rcvr(), reflect.ValueOf(argv), reflect.ValueOf(replyv.Interface())}) } else { if contextv := reflect.ValueOf(ctx); contextv.IsValid() { - returnValues = method.Method().Func.Call([]reflect.Value{svc.Rcvr(), contextv, reflect.ValueOf(argvTmp), reflect.ValueOf(replyv.Interface())}) + returnValues = method.Method().Func.Call([]reflect.Value{svc.Rcvr(), contextv, reflect.ValueOf(argv), reflect.ValueOf(replyv.Interface())}) } else { - returnValues = method.Method().Func.Call([]reflect.Value{svc.Rcvr(), reflect.Zero(method.CtxType()), reflect.ValueOf(argvTmp), reflect.ValueOf(replyv.Interface())}) + returnValues = method.Method().Func.Call([]reflect.Value{svc.Rcvr(), reflect.Zero(method.CtxType()), reflect.ValueOf(argv), reflect.ValueOf(replyv.Interface())}) } } diff --git a/protocol/jsonrpc/server.go b/protocol/jsonrpc/server.go index 78c1b791e2b462fc58a9b519901b936f6f564a9d..0d625b347d076cdb514a067e68b2d78d6149f35f 100644 --- a/protocol/jsonrpc/server.go +++ b/protocol/jsonrpc/server.go @@ -345,25 +345,6 @@ func serveRequest(ctx context.Context, return jerrors.New("cannot find method " + methodName + " of svc " + serviceName) } - // get args - var argv reflect.Value - argIsValue := false - if mtype.ArgType().Kind() == reflect.Ptr { - argv = reflect.New(mtype.ArgType().Elem()) - } else { - argv = reflect.New(mtype.ArgType()) - argIsValue = true - } - // argv guaranteed to be a pointer now. - argvTmp := argv.Interface() - argvTmp = args - //if err = codec.ReadBody(argv.Interface()); err != nil { - // return jerrors.Trace(err) - //} - if argIsValue { - argv = argv.Elem() - } - replyv := reflect.New(mtype.ReplyType().Elem()) // call service.method(args) @@ -374,14 +355,14 @@ func serveRequest(ctx context.Context, if mtype.CtxType() == nil { returnValues = mtype.Method().Func.Call([]reflect.Value{ svc.Rcvr(), - reflect.ValueOf(argvTmp), + reflect.ValueOf(args), reflect.ValueOf(replyv.Interface()), }) } else { returnValues = mtype.Method().Func.Call([]reflect.Value{ svc.Rcvr(), mtype.SuiteContext(ctx), - reflect.ValueOf(argvTmp), + reflect.ValueOf(args), reflect.ValueOf(replyv.Interface()), }) }