diff --git a/schema_parse.go b/schema_parse.go index 76e21e1..3022116 100644 --- a/schema_parse.go +++ b/schema_parse.go @@ -564,6 +564,13 @@ func derefSchema(schema Schema) Schema { return walkSchema(schema, func(schema Schema) Schema { if ns, ok := schema.(NamedSchema); ok { + if _, hasSeen := seen[ns.FullName()]; hasSeen { + // This NamedSchema has been seen in this run, it needs + // to be turned into a reference. It is possible it was + // dereferenced in a previous run. + return NewRefSchema(ns) + } + seen[ns.FullName()] = struct{}{} return schema } diff --git a/schema_test.go b/schema_test.go index 1cbc8d3..b74265b 100644 --- a/schema_test.go +++ b/schema_test.go @@ -2,6 +2,7 @@ package avro_test import ( "encoding/json" + "strings" "testing" "github.com/hamba/avro/v2" @@ -1480,3 +1481,50 @@ func TestSchema_ParseBackAndForth(t *testing.T) { assert.NoError(t, err) assert.Equal(t, schema, schema2) } + +func TestSchema_DereferencingRectifiesAlreadySeenSchema(t *testing.T) { + schmCache := &avro.SchemaCache{} + _, err := avro.ParseWithCache(`{ + "type": "record", + "name": "test1", + "namespace": "org.hamba.avro", + "fields": [ + {"name": "a", "type": "string"} + ] +}`, "", schmCache) + require.NoError(t, err) + _, err = avro.ParseWithCache(`{ + "type": "record", + "name": "test2", + "namespace": "org.hamba.avro", + "fields": [ + { + "name": "inner", + "type": { + "name": "InnerRecord", + "type": "record", + "fields": [ + {"name": "b", "type": "org.hamba.avro.test1"} + ] + } + } + ] +}`, "", schmCache) + require.NoError(t, err) + schm, err := avro.ParseWithCache(`{ + "type": "record", + "name": "test3", + "namespace": "org.hamba.avro", + "fields": [ + {"name": "c", "type": "org.hamba.avro.test1"}, + {"name": "d", "type": "org.hamba.avro.test2"} + ] +} +`, "", schmCache) + require.NoError(t, err) + + strSchema := schm.String() + + n := strings.Count(strSchema, `"name":"org.hamba.avro.test1"`) + assert.Equal(t, 1, n) +}