Skip to content

Commit

Permalink
Merge pull request apache#80 from williamfeng323/feature/type-convert
Browse files Browse the repository at this point in the history
auto convert the type for dubbo call

Former-commit-id: 0106e81
Former-commit-id: 97fe405
  • Loading branch information
cityiron authored Dec 21, 2020
2 parents 95e1cd8 + 6feade6 commit 0f5cc18
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 17 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/goinggo/mapstructure v0.0.0-20140717182941-194205d9b4a9
github.com/hashicorp/consul/api v1.5.0
github.com/pkg/errors v0.9.1
github.com/spf13/cast v1.3.1
github.com/stretchr/testify v1.5.1
github.com/urfave/cli v1.22.4
go.uber.org/zap v1.15.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,8 @@ github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
Expand Down
4 changes: 4 additions & 0 deletions pkg/client/dubbo/dubbo.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/dubbogo/dubbo-go-proxy/pkg/client"
"github.com/dubbogo/dubbo-go-proxy/pkg/config"
"github.com/dubbogo/dubbo-go-proxy/pkg/logger"
"github.com/pkg/errors"
)

// TODO java class name elem
Expand Down Expand Up @@ -167,6 +168,9 @@ func (dc *Client) genericArgs(req *client.Request) ([]string, interface{}, error
// MapParams params mapping to api.
func (dc *Client) MapParams(req *client.Request) (interface{}, error) {
r := req.API.Method.IntegrationRequest
if len(r.ParamTypes) != len(r.MappingParams) {
return nil, errors.New("Numbers of param types and paramMappings are not the same")
}
var values []interface{}
for _, mappingParam := range r.MappingParams {
source, _, err := client.ParseMapSource(mappingParam.Name)
Expand Down
22 changes: 19 additions & 3 deletions pkg/client/dubbo/dubbo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,15 @@ func TestMappingParams(t *testing.T) {
MapTo: "1",
},
}
api.IntegrationRequest.ParamTypes = []string{
"string",
"int",
}
req := client.NewReq(context.TODO(), r, api)
params, err := dClient.MapParams(req)
assert.Nil(t, err)
assert.Equal(t, params.([]interface{})[0], "12345")
assert.Equal(t, params.([]interface{})[1], "19")
assert.Equal(t, params.([]interface{})[1], int32(19))

r, _ = http.NewRequest("GET", "/mock/test?id=12345&age=19", bytes.NewReader([]byte("")))
api = mock.GetMockAPI(config.MethodGet, "/mock/test")
Expand All @@ -125,12 +129,17 @@ func TestMappingParams(t *testing.T) {
MapTo: "2",
},
}
api.IntegrationRequest.ParamTypes = []string{
"string",
"int",
"string",
}
r.Header.Set("Auth", "1234567")
req = client.NewReq(context.TODO(), r, api)
params, err = dClient.MapParams(req)
assert.Nil(t, err)
assert.Equal(t, params.([]interface{})[0], "12345")
assert.Equal(t, params.([]interface{})[1], "19")
assert.Equal(t, params.([]interface{})[1], int32(19))
assert.Equal(t, params.([]interface{})[2], "1234567")

r, _ = http.NewRequest("POST", "/mock/test?id=12345&age=19", bytes.NewReader([]byte(`{"sex": "male", "name":{"firstName": "Joe", "lastName": "Biden"}}`)))
Expand All @@ -157,12 +166,19 @@ func TestMappingParams(t *testing.T) {
MapTo: "4",
},
}
api.IntegrationRequest.ParamTypes = []string{
"string",
"int",
"string",
"string",
"java.lang.String",
}
r.Header.Set("Auth", "1234567")
req = client.NewReq(context.TODO(), r, api)
params, err = dClient.MapParams(req)
assert.Nil(t, err)
assert.Equal(t, params.([]interface{})[0], "12345")
assert.Equal(t, params.([]interface{})[1], "19")
assert.Equal(t, params.([]interface{})[1], int32(19))
assert.Equal(t, params.([]interface{})[2], "1234567")
assert.Equal(t, params.([]interface{})[3], "male")
assert.Equal(t, params.([]interface{})[4], "Joe")
Expand Down
48 changes: 37 additions & 11 deletions pkg/client/dubbo/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ import (
"net/url"
"reflect"
"strconv"
"time"
)

import (
"github.com/pkg/errors"
"github.com/spf13/cast"
)

import (
Expand Down Expand Up @@ -68,9 +70,7 @@ func (qm queryStringsMapper) Map(mp config.MappingParam, c *client.Request, targ
return errors.Errorf("Query parameter %s does not exist", key)
}

setTargetWithOpt(c, option, rv, pos, qValue)

return nil
return setTargetWithOpt(c, option, rv, pos, qValue, c.API.IntegrationRequest.ParamTypes[pos])
}

type headerMapper struct{}
Expand All @@ -91,9 +91,7 @@ func (hm headerMapper) Map(mp config.MappingParam, c *client.Request, target int
return errors.Errorf("Header %s not found", key[0])
}

setTargetWithOpt(c, option, rv, pos, header)

return nil
return setTargetWithOpt(c, option, rv, pos, header, c.API.IntegrationRequest.ParamTypes[pos])
}

type bodyMapper struct{}
Expand Down Expand Up @@ -125,7 +123,9 @@ func (bm bodyMapper) Map(mp config.MappingParam, c *client.Request, target inter
json.Unmarshal(rawBody, &mapBody)
val, err := client.GetMapValue(mapBody, keys)

setTargetWithOpt(c, option, rv, pos, val)
if err := setTargetWithOpt(c, option, rv, pos, val, c.API.IntegrationRequest.ParamTypes[pos]); err != nil {
return err
}

c.IngressRequest.Body = ioutil.NopCloser(bytes.NewBuffer(rawBody))
return nil
Expand All @@ -149,9 +149,7 @@ func (um uriMapper) Map(mp config.MappingParam, c *client.Request, target interf
}
uriValues := c.API.GetURIParams(*c.IngressRequest.URL)

setTargetWithOpt(c, option, rv, pos, uriValues.Get(keys[0]))

return nil
return setTargetWithOpt(c, option, rv, pos, uriValues.Get(keys[0]), c.API.IntegrationRequest.ParamTypes[pos])
}

// validateTarget verify if the incoming target for the Map function
Expand All @@ -167,14 +165,19 @@ func validateTarget(target interface{}) (reflect.Value, error) {
return rv, nil
}

func setTargetWithOpt(req *client.Request, option client.RequestOption, rv reflect.Value, pos int, value interface{}) {
func setTargetWithOpt(req *client.Request, option client.RequestOption, rv reflect.Value, pos int, value interface{}, targetType string) error {
value, err := mapTypes(targetType, value)
if err != nil {
return err
}
if option == nil || option.Usable() {
setTarget(rv, pos, value)
}

if option != nil {
option.Action(req, value)
}
return nil
}

func setTarget(rv reflect.Value, pos int, value interface{}) {
Expand Down Expand Up @@ -215,3 +218,26 @@ func setTarget(rv reflect.Value, pos int, value interface{}) {
tempValue[pos] = value
rv.Set(reflect.ValueOf(tempValue))
}

func mapTypes(jType string, originVal interface{}) (interface{}, error) {
targetType, ok := constant.JTypeMapper[jType]
if !ok {
return nil, errors.Errorf("Invalid parameter type: %s", jType)
}
switch targetType {
case reflect.TypeOf(""):
return cast.ToStringE(originVal)
case reflect.TypeOf(int32(0)):
return cast.ToInt32E(originVal)
case reflect.TypeOf(int64(0)):
return cast.ToInt64E(originVal)
case reflect.TypeOf(float64(0)):
return cast.ToFloat64E(originVal)
case reflect.TypeOf(true):
return cast.ToBoolE(originVal)
case reflect.TypeOf(time.Time{}):
return cast.ToBoolE(originVal)
default:
return originVal, nil
}
}
53 changes: 53 additions & 0 deletions pkg/client/dubbo/mapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ func TestQueryStringsMapper(t *testing.T) {
MapTo: "jk",
},
}
api.IntegrationRequest.ParamTypes = []string{
"string",
"string",
"int",
}
req := client.NewReq(context.TODO(), r, api)

var params []interface{}
Expand All @@ -75,6 +80,10 @@ func TestQueryStringsMapper(t *testing.T) {
MapTo: "0",
},
}
api.IntegrationRequest.ParamTypes = []string{
"string",
"string",
}
req = client.NewReq(context.TODO(), r, api)
params = []interface{}{}
err = qs.Map(api.IntegrationRequest.MappingParams[0], req, &params, nil)
Expand All @@ -97,6 +106,9 @@ func TestHeaderMapper(t *testing.T) {
MapTo: "0",
},
}
api.IntegrationRequest.ParamTypes = []string{
"string",
}
hm := headerMapper{}
target := []interface{}{}
req := client.NewReq(context.TODO(), r, api)
Expand Down Expand Up @@ -127,6 +139,11 @@ func TestBodyMapper(t *testing.T) {
MapTo: "2",
},
}
api.IntegrationRequest.ParamTypes = []string{
"string",
"string",
"object",
}
bm := bodyMapper{}
target := []interface{}{}
req := client.NewReq(context.TODO(), r, api)
Expand Down Expand Up @@ -166,6 +183,12 @@ func TestURIMapper(t *testing.T) {
MapTo: "3",
},
}
api.IntegrationRequest.ParamTypes = []string{
"string",
"string",
"object",
"string",
}
um := uriMapper{}
target := []interface{}{}
req := client.NewReq(context.TODO(), r, api)
Expand All @@ -188,3 +211,33 @@ func TestValidateTarget(t *testing.T) {
_, err = validateTarget(&target2)
assert.EqualError(t, err, "Target params for dubbo backend must be *[]interface{}")
}

