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 985922824396a05ceb334b9c64a491734e5ff3d9
Author: Steven Aerts <[email protected]>
AuthorDate: Tue Jun 10 13:48:18 2025 +0200

    AVRO-3527: codegen equals and hashCode for Records (#1708)
    
    Update the compiler to generate the implementation of the `.equals()`
    and `.hashCode() function, instead of relying on the
    implementation of GenericData.  This improves the performance of
    those functions significantly.
    
    The generated implementations are factor 10 to 20 faster for
    `.equals()` and a factor 5 to 10 for `.hashCode()`.
    
    Result of Perf test before the change:
    
    ```
    Benchmark              Mode  Cnt          Score             Error  Units
    SpecficTest.equals    thrpt    3   12598610.194 +/-  11160265.279  ops/s
    SpecficTest.hashCode  thrpt    3   24729446.862 +/-  29051332.794  ops/s
    ```
    
    Results using generated functions:
    
    ```
    Benchmark              Mode  Cnt          Score             Error  Units
    SpecficTest.equals    thrpt    3  211314296.950 +/- 104154793.126  ops/s
    SpecficTest.hashCode  thrpt    3  180349506.632 +/- 143639246.771  ops/s
    ```
    
    Signed-off-by: Steven Aerts <[email protected]>
    (cherry picked from commit c880f4729e0dcb99bab82dd5b5efb15f0da55890)
---
 .../java/org/apache/avro/generic/GenericData.java  |  6 +--
 .../src/main/java/org/apache/avro/util/Utf8.java   | 24 ++++++++++++
 .../avro/compiler/specific/SpecificCompiler.java   | 40 ++++++++++++++++++++
 .../specific/templates/java/classic/record.vm      | 41 ++++++++++++++++++++
 .../avro/examples/baseball/FieldTest.java          | 44 ++++++++++++++++++++++
 .../JSpecifyNullSafeAnnotationsFieldsTest.java     | 34 +++++++++++++++++
 .../JetBrainsNullSafeAnnotationsFieldsTest.java    | 34 +++++++++++++++++
 .../avro/examples/baseball/Player.java             | 36 ++++++++++++++++++
 .../avro/examples/baseball/Proto.java              |  2 +-
 .../output/AddExtraOptionalGettersTest.java        | 28 ++++++++++++++
 .../src/test/compiler/output/NoSettersTest.java    | 28 ++++++++++++++
 .../output/OptionalGettersAllFieldsTest.java       | 36 ++++++++++++++++++
 .../output/OptionalGettersNullableFieldsTest.java  | 38 +++++++++++++++++++
 .../tools/src/test/compiler/output/Player.java     | 36 ++++++++++++++++++
 14 files changed, 423 insertions(+), 4 deletions(-)

diff --git 
a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java 
b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
index 30cd133586..23fe4a63d2 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
@@ -1312,9 +1312,9 @@ public class GenericData {
     case NULL:
       return 0;
     case STRING:
-      Utf8 u1 = o1 instanceof Utf8 ? (Utf8) o1 : new Utf8(o1.toString());
-      Utf8 u2 = o2 instanceof Utf8 ? (Utf8) o2 : new Utf8(o2.toString());
-      return u1.compareTo(u2);
+      CharSequence cs1 = o1 instanceof CharSequence ? (CharSequence) o1 : 
o1.toString();
+      CharSequence cs2 = o2 instanceof CharSequence ? (CharSequence) o2 : 
o2.toString();
+      return Utf8.compareSequences(cs1, cs2);
     default:
       return ((Comparable) o1).compareTo(o2);
     }
diff --git a/lang/java/avro/src/main/java/org/apache/avro/util/Utf8.java 
b/lang/java/avro/src/main/java/org/apache/avro/util/Utf8.java
index c837708765..b315e517f6 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/util/Utf8.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/util/Utf8.java
@@ -218,4 +218,28 @@ public class Utf8 implements Comparable<Utf8>, 
CharSequence, Externalizable {
     setByteLength(in.readInt());
     in.readFully(bytes);
   }
+
+  public static int compareSequences(CharSequence cs1, CharSequence cs2) {
+    if (cs1 == cs2) {
+      return 0;
+    }
+
+    if (cs1 == null || cs2 == null) {
+      return cs1 == null ? 1 : -1;
+    }
+
+    if (cs1.getClass() == cs2.getClass() && cs1 instanceof Comparable) {
+      return ((Comparable<Object>) cs1).compareTo(cs2);
+    }
+
+    for (int i = 0, len = Math.min(cs1.length(), cs2.length()); i < len; i++) {
+      char a = cs1.charAt(i);
+      char b = cs2.charAt(i);
+      if (a != b) {
+        return a - b;
+      }
+    }
+
+    return cs1.length() - cs2.length();
+  }
 }
diff --git 
a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java
 
b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java
index 04eb11801e..b5940baa85 100644
--- 
a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java
+++ 
b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java
@@ -1139,6 +1139,46 @@ public class SpecificCompiler {
     return SpecificData.mangle(word, reservedWords, isMethod);
   }
 
+  public boolean canGenerateEqualsAndHashCode(Schema schema) {
+    return getUsedCustomLogicalTypeFactories(schema).isEmpty();
+  }
+
+  public boolean isPrimitiveType(Schema schema) {
+    return !isUnboxedJavaTypeNullable(schema) && 
getConvertedLogicalType(schema) == null;
+  }
+
+  public String hashCodeFor(Schema schema, String name) {
+    switch (javaUnbox(schema, false)) {
+    case "int":
+      return "Integer.hashCode(" + name + ")";
+    case "long":
+      return "Long.hashCode(" + name + ")";
+    case "float":
+      return "Float.hashCode(" + name + ")";
+    case "double":
+      return "Double.hashCode(" + name + ")";
+    case "boolean":
+      return "Boolean.hashCode(" + name + ")";
+    default:
+      // Hashcode of Union is expected to match ordinal
+      if (schema.getType() == Schema.Type.ENUM || ((schema.getType() == 
Schema.Type.UNION)
+          && (schema.getTypes().stream().anyMatch(t -> t.getType() == 
Schema.Type.ENUM)))) {
+        if (schema.getType() == Schema.Type.ENUM
+            || (schema.getTypes().size() == 2 && 
schema.getTypes().contains(NULL_SCHEMA))) {
+          return "(" + name + " == null ? 0 : ((java.lang.Enum) " + name + 
").ordinal())";
+        } else {
+          return "(" + name + " == null ? 0 : " + name + " instanceof 
java.lang.Enum ? ((java.lang.Enum) " + name
+              + ").ordinal() : " + name + ".hashCode())";
+        }
+      }
+      return "(" + name + " == null ? 0 : " + name + ".hashCode())";
+    }
+  }
+
+  public boolean ignoredField(Field field) {
+    return field.order() == Field.Order.IGNORE;
+  }
+
   /**
    * Utility for use by templates. Return schema fingerprint as a long.
    */
diff --git 
a/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm
 
b/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm
index 9c3e8dc332..3d877cc495 100755
--- 
a/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm
+++ 
b/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm
@@ -616,6 +616,47 @@ public class 
${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS
     }
   }
 #end
+#if ($this.canGenerateEqualsAndHashCode($schema))
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+#foreach ($field in $schema.getFields())
+#if (!${this.ignoredField($field)})
+#set ($n = ${this.mangle($field.name(), $schema.isError())})
+    result = 31 * result + ${this.hashCodeFor($field.schema(), $n)};
+#end
+#end
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof ${this.mangleTypeIdentifier($schema.getName())})) {
+      return false;
+    }
+    ${this.mangleTypeIdentifier($schema.getName())} other = 
(${this.mangleTypeIdentifier($schema.getName())}) o;
+#foreach ($field in $schema.getFields())
+#if (!${this.ignoredField($field)})
+#set ($n = ${this.mangle($field.name(), $schema.isError())})
+#set ($s = $field.schema())
+#if (${this.isPrimitiveType($s)})
+    if (this.$n != other.$n) {
+#elseif (${this.javaType($field.schema()).equals("java.lang.CharSequence")})
+    if (Utf8.compareSequences(this.$n, other.$n) != 0) {
+#else
+    if (!java.util.Objects.equals(this.$n, other.$n)) {
+#end
+      return false;
+    }
+#end
+#end
+    return true;
+  }
+#end
 }
 
 #macro( encodeVar $indent $var $s )
diff --git 
a/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/FieldTest.java
 
b/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/FieldTest.java
index 6e69cd3df4..8799e202fc 100644
--- 
a/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/FieldTest.java
+++ 
b/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/FieldTest.java
@@ -15,6 +15,8 @@ import org.apache.avro.message.SchemaStore;
 @org.apache.avro.specific.AvroGenerated
 public class FieldTest extends org.apache.avro.specific.SpecificRecordBase 
implements org.apache.avro.specific.SpecificRecord {
   private static final long serialVersionUID = 4609235620572341636L;
+
+
   public static final org.apache.avro.Schema SCHEMA$ = new 
org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"FieldTest\",\"namespace\":\"avro.examples.baseball\",\"doc\":\"Test
 various field 
types\",\"fields\":[{\"name\":\"number\",\"type\":\"int\",\"doc\":\"The number 
of the 
player\"},{\"name\":\"last_name\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},{\"name\":\"timestamp\",\"type\":{\"type\":\"long\",\"logicalType\":\"timestamp-millis\"}},{\"na
 [...]
   public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
 
@@ -659,6 +661,48 @@ public class FieldTest extends 
org.apache.avro.specific.SpecificRecordBase imple
     READER$.read(this, SpecificData.getDecoder(in));
   }
 
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    result = 31 * result + Integer.hashCode(number);
+    result = 31 * result + (last_name == null ? 0 : last_name.hashCode());
+    result = 31 * result + (timestamp == null ? 0 : timestamp.hashCode());
+    result = 31 * result + (timestampMicros == null ? 0 : 
timestampMicros.hashCode());
+    result = 31 * result + (timeMillis == null ? 0 : timeMillis.hashCode());
+    result = 31 * result + (timeMicros == null ? 0 : timeMicros.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof FieldTest)) {
+      return false;
+    }
+    FieldTest other = (FieldTest) o;
+    if (this.number != other.number) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.last_name, other.last_name)) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.timestamp, other.timestamp)) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.timestampMicros, 
other.timestampMicros)) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.timeMillis, other.timeMillis)) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.timeMicros, other.timeMicros)) {
+      return false;
+    }
+    return true;
+  }
 }
 
 
diff --git 
a/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/JSpecifyNullSafeAnnotationsFieldsTest.java
 
b/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/JSpecifyNullSafeAnnotationsFieldsTest.java
index 7a352b703d..e99e04dc52 100644
--- 
a/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/JSpecifyNullSafeAnnotationsFieldsTest.java
+++ 
b/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/JSpecifyNullSafeAnnotationsFieldsTest.java
@@ -581,6 +581,40 @@ public class JSpecifyNullSafeAnnotationsFieldsTest extends 
org.apache.avro.speci
       }
     }
   }
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    result = 31 * result + (name == null ? 0 : name.hashCode());
+    result = 31 * result + (nullable_name == null ? 0 : 
nullable_name.hashCode());
+    result = 31 * result + Integer.hashCode(favorite_number);
+    result = 31 * result + (nullable_favorite_number == null ? 0 : 
nullable_favorite_number.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof JSpecifyNullSafeAnnotationsFieldsTest)) {
+      return false;
+    }
+    JSpecifyNullSafeAnnotationsFieldsTest other = 
(JSpecifyNullSafeAnnotationsFieldsTest) o;
+    if (!java.util.Objects.equals(this.name, other.name)) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.nullable_name, other.nullable_name)) {
+      return false;
+    }
+    if (this.favorite_number != other.favorite_number) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.nullable_favorite_number, 
other.nullable_favorite_number)) {
+      return false;
+    }
+    return true;
+  }
 }
 
 
diff --git 
a/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/JetBrainsNullSafeAnnotationsFieldsTest.java
 
b/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/JetBrainsNullSafeAnnotationsFieldsTest.java
index 5e898c8847..7df11818f5 100644
--- 
a/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/JetBrainsNullSafeAnnotationsFieldsTest.java
+++ 
b/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/JetBrainsNullSafeAnnotationsFieldsTest.java
@@ -581,6 +581,40 @@ public class JetBrainsNullSafeAnnotationsFieldsTest 
extends org.apache.avro.spec
       }
     }
   }
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    result = 31 * result + (name == null ? 0 : name.hashCode());
+    result = 31 * result + (nullable_name == null ? 0 : 
nullable_name.hashCode());
+    result = 31 * result + Integer.hashCode(favorite_number);
+    result = 31 * result + (nullable_favorite_number == null ? 0 : 
nullable_favorite_number.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof JetBrainsNullSafeAnnotationsFieldsTest)) {
+      return false;
+    }
+    JetBrainsNullSafeAnnotationsFieldsTest other = 
(JetBrainsNullSafeAnnotationsFieldsTest) o;
+    if (!java.util.Objects.equals(this.name, other.name)) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.nullable_name, other.nullable_name)) {
+      return false;
+    }
+    if (this.favorite_number != other.favorite_number) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.nullable_favorite_number, 
other.nullable_favorite_number)) {
+      return false;
+    }
+    return true;
+  }
 }
 
 
diff --git 
a/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java
 
b/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java
index 1821e41cbe..79fc55dbf9 100644
--- 
a/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java
+++ 
b/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Player.java
@@ -15,6 +15,8 @@ import org.apache.avro.message.SchemaStore;
 @org.apache.avro.specific.AvroGenerated
 public class Player extends org.apache.avro.specific.SpecificRecordBase 
implements org.apache.avro.specific.SpecificRecord {
   private static final long serialVersionUID = 3865593031278745715L;
+
+
   public static final org.apache.avro.Schema SCHEMA$ = new 
org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"Player\",\"namespace\":\"avro.examples.baseball\",\"doc\":\"選手
 is Japanese for 
player.\",\"fields\":[{\"name\":\"number\",\"type\":\"int\",\"doc\":\"The 
number of the 
player\"},{\"name\":\"first_name\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},{\"name\":\"last_name\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},{\"name\
 [...]
   public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
 
@@ -587,6 +589,40 @@ public class Player extends 
org.apache.avro.specific.SpecificRecordBase implemen
       }
     }
   }
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    result = 31 * result + Integer.hashCode(number);
+    result = 31 * result + (first_name == null ? 0 : first_name.hashCode());
+    result = 31 * result + (last_name == null ? 0 : last_name.hashCode());
+    result = 31 * result + (position == null ? 0 : position.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof Player)) {
+      return false;
+    }
+    Player other = (Player) o;
+    if (this.number != other.number) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.first_name, other.first_name)) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.last_name, other.last_name)) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.position, other.position)) {
+      return false;
+    }
+    return true;
+  }
 }
 
 
diff --git 
a/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Proto.java
 
b/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Proto.java
index def7bca42b..45c104530d 100644
--- 
a/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Proto.java
+++ 
b/lang/java/tools/src/test/compiler/output-string/avro/examples/baseball/Proto.java
@@ -24,4 +24,4 @@ public interface Proto {
      */
     void bar(org.apache.avro.ipc.Callback<java.lang.Void> callback) throws 
java.io.IOException;
   }
-}
+}
\ No newline at end of file
diff --git 
a/lang/java/tools/src/test/compiler/output/AddExtraOptionalGettersTest.java 
b/lang/java/tools/src/test/compiler/output/AddExtraOptionalGettersTest.java
index d8c5361848..328091ac8b 100644
--- a/lang/java/tools/src/test/compiler/output/AddExtraOptionalGettersTest.java
+++ b/lang/java/tools/src/test/compiler/output/AddExtraOptionalGettersTest.java
@@ -15,6 +15,8 @@ import java.util.Optional;
 @org.apache.avro.specific.AvroGenerated
 public class AddExtraOptionalGettersTest extends 
org.apache.avro.specific.SpecificRecordBase implements 
org.apache.avro.specific.SpecificRecord {
   private static final long serialVersionUID = -3300987256178011215L;
+
+
   public static final org.apache.avro.Schema SCHEMA$ = new 
org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"AddExtraOptionalGettersTest\",\"namespace\":\"avro.examples.baseball\",\"doc\":\"Test
 that extra optional getters are 
added\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"favorite_number\",\"type\":[\"int\",\"null\"]}]}");
   public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
 
@@ -428,6 +430,32 @@ public class AddExtraOptionalGettersTest extends 
org.apache.avro.specific.Specif
       }
     }
   }
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    result = 31 * result + (name == null ? 0 : name.hashCode());
+    result = 31 * result + (favorite_number == null ? 0 : 
favorite_number.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof AddExtraOptionalGettersTest)) {
+      return false;
+    }
+    AddExtraOptionalGettersTest other = (AddExtraOptionalGettersTest) o;
+    if (Utf8.compareSequences(this.name, other.name) != 0) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.favorite_number, 
other.favorite_number)) {
+      return false;
+    }
+    return true;
+  }
 }
 
 
diff --git a/lang/java/tools/src/test/compiler/output/NoSettersTest.java 
b/lang/java/tools/src/test/compiler/output/NoSettersTest.java
index 6e4cea44f8..92c91854cf 100644
--- a/lang/java/tools/src/test/compiler/output/NoSettersTest.java
+++ b/lang/java/tools/src/test/compiler/output/NoSettersTest.java
@@ -15,6 +15,8 @@ import org.apache.avro.message.SchemaStore;
 @org.apache.avro.specific.AvroGenerated
 public class NoSettersTest extends org.apache.avro.specific.SpecificRecordBase 
implements org.apache.avro.specific.SpecificRecord {
   private static final long serialVersionUID = 8604146783520861700L;
+
+
   public static final org.apache.avro.Schema SCHEMA$ = new 
org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"NoSettersTest\",\"namespace\":\"avro.examples.baseball\",\"doc\":\"Test
 that setters are 
omitted\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"favorite_number\",\"type\":[\"int\",\"null\"]}]}");
   public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
 
@@ -386,6 +388,32 @@ public class NoSettersTest extends 
org.apache.avro.specific.SpecificRecordBase i
       }
     }
   }
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    result = 31 * result + (name == null ? 0 : name.hashCode());
+    result = 31 * result + (favorite_number == null ? 0 : 
favorite_number.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof NoSettersTest)) {
+      return false;
+    }
+    NoSettersTest other = (NoSettersTest) o;
+    if (Utf8.compareSequences(this.name, other.name) != 0) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.favorite_number, 
other.favorite_number)) {
+      return false;
+    }
+    return true;
+  }
 }
 
 
diff --git 
a/lang/java/tools/src/test/compiler/output/OptionalGettersAllFieldsTest.java 
b/lang/java/tools/src/test/compiler/output/OptionalGettersAllFieldsTest.java
index ece62933a8..0194aeaed0 100644
--- a/lang/java/tools/src/test/compiler/output/OptionalGettersAllFieldsTest.java
+++ b/lang/java/tools/src/test/compiler/output/OptionalGettersAllFieldsTest.java
@@ -15,6 +15,8 @@ import java.util.Optional;
 @org.apache.avro.specific.AvroGenerated
 public class OptionalGettersAllFieldsTest extends 
org.apache.avro.specific.SpecificRecordBase implements 
org.apache.avro.specific.SpecificRecord {
   private static final long serialVersionUID = 874861432798554536L;
+
+
   public static final org.apache.avro.Schema SCHEMA$ = new 
org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"OptionalGettersAllFieldsTest\",\"namespace\":\"avro.examples.baseball\",\"doc\":\"Test
 that optional getters are created for all 
fields\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"nullable_name\",\"type\":[\"string\",\"null\"]},{\"name\":\"favorite_number\",\"type\":[\"int\"]},{\"name\":\"nullable_favorite_number\",\"type\":[\"int\",\"nul
 [...]
   public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
 
@@ -491,6 +493,40 @@ public class OptionalGettersAllFieldsTest extends 
org.apache.avro.specific.Speci
     READER$.read(this, SpecificData.getDecoder(in));
   }
 
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    result = 31 * result + (name == null ? 0 : name.hashCode());
+    result = 31 * result + (nullable_name == null ? 0 : 
nullable_name.hashCode());
+    result = 31 * result + (favorite_number == null ? 0 : 
favorite_number.hashCode());
+    result = 31 * result + (nullable_favorite_number == null ? 0 : 
nullable_favorite_number.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof OptionalGettersAllFieldsTest)) {
+      return false;
+    }
+    OptionalGettersAllFieldsTest other = (OptionalGettersAllFieldsTest) o;
+    if (Utf8.compareSequences(this.name, other.name) != 0) {
+      return false;
+    }
+    if (Utf8.compareSequences(this.nullable_name, other.nullable_name) != 0) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.favorite_number, 
other.favorite_number)) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.nullable_favorite_number, 
other.nullable_favorite_number)) {
+      return false;
+    }
+    return true;
+  }
 }
 
 
diff --git 
a/lang/java/tools/src/test/compiler/output/OptionalGettersNullableFieldsTest.java
 
b/lang/java/tools/src/test/compiler/output/OptionalGettersNullableFieldsTest.java
index 60c87c2953..ad9b9c3863 100644
--- 
a/lang/java/tools/src/test/compiler/output/OptionalGettersNullableFieldsTest.java
+++ 
b/lang/java/tools/src/test/compiler/output/OptionalGettersNullableFieldsTest.java
@@ -565,6 +565,44 @@ public class OptionalGettersNullableFieldsTest extends 
org.apache.avro.specific.
     READER$.read(this, SpecificData.getDecoder(in));
   }
 
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    result = 31 * result + (name == null ? 0 : name.hashCode());
+    result = 31 * result + (nullable_name == null ? 0 : 
nullable_name.hashCode());
+    result = 31 * result + (favorite_number == null ? 0 : 
favorite_number.hashCode());
+    result = 31 * result + (nullable_favorite_number == null ? 0 : 
nullable_favorite_number.hashCode());
+    result = 31 * result + (nullable_array == null ? 0 : 
nullable_array.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof OptionalGettersNullableFieldsTest)) {
+      return false;
+    }
+    OptionalGettersNullableFieldsTest other = 
(OptionalGettersNullableFieldsTest) o;
+    if (Utf8.compareSequences(this.name, other.name) != 0) {
+      return false;
+    }
+    if (Utf8.compareSequences(this.nullable_name, other.nullable_name) != 0) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.favorite_number, 
other.favorite_number)) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.nullable_favorite_number, 
other.nullable_favorite_number)) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.nullable_array, other.nullable_array)) {
+      return false;
+    }
+    return true;
+  }
 }
 
 
diff --git a/lang/java/tools/src/test/compiler/output/Player.java 
b/lang/java/tools/src/test/compiler/output/Player.java
index e1f6f91c84..adc1e2be7f 100644
--- a/lang/java/tools/src/test/compiler/output/Player.java
+++ b/lang/java/tools/src/test/compiler/output/Player.java
@@ -15,6 +15,8 @@ import org.apache.avro.message.SchemaStore;
 @org.apache.avro.specific.AvroGenerated
 public class Player extends org.apache.avro.specific.SpecificRecordBase 
implements org.apache.avro.specific.SpecificRecord {
   private static final long serialVersionUID = 3865593031278745715L;
+
+
   public static final org.apache.avro.Schema SCHEMA$ = new 
org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"Player\",\"namespace\":\"avro.examples.baseball\",\"doc\":\"選手
 is Japanese for 
player.\",\"fields\":[{\"name\":\"number\",\"type\":\"int\",\"doc\":\"The 
number of the 
player\"},{\"name\":\"first_name\",\"type\":\"string\"},{\"name\":\"last_name\",\"type\":\"string\"},{\"name\":\"position\",\"type\":{\"type\":\"array\",\"items\":{\"type\":\"enum\",\"name\":\"Po
 [...]
   public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
 
@@ -587,6 +589,40 @@ public class Player extends 
org.apache.avro.specific.SpecificRecordBase implemen
       }
     }
   }
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    result = 31 * result + Integer.hashCode(number);
+    result = 31 * result + (first_name == null ? 0 : first_name.hashCode());
+    result = 31 * result + (last_name == null ? 0 : last_name.hashCode());
+    result = 31 * result + (position == null ? 0 : position.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof Player)) {
+      return false;
+    }
+    Player other = (Player) o;
+    if (this.number != other.number) {
+      return false;
+    }
+    if (Utf8.compareSequences(this.first_name, other.first_name) != 0) {
+      return false;
+    }
+    if (Utf8.compareSequences(this.last_name, other.last_name) != 0) {
+      return false;
+    }
+    if (!java.util.Objects.equals(this.position, other.position)) {
+      return false;
+    }
+    return true;
+  }
 }
 
 

Reply via email to