diff --git a/CHANGELOG.md b/CHANGELOG.md index 62f16f7..1577e22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,14 +4,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm The structure and content of this file follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## [1.21.0] - unreleased +## [1.21.0] - 2023-12-18 ### Added - Added the Expr function `BracketString` to force the use of bracket notation to for normalized paths as described by the draft IETF JSONPath document in section 2.7. - Added `jp.Expr.Locate()` function that returns normalized paths for JSONPath expression. ### Fixed -- TBD Unmarshal now supports arrays such as `[4]int`. +- Unmarshal now supports arrays such as `[4]int`. ## [1.20.3] - 2023-11-09 ### Added diff --git a/alt/recomposer.go b/alt/recomposer.go index b5ae5ea..d7a282b 100644 --- a/alt/recomposer.go +++ b/alt/recomposer.go @@ -318,7 +318,7 @@ func (r *Recomposer) recomp(v any, rv reflect.Value) { rv = rv.Elem() } switch rv.Kind() { - case reflect.Array, reflect.Slice: + case reflect.Slice: va, ok := (v).([]any) if !ok { vv := reflect.ValueOf(v) @@ -346,6 +346,23 @@ func (r *Recomposer) recomp(v any, rv reflect.Value) { } } rv.Set(av) + case reflect.Array: + vv := reflect.ValueOf(v) + if vv.Kind() != reflect.Slice { + panic(fmt.Errorf("can only recompose a %s from a []any, not a %T", rv.Type(), v)) + } + inSize := vv.Len() + size := rv.Len() + for i := 0; i < inSize; i++ { + if size <= i { + break + } + // Kind of awkward but the double reflect is needed to get the + // actual type of the element value if the slice input is []any. + ev := vv.Index(i).Interface() + ri := rv.Index(i) + r.setValue(ev, ri, nil) + } case reflect.Map: if v == nil { return @@ -404,7 +421,6 @@ func (r *Recomposer) recomp(v any, rv reflect.Value) { } break } - vv := reflect.ValueOf(v) if vv.Kind() != reflect.Map { panic(fmt.Errorf("can only recompose a %s from a map[string]any, not a %T", rv.Type(), v)) diff --git a/alt/recomposer_test.go b/alt/recomposer_test.go index d075226..fafbe6c 100644 --- a/alt/recomposer_test.go +++ b/alt/recomposer_test.go @@ -838,3 +838,21 @@ func TestRecomposeReflectNumber(t *testing.T) { src["asInt"] = json.Number("123.4") tt.Panic(t, func() { _ = r.MustRecompose(src, &pan) }) } + +type Triple [3]int + +func TestRecomposeReflectArray(t *testing.T) { + r, err := alt.NewRecomposer("type", nil) + tt.Nil(t, err, "NewRecomposer") + + var tri Triple + + _ = r.MustRecompose([]any{1, 2, 3}, &tri) + tt.Equal(t, `[1 2 3]`, pretty.SEN(tri)) + + tri = Triple{0, 0, 0} + _ = r.MustRecompose([]any{1, 2, 3, 4}, &tri) + tt.Equal(t, `[1 2 3]`, pretty.SEN(tri)) + + tt.Panic(t, func() { _ = r.MustRecompose(map[string]any{"a": 1}, &tri) }) +} diff --git a/go.mod b/go.mod index 8a3922c..091515e 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/ohler55/ojg -go 1.20 +go 1.21 diff --git a/jp/get_test.go b/jp/get_test.go index 63997e3..34645a9 100644 --- a/jp/get_test.go +++ b/jp/get_test.go @@ -34,6 +34,8 @@ type Any struct { X any } +type triple [3]int + var ( getTestData = []*getData{ {path: "", expect: []any{}}, @@ -155,6 +157,7 @@ var ( {path: "a..b", expect: []any{112, 122, 132, 142}}, {path: "[1]", expect: []any{2}, data: []int{1, 2, 3}}, {path: "[-1]", expect: []any{3}, data: []int{1, 2, 3}}, + {path: "[1]", expect: []any{2}, data: triple{1, 2, 3}}, {path: "[-1,'a']", expect: []any{3}, data: []int{1, 2, 3}}, {path: "$[::]", expect: []any{1, 2, 3}, data: []int{1, 2, 3}}, {path: "[-1,'a'].x", diff --git a/jp/locate_test.go b/jp/locate_test.go index a1aa716..a227bf7 100644 --- a/jp/locate_test.go +++ b/jp/locate_test.go @@ -25,6 +25,7 @@ var ( {path: "", expect: []string{}}, {path: "a.b", data: map[string]any{"a": map[string]any{"b": 2}, "x": 3}, expect: []string{"a.b"}}, {path: "a[1]", data: map[string]any{"a": []any{1, 2, 3}}, expect: []string{"a[1]"}}, + {path: "[1]", data: triple{1, 2, 3}, expect: []string{"[1]"}}, {path: "a[-1]", data: map[string]any{"a": []any{1, 2, 3}}, expect: []string{"a[2]"}}, {path: "a[*]", data: map[string]any{"a": []any{1, 2, 3}}, expect: []string{"a[0]", "a[1]", "a[2]"}}, {path: "$.a.*.b", max: 2, expect: []string{"$.a[0].b", "$.a[1].b"}}, diff --git a/oj/unmashall_test.go b/oj/unmashall_test.go index 6987ae1..9d78531 100644 --- a/oj/unmashall_test.go +++ b/oj/unmashall_test.go @@ -74,3 +74,15 @@ func TestUnmarshaler(t *testing.T) { tt.Equal(t, 1, len(tags)) tt.Equal(t, 1, tags["k1"]) } + +type Triple [3]int + +func TestUnmarshalArray(t *testing.T) { + var tri Triple + src := []byte(`[1.0, 2, 3]`) + err := oj.Unmarshal(src, &tri) + tt.Nil(t, err) + tt.Equal(t, 1, tri[0]) + tt.Equal(t, 2, tri[1]) + tt.Equal(t, 3, tri[2]) +}