diff --git a/lang/java/idl/src/main/java/org/apache/avro/idl/IdlReader.java b/lang/java/idl/src/main/java/org/apache/avro/idl/IdlReader.java index f6d1fb49dcb..d31e810d8f3 100644 --- a/lang/java/idl/src/main/java/org/apache/avro/idl/IdlReader.java +++ b/lang/java/idl/src/main/java/org/apache/avro/idl/IdlReader.java @@ -34,6 +34,7 @@ import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.Recognizer; import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.tree.ParseTreeWalker; import org.apache.avro.JsonProperties; import org.apache.avro.JsonSchemaParser; import org.apache.avro.LogicalType; @@ -207,20 +208,22 @@ private IdlFile parse(URI inputDir, CharStream charStream) { IdlParser parser = new IdlParser(tokenStream); parser.removeErrorListeners(); parser.addErrorListener(SIMPLE_AVRO_ERROR_LISTENER); - parser.addParseListener(parseListener); + // parser.addParseListener(parseListener); parser.setTrace(false); - parser.setBuildParseTree(false); + // Parse the input, then walk the parse tree using the listener. + // Although the parse can call the listener directly, there are edge cases where + // the enter and exit rules are not called in pairs. This a known issue and + // currently by design. See: https://github.com/antlr/antlr4/issues/18 try { - // Trigger parsing. - parser.idlFile(); + IdlFileContext idlFileContext = parser.idlFile(); + ParseTreeWalker.DEFAULT.walk(parseListener, idlFileContext); + return parseListener.getIdlFile(); } catch (SchemaParseException e) { throw e; } catch (RuntimeException e) { throw new SchemaParseException(e); } - - return parseListener.getIdlFile(); } /* Package private to facilitate testing */ diff --git a/lang/java/idl/src/test/idl/extra/duplicateNameErrorParsing.avdl b/lang/java/idl/src/test/idl/extra/duplicateNameErrorParsing.avdl new file mode 100644 index 00000000000..f6700b0d77e --- /dev/null +++ b/lang/java/idl/src/test/idl/extra/duplicateNameErrorParsing.avdl @@ -0,0 +1,14 @@ +namespace duplicateNameParseError; + +// Test that parsing fails when redefining an enum with different symbols. +// Avro 1.12.0 fails to parse this, but the correct result is an explicit error that redefinition is not allowed. + +enum Foo { + UNKNOWN, + BAR +} = UNKNOWN; + +enum Foo { + UNKNOWN, + BAZ +} = UNKNOWN; diff --git a/lang/java/idl/src/test/java/org/apache/avro/idl/TestIdlReader.java b/lang/java/idl/src/test/java/org/apache/avro/idl/TestIdlReader.java index 96034cf3950..d437f9299b0 100644 --- a/lang/java/idl/src/test/java/org/apache/avro/idl/TestIdlReader.java +++ b/lang/java/idl/src/test/java/org/apache/avro/idl/TestIdlReader.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.avro.Protocol; import org.apache.avro.Schema; +import org.apache.avro.SchemaParseException; import org.junit.Before; import org.junit.Test; import java.io.BufferedReader; @@ -156,7 +157,16 @@ public void testDocCommentsAndWarnings() throws Exception { warnings); } - @SuppressWarnings("SameParameterValue") + @Test + public void testErrorDuplicateNamedType() throws IOException { + try { + parseExtraIdlFile("duplicateNameErrorParsing.avdl"); + fail("Expected a failure: named schemas cannot be redefined."); + } catch (SchemaParseException e) { + assertEquals("Can't redefine: duplicateNameParseError.Foo", e.getMessage()); + } + } + private IdlFile parseExtraIdlFile(String fileName) throws IOException { return new IdlReader().parse(EXTRA_TEST_DIR.toPath().resolve(fileName)); }