mirror of
https://github.com/json-iterator/go.git
synced 2025-05-13 21:36:29 +02:00
Map keys of custom types should serialize using MarshalText when available (#461)
* Map keys of custom types should serialize/deserialize using MarshalText/UnmarshalText when available - this brings marshaling/unmarshaling behavior in line with encoding/json - in general, any types that implement the interfaces from the encoding package (TextUnmarshaler, TextMarshaler, etc.) should use the provided method when available
This commit is contained in:
parent
0f8241d334
commit
8961be9c21
@ -49,6 +49,33 @@ func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder {
|
|||||||
return decoder
|
return decoder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ptrType := reflect2.PtrTo(typ)
|
||||||
|
if ptrType.Implements(unmarshalerType) {
|
||||||
|
return &referenceDecoder{
|
||||||
|
&unmarshalerDecoder{
|
||||||
|
valType: ptrType,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if typ.Implements(unmarshalerType) {
|
||||||
|
return &unmarshalerDecoder{
|
||||||
|
valType: typ,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ptrType.Implements(textUnmarshalerType) {
|
||||||
|
return &referenceDecoder{
|
||||||
|
&textUnmarshalerDecoder{
|
||||||
|
valType: ptrType,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if typ.Implements(textUnmarshalerType) {
|
||||||
|
return &textUnmarshalerDecoder{
|
||||||
|
valType: typ,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch typ.Kind() {
|
switch typ.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return decoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String))
|
return decoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String))
|
||||||
@ -63,31 +90,6 @@ func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder {
|
|||||||
typ = reflect2.DefaultTypeOfKind(typ.Kind())
|
typ = reflect2.DefaultTypeOfKind(typ.Kind())
|
||||||
return &numericMapKeyDecoder{decoderOfType(ctx, typ)}
|
return &numericMapKeyDecoder{decoderOfType(ctx, typ)}
|
||||||
default:
|
default:
|
||||||
ptrType := reflect2.PtrTo(typ)
|
|
||||||
if ptrType.Implements(unmarshalerType) {
|
|
||||||
return &referenceDecoder{
|
|
||||||
&unmarshalerDecoder{
|
|
||||||
valType: ptrType,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if typ.Implements(unmarshalerType) {
|
|
||||||
return &unmarshalerDecoder{
|
|
||||||
valType: typ,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ptrType.Implements(textUnmarshalerType) {
|
|
||||||
return &referenceDecoder{
|
|
||||||
&textUnmarshalerDecoder{
|
|
||||||
valType: ptrType,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if typ.Implements(textUnmarshalerType) {
|
|
||||||
return &textUnmarshalerDecoder{
|
|
||||||
valType: typ,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &lazyErrorDecoder{err: fmt.Errorf("unsupported map key type: %v", typ)}
|
return &lazyErrorDecoder{err: fmt.Errorf("unsupported map key type: %v", typ)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,6 +105,19 @@ func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder {
|
|||||||
return encoder
|
return encoder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if typ == textMarshalerType {
|
||||||
|
return &directTextMarshalerEncoder{
|
||||||
|
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if typ.Implements(textMarshalerType) {
|
||||||
|
return &textMarshalerEncoder{
|
||||||
|
valType: typ,
|
||||||
|
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch typ.Kind() {
|
switch typ.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return encoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String))
|
return encoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String))
|
||||||
@ -117,17 +132,6 @@ func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder {
|
|||||||
typ = reflect2.DefaultTypeOfKind(typ.Kind())
|
typ = reflect2.DefaultTypeOfKind(typ.Kind())
|
||||||
return &numericMapKeyEncoder{encoderOfType(ctx, typ)}
|
return &numericMapKeyEncoder{encoderOfType(ctx, typ)}
|
||||||
default:
|
default:
|
||||||
if typ == textMarshalerType {
|
|
||||||
return &directTextMarshalerEncoder{
|
|
||||||
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if typ.Implements(textMarshalerType) {
|
|
||||||
return &textMarshalerEncoder{
|
|
||||||
valType: typ,
|
|
||||||
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if typ.Kind() == reflect.Interface {
|
if typ.Kind() == reflect.Interface {
|
||||||
return &dynamicMapKeyEncoder{ctx, typ}
|
return &dynamicMapKeyEncoder{ctx, typ}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ func init() {
|
|||||||
map[string]*json.RawMessage{"hello": pRawMessage(json.RawMessage("[]"))},
|
map[string]*json.RawMessage{"hello": pRawMessage(json.RawMessage("[]"))},
|
||||||
map[Date]bool{{}: true},
|
map[Date]bool{{}: true},
|
||||||
map[Date2]bool{{}: true},
|
map[Date2]bool{{}: true},
|
||||||
|
map[customKey]string{customKey(1): "bar"},
|
||||||
)
|
)
|
||||||
unmarshalCases = append(unmarshalCases, unmarshalCase{
|
unmarshalCases = append(unmarshalCases, unmarshalCase{
|
||||||
ptr: (*map[string]string)(nil),
|
ptr: (*map[string]string)(nil),
|
||||||
@ -55,6 +56,9 @@ func init() {
|
|||||||
"2018-12-13": true,
|
"2018-12-13": true,
|
||||||
"2018-12-14": true
|
"2018-12-14": true
|
||||||
}`,
|
}`,
|
||||||
|
}, unmarshalCase{
|
||||||
|
ptr: (*map[customKey]string)(nil),
|
||||||
|
input: `{"foo": "bar"}`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,3 +119,14 @@ func (d Date2) UnmarshalJSON(b []byte) error {
|
|||||||
func (d Date2) MarshalJSON() ([]byte, error) {
|
func (d Date2) MarshalJSON() ([]byte, error) {
|
||||||
return []byte(d.Time.Format("2006-01-02")), nil
|
return []byte(d.Time.Format("2006-01-02")), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type customKey int32
|
||||||
|
|
||||||
|
func (c customKey) MarshalText() ([]byte, error) {
|
||||||
|
return []byte("foo"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *customKey) UnmarshalText(value []byte) error {
|
||||||
|
*c = 1
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user