Skip to content

Commit a258996

Browse files
author
James Crasta
committed
Support absolute name type references.
When we have schemas that reference schemas in a different packages, you use the full dotted path name to reference the type. Support these paths during schema import.
1 parent 415d6fa commit a258996

File tree

3 files changed

+39
-8
lines changed

3 files changed

+39
-8
lines changed

schema.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"io/ioutil"
77
"math"
88
"reflect"
9+
"strings"
910
)
1011

1112
const (
@@ -957,7 +958,14 @@ func schemaByType(i interface{}, registry map[string]Schema, namespace string) (
957958
case typeString:
958959
return new(StringSchema), nil
959960
default:
960-
schema, ok := registry[getFullName(v, namespace)]
961+
// If a name reference contains a dot, we consider it a full name reference.
962+
// Otherwise, use the getFullName helper to look up the name.
963+
// See https://avro.apache.org/docs/1.7.7/spec.html#Names
964+
fullName := v
965+
if !strings.ContainsRune(fullName, '.') {
966+
fullName = getFullName(v, namespace)
967+
}
968+
schema, ok := registry[fullName]
961969
if !ok {
962970
return nil, fmt.Errorf("Unknown type name: %s", v)
963971
}
@@ -1002,6 +1010,10 @@ func schemaByType(i interface{}, registry map[string]Schema, namespace string) (
10021010
return parseFixedSchema(v, registry, namespace)
10031011
case typeRecord:
10041012
return parseRecordSchema(v, registry, namespace)
1013+
default:
1014+
// Type references can also be done as {"type": "otherType"}.
1015+
// Just call back in so we can handle this scenario in the string matcher above.
1016+
return schemaByType(v[schemaTypeField], registry, namespace)
10051017
}
10061018
case []interface{}:
10071019
return parseUnionSchema(v, registry, namespace)
@@ -1128,7 +1140,7 @@ func addSchema(name string, schema Schema, schemas map[string]Schema) Schema {
11281140
}
11291141

11301142
func getFullName(name string, namespace string) string {
1131-
if len(namespace) > 0 {
1143+
if len(namespace) > 0 && !strings.ContainsRune(name, '.') {
11321144
return namespace + "." + name
11331145
}
11341146

schema_test.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -260,13 +260,21 @@ func TestFixedSchema(t *testing.T) {
260260
}
261261

262262
func TestSchemaRegistryMap(t *testing.T) {
263-
rawSchema1 := `{"type": "record", "name": "TestRecord", "fields": [
264-
{"name": "longRecordField", "type": "long"}
265-
]}`
263+
rawSchema1 := `{"type": "record", "name": "TestRecord", "namespace": "com.github.elodina", "fields": [
264+
{"name": "longRecordField", "type": "long"}
265+
]}`
266266

267-
rawSchema2 := `{"type": "record", "name": "TestRecord2", "fields": [
268-
{"name": "record", "type": ["null", "TestRecord"]}
269-
]}`
267+
rawSchema2 := `{"type": "record", "name": "TestRecord2", "namespace": "com.github.elodina", "fields": [
268+
{"name": "record", "type": ["null", "TestRecord"]}
269+
]}`
270+
271+
rawSchema3 := `{"type": "record", "name": "TestRecord3", "namespace": "com.github.other", "fields": [
272+
{"name": "record", "type": ["null", "com.github.elodina.TestRecord2"]}
273+
]}`
274+
275+
rawSchema4 := `{"type": "record", "name": "TestRecord3", "namespace": "com.github.elodina", "fields": [
276+
{"name": "record", "type": ["null", {"type": "TestRecord2"}, "com.github.other.TestRecord3"]}
277+
]}`
270278

271279
registry := make(map[string]Schema)
272280

@@ -279,6 +287,16 @@ func TestSchemaRegistryMap(t *testing.T) {
279287
assert(t, err, nil)
280288
assert(t, s2.Type(), Record)
281289
assert(t, len(registry), 2)
290+
291+
s3, err := ParseSchemaWithRegistry(rawSchema3, registry)
292+
assert(t, err, nil)
293+
assert(t, s3.Type(), Record)
294+
assert(t, len(registry), 3)
295+
296+
s4, err := ParseSchemaWithRegistry(rawSchema4, registry)
297+
assert(t, err, nil)
298+
assert(t, s4.Type(), Record)
299+
assert(t, len(registry), 4)
282300
}
283301

284302
func TestRecordCustomProps(t *testing.T) {

utils_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ func assert(t *testing.T, actual interface{}, expected interface{}) {
1212
if !reflect.DeepEqual(actual, expected) {
1313
_, fn, line, _ := runtime.Caller(1)
1414
t.Errorf("Expected %v, actual %v\n@%s:%d", expected, actual, fn, line)
15+
t.FailNow()
1516
}
1617
}
1718

0 commit comments

Comments
 (0)