Skip to content

Commit 59e4857

Browse files
committed
Unmarshal null should be have like json.Unmarshal
There's a subtle behavior in json.Unmarshal that needs to be captured. When unmashaling `null` it: - basic type - leaves existing value - pointer - overwrites with nil - interface{} - overwrites with nil Current behavour is incorrect because it returns an error, and the aim should be to behave in the same way as json.Unmarshal
1 parent b3349b2 commit 59e4857

File tree

2 files changed

+57
-5
lines changed

2 files changed

+57
-5
lines changed

unmarhsal.go renamed to unmarshal.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,35 +104,50 @@ func unmarshalInfoLeaf(ctx context.Context, target reflect.Value, found bool, so
104104
return unmarshalInfoLeaf(ctx, allocateIfNeeded(target), found, source)
105105
}
106106
case reflect.String:
107-
if s, ok := source.(string); ok {
107+
switch s := source.(type) {
108+
case string:
108109
target.SetString(s)
109110
return nil
111+
case nil:
112+
return nil
110113
}
111114
case reflect.Bool:
112-
if b, ok := source.(bool); ok {
115+
switch b := source.(type) {
116+
case bool:
113117
target.SetBool(b)
114118
return nil
119+
case nil:
120+
return nil
115121
}
116122
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
117-
if n, ok := source.(json.Number); ok {
123+
switch n := source.(type) {
124+
case json.Number:
118125
if i, err := strconv.ParseInt(n.String(), 10, 64); err == nil {
119126
target.SetInt(i)
120127
return nil
121128
}
129+
case nil:
130+
return nil
122131
}
123132
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
124-
if n, ok := source.(json.Number); ok {
133+
switch n := source.(type) {
134+
case json.Number:
125135
if i, err := strconv.ParseUint(n.String(), 10, 64); err == nil {
126136
target.SetUint(i)
127137
return nil
128138
}
139+
case nil:
140+
return nil
129141
}
130142
case reflect.Float32, reflect.Float64:
131-
if n, ok := source.(json.Number); ok {
143+
switch n := source.(type) {
144+
case json.Number:
132145
if f, err := strconv.ParseFloat(n.String(), 64); err == nil {
133146
target.SetFloat(f)
134147
return nil
135148
}
149+
case nil:
150+
return nil
136151
}
137152
case reflect.Interface:
138153
switch source {

unmarshal_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,43 @@ var _ = Describe("Unmarshal", func() {
311311
expectToFail(&s, `{"A":12}`, `cannot unmarshal "12" type "number" into field "A" (type "string")`)
312312
expectToFail(&s, `{"N":13}`, `cannot unmarshal "13" type "number" into field "N" (type "jsonry_test.named")`)
313313
})
314+
315+
When("unmarshalling null", func() {
316+
It("leaves basic types untouched", func() {
317+
s := struct {
318+
S string
319+
T int
320+
U uint
321+
V float64
322+
W bool
323+
}{
324+
S: "foo",
325+
T: -65,
326+
U: 12,
327+
V: 3.14,
328+
W: true,
329+
}
330+
unmarshal(&s, `{"S": null, "T": null, "U": null, "V": null, "W": null}`)
331+
Expect(s.S).To(Equal("foo"))
332+
Expect(s.T).To(Equal(-65))
333+
Expect(s.U).To(Equal(uint(12)))
334+
Expect(s.V).To(Equal(3.14))
335+
Expect(s.W).To(BeTrue())
336+
})
337+
338+
It("overwrites a pointer as nil", func() {
339+
v := "hello"
340+
s := struct{ S *string }{S: &v}
341+
unmarshal(&s, `{"S": null}`)
342+
Expect(s.S).To(BeNil())
343+
})
344+
345+
It("overwrites an interface{} as nil", func() {
346+
s := struct{ S interface{} }{S: "hello"}
347+
unmarshal(&s, `{"S": null}`)
348+
Expect(s.S).To(BeNil())
349+
})
350+
})
314351
})
315352

316353
Describe("recursive composition", func() {

0 commit comments

Comments
 (0)