Compare commits

..

2 Commits

Author SHA1 Message Date
6d7cfb86f8 v0.0.260 wmo: fix endless recursion in wmo reflection
All checks were successful
Build Docker and Deploy / Run goext test-suite (push) Successful in 50s
2023-09-12 11:40:39 +02:00
1e9d663ffe fix endless recursion in wmo reflection 2023-09-12 11:39:51 +02:00
3 changed files with 30 additions and 10 deletions

View File

@ -1,5 +1,5 @@
package goext package goext
const GoextVersion = "0.0.259" const GoextVersion = "0.0.260"
const GoextVersionTimestamp = "2023-09-12T10:48:57+0200" const GoextVersionTimestamp = "2023-09-12T11:40:39+0200"

View File

@ -25,7 +25,7 @@ func (c *Coll[TData]) EnsureInitializedReflection(v TData) {
m := make(map[string]fullTypeRef) m := make(map[string]fullTypeRef)
c.initFields("", rval.Type(), m, make([]int, 0)) c.initFields("", rval.Type(), m, make([]int, 0), make([]reflect.Type, 0))
c.implDataTypeMap[rval.Type()] = m c.implDataTypeMap[rval.Type()] = m
} }
@ -50,14 +50,13 @@ func (c *Coll[TData]) init() {
c.implDataTypeMap = make(map[reflect.Type]map[string]fullTypeRef) c.implDataTypeMap = make(map[reflect.Type]map[string]fullTypeRef)
v := reflect.ValueOf(example) v := reflect.ValueOf(example)
c.initFields("", v.Type(), c.dataTypeMap, make([]int, 0)) c.initFields("", v.Type(), c.dataTypeMap, make([]int, 0), make([]reflect.Type, 0))
} }
} }
func (c *Coll[TData]) initFields(prefix string, rtyp reflect.Type, m map[string]fullTypeRef, idxarr []int) { func (c *Coll[TData]) initFields(prefix string, rtyp reflect.Type, m map[string]fullTypeRef, idxarr []int, typesInPath []reflect.Type) {
for i := 0; i < rtyp.NumField(); i++ { for i := 0; i < rtyp.NumField(); i++ {
rsfield := rtyp.Field(i) rsfield := rtyp.Field(i)
@ -91,7 +90,7 @@ func (c *Coll[TData]) initFields(prefix string, rtyp reflect.Type, m map[string]
if langext.InArray("inline", bsontags) && rsfield.Type.Kind() == reflect.Struct { if langext.InArray("inline", bsontags) && rsfield.Type.Kind() == reflect.Struct {
// pass-through field // pass-through field
c.initFields(prefix, rsfield.Type, m, newIdxArr) c.initFields(prefix, rsfield.Type, m, newIdxArr, typesInPath)
} else { } else {
@ -122,11 +121,25 @@ func (c *Coll[TData]) initFields(prefix string, rtyp reflect.Type, m map[string]
} }
if rsfield.Type.Kind() == reflect.Struct { if rsfield.Type.Kind() == reflect.Struct {
c.initFields(fullKey+".", rsfield.Type, m, newIdxArr) c.initFields(fullKey+".", rsfield.Type, m, newIdxArr, typesInPath)
} }
if rsfield.Type.Kind() == reflect.Pointer && rsfield.Type.Elem().Kind() == reflect.Struct { if rsfield.Type.Kind() == reflect.Pointer && rsfield.Type.Elem().Kind() == reflect.Struct {
c.initFields(fullKey+".", rsfield.Type.Elem(), m, newIdxArr) innerType := rsfield.Type.Elem()
// check if there is recursion
recursion := false
for _, typ := range typesInPath {
recursion = recursion || (typ == innerType)
}
if !recursion {
// Store all seen types before that deref a pointer to prevent endless recursion
newTypesInPath := make([]reflect.Type, len(typesInPath))
copy(newTypesInPath, typesInPath)
newTypesInPath = append(newTypesInPath, rtyp)
c.initFields(fullKey+".", innerType, m, newIdxArr, newTypesInPath)
}
} }
} }

View File

@ -113,19 +113,25 @@ func TestReflectionGetTokenValueAsMongoType(t *testing.T) {
type IDType string type IDType string
type RecurseiveType struct {
Other int `bson:"other"`
Inner *RecurseiveType `bson:"inner"`
}
type TestData struct { type TestData struct {
ID IDType `bson:"_id"` ID IDType `bson:"_id"`
CDate time.Time `bson:"cdate"` CDate time.Time `bson:"cdate"`
Sub struct { Sub struct {
A string `bson:"a"` A string `bson:"a"`
} `bson:"sub"` } `bson:"sub"`
SubPtr struct { SubPtr *struct {
A string `bson:"a"` A string `bson:"a"`
} `bson:"subPtr"` } `bson:"subPtr"`
Str string `bson:"str"` Str string `bson:"str"`
Ptr *int `bson:"ptr"` Ptr *int `bson:"ptr"`
Num int `bson:"num"` Num int `bson:"num"`
MDate rfctime.RFC3339NanoTime `bson:"mdate"` MDate rfctime.RFC3339NanoTime `bson:"mdate"`
Rec RecurseiveType `bson:"rec"`
} }
coll := W[TestData](&mongo.Collection{}) coll := W[TestData](&mongo.Collection{})
@ -149,6 +155,7 @@ func TestReflectionGetTokenValueAsMongoType(t *testing.T) {
tst.AssertEqual(t, gtvasmt("hello", "str").(string), "hello") tst.AssertEqual(t, gtvasmt("hello", "str").(string), "hello")
tst.AssertEqual(t, gtvasmt("hello", "sub.a").(string), "hello") tst.AssertEqual(t, gtvasmt("hello", "sub.a").(string), "hello")
tst.AssertEqual(t, gtvasmt("hello", "subPtr.a").(string), "hello") tst.AssertEqual(t, gtvasmt("hello", "subPtr.a").(string), "hello")
tst.AssertEqual(t, gtvasmt("4", "rec.other").(int), 4)
tst.AssertEqual(t, gtvasmt("4", "num").(int), 4) tst.AssertEqual(t, gtvasmt("4", "num").(int), 4)
tst.AssertEqual(t, gtvasmt("asdf", "_id").(IDType), "asdf") tst.AssertEqual(t, gtvasmt("asdf", "_id").(IDType), "asdf")
tst.AssertEqual(t, gtvasmt("", "ptr").(*int), nil) tst.AssertEqual(t, gtvasmt("", "ptr").(*int), nil)