func TestMapType(t *testing.T) {
_, err := mapTypes("strings", 123)
assert.EqualError(t, err, "Invalid parameter type: strings")

val, err := mapTypes("string", 123)
assert.Nil(t, err)
assert.Equal(t, val, "123")
_, err = mapTypes("string", []int{123, 222})
assert.EqualError(t, err, "unable to cast []int{123, 222} of type []int to string")

val, err = mapTypes("int", "123")
assert.Nil(t, err)
assert.Equal(t, val, int32(123))
val, err = mapTypes("int", 123.6)
assert.Nil(t, err)
assert.Equal(t, val, int32(123))
_, err = mapTypes("int", "123a")
assert.EqualError(t, err, "unable to cast \"123a\" of type string to int32")

val, err = mapTypes("object", map[string]string{"abc": "123"})
assert.Nil(t, err)
assert.Equal(t, val, map[string]string{"abc": "123"})
val, err = mapTypes("object", struct{ Abc string }{Abc: "123"})
assert.Nil(t, err)
assert.Equal(t, val, struct{ Abc string }{Abc: "123"})
val, err = mapTypes("object", 123.6)
assert.Nil(t, err)
assert.Equal(t, val, 123.6)
}
43 changes: 43 additions & 0 deletions pkg/common/constant/jtypes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package constant

import (
"reflect"
"time"
)

// Object represents the java.lang.Object type
type Object interface{}

// JTypeMapper maps the java basic types to golang types
var JTypeMapper = map[string]reflect.Type{
"string": reflect.TypeOf(""),
"java.lang.String": reflect.TypeOf(""),
"char": reflect.TypeOf(""),
"short": reflect.TypeOf(int32(0)),
"int": reflect.TypeOf(int32(0)),
"long": reflect.TypeOf(int64(0)),
"float": reflect.TypeOf(float64(0)),
"double": reflect.TypeOf(float64(0)),
"boolean": reflect.TypeOf(true),
"java.util.Date": reflect.TypeOf(time.Time{}),
"date": reflect.TypeOf(time.Time{}),
"object": reflect.TypeOf([]Object{}).Elem(),
"java.lang.Object": reflect.TypeOf([]Object{}).Elem(),
}
8 changes: 5 additions & 3 deletions sample/dubbogo/proxy/api_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ resources:
required: false
integrationRequest:
requestType: dubbo
paramTypes: [ "string", "string", "string", "string", "string", "string", "string" ]
mappingParams:
- name: requestBody.values
mapTo: 0
Expand Down Expand Up @@ -69,13 +70,13 @@ resources:
required: true
integrationRequest:
requestType: dubbo
paramTypes: [ "java.lang.String" ]
mappingParams:
- name: queryStrings.name
mapTo: 0
applicationName: "UserProvider"
interface: "com.ic.user.UserProvider"
method: "GetUserByName"
paramTypes: [ "java.lang.String" ]
group: "test"
version: 1.0.0
clusterName: "test_dubbo"
Expand All @@ -88,13 +89,13 @@ resources:
# - definitionName: "userCreate"
integrationRequest:
requestType: dubbo
paramTypes: [ "object" ]
mappingParams:
- name: requestBody._all
mapTo: 0
applicationName: "UserProvider"
interface: "com.ic.user.UserProvider"
method: "CreateUser"
paramTypes: [ "com.ikurento.user.User" ]
group: "test"
version: 1.0.0
clusterName: "test_dubbo"
Expand All @@ -115,6 +116,7 @@ resources:
required: true
integrationRequest:
requestType: dubbo
paramTypes: [ "string" ]
mappingParams:
- name: queryStrings.name
mapTo: 1
Expand All @@ -135,6 +137,7 @@ resources:
requestType: http
integrationRequest:
requestType: dubbo
paramTypes: [ "string", "string", "int" ]
mappingParams:
- name: requestBody.name
mapTo: 0
Expand All @@ -145,7 +148,6 @@ resources:
applicationName: "UserProvider"
interface: "com.ic.user.UserProvider"
method: "CreateUser"
paramTypes: [ "com.ikurento.user.User" ]
group: "test"
version: 1.0.0
clusterName: "test_dubbo"
Expand Down

0 comments on commit 0f5cc18

Please sign in to comment.