diff --git a/binding/gjson/gjson.go b/binding/gjson/gjson.go index 0c5e5a3..95a4e22 100644 --- a/binding/gjson/gjson.go +++ b/binding/gjson/gjson.go @@ -38,7 +38,10 @@ import ( "github.com/bytedance/go-tagexpr/v2/binding/gjson/internal/rt" ) -var programCache = caching.CreateProgramCache() +var ( + programCache = caching.CreateProgramCache() + unmarshalerInterface = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() +) func init() { gjson.DisableModifiers = true @@ -97,7 +100,13 @@ func assign(jsval gjson.Result, goval reflect.Value) (err error) { goval.Set(reflect.ValueOf(data)) } else { if !jsval.IsArray() { - return nil + // canAddr: true, implement unmarshaler : true -> continue + // canAddr: true, implement unmarshaler : false -> return + // canAddr: false, implement unmarshaler : true -> return + // canAddr: false, implement unmarshaler : false -> return + if !goval.CanAddr() || !goval.Addr().Type().Implements(unmarshalerInterface) { + return nil + } } jsvals := jsval.Array() slice := reflect.MakeSlice(t, len(jsvals), len(jsvals)) diff --git a/binding/gjson/gjson_test.go b/binding/gjson/gjson_test.go index e4ae694..c4bbcf1 100644 --- a/binding/gjson/gjson_test.go +++ b/binding/gjson/gjson_test.go @@ -236,3 +236,43 @@ func getFiledInfoWithMap(t reflect.Type) map[string][]int { } return sf } + + +// MarshalJSON to output non base64 encoded []byte +func (j ByteSlice) MarshalJSON() ([]byte, error) { + if len(j) == 0 { + return []byte("null"), nil + } + + return json.RawMessage(j).MarshalJSON() +} + +// UnmarshalJSON to deserialize []byte +func (j *ByteSlice) UnmarshalJSON(b []byte) error { + result := json.RawMessage{} + err := result.UnmarshalJSON(b) + *j = ByteSlice(result) + return err +} + +type ByteSlice []byte + +func TestCustomizedGjsonUnmarshal(t *testing.T) { + str := `{"h1":{"h2":1}}` + type F struct { + H ByteSlice `json:"h1"` + } + + obj := F{} + err := Unmarshal([]byte(str), &obj) + + assert.NoError(t, err) + assert.Equal(t, "{\"h2\":1}", string(obj.H)) + + obj2 := F{} + err = json.Unmarshal([]byte(str), &obj2) + assert.NoError(t, err) + assert.Equal(t, "{\"h2\":1}", string(obj2.H)) + + assert.Equal(t, obj.H, obj2.H) +}