From 3865773750526b1e7e266aab2f41ce793194cb2d Mon Sep 17 00:00:00 2001 From: David Grossman Date: Mon, 1 May 2023 18:43:21 -0700 Subject: [PATCH] [parser] fix default parsing of record field's of type union (#487) --- .../avroutil1/parser/avsc/AvscParser.java | 36 +-------------- .../avroutil1/parser/avsc/AvscParserTest.java | 11 +++++ .../schemas/RecordDefaultWithUnionField.avsc | 45 +++++++++++++++++++ .../test/resources/schemas/TestTreeNode.avsc | 5 ++- 4 files changed, 61 insertions(+), 36 deletions(-) create mode 100644 parser/src/test/resources/schemas/RecordDefaultWithUnionField.avsc diff --git a/parser/src/main/java/com/linkedin/avroutil1/parser/avsc/AvscParser.java b/parser/src/main/java/com/linkedin/avroutil1/parser/avsc/AvscParser.java index 71d8d5fe6..2915f1635 100644 --- a/parser/src/main/java/com/linkedin/avroutil1/parser/avsc/AvscParser.java +++ b/parser/src/main/java/com/linkedin/avroutil1/parser/avsc/AvscParser.java @@ -857,44 +857,12 @@ mapSchema, locationOf(context.getUri(), literalNode), map AvroUnionSchema unionSchema = (AvroUnionSchema) fieldSchema; //union values are encoded as a json object {"" : } //except for null - JsonValue.ValueType valueType = fieldLiteral.getValueType(); - int branchNumber; - switch (valueType) { - case NULL: - branchNumber = unionSchema.resolve(AvroType.NULL); - literal = fieldLiteral; - break; - case OBJECT: - Set> unionObjectProps = ((JsonObjectExt) fieldLiteral).entrySet(); - if (unionObjectProps.size() != 1) { - //TODO - provide more details (union object expected to only have a single prop) - issue = AvscIssues.badFieldDefaultValue(locationOf(context.getUri(), literalNode), - literalNode.toString(), avroType, fieldName); - return new LiteralOrIssue(issue); - } - Map.Entry discriminatorEntry = unionObjectProps.iterator().next(); - String discriminator = discriminatorEntry.getKey(); - literal = (JsonValueExt) discriminatorEntry.getValue(); - AvroType literalType = AvroType.fromTypeName(discriminator); - if (literalType != null) { - branchNumber = unionSchema.resolve(literalType); - } else { - //assume fullname then - branchNumber = unionSchema.resolve(discriminator); - } - break; - default: - issue = AvscIssues.badFieldDefaultValue(locationOf(context.getUri(), literalNode), - literalNode.toString(), avroType, fieldName); - return new LiteralOrIssue(issue); - - } - if (branchNumber < 0) { + if (unionSchema.getTypes().size() == 0) { issue = AvscIssues.badFieldDefaultValue(locationOf(context.getUri(), literalNode), literalNode.toString(), avroType, fieldName); return new LiteralOrIssue(issue); } - literalSchema = unionSchema.getTypes().get(branchNumber).getSchema(); + literalSchema = unionSchema.getTypes().get(0).getSchema(); } LiteralOrIssue fieldValueOrIssue = parseLiteral(literal, literalSchema, fieldName, context); if (fieldValueOrIssue.getIssue() != null) { diff --git a/parser/src/test/java/com/linkedin/avroutil1/parser/avsc/AvscParserTest.java b/parser/src/test/java/com/linkedin/avroutil1/parser/avsc/AvscParserTest.java index a62a6e43f..66f1e0439 100644 --- a/parser/src/test/java/com/linkedin/avroutil1/parser/avsc/AvscParserTest.java +++ b/parser/src/test/java/com/linkedin/avroutil1/parser/avsc/AvscParserTest.java @@ -17,6 +17,7 @@ import com.linkedin.avroutil1.model.AvroMapLiteral; import com.linkedin.avroutil1.model.AvroMapSchema; import com.linkedin.avroutil1.model.AvroPrimitiveSchema; +import com.linkedin.avroutil1.model.AvroRecordLiteral; import com.linkedin.avroutil1.model.AvroRecordSchema; import com.linkedin.avroutil1.model.AvroSchema; import com.linkedin.avroutil1.model.AvroSchemaField; @@ -72,6 +73,16 @@ public void testParseInvalidType2() throws Exception { Assert.assertTrue(result.getParseError() instanceof AvroSyntaxException); } + @Test + public void testRecordDefaults() throws Exception { + String avsc = TestUtil.load("schemas/RecordDefaultWithUnionField.avsc"); + AvscParser parser = new AvscParser(); + AvscParseResult result = parser.parse(avsc); + Assert.assertNull(result.getParseError()); + AvroRecordLiteral defaultFieldValue = + (AvroRecordLiteral) ((AvroRecordSchema) result.getTopLevelSchema()).getFields().get(0).getDefaultValue(); + Assert.assertEquals(defaultFieldValue.getValue().toString(), "{f2=null, f3=Enum1, f1=someString}"); + } @Test public void testParseInvalidDoc() throws Exception { String avsc = TestUtil.load("schemas/TestInvalidDocRecord.avsc"); diff --git a/parser/src/test/resources/schemas/RecordDefaultWithUnionField.avsc b/parser/src/test/resources/schemas/RecordDefaultWithUnionField.avsc new file mode 100644 index 000000000..632f78ad8 --- /dev/null +++ b/parser/src/test/resources/schemas/RecordDefaultWithUnionField.avsc @@ -0,0 +1,45 @@ +{ + "type": "record", + "name": "SchemaWithRecordDefault", + "fields": [ + { + "name": "mainField", + "type": { + "type": "record", + "name": "InnerRecord", + "fields": [ + { + "name": "f1", + "type": [ + "string", + "null" + ] + }, + { + "name": "f2", + "type": [ + "null", + "string" + ] + }, + { + "name": "f3", + "type": { + "type": "enum", + "name": "MyEnum", + "symbols": [ + "Enum1", + "Enum2" + ] + } + } + ] + }, + "default": { + "f1": "someString", + "f2": null, + "f3": "Enum1" + } + } + ] +} \ No newline at end of file diff --git a/parser/src/test/resources/schemas/TestTreeNode.avsc b/parser/src/test/resources/schemas/TestTreeNode.avsc index 460a0dd6d..db819864d 100644 --- a/parser/src/test/resources/schemas/TestTreeNode.avsc +++ b/parser/src/test/resources/schemas/TestTreeNode.avsc @@ -13,8 +13,9 @@ "null" ], "default": [ - {"children" : {"array": []}}, - {"children" : null} + { + "children": [] + } ] } ]