From 571007c721dfbe64183c8be701a8a7ea36d359b9 Mon Sep 17 00:00:00 2001 From: trobro Date: Thu, 7 Dec 2023 14:27:52 +0100 Subject: [PATCH] Set pointer to nil for null input (#60) --- decode.go | 7 +++++++ hjson_test.go | 53 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/decode.go b/decode.go index 7c871b4..31a0e31 100644 --- a/decode.go +++ b/decode.go @@ -463,6 +463,13 @@ func (p *hjsonParser) readTfnns(dest reflect.Value, t reflect.Type) (interface{} // Do not output anything else than a string if our destination is a string. // Pointer methods can be called if the destination is addressable, // therefore we also check if dest.Addr() implements encoding.TextUnmarshaler. + // But "null" is a special case: unmarshal it as nil if the original + // destination type is a pointer. + if chf == 'n' && !p.nodeDestination && t != nil && t.Kind() == reflect.Pointer && + strings.TrimSpace(value.String()) == "null" { + + return p.maybeWrapNode(&node, nil) + } if (newT == nil || newT.Kind() != reflect.String) && (t == nil || !(t.Implements(unmarshalerText) || dest.CanAddr() && dest.Addr().Type().Implements(unmarshalerText))) { diff --git a/hjson_test.go b/hjson_test.go index 3e42834..5407344 100644 --- a/hjson_test.go +++ b/hjson_test.go @@ -1692,6 +1692,10 @@ func (c *itsJ) UnmarshalText(text []byte) error { return nil } +func (c itsJ) MarshalJSON() ([]byte, error) { + return []byte("{\"anon\": \"" + strings.ReplaceAll(c.anon, "\"", "\\\"") + "\"}"), nil +} + type itsK *itsJ type itsL int @@ -1703,15 +1707,27 @@ func (c *itsL) UnmarshalText(text []byte) error { return nil } +func (c itsL) MarshalJSON() ([]byte, error) { + return []byte(string(rune(c))), nil +} + type itsM itsL func TestUnmarshalText(t *testing.T) { type tsA struct { - A itsJ - B *itsJ - C encoding.TextUnmarshaler - D itsL - E itsM // Does not implement encoding.TextUnmarshaler, will receive int. + A itsJ + B *itsJ + C encoding.TextUnmarshaler + D itsL + E itsM // Does not implement encoding.TextUnmarshaler, will receive int. + F *itsM + G *itsJ + H *itsJ + I *itsJ + J *string + K string + L string + Novalue *string } textA := []byte(` @@ -1720,6 +1736,9 @@ b: 4 c: 5 d: 6 e: 7 +f: null, g: "a text" +h: null, i: "second text" +j: null, k: "another text", l: null `) sA := tsA{ B: &itsJ{}, @@ -1729,13 +1748,25 @@ e: 7 if err != nil { t.Error(err) } else if !reflect.DeepEqual(sA, tsA{ - A: itsJ{"3"}, - B: &itsJ{"4"}, - C: &itsJ{"5"}, - D: itsL([]byte(`6`)[0]), - E: 7, + A: itsJ{"3"}, + B: &itsJ{"4"}, + C: &itsJ{"5"}, + D: itsL([]byte(`6`)[0]), + E: 7, + F: nil, + G: &itsJ{"a text"}, + H: nil, + I: &itsJ{"second text"}, + J: nil, + K: "another text", + L: "null", + Novalue: nil, }) { - t.Errorf("Unexpected struct values:\n%#v\n", sA) + out, errJ := json.MarshalIndent(sA, "", " ") + if errJ != nil { + t.Error(errJ) + } + t.Errorf("Unexpected struct values:\n%s\n", out) } textB := []byte(`8`)