Skip to content

Commit 82392f2

Browse files
committed
Fixed enable the mutation of a unmarshaled json.
In the decode methods the nested orderedMaps had not been pointer with prevents the mutation. To the fix broke some tests the cast to x.(OrderedMap) failed. To Fix this the OrderedMap is now an interface. This broke the TestUnmarshalJSONStruct test to fix the export of OrderedMapImpl is need. This change is a breaking!
1 parent 01810fd commit 82392f2

File tree

2 files changed

+88
-31
lines changed

2 files changed

+88
-31
lines changed

orderedmap.go

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,38 +28,51 @@ func (a ByPair) Len() int { return len(a.Pairs) }
2828
func (a ByPair) Swap(i, j int) { a.Pairs[i], a.Pairs[j] = a.Pairs[j], a.Pairs[i] }
2929
func (a ByPair) Less(i, j int) bool { return a.LessFunc(a.Pairs[i], a.Pairs[j]) }
3030

31-
type OrderedMap struct {
31+
type OrderedMapImpl struct {
3232
keys []string
3333
values map[string]interface{}
3434
escapeHTML bool
3535
}
3636

37-
func New() *OrderedMap {
38-
o := OrderedMap{}
37+
type OrderedMap interface {
38+
SetEscapeHTML(on bool)
39+
Get(key string) (interface{}, bool)
40+
Set(key string, value interface{})
41+
Delete(key string)
42+
Keys() []string
43+
Values() map[string]interface{}
44+
SortKeys(sortFunc func(keys []string))
45+
Sort(lessFunc func(a *Pair, b *Pair) bool)
46+
UnmarshalJSON(b []byte) error
47+
MarshalJSON() ([]byte, error)
48+
}
49+
50+
func New() OrderedMap {
51+
o := OrderedMapImpl{}
3952
o.keys = []string{}
4053
o.values = map[string]interface{}{}
4154
o.escapeHTML = true
4255
return &o
4356
}
4457

45-
func (o *OrderedMap) SetEscapeHTML(on bool) {
58+
func (o *OrderedMapImpl) SetEscapeHTML(on bool) {
4659
o.escapeHTML = on
4760
}
4861

49-
func (o *OrderedMap) Get(key string) (interface{}, bool) {
62+
func (o *OrderedMapImpl) Get(key string) (interface{}, bool) {
5063
val, exists := o.values[key]
5164
return val, exists
5265
}
5366

54-
func (o *OrderedMap) Set(key string, value interface{}) {
67+
func (o *OrderedMapImpl) Set(key string, value interface{}) {
5568
_, exists := o.values[key]
5669
if !exists {
5770
o.keys = append(o.keys, key)
5871
}
5972
o.values[key] = value
6073
}
6174

62-
func (o *OrderedMap) Delete(key string) {
75+
func (o *OrderedMapImpl) Delete(key string) {
6376
// check key is in use
6477
_, ok := o.values[key]
6578
if !ok {
@@ -76,21 +89,21 @@ func (o *OrderedMap) Delete(key string) {
7689
delete(o.values, key)
7790
}
7891

79-
func (o *OrderedMap) Keys() []string {
92+
func (o *OrderedMapImpl) Keys() []string {
8093
return o.keys
8194
}
8295

83-
func (o *OrderedMap) Values() map[string]interface{} {
96+
func (o *OrderedMapImpl) Values() map[string]interface{} {
8497
return o.values
8598
}
8699

87100
// SortKeys Sort the map keys using your sort func
88-
func (o *OrderedMap) SortKeys(sortFunc func(keys []string)) {
101+
func (o *OrderedMapImpl) SortKeys(sortFunc func(keys []string)) {
89102
sortFunc(o.keys)
90103
}
91104

92105
// Sort Sort the map using your sort func
93-
func (o *OrderedMap) Sort(lessFunc func(a *Pair, b *Pair) bool) {
106+
func (o *OrderedMapImpl) Sort(lessFunc func(a *Pair, b *Pair) bool) {
94107
pairs := make([]*Pair, len(o.keys))
95108
for i, key := range o.keys {
96109
pairs[i] = &Pair{key, o.values[key]}
@@ -103,7 +116,7 @@ func (o *OrderedMap) Sort(lessFunc func(a *Pair, b *Pair) bool) {
103116
}
104117
}
105118

106-
func (o *OrderedMap) UnmarshalJSON(b []byte) error {
119+
func (o *OrderedMapImpl) UnmarshalJSON(b []byte) error {
107120
if o.values == nil {
108121
o.values = map[string]interface{}{}
109122
}
@@ -119,7 +132,7 @@ func (o *OrderedMap) UnmarshalJSON(b []byte) error {
119132
return decodeOrderedMap(dec, o)
120133
}
121134

122-
func decodeOrderedMap(dec *json.Decoder, o *OrderedMap) error {
135+
func decodeOrderedMap(dec *json.Decoder, o *OrderedMapImpl) error {
123136
hasKey := make(map[string]bool, len(o.values))
124137
for {
125138
token, err := dec.Token()
@@ -152,26 +165,26 @@ func decodeOrderedMap(dec *json.Decoder, o *OrderedMap) error {
152165
switch delim {
153166
case '{':
154167
if values, ok := o.values[key].(map[string]interface{}); ok {
155-
newMap := OrderedMap{
168+
newMap := &OrderedMapImpl{
156169
keys: make([]string, 0, len(values)),
157170
values: values,
158171
escapeHTML: o.escapeHTML,
159172
}
160-
if err = decodeOrderedMap(dec, &newMap); err != nil {
173+
if err = decodeOrderedMap(dec, newMap); err != nil {
161174
return err
162175
}
163176
o.values[key] = newMap
164-
} else if oldMap, ok := o.values[key].(OrderedMap); ok {
165-
newMap := OrderedMap{
177+
} else if oldMap, ok := o.values[key].(*OrderedMapImpl); ok {
178+
newMap := &OrderedMapImpl{
166179
keys: make([]string, 0, len(oldMap.values)),
167180
values: oldMap.values,
168181
escapeHTML: o.escapeHTML,
169182
}
170-
if err = decodeOrderedMap(dec, &newMap); err != nil {
183+
if err = decodeOrderedMap(dec, newMap); err != nil {
171184
return err
172185
}
173186
o.values[key] = newMap
174-
} else if err = decodeOrderedMap(dec, &OrderedMap{}); err != nil {
187+
} else if err = decodeOrderedMap(dec, &OrderedMapImpl{}); err != nil {
175188
return err
176189
}
177190
case '[':
@@ -198,29 +211,29 @@ func decodeSlice(dec *json.Decoder, s []interface{}, escapeHTML bool) error {
198211
case '{':
199212
if index < len(s) {
200213
if values, ok := s[index].(map[string]interface{}); ok {
201-
newMap := OrderedMap{
214+
newMap := &OrderedMapImpl{
202215
keys: make([]string, 0, len(values)),
203216
values: values,
204217
escapeHTML: escapeHTML,
205218
}
206-
if err = decodeOrderedMap(dec, &newMap); err != nil {
219+
if err = decodeOrderedMap(dec, newMap); err != nil {
207220
return err
208221
}
209222
s[index] = newMap
210-
} else if oldMap, ok := s[index].(OrderedMap); ok {
211-
newMap := OrderedMap{
223+
} else if oldMap, ok := s[index].(*OrderedMapImpl); ok {
224+
newMap := &OrderedMapImpl{
212225
keys: make([]string, 0, len(oldMap.values)),
213226
values: oldMap.values,
214227
escapeHTML: escapeHTML,
215228
}
216-
if err = decodeOrderedMap(dec, &newMap); err != nil {
229+
if err = decodeOrderedMap(dec, newMap); err != nil {
217230
return err
218231
}
219232
s[index] = newMap
220-
} else if err = decodeOrderedMap(dec, &OrderedMap{}); err != nil {
233+
} else if err = decodeOrderedMap(dec, &OrderedMapImpl{}); err != nil {
221234
return err
222235
}
223-
} else if err = decodeOrderedMap(dec, &OrderedMap{}); err != nil {
236+
} else if err = decodeOrderedMap(dec, &OrderedMapImpl{}); err != nil {
224237
return err
225238
}
226239
case '[':
@@ -242,7 +255,7 @@ func decodeSlice(dec *json.Decoder, s []interface{}, escapeHTML bool) error {
242255
}
243256
}
244257

245-
func (o OrderedMap) MarshalJSON() ([]byte, error) {
258+
func (o OrderedMapImpl) MarshalJSON() ([]byte, error) {
246259
var buf bytes.Buffer
247260
buf.WriteByte('{')
248261
encoder := json.NewEncoder(&buf)

orderedmap_test.go

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ func TestOrderedMap(t *testing.T) {
6969
// Values method
7070
values := o.Values()
7171
expectedValues := map[string]interface{}{
72-
"number": 4,
73-
"string": "x",
72+
"number": 4,
73+
"string": "x",
7474
"strings": []string{"t", "u"},
75-
"mixed": []interface{}{ 1, "1" },
75+
"mixed": []interface{}{1, "1"},
7676
}
7777
if !reflect.DeepEqual(values, expectedValues) {
7878
t.Error("Values method returned unexpected map")
@@ -493,7 +493,7 @@ func TestUnmarshalJSONArrayOfMaps(t *testing.T) {
493493

494494
func TestUnmarshalJSONStruct(t *testing.T) {
495495
var v struct {
496-
Data *OrderedMap `json:"data"`
496+
Data OrderedMapImpl `json:"data"`
497497
}
498498

499499
err := json.Unmarshal([]byte(`{ "data": { "x": 1 } }`), &v)
@@ -595,3 +595,47 @@ func TestOrderedMap_empty_map(t *testing.T) {
595595
t.Error("Got", marshalledStr)
596596
}
597597
}
598+
599+
func TestMutableAfterUnmarshal(t *testing.T) {
600+
const input = `{
601+
"foo": "bar",
602+
"prop": {
603+
"v1": 1,
604+
"v2": "v1"
605+
}
606+
}`
607+
out := New()
608+
err := json.Unmarshal([]byte(input), &out)
609+
if err != nil {
610+
t.Fatal(err)
611+
}
612+
613+
iout, _ := out.Get("prop")
614+
iout.(OrderedMap).Set("v3", "blabla")
615+
616+
if out.Keys()[0] != "foo" {
617+
t.Fatal("key order changed")
618+
}
619+
if out.Keys()[1] != "prop" {
620+
t.Fatal("key order changed")
621+
}
622+
inPropX, _ := out.Get("prop")
623+
inProp := inPropX.(OrderedMap)
624+
625+
v1, _ := inProp.Get("v1")
626+
if inProp.Keys()[0] != "v1" || v1.(float64) != 1 {
627+
t.Fatal("key order changed")
628+
}
629+
v2, _ := inProp.Get("v2")
630+
if inProp.Keys()[1] != "v2" || v2.(string) != "v1" {
631+
t.Fatal("key order changed")
632+
}
633+
634+
if inProp.Keys()[2] != "v3" {
635+
t.Fatal("key order changed")
636+
}
637+
v3, _ := inProp.Get("v3")
638+
if v3.(string) != "blabla" {
639+
t.Fatal("expect blabla")
640+
}
641+
}

0 commit comments

Comments
 (0)