mirror of
https://github.com/yusing/godoxy.git
synced 2025-07-22 12:24:02 +02:00
fix deserialization: reflect: indirection through nil pointer to embedded struct
This commit is contained in:
parent
dd0bbdc7b4
commit
d429374924
2 changed files with 44 additions and 5 deletions
|
@ -49,12 +49,12 @@ func New(t reflect.Type) reflect.Value {
|
||||||
return reflect.New(t)
|
return reflect.New(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractFields(t reflect.Type) []reflect.StructField {
|
func extractFields(t reflect.Type) (all, anonymous []reflect.StructField) {
|
||||||
for t.Kind() == reflect.Ptr {
|
for t.Kind() == reflect.Ptr {
|
||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
}
|
}
|
||||||
if t.Kind() != reflect.Struct {
|
if t.Kind() != reflect.Struct {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
var fields []reflect.StructField
|
var fields []reflect.StructField
|
||||||
for i := range t.NumField() {
|
for i := range t.NumField() {
|
||||||
|
@ -63,12 +63,15 @@ func extractFields(t reflect.Type) []reflect.StructField {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if field.Anonymous {
|
if field.Anonymous {
|
||||||
fields = append(fields, extractFields(field.Type)...)
|
f1, f2 := extractFields(field.Type)
|
||||||
|
fields = append(fields, f1...)
|
||||||
|
anonymous = append(anonymous, field)
|
||||||
|
anonymous = append(anonymous, f2...)
|
||||||
} else {
|
} else {
|
||||||
fields = append(fields, field)
|
fields = append(fields, field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fields
|
return fields, anonymous
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deserialize takes a SerializedObject and a target value, and assigns the values in the SerializedObject to the target value.
|
// Deserialize takes a SerializedObject and a target value, and assigns the values in the SerializedObject to the target value.
|
||||||
|
@ -113,7 +116,12 @@ func Deserialize(src SerializedObject, dst any) E.Error {
|
||||||
needValidate := false
|
needValidate := false
|
||||||
mapping := make(map[string]reflect.Value)
|
mapping := make(map[string]reflect.Value)
|
||||||
fieldName := make(map[string]string)
|
fieldName := make(map[string]string)
|
||||||
fields := extractFields(dstT)
|
fields, anonymous := extractFields(dstT)
|
||||||
|
for _, anon := range anonymous {
|
||||||
|
if field := dstV.FieldByName(anon.Name); field.Kind() == reflect.Ptr && field.IsNil() {
|
||||||
|
field.Set(New(anon.Type.Elem()))
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
var key string
|
var key string
|
||||||
if jsonTag, ok := field.Tag.Lookup("json"); ok {
|
if jsonTag, ok := field.Tag.Lookup("json"); ok {
|
||||||
|
@ -413,6 +421,14 @@ func DeserializeYAMLMap[V any](data []byte) (_ functional.Map[string, V], err E.
|
||||||
return functional.NewMapFrom(m2), nil
|
return functional.NewMapFrom(m2), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DeserializeJSON[T any](data []byte, target T) E.Error {
|
||||||
|
m := make(map[string]any)
|
||||||
|
if err := json.Unmarshal(data, &m); err != nil {
|
||||||
|
return E.From(err)
|
||||||
|
}
|
||||||
|
return Deserialize(m, target)
|
||||||
|
}
|
||||||
|
|
||||||
func LoadJSON[T any](path string, dst *T) error {
|
func LoadJSON[T any](path string, dst *T) error {
|
||||||
data, err := os.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -428,3 +444,14 @@ func SaveJSON[T any](path string, src *T, perm os.FileMode) error {
|
||||||
}
|
}
|
||||||
return os.WriteFile(path, data, perm)
|
return os.WriteFile(path, data, perm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoadJSONIfExist[T any](path string, dst *T) error {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return LoadJSON(path, dst)
|
||||||
|
}
|
||||||
|
|
|
@ -53,11 +53,23 @@ func TestDeserializeAnonymousField(t *testing.T) {
|
||||||
Anon
|
Anon
|
||||||
C int
|
C int
|
||||||
}
|
}
|
||||||
|
var s2 struct {
|
||||||
|
*Anon
|
||||||
|
C int
|
||||||
|
}
|
||||||
|
// all, anon := extractFields(reflect.TypeOf(s2))
|
||||||
|
// t.Fatalf("anon %v, all %v", anon, all)
|
||||||
err := Deserialize(map[string]any{"a": 1, "b": 2, "c": 3}, &s)
|
err := Deserialize(map[string]any{"a": 1, "b": 2, "c": 3}, &s)
|
||||||
ExpectNoError(t, err)
|
ExpectNoError(t, err)
|
||||||
ExpectEqual(t, s.A, 1)
|
ExpectEqual(t, s.A, 1)
|
||||||
ExpectEqual(t, s.B, 2)
|
ExpectEqual(t, s.B, 2)
|
||||||
ExpectEqual(t, s.C, 3)
|
ExpectEqual(t, s.C, 3)
|
||||||
|
|
||||||
|
err = Deserialize(map[string]any{"a": 1, "b": 2, "c": 3}, &s2)
|
||||||
|
ExpectNoError(t, err)
|
||||||
|
ExpectEqual(t, s2.A, 1)
|
||||||
|
ExpectEqual(t, s2.B, 2)
|
||||||
|
ExpectEqual(t, s2.C, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStringIntConvert(t *testing.T) {
|
func TestStringIntConvert(t *testing.T) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue