mirror of https://github.com/k3s-io/k3s
Merge pull request #65034 from caesarxuchao/json-case-sensitive
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Make kubernetes json serializer case sensitive This PR imported the latest jsoniterator library so that case sensitivity during unmarhsaling is optional. The PR also set Kubernetes json serializer to be case sensitive. Kubernetes json serializer had been case sensitive for 1.1-1.7 as we were using ugorji. This PR restores the behavior. Fix #64612. ```release-notes Kubernetes json deserializer is now case-sensitive as it was before 1.8. If your config files contains fields with wrong case, the config files will be now invalid. ```pull/8/head
commit
a2de1398f8
|
@ -2029,8 +2029,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/json-iterator/go",
|
"ImportPath": "github.com/json-iterator/go",
|
||||||
"Comment": "1.1.3-16-g2ddf6d7",
|
"Comment": "1.1.3-22-gf2b4162",
|
||||||
"Rev": "2ddf6d758266fcb080a4f9e054b9f292c85e6798"
|
"Rev": "f2b4162afba35581b6d4a50d3b8f34e33c144682"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/jteeuwen/go-bindata",
|
"ImportPath": "github.com/jteeuwen/go-bindata",
|
||||||
|
|
|
@ -58,7 +58,6 @@ go_library(
|
||||||
"//pkg/proxy/apis/kubeproxyconfig/scheme:go_default_library",
|
"//pkg/proxy/apis/kubeproxyconfig/scheme:go_default_library",
|
||||||
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1:go_default_library",
|
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1:go_default_library",
|
||||||
"//pkg/util/pointer:go_default_library",
|
"//pkg/util/pointer:go_default_library",
|
||||||
"//vendor/github.com/json-iterator/go:go_default_library",
|
|
||||||
"//vendor/github.com/ugorji/go/codec:go_default_library",
|
"//vendor/github.com/ugorji/go/codec:go_default_library",
|
||||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
"github.com/ugorji/go/codec"
|
"github.com/ugorji/go/codec"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
@ -31,8 +30,6 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
)
|
)
|
||||||
|
|
||||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
|
||||||
|
|
||||||
type configMutationFunc func(map[string]interface{}) error
|
type configMutationFunc func(map[string]interface{}) error
|
||||||
|
|
||||||
// These migrations are a stop-gap until we get a properly-versioned configuration file for MasterConfiguration.
|
// These migrations are a stop-gap until we get a properly-versioned configuration file for MasterConfiguration.
|
||||||
|
|
|
@ -64,7 +64,7 @@ KubeProxy:
|
||||||
minSyncPeriod: 0s
|
minSyncPeriod: 0s
|
||||||
syncPeriod: 30s
|
syncPeriod: 30s
|
||||||
ipvs:
|
ipvs:
|
||||||
ExcludeCIDRs: null
|
excludeCIDRs: null
|
||||||
minSyncPeriod: 0s
|
minSyncPeriod: 0s
|
||||||
scheduler: ""
|
scheduler: ""
|
||||||
syncPeriod: 30s
|
syncPeriod: 30s
|
||||||
|
|
|
@ -53,7 +53,7 @@ kubeProxy:
|
||||||
minSyncPeriod: 0s
|
minSyncPeriod: 0s
|
||||||
syncPeriod: 30s
|
syncPeriod: 30s
|
||||||
ipvs:
|
ipvs:
|
||||||
ExcludeCIDRs: null
|
excludeCIDRs: null
|
||||||
minSyncPeriod: 0s
|
minSyncPeriod: 0s
|
||||||
scheduler: ""
|
scheduler: ""
|
||||||
syncPeriod: 30s
|
syncPeriod: 30s
|
||||||
|
|
|
@ -50,7 +50,7 @@ kubeProxy:
|
||||||
minSyncPeriod: 0s
|
minSyncPeriod: 0s
|
||||||
syncPeriod: 30s
|
syncPeriod: 30s
|
||||||
ipvs:
|
ipvs:
|
||||||
ExcludeCIDRs: null
|
excludeCIDRs: null
|
||||||
minSyncPeriod: 0s
|
minSyncPeriod: 0s
|
||||||
scheduler: ""
|
scheduler: ""
|
||||||
syncPeriod: 30s
|
syncPeriod: 30s
|
||||||
|
|
|
@ -54,7 +54,7 @@ kubeProxy:
|
||||||
minSyncPeriod: 0s
|
minSyncPeriod: 0s
|
||||||
syncPeriod: 30s
|
syncPeriod: 30s
|
||||||
ipvs:
|
ipvs:
|
||||||
ExcludeCIDRs: null
|
excludeCIDRs: null
|
||||||
minSyncPeriod: 0s
|
minSyncPeriod: 0s
|
||||||
scheduler: ""
|
scheduler: ""
|
||||||
syncPeriod: 30s
|
syncPeriod: 30s
|
||||||
|
|
|
@ -49,7 +49,7 @@ kubeProxy:
|
||||||
minSyncPeriod: 0s
|
minSyncPeriod: 0s
|
||||||
syncPeriod: 30s
|
syncPeriod: 30s
|
||||||
ipvs:
|
ipvs:
|
||||||
ExcludeCIDRs: null
|
excludeCIDRs: null
|
||||||
minSyncPeriod: 0s
|
minSyncPeriod: 0s
|
||||||
scheduler: ""
|
scheduler: ""
|
||||||
syncPeriod: 30s
|
syncPeriod: 30s
|
||||||
|
|
|
@ -49,7 +49,7 @@ kubeProxy:
|
||||||
minSyncPeriod: 0s
|
minSyncPeriod: 0s
|
||||||
syncPeriod: 30s
|
syncPeriod: 30s
|
||||||
ipvs:
|
ipvs:
|
||||||
ExcludeCIDRs: null
|
excludeCIDRs: null
|
||||||
minSyncPeriod: 0s
|
minSyncPeriod: 0s
|
||||||
scheduler: ""
|
scheduler: ""
|
||||||
syncPeriod: 30s
|
syncPeriod: 30s
|
||||||
|
|
|
@ -96,6 +96,7 @@ go_test(
|
||||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
|
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/conversion"
|
"k8s.io/apimachinery/pkg/conversion"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
k8s_json "k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
||||||
"k8s.io/apimachinery/pkg/util/diff"
|
"k8s.io/apimachinery/pkg/util/diff"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
@ -560,9 +561,10 @@ func BenchmarkDecodeIntoJSONCodecGenConfigFast(b *testing.B) {
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
}
|
}
|
||||||
|
|
||||||
// BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary
|
// BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary provides a
|
||||||
// provides a baseline for JSON decode performance
|
// baseline for JSON decode performance with
|
||||||
// with jsoniter.ConfigCompatibleWithStandardLibrary
|
// jsoniter.ConfigCompatibleWithStandardLibrary, but with case sensitivity set
|
||||||
|
// to true
|
||||||
func BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary(b *testing.B) {
|
func BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary(b *testing.B) {
|
||||||
kcodec := testapi.Default.Codec()
|
kcodec := testapi.Default.Codec()
|
||||||
items := benchmarkItems(b)
|
items := benchmarkItems(b)
|
||||||
|
@ -577,9 +579,10 @@ func BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary(b *testi
|
||||||
}
|
}
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
iter := k8s_json.CaseSensitiveJsonIterator()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
obj := v1.Pod{}
|
obj := v1.Pod{}
|
||||||
if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(encoded[i%width], &obj); err != nil {
|
if err := iter.Unmarshal(encoded[i%width], &obj); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ type KubeProxyIPVSConfiguration struct {
|
||||||
Scheduler string `json:"scheduler"`
|
Scheduler string `json:"scheduler"`
|
||||||
// excludeCIDRs is a list of CIDR's which the ipvs proxier should not touch
|
// excludeCIDRs is a list of CIDR's which the ipvs proxier should not touch
|
||||||
// when cleaning up ipvs services.
|
// when cleaning up ipvs services.
|
||||||
ExcludeCIDRs []string
|
ExcludeCIDRs []string `json:"excludeCIDRs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// KubeProxyConntrackConfiguration contains conntrack settings for
|
// KubeProxyConntrackConfiguration contains conntrack settings for
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/json-iterator/go",
|
"ImportPath": "github.com/json-iterator/go",
|
||||||
"Rev": "2ddf6d758266fcb080a4f9e054b9f292c85e6798"
|
"Rev": "f2b4162afba35581b6d4a50d3b8f34e33c144682"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/modern-go/concurrent",
|
"ImportPath": "github.com/modern-go/concurrent",
|
||||||
|
|
|
@ -532,7 +532,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/json-iterator/go",
|
"ImportPath": "github.com/json-iterator/go",
|
||||||
"Rev": "2ddf6d758266fcb080a4f9e054b9f292c85e6798"
|
"Rev": "f2b4162afba35581b6d4a50d3b8f34e33c144682"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/mailru/easyjson/buffer",
|
"ImportPath": "github.com/mailru/easyjson/buffer",
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/json-iterator/go",
|
"ImportPath": "github.com/json-iterator/go",
|
||||||
"Rev": "2ddf6d758266fcb080a4f9e054b9f292c85e6798"
|
"Rev": "f2b4162afba35581b6d4a50d3b8f34e33c144682"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/modern-go/concurrent",
|
"ImportPath": "github.com/modern-go/concurrent",
|
||||||
|
|
|
@ -21,9 +21,9 @@ go_test(
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
"//vendor/github.com/ghodss/yaml:go_default_library",
|
"//vendor/github.com/ghodss/yaml:go_default_library",
|
||||||
"//vendor/github.com/json-iterator/go:go_default_library",
|
|
||||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
k8s_json "k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GroupVersionHolder struct {
|
type GroupVersionHolder struct {
|
||||||
|
@ -47,7 +47,8 @@ func TestGroupVersionUnmarshalJSON(t *testing.T) {
|
||||||
t.Errorf("JSON codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV)
|
t.Errorf("JSON codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV)
|
||||||
}
|
}
|
||||||
// test the json-iterator codec
|
// test the json-iterator codec
|
||||||
if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(c.input, &result); err != nil {
|
iter := k8s_json.CaseSensitiveJsonIterator()
|
||||||
|
if err := iter.Unmarshal(c.input, &result); err != nil {
|
||||||
t.Errorf("json-iterator codec failed to unmarshal input '%v': %v", c.input, err)
|
t.Errorf("json-iterator codec failed to unmarshal input '%v': %v", c.input, err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(result.GV, c.expect) {
|
if !reflect.DeepEqual(result.GV, c.expect) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
k8s_json "k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestVerbsUgorjiMarshalJSON(t *testing.T) {
|
func TestVerbsUgorjiMarshalJSON(t *testing.T) {
|
||||||
|
@ -45,7 +45,7 @@ func TestVerbsUgorjiMarshalJSON(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVerbsUgorjiUnmarshalJSON(t *testing.T) {
|
func TestVerbsUJsonIterUnmarshalJSON(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
input string
|
input string
|
||||||
result APIResource
|
result APIResource
|
||||||
|
@ -56,9 +56,10 @@ func TestVerbsUgorjiUnmarshalJSON(t *testing.T) {
|
||||||
{`{"verbs":["delete"]}`, APIResource{Verbs: Verbs([]string{"delete"})}},
|
{`{"verbs":["delete"]}`, APIResource{Verbs: Verbs([]string{"delete"})}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iter := k8s_json.CaseSensitiveJsonIterator()
|
||||||
for i, c := range cases {
|
for i, c := range cases {
|
||||||
var result APIResource
|
var result APIResource
|
||||||
if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal([]byte(c.input), &result); err != nil {
|
if err := iter.Unmarshal([]byte(c.input), &result); err != nil {
|
||||||
t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err)
|
t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(result, c.result) {
|
if !reflect.DeepEqual(result, c.result) {
|
||||||
|
|
|
@ -93,6 +93,20 @@ func init() {
|
||||||
jsoniter.RegisterTypeDecoderFunc("interface {}", decodeNumberAsInt64IfPossible)
|
jsoniter.RegisterTypeDecoderFunc("interface {}", decodeNumberAsInt64IfPossible)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CaseSensitiveJsonIterator returns a jsoniterator API that's configured to be
|
||||||
|
// case-sensitive when unmarshalling, and otherwise compatible with
|
||||||
|
// the encoding/json standard library.
|
||||||
|
func CaseSensitiveJsonIterator() jsoniter.API {
|
||||||
|
return jsoniter.Config{
|
||||||
|
EscapeHTML: true,
|
||||||
|
SortMapKeys: true,
|
||||||
|
ValidateJsonRawMessage: true,
|
||||||
|
CaseSensitive: true,
|
||||||
|
}.Froze()
|
||||||
|
}
|
||||||
|
|
||||||
|
var caseSensitiveJsonIterator = CaseSensitiveJsonIterator()
|
||||||
|
|
||||||
// gvkWithDefaults returns group kind and version defaulting from provided default
|
// gvkWithDefaults returns group kind and version defaulting from provided default
|
||||||
func gvkWithDefaults(actual, defaultGVK schema.GroupVersionKind) schema.GroupVersionKind {
|
func gvkWithDefaults(actual, defaultGVK schema.GroupVersionKind) schema.GroupVersionKind {
|
||||||
if len(actual.Kind) == 0 {
|
if len(actual.Kind) == 0 {
|
||||||
|
@ -157,7 +171,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, i
|
||||||
types, _, err := s.typer.ObjectKinds(into)
|
types, _, err := s.typer.ObjectKinds(into)
|
||||||
switch {
|
switch {
|
||||||
case runtime.IsNotRegisteredError(err), isUnstructured:
|
case runtime.IsNotRegisteredError(err), isUnstructured:
|
||||||
if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(data, into); err != nil {
|
if err := caseSensitiveJsonIterator.Unmarshal(data, into); err != nil {
|
||||||
return nil, actual, err
|
return nil, actual, err
|
||||||
}
|
}
|
||||||
return into, actual, nil
|
return into, actual, nil
|
||||||
|
@ -181,7 +195,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, i
|
||||||
return nil, actual, err
|
return nil, actual, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(data, obj); err != nil {
|
if err := caseSensitiveJsonIterator.Unmarshal(data, obj); err != nil {
|
||||||
return nil, actual, err
|
return nil, actual, err
|
||||||
}
|
}
|
||||||
return obj, actual, nil
|
return obj, actual, nil
|
||||||
|
@ -190,7 +204,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, i
|
||||||
// Encode serializes the provided object to the given writer.
|
// Encode serializes the provided object to the given writer.
|
||||||
func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error {
|
func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error {
|
||||||
if s.yaml {
|
if s.yaml {
|
||||||
json, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(obj)
|
json, err := caseSensitiveJsonIterator.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -203,7 +217,7 @@ func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.pretty {
|
if s.pretty {
|
||||||
data, err := jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent(obj, "", " ")
|
data, err := caseSensitiveJsonIterator.MarshalIndent(obj, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,31 @@ import (
|
||||||
|
|
||||||
type testDecodable struct {
|
type testDecodable struct {
|
||||||
Other string
|
Other string
|
||||||
Value int `json:"value"`
|
Value int `json:"value"`
|
||||||
|
Spec DecodableSpec `json:"spec"`
|
||||||
gvk schema.GroupVersionKind
|
gvk schema.GroupVersionKind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecodableSpec has 15 fields. json-iterator treats struct with more than 10
|
||||||
|
// fields differently from struct that has less than 10 fields.
|
||||||
|
type DecodableSpec struct {
|
||||||
|
A int `json:"A"`
|
||||||
|
B int `json:"B"`
|
||||||
|
C int `json:"C"`
|
||||||
|
D int `json:"D"`
|
||||||
|
E int `json:"E"`
|
||||||
|
F int `json:"F"`
|
||||||
|
G int `json:"G"`
|
||||||
|
H int `json:"h"`
|
||||||
|
I int `json:"i"`
|
||||||
|
J int `json:"j"`
|
||||||
|
K int `json:"k"`
|
||||||
|
L int `json:"l"`
|
||||||
|
M int `json:"m"`
|
||||||
|
N int `json:"n"`
|
||||||
|
O int `json:"o"`
|
||||||
|
}
|
||||||
|
|
||||||
func (d *testDecodable) GetObjectKind() schema.ObjectKind { return d }
|
func (d *testDecodable) GetObjectKind() schema.ObjectKind { return d }
|
||||||
func (d *testDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
|
func (d *testDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
|
||||||
func (d *testDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk }
|
func (d *testDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk }
|
||||||
|
@ -221,6 +242,28 @@ func TestDecode(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// Unmarshalling is case-sensitive
|
||||||
|
{
|
||||||
|
// "VaLue" should have been "value"
|
||||||
|
data: []byte(`{"kind":"Test","apiVersion":"other/blah","VaLue":1,"Other":"test"}`),
|
||||||
|
into: &testDecodable{},
|
||||||
|
typer: &mockTyper{err: runtime.NewNotRegisteredErrForKind(schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"})},
|
||||||
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||||
|
expectedObject: &testDecodable{
|
||||||
|
Other: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Unmarshalling is case-sensitive for big struct.
|
||||||
|
{
|
||||||
|
// "b" should have been "B", "I" should have been "i"
|
||||||
|
data: []byte(`{"kind":"Test","apiVersion":"other/blah","spec": {"A": 1, "b": 2, "h": 3, "I": 4}}`),
|
||||||
|
into: &testDecodable{},
|
||||||
|
typer: &mockTyper{err: runtime.NewNotRegisteredErrForKind(schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"})},
|
||||||
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||||
|
expectedObject: &testDecodable{
|
||||||
|
Spec: DecodableSpec{A: 1, H: 3},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range testCases {
|
for i, test := range testCases {
|
||||||
|
|
|
@ -504,7 +504,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/json-iterator/go",
|
"ImportPath": "github.com/json-iterator/go",
|
||||||
"Rev": "2ddf6d758266fcb080a4f9e054b9f292c85e6798"
|
"Rev": "f2b4162afba35581b6d4a50d3b8f34e33c144682"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/mailru/easyjson/buffer",
|
"ImportPath": "github.com/mailru/easyjson/buffer",
|
||||||
|
|
|
@ -156,7 +156,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/json-iterator/go",
|
"ImportPath": "github.com/json-iterator/go",
|
||||||
"Rev": "2ddf6d758266fcb080a4f9e054b9f292c85e6798"
|
"Rev": "f2b4162afba35581b6d4a50d3b8f34e33c144682"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/modern-go/concurrent",
|
"ImportPath": "github.com/modern-go/concurrent",
|
||||||
|
|
|
@ -216,7 +216,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/json-iterator/go",
|
"ImportPath": "github.com/json-iterator/go",
|
||||||
"Rev": "2ddf6d758266fcb080a4f9e054b9f292c85e6798"
|
"Rev": "f2b4162afba35581b6d4a50d3b8f34e33c144682"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/mailru/easyjson/buffer",
|
"ImportPath": "github.com/mailru/easyjson/buffer",
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/json-iterator/go",
|
"ImportPath": "github.com/json-iterator/go",
|
||||||
"Rev": "2ddf6d758266fcb080a4f9e054b9f292c85e6798"
|
"Rev": "f2b4162afba35581b6d4a50d3b8f34e33c144682"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/modern-go/concurrent",
|
"ImportPath": "github.com/modern-go/concurrent",
|
||||||
|
|
|
@ -208,7 +208,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/json-iterator/go",
|
"ImportPath": "github.com/json-iterator/go",
|
||||||
"Rev": "2ddf6d758266fcb080a4f9e054b9f292c85e6798"
|
"Rev": "f2b4162afba35581b6d4a50d3b8f34e33c144682"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/mailru/easyjson/buffer",
|
"ImportPath": "github.com/mailru/easyjson/buffer",
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/json-iterator/go",
|
"ImportPath": "github.com/json-iterator/go",
|
||||||
"Rev": "2ddf6d758266fcb080a4f9e054b9f292c85e6798"
|
"Rev": "f2b4162afba35581b6d4a50d3b8f34e33c144682"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/modern-go/concurrent",
|
"ImportPath": "github.com/modern-go/concurrent",
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/json-iterator/go"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "ca39e5af3ece67bbcda3d0f4f56a8e24d9f2dad4"
|
||||||
|
version = "1.1.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/modern-go/concurrent"
|
name = "github.com/modern-go/concurrent"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
@ -16,6 +22,6 @@
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "ac7003b5a981716353a43055ab7d4c5357403cb30a60de2dbdeb446c1544beaa"
|
inputs-digest = "56a0b9e9e61d2bc8af5e1b68537401b7f4d60805eda3d107058f3171aa5cf793"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
|
@ -2,12 +2,13 @@ package jsoniter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/modern-go/concurrent"
|
|
||||||
"github.com/modern-go/reflect2"
|
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/modern-go/concurrent"
|
||||||
|
"github.com/modern-go/reflect2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config customize how the API should behave.
|
// Config customize how the API should behave.
|
||||||
|
@ -23,6 +24,7 @@ type Config struct {
|
||||||
OnlyTaggedField bool
|
OnlyTaggedField bool
|
||||||
ValidateJsonRawMessage bool
|
ValidateJsonRawMessage bool
|
||||||
ObjectFieldMustBeSimpleString bool
|
ObjectFieldMustBeSimpleString bool
|
||||||
|
CaseSensitive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// API the public interface of this package.
|
// API the public interface of this package.
|
||||||
|
@ -75,6 +77,7 @@ type frozenConfig struct {
|
||||||
extensions []Extension
|
extensions []Extension
|
||||||
streamPool *sync.Pool
|
streamPool *sync.Pool
|
||||||
iteratorPool *sync.Pool
|
iteratorPool *sync.Pool
|
||||||
|
caseSensitive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *frozenConfig) initCache() {
|
func (cfg *frozenConfig) initCache() {
|
||||||
|
@ -128,6 +131,7 @@ func (cfg Config) Froze() API {
|
||||||
objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString,
|
objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString,
|
||||||
onlyTaggedField: cfg.OnlyTaggedField,
|
onlyTaggedField: cfg.OnlyTaggedField,
|
||||||
disallowUnknownFields: cfg.DisallowUnknownFields,
|
disallowUnknownFields: cfg.DisallowUnknownFields,
|
||||||
|
caseSensitive: cfg.CaseSensitive,
|
||||||
}
|
}
|
||||||
api.streamPool = &sync.Pool{
|
api.streamPool = &sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
|
|
|
@ -60,7 +60,7 @@ func (iter *Iterator) readFieldHash() int64 {
|
||||||
if b == '\\' {
|
if b == '\\' {
|
||||||
iter.head = i
|
iter.head = i
|
||||||
for _, b := range iter.readStringSlowPath() {
|
for _, b := range iter.readStringSlowPath() {
|
||||||
if 'A' <= b && b <= 'Z' {
|
if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive {
|
||||||
b += 'a' - 'A'
|
b += 'a' - 'A'
|
||||||
}
|
}
|
||||||
hash ^= int64(b)
|
hash ^= int64(b)
|
||||||
|
@ -82,7 +82,7 @@ func (iter *Iterator) readFieldHash() int64 {
|
||||||
}
|
}
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
if 'A' <= b && b <= 'Z' {
|
if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive {
|
||||||
b += 'a' - 'A'
|
b += 'a' - 'A'
|
||||||
}
|
}
|
||||||
hash ^= int64(b)
|
hash ^= int64(b)
|
||||||
|
@ -95,10 +95,14 @@ func (iter *Iterator) readFieldHash() int64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func calcHash(str string) int64 {
|
func calcHash(str string, caseSensitive bool) int64 {
|
||||||
hash := int64(0x811c9dc5)
|
hash := int64(0x811c9dc5)
|
||||||
for _, b := range str {
|
for _, b := range str {
|
||||||
hash ^= int64(unicode.ToLower(b))
|
if caseSensitive {
|
||||||
|
hash ^= int64(b)
|
||||||
|
} else {
|
||||||
|
hash ^= int64(unicode.ToLower(b))
|
||||||
|
}
|
||||||
hash *= 0x1000193
|
hash *= 0x1000193
|
||||||
}
|
}
|
||||||
return int64(hash)
|
return int64(hash)
|
||||||
|
|
|
@ -2,9 +2,10 @@ package jsoniter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/modern-go/reflect2"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/modern-go/reflect2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValDecoder is an internal type registered to cache as needed.
|
// ValDecoder is an internal type registered to cache as needed.
|
||||||
|
@ -40,6 +41,14 @@ type ctx struct {
|
||||||
decoders map[reflect2.Type]ValDecoder
|
decoders map[reflect2.Type]ValDecoder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *ctx) caseSensitive() bool {
|
||||||
|
if b.frozenConfig == nil {
|
||||||
|
// default is case-insensitive
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return b.frozenConfig.caseSensitive
|
||||||
|
}
|
||||||
|
|
||||||
func (b *ctx) append(prefix string) *ctx {
|
func (b *ctx) append(prefix string) *ctx {
|
||||||
return &ctx{
|
return &ctx{
|
||||||
frozenConfig: b.frozenConfig,
|
frozenConfig: b.frozenConfig,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package jsoniter
|
package jsoniter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -418,20 +417,11 @@ func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
}
|
}
|
||||||
switch iter.WhatIsNext() {
|
switch iter.WhatIsNext() {
|
||||||
case StringValue:
|
case StringValue:
|
||||||
encoding := base64.StdEncoding
|
src := iter.ReadString()
|
||||||
src := iter.SkipAndReturnBytes()
|
dst, err := base64.StdEncoding.DecodeString(src)
|
||||||
// New line characters (\r and \n) are ignored.
|
|
||||||
// Refer to https://golang.org/pkg/encoding/base64/#Encoding.Decode
|
|
||||||
src = bytes.Replace(src, []byte(`\r`), []byte{}, -1)
|
|
||||||
src = bytes.Replace(src, []byte(`\n`), []byte{}, -1)
|
|
||||||
src = src[1 : len(src)-1]
|
|
||||||
decodedLen := encoding.DecodedLen(len(src))
|
|
||||||
dst := make([]byte, decodedLen)
|
|
||||||
len, err := encoding.Decode(dst, src)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
iter.ReportError("decode base64", err.Error())
|
iter.ReportError("decode base64", err.Error())
|
||||||
} else {
|
} else {
|
||||||
dst = dst[:len]
|
|
||||||
codec.sliceType.UnsafeSet(ptr, unsafe.Pointer(&dst))
|
codec.sliceType.UnsafeSet(ptr, unsafe.Pointer(&dst))
|
||||||
}
|
}
|
||||||
case ArrayValue:
|
case ArrayValue:
|
||||||
|
|
|
@ -2,10 +2,11 @@ package jsoniter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/modern-go/reflect2"
|
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/modern-go/reflect2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder {
|
func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder {
|
||||||
|
@ -31,11 +32,15 @@ func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder {
|
||||||
for k, binding := range bindings {
|
for k, binding := range bindings {
|
||||||
fields[k] = binding.Decoder.(*structFieldDecoder)
|
fields[k] = binding.Decoder.(*structFieldDecoder)
|
||||||
}
|
}
|
||||||
for k, binding := range bindings {
|
|
||||||
if _, found := fields[strings.ToLower(k)]; !found {
|
if !ctx.caseSensitive() {
|
||||||
fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder)
|
for k, binding := range bindings {
|
||||||
|
if _, found := fields[strings.ToLower(k)]; !found {
|
||||||
|
fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return createStructDecoder(ctx, typ, fields)
|
return createStructDecoder(ctx, typ, fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,12 +51,13 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF
|
||||||
knownHash := map[int64]struct{}{
|
knownHash := map[int64]struct{}{
|
||||||
0: {},
|
0: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
switch len(fields) {
|
switch len(fields) {
|
||||||
case 0:
|
case 0:
|
||||||
return &skipObjectDecoder{typ}
|
return &skipObjectDecoder{typ}
|
||||||
case 1:
|
case 1:
|
||||||
for fieldName, fieldDecoder := range fields {
|
for fieldName, fieldDecoder := range fields {
|
||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName, ctx.caseSensitive())
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields, false}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
|
@ -65,7 +71,7 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF
|
||||||
var fieldDecoder1 *structFieldDecoder
|
var fieldDecoder1 *structFieldDecoder
|
||||||
var fieldDecoder2 *structFieldDecoder
|
var fieldDecoder2 *structFieldDecoder
|
||||||
for fieldName, fieldDecoder := range fields {
|
for fieldName, fieldDecoder := range fields {
|
||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName, ctx.caseSensitive())
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields, false}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
|
@ -88,7 +94,7 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF
|
||||||
var fieldDecoder2 *structFieldDecoder
|
var fieldDecoder2 *structFieldDecoder
|
||||||
var fieldDecoder3 *structFieldDecoder
|
var fieldDecoder3 *structFieldDecoder
|
||||||
for fieldName, fieldDecoder := range fields {
|
for fieldName, fieldDecoder := range fields {
|
||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName, ctx.caseSensitive())
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields, false}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
|
@ -119,7 +125,7 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF
|
||||||
var fieldDecoder3 *structFieldDecoder
|
var fieldDecoder3 *structFieldDecoder
|
||||||
var fieldDecoder4 *structFieldDecoder
|
var fieldDecoder4 *structFieldDecoder
|
||||||
for fieldName, fieldDecoder := range fields {
|
for fieldName, fieldDecoder := range fields {
|
||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName, ctx.caseSensitive())
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields, false}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
|
@ -156,7 +162,7 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF
|
||||||
var fieldDecoder4 *structFieldDecoder
|
var fieldDecoder4 *structFieldDecoder
|
||||||
var fieldDecoder5 *structFieldDecoder
|
var fieldDecoder5 *structFieldDecoder
|
||||||
for fieldName, fieldDecoder := range fields {
|
for fieldName, fieldDecoder := range fields {
|
||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName, ctx.caseSensitive())
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields, false}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
|
@ -199,7 +205,7 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF
|
||||||
var fieldDecoder5 *structFieldDecoder
|
var fieldDecoder5 *structFieldDecoder
|
||||||
var fieldDecoder6 *structFieldDecoder
|
var fieldDecoder6 *structFieldDecoder
|
||||||
for fieldName, fieldDecoder := range fields {
|
for fieldName, fieldDecoder := range fields {
|
||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName, ctx.caseSensitive())
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields, false}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
|
@ -248,7 +254,7 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF
|
||||||
var fieldDecoder6 *structFieldDecoder
|
var fieldDecoder6 *structFieldDecoder
|
||||||
var fieldDecoder7 *structFieldDecoder
|
var fieldDecoder7 *structFieldDecoder
|
||||||
for fieldName, fieldDecoder := range fields {
|
for fieldName, fieldDecoder := range fields {
|
||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName, ctx.caseSensitive())
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields, false}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
|
@ -303,7 +309,7 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF
|
||||||
var fieldDecoder7 *structFieldDecoder
|
var fieldDecoder7 *structFieldDecoder
|
||||||
var fieldDecoder8 *structFieldDecoder
|
var fieldDecoder8 *structFieldDecoder
|
||||||
for fieldName, fieldDecoder := range fields {
|
for fieldName, fieldDecoder := range fields {
|
||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName, ctx.caseSensitive())
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields, false}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
|
@ -364,7 +370,7 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF
|
||||||
var fieldDecoder8 *structFieldDecoder
|
var fieldDecoder8 *structFieldDecoder
|
||||||
var fieldDecoder9 *structFieldDecoder
|
var fieldDecoder9 *structFieldDecoder
|
||||||
for fieldName, fieldDecoder := range fields {
|
for fieldName, fieldDecoder := range fields {
|
||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName, ctx.caseSensitive())
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields, false}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
|
@ -431,7 +437,7 @@ func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structF
|
||||||
var fieldDecoder9 *structFieldDecoder
|
var fieldDecoder9 *structFieldDecoder
|
||||||
var fieldDecoder10 *structFieldDecoder
|
var fieldDecoder10 *structFieldDecoder
|
||||||
for fieldName, fieldDecoder := range fields {
|
for fieldName, fieldDecoder := range fields {
|
||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName, ctx.caseSensitive())
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields, false}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
|
@ -513,13 +519,13 @@ func (decoder *generalStructDecoder) decodeOneField(ptr unsafe.Pointer, iter *It
|
||||||
fieldBytes := iter.ReadStringAsSlice()
|
fieldBytes := iter.ReadStringAsSlice()
|
||||||
field = *(*string)(unsafe.Pointer(&fieldBytes))
|
field = *(*string)(unsafe.Pointer(&fieldBytes))
|
||||||
fieldDecoder = decoder.fields[field]
|
fieldDecoder = decoder.fields[field]
|
||||||
if fieldDecoder == nil {
|
if fieldDecoder == nil && !iter.cfg.caseSensitive {
|
||||||
fieldDecoder = decoder.fields[strings.ToLower(field)]
|
fieldDecoder = decoder.fields[strings.ToLower(field)]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
field = iter.ReadString()
|
field = iter.ReadString()
|
||||||
fieldDecoder = decoder.fields[field]
|
fieldDecoder = decoder.fields[field]
|
||||||
if fieldDecoder == nil {
|
if fieldDecoder == nil && !iter.cfg.caseSensitive {
|
||||||
fieldDecoder = decoder.fields[strings.ToLower(field)]
|
fieldDecoder = decoder.fields[strings.ToLower(field)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue