This is an automated email from the ASF dual-hosted git repository.

opwvhk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/main by this push:
     new cea41a49c8 AVRO-3940: [java] Allow schema redefinition when equal 
(#3304)
cea41a49c8 is described below

commit cea41a49c89188bdff3a8fcd3f4ebb4e5ae2a2a1
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.
---
 .../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 f3bba56d43..f08afa23d1 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
@@ -1863,7 +1863,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())
@@ -1880,6 +1879,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;
   }
 
@@ -1925,9 +1925,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;
   }
 
@@ -1960,9 +1960,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 d4a4bec30f..9e5c78c71e 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
@@ -723,7 +723,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)) {
@@ -769,6 +768,7 @@ public class ReflectData extends SpecificData {
         }
         names.put(fullName, schema);
       }
+      names.put(c.getName(), schema);
       return schema;
     }
     return super.createSchema(type, names);
@@ -907,11 +907,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"
+          }
+        ]
+      }
     }
   ]
 

Reply via email to