mirror of https://github.com/goccy/go-json.git
Merge pull request #153 from goccy/feature/fix-marshaler
Fix encoding of marshaler
This commit is contained in:
commit
9564532feb
|
@ -2,6 +2,7 @@ package json_test
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
|
@ -12,7 +13,7 @@ type coverMarshalJSON struct {
|
|||
}
|
||||
|
||||
func (c coverMarshalJSON) MarshalJSON() ([]byte, error) {
|
||||
return []byte(`"hello"`), nil
|
||||
return []byte(fmt.Sprint(c.A)), nil
|
||||
}
|
||||
|
||||
type coverPtrMarshalJSON struct {
|
||||
|
@ -20,7 +21,22 @@ type coverPtrMarshalJSON struct {
|
|||
}
|
||||
|
||||
func (c *coverPtrMarshalJSON) MarshalJSON() ([]byte, error) {
|
||||
return []byte(`"hello"`), nil
|
||||
if c == nil {
|
||||
return []byte(`"NULL"`), nil
|
||||
}
|
||||
return []byte(fmt.Sprint(c.B)), nil
|
||||
}
|
||||
|
||||
type coverPtrMarshalJSONString struct {
|
||||
dummy int
|
||||
C string
|
||||
}
|
||||
|
||||
func (c *coverPtrMarshalJSONString) MarshalJSON() ([]byte, error) {
|
||||
if c == nil {
|
||||
return []byte(`"NULL"`), nil
|
||||
}
|
||||
return []byte(c.C), nil
|
||||
}
|
||||
|
||||
func TestCoverMarshalJSON(t *testing.T) {
|
||||
|
@ -66,6 +82,117 @@ func TestCoverMarshalJSON(t *testing.T) {
|
|||
name string
|
||||
data interface{}
|
||||
}{
|
||||
{
|
||||
name: "MarshalJSON",
|
||||
data: coverMarshalJSON{A: 1},
|
||||
},
|
||||
{
|
||||
name: "PtrMarshalJSON",
|
||||
data: &coverMarshalJSON{A: 1},
|
||||
},
|
||||
{
|
||||
name: "PtrMarshalJSON",
|
||||
data: coverPtrMarshalJSON{B: 1},
|
||||
},
|
||||
{
|
||||
name: "PtrPtrMarshalJSON",
|
||||
data: &coverPtrMarshalJSON{B: 1},
|
||||
},
|
||||
{
|
||||
name: "SliceMarshalJSON",
|
||||
data: []coverMarshalJSON{{A: 1}, {A: 2}},
|
||||
},
|
||||
{
|
||||
name: "SliceAddrMarshalJSON",
|
||||
data: []*coverMarshalJSON{{A: 1}, {A: 2}},
|
||||
},
|
||||
{
|
||||
name: "SlicePtrMarshalJSON",
|
||||
data: []coverPtrMarshalJSON{{B: 1}, {B: 2}},
|
||||
},
|
||||
{
|
||||
name: "SliceAddrPtrMarshalJSON",
|
||||
data: []*coverPtrMarshalJSON{{B: 1}, {B: 2}},
|
||||
},
|
||||
{
|
||||
name: "StructSliceMarshalJSON",
|
||||
data: struct {
|
||||
A []coverMarshalJSON
|
||||
}{A: []coverMarshalJSON{{A: 1}, {A: 2}}},
|
||||
},
|
||||
{
|
||||
name: "StructSliceAddrMarshalJSON",
|
||||
data: struct {
|
||||
A []*coverMarshalJSON
|
||||
}{A: []*coverMarshalJSON{{A: 1}, {A: 2}}},
|
||||
},
|
||||
{
|
||||
name: "StructSlicePtrMarshalJSON",
|
||||
data: struct {
|
||||
A []coverPtrMarshalJSON
|
||||
}{A: []coverPtrMarshalJSON{{B: 1}, {B: 2}}},
|
||||
},
|
||||
{
|
||||
name: "StructSliceAddrPtrMarshalJSON",
|
||||
data: struct {
|
||||
A []*coverPtrMarshalJSON
|
||||
}{A: []*coverPtrMarshalJSON{{B: 1}, {B: 2}}},
|
||||
},
|
||||
{
|
||||
name: "PtrStructSliceMarshalJSON",
|
||||
data: &struct {
|
||||
A []coverMarshalJSON
|
||||
}{A: []coverMarshalJSON{{A: 1}, {A: 2}}},
|
||||
},
|
||||
{
|
||||
name: "PtrStructSliceAddrMarshalJSON",
|
||||
data: &struct {
|
||||
A []*coverMarshalJSON
|
||||
}{A: []*coverMarshalJSON{{A: 1}, {A: 2}}},
|
||||
},
|
||||
{
|
||||
name: "PtrStructSlicePtrMarshalJSON",
|
||||
data: &struct {
|
||||
A []coverPtrMarshalJSON
|
||||
}{A: []coverPtrMarshalJSON{{B: 1}, {B: 2}}},
|
||||
},
|
||||
{
|
||||
name: "PtrStructSlicePtrMarshalJSONString",
|
||||
data: &struct {
|
||||
A []coverPtrMarshalJSONString
|
||||
}{A: []coverPtrMarshalJSONString{{C: "1"}, {C: "2"}}},
|
||||
},
|
||||
{
|
||||
name: "PtrStructSliceAddrPtrMarshalJSONString",
|
||||
data: &struct {
|
||||
A []*coverPtrMarshalJSONString
|
||||
}{A: []*coverPtrMarshalJSONString{{C: "1"}, {C: "2"}}},
|
||||
},
|
||||
{
|
||||
name: "PtrStructArrayPtrMarshalJSONString",
|
||||
data: &struct {
|
||||
A [2]coverPtrMarshalJSONString
|
||||
}{A: [2]coverPtrMarshalJSONString{{C: "1"}, {C: "2"}}},
|
||||
},
|
||||
{
|
||||
name: "PtrStructArrayAddrPtrMarshalJSONString",
|
||||
data: &struct {
|
||||
A [2]*coverPtrMarshalJSONString
|
||||
}{A: [2]*coverPtrMarshalJSONString{{C: "1"}, {C: "2"}}},
|
||||
},
|
||||
{
|
||||
name: "PtrStructMapPtrMarshalJSONString",
|
||||
data: &struct {
|
||||
A map[string]coverPtrMarshalJSONString
|
||||
}{A: map[string]coverPtrMarshalJSONString{"a": {C: "1"}, "b": {C: "2"}}},
|
||||
},
|
||||
{
|
||||
name: "PtrStructMapAddrPtrMarshalJSONString",
|
||||
data: &struct {
|
||||
A map[string]*coverPtrMarshalJSONString
|
||||
}{A: map[string]*coverPtrMarshalJSONString{"a": {C: "1"}, "b": {C: "2"}}},
|
||||
},
|
||||
|
||||
// HeadMarshalJSONZero
|
||||
{
|
||||
name: "HeadMarshalJSONZero",
|
||||
|
|
|
@ -600,10 +600,11 @@ func compileSlice(ctx *compileContext) (*Opcode, error) {
|
|||
header := newSliceHeaderCode(ctx)
|
||||
ctx.incIndex()
|
||||
|
||||
code, err := compileSliceElem(ctx.withType(elem).incIndent())
|
||||
code, err := compileListElem(ctx.withType(elem).incIndent())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
code.Indirect = true
|
||||
|
||||
// header => opcode => elem => end
|
||||
// ^ |
|
||||
|
@ -624,7 +625,7 @@ func compileSlice(ctx *compileContext) (*Opcode, error) {
|
|||
return (*Opcode)(unsafe.Pointer(header)), nil
|
||||
}
|
||||
|
||||
func compileSliceElem(ctx *compileContext) (*Opcode, error) {
|
||||
func compileListElem(ctx *compileContext) (*Opcode, error) {
|
||||
typ := ctx.typ
|
||||
switch {
|
||||
case !typ.Implements(marshalJSONType) && runtime.PtrTo(typ).Implements(marshalJSONType):
|
||||
|
@ -645,10 +646,11 @@ func compileArray(ctx *compileContext) (*Opcode, error) {
|
|||
header := newArrayHeaderCode(ctx, alen)
|
||||
ctx.incIndex()
|
||||
|
||||
code, err := compile(ctx.withType(elem).incIndent(), false)
|
||||
code, err := compileListElem(ctx.withType(elem).incIndent())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
code.Indirect = true
|
||||
// header => opcode => elem => end
|
||||
// ^ |
|
||||
// |________|
|
||||
|
@ -690,6 +692,7 @@ func compileMap(ctx *compileContext) (*Opcode, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
valueCode.Indirect = true
|
||||
|
||||
key := newMapKeyCode(ctx, header)
|
||||
ctx.incIndex()
|
||||
|
@ -1057,10 +1060,11 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
|
|||
// *struct{ field T } => struct { field *T }
|
||||
// func (*T) MarshalJSON() ([]byte, error)
|
||||
// move pointer position from head to first field
|
||||
code, err := compileMarshalJSON(ctx.withType(runtime.PtrTo(fieldType)))
|
||||
code, err := compileMarshalJSON(ctx.withType(fieldType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addrForMarshaler = true
|
||||
valueCode = code
|
||||
nilcheck = false
|
||||
indirect = false
|
||||
|
@ -1069,10 +1073,11 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
|
|||
// *struct{ field T } => struct { field *T }
|
||||
// func (*T) MarshalText() ([]byte, error)
|
||||
// move pointer position from head to first field
|
||||
code, err := compileMarshalText(ctx.withType(runtime.PtrTo(fieldType)))
|
||||
code, err := compileMarshalText(ctx.withType(fieldType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addrForMarshaler = true
|
||||
valueCode = code
|
||||
nilcheck = false
|
||||
indirect = false
|
||||
|
|
|
@ -272,6 +272,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
if code.Type.Kind() == reflect.Ptr && code.Indirect {
|
||||
p = ptrToPtr(p)
|
||||
}
|
||||
bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -296,6 +299,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
if code.Type.Kind() == reflect.Ptr && code.Indirect {
|
||||
p = ptrToPtr(p)
|
||||
}
|
||||
bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -272,6 +272,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
if code.Type.Kind() == reflect.Ptr && code.Indirect {
|
||||
p = ptrToPtr(p)
|
||||
}
|
||||
bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -296,6 +299,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
if code.Type.Kind() == reflect.Ptr && code.Indirect {
|
||||
p = ptrToPtr(p)
|
||||
}
|
||||
bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -270,6 +270,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
if code.Type.Kind() == reflect.Ptr && code.Indirect {
|
||||
p = ptrToPtr(p)
|
||||
}
|
||||
bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -294,6 +297,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
if code.Type.Kind() == reflect.Ptr && code.Indirect {
|
||||
p = ptrToPtr(p)
|
||||
}
|
||||
bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -276,6 +276,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
if code.Type.Kind() == reflect.Ptr && code.Indirect {
|
||||
p = ptrToPtr(p)
|
||||
}
|
||||
bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -300,6 +303,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
if code.Type.Kind() == reflect.Ptr && code.Indirect {
|
||||
p = ptrToPtr(p)
|
||||
}
|
||||
bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
Loading…
Reference in New Issue