From adac27bdf3378dfa62a49451530a34c3f4e7a254 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 26 Jun 2024 10:50:14 -0400 Subject: [PATCH 1/4] Add generation of equals/hashCode --- packages/pigeon/CHANGELOG.md | 5 ++-- packages/pigeon/lib/generator_tools.dart | 2 +- packages/pigeon/lib/java_generator.dart | 30 ++++++++++++++++++++++++ packages/pigeon/pubspec.yaml | 2 +- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index 6e039a92362..e13c7e3c4dd 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 20.0.2 +* [java] Adds `equals` and `hashCode` support for data classes. * [swift] Fully-qualifies types in Equatable extension test. ## 20.0.1 @@ -17,7 +18,7 @@ ## 19.0.2 -* [kotlin] Adds the `@JvmOverloads` to the `HostApi` setUp method. This prevents the calling Java code from having to provide an empty `String` as Kotlin provides it by default +* [kotlin] Adds the `@JvmOverloads` to the `HostApi` setUp method. This prevents the calling Java code from having to provide an empty `String` as Kotlin provides it by default ## 19.0.1 diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index 7c43243b0f5..c78761ecef9 100644 --- a/packages/pigeon/lib/generator_tools.dart +++ b/packages/pigeon/lib/generator_tools.dart @@ -13,7 +13,7 @@ import 'ast.dart'; /// The current version of pigeon. /// /// This must match the version in pubspec.yaml. -const String pigeonVersion = '20.0.1'; +const String pigeonVersion = '20.0.2'; /// Prefix for all local variables in methods. /// diff --git a/packages/pigeon/lib/java_generator.dart b/packages/pigeon/lib/java_generator.dart index 55622995b71..c3db7b3fa99 100644 --- a/packages/pigeon/lib/java_generator.dart +++ b/packages/pigeon/lib/java_generator.dart @@ -141,6 +141,7 @@ class JavaGenerator extends StructuredGenerator { indent.writeln('import java.util.HashMap;'); indent.writeln('import java.util.List;'); indent.writeln('import java.util.Map;'); + indent.writeln('import java.util.Objects;'); indent.newln(); } @@ -233,6 +234,7 @@ class JavaGenerator extends StructuredGenerator { indent.writeln('${classDefinition.name}() {}'); indent.newln(); } + _writeEquality(indent, classDefinition); _writeClassBuilder(generatorOptions, root, indent, classDefinition); writeClassEncode( @@ -282,6 +284,34 @@ class JavaGenerator extends StructuredGenerator { }); } + void _writeEquality(Indent indent, Class classDefinition) { + // Implement equals(...). + indent.writeln('@Override'); + indent.addScoped('public boolean equals(Object o) {', '}', () { + indent.writeln('if (this == o) { return true; }'); + indent.writeln( + 'if (o == null || getClass() != o.getClass()) { return false; }'); + indent.writeln( + '${classDefinition.name} that = (${classDefinition.name}) o;'); + final Iterable checks = classDefinition.fields.map( + (NamedType field) { + return field.type.isNullable + ? 'Objects.equals(${field.name}, that.${field.name})' + : '${field.name}.equals(that.${field.name})'; + }, + ); + indent.writeln('return ${checks.join(' && ')};'); + }); + + // Implement hashCode(). + indent.writeln('@Override'); + indent.addScoped('public int hashCode() {', '}', () { + final Iterable fieldNames = + classDefinition.fields.map((NamedType field) => field.name); + indent.writeln('return Objects.hash(${fieldNames.join(', ')});'); + }); + } + void _writeClassBuilder( JavaOptions generatorOptions, Root root, diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index 413804a0691..411d3bdb581 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -2,7 +2,7 @@ name: pigeon description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. repository: https://github.com/flutter/packages/tree/main/packages/pigeon issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+pigeon%22 -version: 20.0.1 # This must match the version in lib/generator_tools.dart +version: 20.0.2 # This must match the version in lib/generator_tools.dart environment: sdk: ^3.2.0 From 62590d09b818fa08214964aeecf731ca63d454ca Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 26 Jun 2024 10:54:37 -0400 Subject: [PATCH 2/4] Update generated output --- .../CoreTests.java | 203 ++++++++++++++++++ 1 file changed, 203 insertions(+) diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java index d0b5b600836..d3dd5bc9a47 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java @@ -26,6 +26,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; /** Generated class from Pigeon. */ @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"}) @@ -318,6 +319,56 @@ public void setMap(@NonNull Map setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ AllTypes() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AllTypes that = (AllTypes) o; + return aBool.equals(that.aBool) + && anInt.equals(that.anInt) + && anInt64.equals(that.anInt64) + && aDouble.equals(that.aDouble) + && aByteArray.equals(that.aByteArray) + && a4ByteArray.equals(that.a4ByteArray) + && a8ByteArray.equals(that.a8ByteArray) + && aFloatArray.equals(that.aFloatArray) + && anEnum.equals(that.anEnum) + && aString.equals(that.aString) + && anObject.equals(that.anObject) + && list.equals(that.list) + && stringList.equals(that.stringList) + && intList.equals(that.intList) + && doubleList.equals(that.doubleList) + && boolList.equals(that.boolList) + && map.equals(that.map); + } + + @Override + public int hashCode() { + return Objects.hash( + aBool, + anInt, + anInt64, + aDouble, + aByteArray, + a4ByteArray, + a8ByteArray, + aFloatArray, + anEnum, + aString, + anObject, + list, + stringList, + intList, + doubleList, + boolList, + map); + } + public static final class Builder { private @Nullable Boolean aBool; @@ -772,6 +823,66 @@ public void setMap(@Nullable Map setterArg) { this.map = setterArg; } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AllNullableTypes that = (AllNullableTypes) o; + return Objects.equals(aNullableBool, that.aNullableBool) + && Objects.equals(aNullableInt, that.aNullableInt) + && Objects.equals(aNullableInt64, that.aNullableInt64) + && Objects.equals(aNullableDouble, that.aNullableDouble) + && Objects.equals(aNullableByteArray, that.aNullableByteArray) + && Objects.equals(aNullable4ByteArray, that.aNullable4ByteArray) + && Objects.equals(aNullable8ByteArray, that.aNullable8ByteArray) + && Objects.equals(aNullableFloatArray, that.aNullableFloatArray) + && Objects.equals(nullableNestedList, that.nullableNestedList) + && Objects.equals(nullableMapWithAnnotations, that.nullableMapWithAnnotations) + && Objects.equals(nullableMapWithObject, that.nullableMapWithObject) + && Objects.equals(aNullableEnum, that.aNullableEnum) + && Objects.equals(aNullableString, that.aNullableString) + && Objects.equals(aNullableObject, that.aNullableObject) + && Objects.equals(allNullableTypes, that.allNullableTypes) + && Objects.equals(list, that.list) + && Objects.equals(stringList, that.stringList) + && Objects.equals(intList, that.intList) + && Objects.equals(doubleList, that.doubleList) + && Objects.equals(boolList, that.boolList) + && Objects.equals(nestedClassList, that.nestedClassList) + && Objects.equals(map, that.map); + } + + @Override + public int hashCode() { + return Objects.hash( + aNullableBool, + aNullableInt, + aNullableInt64, + aNullableDouble, + aNullableByteArray, + aNullable4ByteArray, + aNullable8ByteArray, + aNullableFloatArray, + nullableNestedList, + nullableMapWithAnnotations, + nullableMapWithObject, + aNullableEnum, + aNullableString, + aNullableObject, + allNullableTypes, + list, + stringList, + intList, + doubleList, + boolList, + nestedClassList, + map); + } + public static final class Builder { private @Nullable Boolean aNullableBool; @@ -1272,6 +1383,62 @@ public void setMap(@Nullable Map setterArg) { this.map = setterArg; } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AllNullableTypesWithoutRecursion that = (AllNullableTypesWithoutRecursion) o; + return Objects.equals(aNullableBool, that.aNullableBool) + && Objects.equals(aNullableInt, that.aNullableInt) + && Objects.equals(aNullableInt64, that.aNullableInt64) + && Objects.equals(aNullableDouble, that.aNullableDouble) + && Objects.equals(aNullableByteArray, that.aNullableByteArray) + && Objects.equals(aNullable4ByteArray, that.aNullable4ByteArray) + && Objects.equals(aNullable8ByteArray, that.aNullable8ByteArray) + && Objects.equals(aNullableFloatArray, that.aNullableFloatArray) + && Objects.equals(nullableNestedList, that.nullableNestedList) + && Objects.equals(nullableMapWithAnnotations, that.nullableMapWithAnnotations) + && Objects.equals(nullableMapWithObject, that.nullableMapWithObject) + && Objects.equals(aNullableEnum, that.aNullableEnum) + && Objects.equals(aNullableString, that.aNullableString) + && Objects.equals(aNullableObject, that.aNullableObject) + && Objects.equals(list, that.list) + && Objects.equals(stringList, that.stringList) + && Objects.equals(intList, that.intList) + && Objects.equals(doubleList, that.doubleList) + && Objects.equals(boolList, that.boolList) + && Objects.equals(map, that.map); + } + + @Override + public int hashCode() { + return Objects.hash( + aNullableBool, + aNullableInt, + aNullableInt64, + aNullableDouble, + aNullableByteArray, + aNullable4ByteArray, + aNullable8ByteArray, + aNullableFloatArray, + nullableNestedList, + nullableMapWithAnnotations, + nullableMapWithObject, + aNullableEnum, + aNullableString, + aNullableObject, + list, + stringList, + intList, + doubleList, + boolList, + map); + } + public static final class Builder { private @Nullable Boolean aNullableBool; @@ -1589,6 +1756,25 @@ public void setAllTypes(@Nullable AllTypes setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ AllClassesWrapper() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AllClassesWrapper that = (AllClassesWrapper) o; + return allNullableTypes.equals(that.allNullableTypes) + && Objects.equals(allNullableTypesWithoutRecursion, that.allNullableTypesWithoutRecursion) + && Objects.equals(allTypes, that.allTypes); + } + + @Override + public int hashCode() { + return Objects.hash(allNullableTypes, allNullableTypesWithoutRecursion, allTypes); + } + public static final class Builder { private @Nullable AllNullableTypes allNullableTypes; @@ -1663,6 +1849,23 @@ public void setTestList(@Nullable List setterArg) { this.testList = setterArg; } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TestMessage that = (TestMessage) o; + return Objects.equals(testList, that.testList); + } + + @Override + public int hashCode() { + return Objects.hash(testList); + } + public static final class Builder { private @Nullable List testList; From e3c06e847ef16e095e283edd3e76b491c7622b78 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 26 Jun 2024 12:47:50 -0400 Subject: [PATCH 3/4] Add native unit testing, and fix array handling --- packages/pigeon/lib/java_generator.dart | 42 ++++- .../CoreTests.java | 154 +++++++++--------- .../AllDatatypesTest.java | 17 +- 3 files changed, 131 insertions(+), 82 deletions(-) diff --git a/packages/pigeon/lib/java_generator.dart b/packages/pigeon/lib/java_generator.dart index c3db7b3fa99..329bf37dab0 100644 --- a/packages/pigeon/lib/java_generator.dart +++ b/packages/pigeon/lib/java_generator.dart @@ -287,7 +287,7 @@ class JavaGenerator extends StructuredGenerator { void _writeEquality(Indent indent, Class classDefinition) { // Implement equals(...). indent.writeln('@Override'); - indent.addScoped('public boolean equals(Object o) {', '}', () { + indent.writeScoped('public boolean equals(Object o) {', '}', () { indent.writeln('if (this == o) { return true; }'); indent.writeln( 'if (o == null || getClass() != o.getClass()) { return false; }'); @@ -295,6 +295,10 @@ class JavaGenerator extends StructuredGenerator { '${classDefinition.name} that = (${classDefinition.name}) o;'); final Iterable checks = classDefinition.fields.map( (NamedType field) { + // Objects.equals only does pointer equality for array types. + if (_javaTypeIsArray(field.type)) { + return 'Arrays.equals(${field.name}, that.${field.name})'; + } return field.type.isNullable ? 'Objects.equals(${field.name}, that.${field.name})' : '${field.name}.equals(that.${field.name})'; @@ -302,14 +306,38 @@ class JavaGenerator extends StructuredGenerator { ); indent.writeln('return ${checks.join(' && ')};'); }); + indent.newln(); // Implement hashCode(). indent.writeln('@Override'); - indent.addScoped('public int hashCode() {', '}', () { - final Iterable fieldNames = - classDefinition.fields.map((NamedType field) => field.name); - indent.writeln('return Objects.hash(${fieldNames.join(', ')});'); + indent.writeScoped('public int hashCode() {', '}', () { + // As with equalty checks, arrays need special handling. + final Iterable arrayFieldNames = classDefinition.fields + .where((NamedType field) => _javaTypeIsArray(field.type)) + .map((NamedType field) => field.name); + final Iterable nonArrayFieldNames = classDefinition.fields + .where((NamedType field) => !_javaTypeIsArray(field.type)) + .map((NamedType field) => field.name); + final String nonArrayHashValue = nonArrayFieldNames.isNotEmpty + ? 'Objects.hash(${nonArrayFieldNames.join(', ')})' + : '0'; + + if (arrayFieldNames.isEmpty) { + // Return directly if there are no array variables, to avoid redundant + // variable lint warnings. + indent.writeln('return $nonArrayHashValue;'); + } else { + const String resultVar = '${varNamePrefix}result'; + indent.writeln('int $resultVar = $nonArrayHashValue;'); + // Manually mix in the Arrays.hashCode values. + for (final String name in arrayFieldNames) { + indent.writeln( + '$resultVar = 31 * $resultVar + Arrays.hashCode($name);'); + } + indent.writeln('return $resultVar;'); + } }); + indent.newln(); } void _writeClassBuilder( @@ -1052,6 +1080,10 @@ String _javaTypeForBuiltinGenericDartType( } } +bool _javaTypeIsArray(TypeDeclaration type) { + return _javaTypeForBuiltinDartType(type)?.endsWith('[]') ?? false; +} + String? _javaTypeForBuiltinDartType(TypeDeclaration type) { const Map javaTypeForDartTypeMap = { 'bool': 'Boolean', diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java index d3dd5bc9a47..d7c5ea64ff1 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java @@ -332,10 +332,10 @@ public boolean equals(Object o) { && anInt.equals(that.anInt) && anInt64.equals(that.anInt64) && aDouble.equals(that.aDouble) - && aByteArray.equals(that.aByteArray) - && a4ByteArray.equals(that.a4ByteArray) - && a8ByteArray.equals(that.a8ByteArray) - && aFloatArray.equals(that.aFloatArray) + && Arrays.equals(aByteArray, that.aByteArray) + && Arrays.equals(a4ByteArray, that.a4ByteArray) + && Arrays.equals(a8ByteArray, that.a8ByteArray) + && Arrays.equals(aFloatArray, that.aFloatArray) && anEnum.equals(that.anEnum) && aString.equals(that.aString) && anObject.equals(that.anObject) @@ -349,24 +349,26 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash( - aBool, - anInt, - anInt64, - aDouble, - aByteArray, - a4ByteArray, - a8ByteArray, - aFloatArray, - anEnum, - aString, - anObject, - list, - stringList, - intList, - doubleList, - boolList, - map); + int __pigeon_result = + Objects.hash( + aBool, + anInt, + anInt64, + aDouble, + anEnum, + aString, + anObject, + list, + stringList, + intList, + doubleList, + boolList, + map); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(aByteArray); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(a4ByteArray); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(a8ByteArray); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(aFloatArray); + return __pigeon_result; } public static final class Builder { @@ -836,10 +838,10 @@ public boolean equals(Object o) { && Objects.equals(aNullableInt, that.aNullableInt) && Objects.equals(aNullableInt64, that.aNullableInt64) && Objects.equals(aNullableDouble, that.aNullableDouble) - && Objects.equals(aNullableByteArray, that.aNullableByteArray) - && Objects.equals(aNullable4ByteArray, that.aNullable4ByteArray) - && Objects.equals(aNullable8ByteArray, that.aNullable8ByteArray) - && Objects.equals(aNullableFloatArray, that.aNullableFloatArray) + && Arrays.equals(aNullableByteArray, that.aNullableByteArray) + && Arrays.equals(aNullable4ByteArray, that.aNullable4ByteArray) + && Arrays.equals(aNullable8ByteArray, that.aNullable8ByteArray) + && Arrays.equals(aNullableFloatArray, that.aNullableFloatArray) && Objects.equals(nullableNestedList, that.nullableNestedList) && Objects.equals(nullableMapWithAnnotations, that.nullableMapWithAnnotations) && Objects.equals(nullableMapWithObject, that.nullableMapWithObject) @@ -858,29 +860,31 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash( - aNullableBool, - aNullableInt, - aNullableInt64, - aNullableDouble, - aNullableByteArray, - aNullable4ByteArray, - aNullable8ByteArray, - aNullableFloatArray, - nullableNestedList, - nullableMapWithAnnotations, - nullableMapWithObject, - aNullableEnum, - aNullableString, - aNullableObject, - allNullableTypes, - list, - stringList, - intList, - doubleList, - boolList, - nestedClassList, - map); + int __pigeon_result = + Objects.hash( + aNullableBool, + aNullableInt, + aNullableInt64, + aNullableDouble, + nullableNestedList, + nullableMapWithAnnotations, + nullableMapWithObject, + aNullableEnum, + aNullableString, + aNullableObject, + allNullableTypes, + list, + stringList, + intList, + doubleList, + boolList, + nestedClassList, + map); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(aNullableByteArray); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(aNullable4ByteArray); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(aNullable8ByteArray); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(aNullableFloatArray); + return __pigeon_result; } public static final class Builder { @@ -1396,10 +1400,10 @@ public boolean equals(Object o) { && Objects.equals(aNullableInt, that.aNullableInt) && Objects.equals(aNullableInt64, that.aNullableInt64) && Objects.equals(aNullableDouble, that.aNullableDouble) - && Objects.equals(aNullableByteArray, that.aNullableByteArray) - && Objects.equals(aNullable4ByteArray, that.aNullable4ByteArray) - && Objects.equals(aNullable8ByteArray, that.aNullable8ByteArray) - && Objects.equals(aNullableFloatArray, that.aNullableFloatArray) + && Arrays.equals(aNullableByteArray, that.aNullableByteArray) + && Arrays.equals(aNullable4ByteArray, that.aNullable4ByteArray) + && Arrays.equals(aNullable8ByteArray, that.aNullable8ByteArray) + && Arrays.equals(aNullableFloatArray, that.aNullableFloatArray) && Objects.equals(nullableNestedList, that.nullableNestedList) && Objects.equals(nullableMapWithAnnotations, that.nullableMapWithAnnotations) && Objects.equals(nullableMapWithObject, that.nullableMapWithObject) @@ -1416,27 +1420,29 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash( - aNullableBool, - aNullableInt, - aNullableInt64, - aNullableDouble, - aNullableByteArray, - aNullable4ByteArray, - aNullable8ByteArray, - aNullableFloatArray, - nullableNestedList, - nullableMapWithAnnotations, - nullableMapWithObject, - aNullableEnum, - aNullableString, - aNullableObject, - list, - stringList, - intList, - doubleList, - boolList, - map); + int __pigeon_result = + Objects.hash( + aNullableBool, + aNullableInt, + aNullableInt64, + aNullableDouble, + nullableNestedList, + nullableMapWithAnnotations, + nullableMapWithObject, + aNullableEnum, + aNullableString, + aNullableObject, + list, + stringList, + intList, + doubleList, + boolList, + map); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(aNullableByteArray); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(aNullable4ByteArray); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(aNullable8ByteArray); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(aNullableFloatArray); + return __pigeon_result; } public static final class Builder { diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AllDatatypesTest.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AllDatatypesTest.java index c5f7857915a..20146fdc0e0 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AllDatatypesTest.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AllDatatypesTest.java @@ -24,10 +24,10 @@ void compareAllTypes(AllTypes firstTypes, AllTypes secondTypes) { if (firstTypes == null || secondTypes == null) { return; } + // Check all the fields individually to ensure that everything is as expected. assertEquals(firstTypes.getABool(), secondTypes.getABool()); assertEquals(firstTypes.getAnInt(), secondTypes.getAnInt()); assertEquals(firstTypes.getAnInt64(), secondTypes.getAnInt64()); - assertEquals(firstTypes.getADouble(), secondTypes.getADouble()); assertArrayEquals(firstTypes.getAByteArray(), secondTypes.getAByteArray()); assertArrayEquals(firstTypes.getA4ByteArray(), secondTypes.getA4ByteArray()); @@ -44,6 +44,10 @@ void compareAllTypes(AllTypes firstTypes, AllTypes secondTypes) { firstTypes.getMap().keySet().toArray(), secondTypes.getMap().keySet().toArray()); assertArrayEquals( firstTypes.getMap().values().toArray(), secondTypes.getMap().values().toArray()); + + // Also check that the implementation of equality works. + assertEquals(firstTypes, secondTypes); + assertEquals(firstTypes.hashCode(), secondTypes.hashCode()); } void compareAllNullableTypes(AllNullableTypes firstTypes, AllNullableTypes secondTypes) { @@ -51,6 +55,7 @@ void compareAllNullableTypes(AllNullableTypes firstTypes, AllNullableTypes secon if (firstTypes == null || secondTypes == null) { return; } + // Check all the fields individually to ensure that everything is as expected. assertEquals(firstTypes.getANullableBool(), secondTypes.getANullableBool()); assertEquals(firstTypes.getANullableInt(), secondTypes.getANullableInt()); assertEquals(firstTypes.getANullableDouble(), secondTypes.getANullableDouble()); @@ -74,6 +79,10 @@ void compareAllNullableTypes(AllNullableTypes firstTypes, AllNullableTypes secon firstTypes.getMap().keySet().toArray(), secondTypes.getMap().keySet().toArray()); assertArrayEquals( firstTypes.getMap().values().toArray(), secondTypes.getMap().values().toArray()); + + // Also check that the implementation of equality works. + assertEquals(firstTypes, secondTypes); + assertEquals(firstTypes.hashCode(), secondTypes.hashCode()); } @Test @@ -152,6 +161,8 @@ private static boolean floatArraysEqual(double[] x, double[] y) { @Test public void hasValues() { + // Not inline due to warnings about an ambiguous varargs call when inline. + final Object[] genericList = new Boolean[] {true, false}; AllTypes allEverything = new AllTypes.Builder() .setABool(false) @@ -168,7 +179,7 @@ public void hasValues() { .setBoolList(Arrays.asList(new Boolean[] {true, false})) .setDoubleList(Arrays.asList(new Double[] {0.5, 0.25, 1.5, 1.25})) .setIntList(Arrays.asList(new Long[] {1l, 2l, 3l, 4l})) - .setList(Arrays.asList(new int[] {1, 2, 3, 4})) + .setList(Arrays.asList(genericList)) .setStringList(Arrays.asList(new String[] {"string", "another one"})) .setMap(makeMap("hello", 1234)) .build(); @@ -188,7 +199,7 @@ public void hasValues() { .setBoolList(Arrays.asList(new Boolean[] {true, false})) .setDoubleList(Arrays.asList(new Double[] {0.5, 0.25, 1.5, 1.25})) .setIntList(Arrays.asList(new Long[] {1l, 2l, 3l, 4l})) - .setList(Arrays.asList(new int[] {1, 2, 3, 4})) + .setList(Arrays.asList(genericList)) .setStringList(Arrays.asList(new String[] {"string", "another one"})) .setMap(makeMap("hello", 1234)) .build(); From d8f1bbb6095826cbe14d4f828df9466d10523fa3 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 26 Jun 2024 19:41:36 -0400 Subject: [PATCH 4/4] Generate --- .../java/io/flutter/plugins/Messages.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java b/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java index 4993909460e..8b07206873a 100644 --- a/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java +++ b/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; /** Generated class from Pigeon. */ @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"}) @@ -132,6 +133,26 @@ public void setData(@NonNull Map setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ MessageData() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MessageData that = (MessageData) o; + return Objects.equals(name, that.name) + && Objects.equals(description, that.description) + && code.equals(that.code) + && data.equals(that.data); + } + + @Override + public int hashCode() { + return Objects.hash(name, description, code, data); + } + public static final class Builder { private @Nullable String name;