This is an automated email from the ASF dual-hosted git repository. opwvhk pushed a commit to branch branch-1.12 in repository https://gitbox.apache.org/repos/asf/avro.git
commit a10fc5eaae3d5107b0266880472f6a03c9591f2b Author: Michel Davit <[email protected]> AuthorDate: Thu May 29 16:34:14 2025 +0200 AVRO-3940: [java] Allow schema redefinition when equal (#3304) ParseContext.put accept known schemas when strictly identical. Call to this method was made before schema was fully parsed avoiding exact schema redefinition in files. Call ParseContext.put when schema is fully parsed. This has an inpact on the schemas ordering returned by the parser. (cherry picked from commit cea41a49c89188bdff3a8fcd3f4ebb4e5ae2a2a1) --- .../avro/src/main/java/org/apache/avro/ParseContext.java | 2 +- lang/java/avro/src/main/java/org/apache/avro/Schema.java | 6 +++--- .../main/java/org/apache/avro/reflect/ReflectData.java | 8 ++------ .../avro/src/test/java/org/apache/avro/TestSchema.java | 14 +++++++++----- .../test/resources/multipleFile/ApplicationEvent.avsc | 16 ++++++++++++++++ .../src/test/avro/multipleSchemas/ApplicationEvent.avsc | 16 ++++++++++++++++ 6 files changed, 47 insertions(+), 15 deletions(-) diff --git a/lang/java/avro/src/main/java/org/apache/avro/ParseContext.java b/lang/java/avro/src/main/java/org/apache/avro/ParseContext.java index 0c405dd640..1d0873eb8b 100644 --- a/lang/java/avro/src/main/java/org/apache/avro/ParseContext.java +++ b/lang/java/avro/src/main/java/org/apache/avro/ParseContext.java @@ -277,7 +277,7 @@ public class ParseContext { * references, even if parsed from different files. Note: the context must be * committed for this method to work. * - * @return all parsed schemas, in the order they were parsed + * @return all parsed schemas * @throws AvroTypeException if a schema reference cannot be resolved */ public List<Schema> resolveAllSchemas() { diff --git a/lang/java/avro/src/main/java/org/apache/avro/Schema.java b/lang/java/avro/src/main/java/org/apache/avro/Schema.java index 2f0711ed40..8805061073 100644 --- a/lang/java/avro/src/main/java/org/apache/avro/Schema.java +++ b/lang/java/avro/src/main/java/org/apache/avro/Schema.java @@ -1862,7 +1862,6 @@ public abstract class Schema extends JsonProperties implements Serializable { Name name = parseName(schema, currentNameSpace); String doc = parseDoc(schema); Schema result = new RecordSchema(name, doc, isTypeError); - context.put(result); JsonNode fieldsNode = schema.get("fields"); if (fieldsNode == null || !fieldsNode.isArray()) @@ -1879,6 +1878,7 @@ public abstract class Schema extends JsonProperties implements Serializable { result.setFields(fields); parsePropertiesAndLogicalType(schema, result, SCHEMA_RESERVED); parseAliases(schema, result); + context.put(result); return result; } @@ -1924,9 +1924,9 @@ public abstract class Schema extends JsonProperties implements Serializable { } Schema result = new EnumSchema(name, doc, symbols, defaultSymbol); - context.put(result); parsePropertiesAndLogicalType(schema, result, ENUM_RESERVED); parseAliases(schema, result); + context.put(result); return result; } @@ -1959,9 +1959,9 @@ public abstract class Schema extends JsonProperties implements Serializable { throw new SchemaParseException("Invalid or no size: " + schema); Schema result = new FixedSchema(name, doc, sizeNode.intValue()); - context.put(result); parsePropertiesAndLogicalType(schema, result, SCHEMA_RESERVED); parseAliases(schema, result); + context.put(result); return result; } diff --git a/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java b/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java index 19c3027f27..5bde470571 100644 --- a/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java +++ b/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java @@ -725,7 +725,6 @@ public class ReflectData extends SpecificData { boolean error = Throwable.class.isAssignableFrom(c); schema = Schema.createRecord(name, doc, space, error); consumeAvroAliasAnnotation(c, schema); - names.put(c.getName(), schema); for (Field field : getCachedFields(c)) if ((field.getModifiers() & (Modifier.TRANSIENT | Modifier.STATIC)) == 0 && !field.isAnnotationPresent(AvroIgnore.class)) { @@ -771,6 +770,7 @@ public class ReflectData extends SpecificData { } names.put(fullName, schema); } + names.put(c.getName(), schema); return schema; } return super.createSchema(type, names); @@ -909,11 +909,7 @@ public class ReflectData extends SpecificData { } } - // reverse types, since they were defined in reference order - List<Schema> types = new ArrayList<>(names.values()); - Collections.reverse(types); - protocol.setTypes(types); - + protocol.setTypes(new ArrayList<>(names.values())); return protocol; } diff --git a/lang/java/avro/src/test/java/org/apache/avro/TestSchema.java b/lang/java/avro/src/test/java/org/apache/avro/TestSchema.java index 9a3b14ee75..d8fb94f9f0 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/TestSchema.java +++ b/lang/java/avro/src/test/java/org/apache/avro/TestSchema.java @@ -32,7 +32,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; @@ -606,13 +609,14 @@ public class TestSchema { parser.parse(f1); parser.parse(f2); parser.parse(f3); - final List<Schema> schemas = parser.getParsedNamedSchemas(); + final Map<String, Schema> schemas = parser.getParsedNamedSchemas().stream() + .collect(Collectors.toMap(Schema::getName, Function.identity())); Assertions.assertEquals(3, schemas.size()); - Schema schemaAppEvent = schemas.get(0); - Schema schemaDocInfo = schemas.get(1); - Schema schemaResponse = schemas.get(2); + Schema schemaAppEvent = schemas.get("ApplicationEvent"); + Schema schemaDocInfo = schemas.get("DocumentInfo"); + Schema schemaResponse = schemas.get("MyResponse"); Assertions.assertNotNull(schemaAppEvent); - Assertions.assertEquals(3, schemaAppEvent.getFields().size()); + Assertions.assertEquals(4, schemaAppEvent.getFields().size()); Field documents = schemaAppEvent.getField("documents"); Schema docSchema = documents.schema().getTypes().get(1).getElementType(); Assertions.assertEquals(docSchema, schemaDocInfo); diff --git a/lang/java/avro/src/test/resources/multipleFile/ApplicationEvent.avsc b/lang/java/avro/src/test/resources/multipleFile/ApplicationEvent.avsc index 6902084350..efc7fbf613 100644 --- a/lang/java/avro/src/test/resources/multipleFile/ApplicationEvent.avsc +++ b/lang/java/avro/src/test/resources/multipleFile/ApplicationEvent.avsc @@ -22,6 +22,22 @@ }], "doc": "", "default": null + }, + { + "name": "response", + "type": { + "namespace": "model", + "type": "record", + "doc": "", + "name": "MyResponse", + "fields": [ + { + "name": "isSuccessful", + "type": "boolean", + "doc": "Indicator for successful or unsuccessful call" + } + ] + } } ] diff --git a/lang/java/maven-plugin/src/test/avro/multipleSchemas/ApplicationEvent.avsc b/lang/java/maven-plugin/src/test/avro/multipleSchemas/ApplicationEvent.avsc index 6902084350..efc7fbf613 100644 --- a/lang/java/maven-plugin/src/test/avro/multipleSchemas/ApplicationEvent.avsc +++ b/lang/java/maven-plugin/src/test/avro/multipleSchemas/ApplicationEvent.avsc @@ -22,6 +22,22 @@ }], "doc": "", "default": null + }, + { + "name": "response", + "type": { + "namespace": "model", + "type": "record", + "doc": "", + "name": "MyResponse", + "fields": [ + { + "name": "isSuccessful", + "type": "boolean", + "doc": "Indicator for successful or unsuccessful call" + } + ] + } } ]
