- Using jsoniter.Marshal against struct types which contain recursive embedded type causes stack overflow.
- std's
encoding/json prevents this by these lines
- Jsoniter seemingly does not have that
visited map by quick read through of source code.
- Also handling of overlapping tagged field names are not aligned to what is of std lib.
- std's
encoding/json describes this behavior in its source code but is not documented.
Searching through issues with "recursive" does not give me any similar issues.
Are these behaviors intentionally dropped?
> go version
go version go1.20 linux/amd64
require github.com/json-iterator/go v1.1.12
I've uploaded test code here.
https://github.com/ngicks/test-jsoniter
package testjsoniter_test
import (
"encoding/json"
"testing"
jsoniter "github.com/json-iterator/go"
)
type OverlappingKey1 struct {
Foo string
Bar string `json:"Baz"`
Baz string
}
type OverlappingKey2 struct {
Foo string
Bar string `json:"Bar"`
Baz string `json:"Bar"`
}
type OverlappingKey3 struct {
Foo string
Bar string `json:"Baz"`
Baz string
Qux string `json:"Baz"`
}
type Sub1 struct {
Foo string
Bar string `json:"Bar"`
}
type OverlappingKey4 struct {
Foo string
Bar string
Baz string
Sub1
}
type Recursive1 struct {
R string `json:"r"`
Recursive2
}
type Recursive2 struct {
R string `json:"r"`
RR string `json:"rr"`
*OverlappingKey5
}
type OverlappingKey5 struct {
Foo string
Recursive1
}
func TestJsonIter_behavioral_deference(t *testing.T) {
for _, config := range []jsoniter.API{
jsoniter.ConfigCompatibleWithStandardLibrary,
jsoniter.ConfigDefault,
} {
for _, v := range []any{
OverlappingKey1{"foo", "bar", "baz"},
OverlappingKey2{"foo", "bar", "baz"},
OverlappingKey3{"foo", "bar", "baz", "qux"},
OverlappingKey4{Foo: "foo", Bar: "bar", Baz: "baz", Sub1: Sub1{Foo: "foofoo", Bar: "barbar"}},
// These cause stack overflow
// OverlappingKey5{Foo: "foo", Recursive1: Recursive1{R: "r", Recursive2: Recursive2{R: "rr"}}},
// OverlappingKey5{Foo: "foo", Recursive1: Recursive1{R: "r", Recursive2: Recursive2{R: "rr", OverlappingKey5: &OverlappingKey5{Foo: "foo"}}}},
} {
binOrg, err := json.Marshal(v)
if err != nil {
panic(err)
}
binMimic, err := config.Marshal(v)
if err != nil {
panic(err)
}
str1, str2 := string(binOrg), string(binMimic)
if str1 != str2 {
t.Errorf("not same, type = %T. org = %s, jsoniter = %s\n", v, str1, str2)
}
}
}
}
This gives result of
> go test -v ./...
=== RUN TestJsonIter_behavioral_deference
recursive_test.go:82: not same, type = testjsoniter_test.OverlappingKey1. org = {"Foo":"foo","Baz":"bar"}, jsoniter = {"Foo":"foo","Baz":"baz"}
recursive_test.go:82: not same, type = testjsoniter_test.OverlappingKey3. org = {"Foo":"foo"}, jsoniter = {"Foo":"foo","Baz":"qux"}
recursive_test.go:82: not same, type = testjsoniter_test.OverlappingKey4. org = {"Foo":"foo","Bar":"bar","Baz":"baz"}, jsoniter = {"Foo":"foo","Baz":"baz","Bar":"barbar"}
recursive_test.go:82: not same, type = testjsoniter_test.OverlappingKey1. org = {"Foo":"foo","Baz":"bar"}, jsoniter = {"Foo":"foo","Baz":"baz"}
recursive_test.go:82: not same, type = testjsoniter_test.OverlappingKey3. org = {"Foo":"foo"}, jsoniter = {"Foo":"foo","Baz":"qux"}
recursive_test.go:82: not same, type = testjsoniter_test.OverlappingKey4. org = {"Foo":"foo","Bar":"bar","Baz":"baz"}, jsoniter = {"Foo":"foo","Baz":"baz","Bar":"barbar"}
--- FAIL: TestJsonIter_behavioral_deference (0.00s)
FAIL
FAIL github.com/ngicks/test-jsoniter.git 0.002s
FAIL
encoding/jsonprevents this by these linesvisitedmap by quick read through of source code.encoding/jsondescribes this behavior in its source code but is not documented.Searching through issues with "recursive" does not give me any similar issues.
Are these behaviors intentionally dropped?
I've uploaded test code here.
https://github.com/ngicks/test-jsoniter
This gives result of