Skip to content

Commit

Permalink
Ftr: add json generalizer (#1343)
Browse files Browse the repository at this point in the history
* Ftr: add json generalizer

Fix: go fmt

* Fix: hessian pojo

* fix: restart ci

* Fix: imports format
  • Loading branch information
EnableAsync committed Jul 28, 2021
1 parent dd517d6 commit 103cf14
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 0 deletions.
1 change: 1 addition & 0 deletions common/constant/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,4 +314,5 @@ const (
GenericSerializationDefault = "true"
// disable "protobuf-json" temporarily
//GenericSerializationProtobuf = "protobuf-json"
GenericSerializationGson = "gson"
)
99 changes: 99 additions & 0 deletions filter/generic/generalizer/gson.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* 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 generalizer

import (
"encoding/json"
"reflect"
"sync"
)

import (
hessian "github.com/apache/dubbo-go-hessian2"
perrors "github.com/pkg/errors"
)

import (
"dubbo.apache.org/dubbo-go/v3/common/logger"
"dubbo.apache.org/dubbo-go/v3/protocol/dubbo/hessian2"
)

var (
jsonGeneralizer Generalizer
jsonGeneralizerOnce sync.Once
)

func GetGsonGeneralizer() Generalizer {
jsonGeneralizerOnce.Do(func() {
jsonGeneralizer = &GsonGeneralizer{}
})
return jsonGeneralizer
}

type GsonGeneralizer struct{}

func (GsonGeneralizer) Generalize(obj interface{}) (interface{}, error) {
newObj, ok := obj.(hessian.POJO)
if !ok {
return nil, perrors.Errorf("unexpected type of obj(=%T), wanted is hessian pojo", obj)
}

jsonbytes, err := json.Marshal(newObj)
if err != nil {
return nil, err
}

return string(jsonbytes), nil
}

func (GsonGeneralizer) Realize(obj interface{}, typ reflect.Type) (interface{}, error) {
jsonbytes, ok := obj.(string)
if !ok {
return nil, perrors.Errorf("unexpected type of obj(=%T), wanted is string", obj)
}

// create the target object
ret, ok := reflect.New(typ).Interface().(hessian.POJO)
if !ok {
return nil, perrors.Errorf("the type of obj(=%s) should be hessian pojo", typ)
}

err := json.Unmarshal([]byte(jsonbytes), ret)
if err != nil {
return nil, err
}

return ret, nil
}

func (GsonGeneralizer) GetType(obj interface{}) (typ string, err error) {
typ, err = hessian2.GetJavaName(obj)
// no error or error is not NilError
if err == nil || err != hessian2.NilError {
return
}

typ = "java.lang.Object"
if err == hessian2.NilError {
logger.Debugf("the type of nil object couldn't be inferred, use the default value(\"%s\")", typ)
return
}

logger.Debugf("the type of object(=%T) couldn't be recognized as a POJO, use the default value(\"%s\")", obj, typ)
return
}
97 changes: 97 additions & 0 deletions filter/generic/generalizer/gson_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* 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 generalizer

import (
"reflect"
"testing"
)

import (
"github.com/stretchr/testify/assert"
)

var mockGsonGeneralizer = GetGsonGeneralizer()

type mockGsonParent struct {
Gender, Email, Name string
Age int
Child *mockGsonChild
}

func (p mockGsonParent) JavaClassName() string {
return "org.apache.dubbo.mockGsonParent"
}

type mockGsonChild struct {
Gender, Email, Name string
Age int
}

func (p mockGsonChild) JavaClassName() string {
return "org.apache.dubbo.mockGsonChild"
}

func TestGsonGeneralizer(t *testing.T) {
c := &mockGsonChild{
Age: 20,
Gender: "male",
Email: "childName@example.com",
Name: "childName",
}
p := mockGsonParent{
Age: 30,
Gender: "male",
Email: "enableasync@example.com",
Name: "enableasync",
Child: c,
}

m, err := mockGsonGeneralizer.Generalize(p)
assert.Nil(t, err)
assert.Equal(t, "{\"Gender\":\"male\",\"Email\":\"enableasync@example.com\",\"Name\":\"enableasync\",\"Age\":30,\"Child\":{\"Gender\":\"male\",\"Email\":\"childName@example.com\",\"Name\":\"childName\",\"Age\":20}}", m)

r, err := mockGsonGeneralizer.Realize(m, reflect.TypeOf(p))
assert.Nil(t, err)
rMockParent, ok := r.(*mockGsonParent)
assert.True(t, ok)
// parent
assert.Equal(t, "enableasync", rMockParent.Name)
assert.Equal(t, 30, rMockParent.Age)
// child
assert.Equal(t, "childName", rMockParent.Child.Name)
assert.Equal(t, 20, rMockParent.Child.Age)
}

func TestGsonPointer(t *testing.T) {
c := &mockGsonChild{
Age: 20,
Gender: "male",
Email: "childName@example.com",
Name: "childName",
}

m, err := mockMapGeneralizer.Generalize(c)
assert.Nil(t, err)
newC, err := mockMapGeneralizer.Realize(m, reflect.TypeOf(c))
assert.Nil(t, err)
rMockChild, ok := newC.(*mockGsonChild)
assert.True(t, ok)
assert.Equal(t, "childName", rMockChild.Name)
assert.Equal(t, 20, rMockChild.Age)
}
3 changes: 3 additions & 0 deletions filter/generic/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ func getGeneralizer(generic string) (g generalizer.Generalizer) {
switch strings.ToLower(generic) {
case constant.GenericSerializationDefault:
g = generalizer.GetMapGeneralizer()
case constant.GenericSerializationGson:
g = generalizer.GetGsonGeneralizer()

default:
logger.Debugf("\"%s\" is not supported, use the default generalizer(MapGeneralizer)", generic)
g = generalizer.GetMapGeneralizer()
Expand Down

0 comments on commit 103cf14

Please sign in to comment.