Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1314,9 +1314,9 @@ protected int compare(Object o1, Object o2, Schema s, boolean equals) {
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);
}
Expand Down
24 changes: 24 additions & 0 deletions lang/java/avro/src/main/java/org/apache/avro/util/Utf8.java
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,28 @@ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundExcept
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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,46 @@ public static String mangle(String word, Set<String> reservedWords, boolean isMe
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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
@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\"}},{\"name\":\"timestampMicros\",\"type\":{\"type\":\"long\",\"logicalType\":\"timestamp-micros\"}},{\"name\":\"timeMillis\",\"type\":{\"type\":\"int\",\"logicalType\":\"time-millis\"}},{\"name\":\"timeMicros\",\"type\":{\"type\":\"long\",\"logicalType\":\"time-micros\"}}]}");
public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }

Expand Down Expand Up @@ -659,6 +661,48 @@ public FieldTest build() {
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;
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,40 @@ public JSpecifyNullSafeAnnotationsFieldsTest build() {
}
}
}

@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;
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,40 @@ public JetBrainsNullSafeAnnotationsFieldsTest build() {
}
}
}

@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;
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
@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\":\"position\",\"type\":{\"type\":\"array\",\"items\":{\"type\":\"enum\",\"name\":\"Position\",\"symbols\":[\"P\",\"C\",\"B1\",\"B2\",\"B3\",\"SS\",\"LF\",\"CF\",\"RF\",\"DH\"]}}}]}");
public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }

Expand Down Expand Up @@ -587,6 +589,40 @@ public Player build() {
}
}
}

@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;
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ public interface Callback extends Proto {
*/
void bar(org.apache.avro.ipc.Callback<java.lang.Void> callback) throws java.io.IOException;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
@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$; }

Expand Down Expand Up @@ -428,6 +430,32 @@ public AddExtraOptionalGettersTest build() {
}
}
}

@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;
}
}


Expand Down
Loading