Skip to content

Commit f1b2af6

Browse files
authored
[pigeon] Encode custom enum as long in Kotlin generator (#10085)
This PR ensures that custom enums are encoded as the expected `Long` type in the Kotlin generator. Without this change it is not possible to perform encoding <-> decoding in Kotlin, because enums are generated to have an `Int` raw value and encoded without first casting to `Long`. Fixes: flutter/flutter#176081 ## Pre-Review Checklist **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent b4decd8 commit f1b2af6

File tree

9 files changed

+70
-35
lines changed

9 files changed

+70
-35
lines changed

packages/pigeon/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 26.0.5
2+
3+
* [kotlin] Serialize custom enums as `Long` instead of `Int` to avoid `ClassCastException` on decoding.
4+
15
## 26.0.4
26

37
* Adds compatibility with `analyzer` 8.x.

packages/pigeon/example/app/android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ private open class MessagesPigeonCodec : StandardMessageCodec() {
142142
when (value) {
143143
is Code -> {
144144
stream.write(129)
145-
writeValue(stream, value.raw)
145+
writeValue(stream, value.raw.toLong())
146146
}
147147
is MessageData -> {
148148
stream.write(130)

packages/pigeon/lib/src/generator_tools.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import 'generator.dart';
1515
/// The current version of pigeon.
1616
///
1717
/// This must match the version in pubspec.yaml.
18-
const String pigeonVersion = '26.0.4';
18+
const String pigeonVersion = '26.0.5';
1919

2020
/// Read all the content from [stdin] to a String.
2121
String readStdin() {

packages/pigeon/lib/src/kotlin/kotlin_generator.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,9 @@ class KotlinGenerator extends StructuredGenerator<InternalKotlinOptions> {
475475

476476
void writeEncodeLogic(EnumeratedType customType) {
477477
final String encodeString =
478-
customType.type == CustomTypes.customClass ? 'toList()' : 'raw';
478+
customType.type == CustomTypes.customClass
479+
? 'toList()'
480+
: 'raw.toLong()';
479481
final String valueString =
480482
customType.enumeration < maximumCodecFieldKey
481483
? 'value.$encodeString'

packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -704,11 +704,11 @@ private open class CoreTestsPigeonCodec : StandardMessageCodec() {
704704
when (value) {
705705
is AnEnum -> {
706706
stream.write(129)
707-
writeValue(stream, value.raw)
707+
writeValue(stream, value.raw.toLong())
708708
}
709709
is AnotherEnum -> {
710710
stream.write(130)
711-
writeValue(stream, value.raw)
711+
writeValue(stream, value.raw.toLong())
712712
}
713713
is UnusedClass -> {
714714
stream.write(131)

packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,11 +477,11 @@ private open class EventChannelTestsPigeonCodec : StandardMessageCodec() {
477477
when (value) {
478478
is EventEnum -> {
479479
stream.write(129)
480-
writeValue(stream, value.raw)
480+
writeValue(stream, value.raw.toLong())
481481
}
482482
is AnotherEventEnum -> {
483483
stream.write(130)
484-
writeValue(stream, value.raw)
484+
writeValue(stream, value.raw.toLong())
485485
}
486486
is EventAllNullableTypes -> {
487487
stream.write(131)

packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/ProxyApiTests.gen.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ private open class ProxyApiTestsPigeonCodec : StandardMessageCodec() {
560560
when (value) {
561561
is ProxyApiTestEnum -> {
562562
stream.write(129)
563-
writeValue(stream, value.raw)
563+
writeValue(stream, value.raw.toLong())
564564
}
565565
else -> super.writeValue(stream, value)
566566
}

packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -46,33 +46,52 @@ internal class AllDatatypesTest {
4646
}
4747

4848
@Test
49-
fun testHasValues() {
49+
fun testRoundtripNullValues() {
50+
val everything = AllNullableTypes()
51+
val codec = FlutterIntegrationCoreApi.codec
52+
val encoded = codec.encodeMessage(everything)
53+
encoded?.rewind()
54+
val decoded = codec.decodeMessage(encoded)
55+
assertEquals(everything, decoded)
56+
}
57+
58+
fun getFullyPopulatedAllNullableTypes(): AllNullableTypes {
5059
val stringList = listOf("string", "another one")
51-
val everything =
52-
AllNullableTypes(
53-
aNullableBool = false,
54-
aNullableInt = 1234L,
55-
aNullableDouble = 2.0,
56-
aNullableString = "hello",
57-
aNullableByteArray = byteArrayOf(1, 2, 3, 4),
58-
aNullable4ByteArray = intArrayOf(1, 2, 3, 4),
59-
aNullable8ByteArray = longArrayOf(1, 2, 3, 4),
60-
aNullableFloatArray = doubleArrayOf(0.5, 0.25, 1.5, 1.25),
61-
aNullableObject = 0,
62-
list = listOf(1, 2, 3),
63-
stringList = stringList,
64-
boolList = listOf(true, false),
65-
intList = listOf(1, 2),
66-
doubleList = listOf(1.1, 2.2),
67-
objectList = listOf(1, 2, 3),
68-
listList = listOf(stringList, stringList.toList()),
69-
mapList = listOf(mapOf("hello" to 1234), mapOf("hello" to 1234)),
70-
map = mapOf("hello" to 1234),
71-
stringMap = mapOf("hello" to "you"),
72-
intMap = mapOf(1L to 0L),
73-
objectMap = mapOf("hello" to 1234),
74-
listMap = mapOf(1L to stringList),
75-
mapMap = mapOf(1L to mapOf()))
60+
61+
return AllNullableTypes(
62+
aNullableBool = false,
63+
aNullableInt = 1234L,
64+
aNullableDouble = 2.0,
65+
aNullableString = "hello",
66+
aNullableByteArray = byteArrayOf(1, 2, 3, 4),
67+
aNullable4ByteArray = intArrayOf(1, 2, 3, 4),
68+
aNullable8ByteArray = longArrayOf(1, 2, 3, 4),
69+
aNullableFloatArray = doubleArrayOf(0.5, 0.25, 1.5, 1.25),
70+
aNullableEnum = AnEnum.TWO,
71+
anotherNullableEnum = AnotherEnum.JUST_IN_CASE,
72+
aNullableObject = 0,
73+
list = listOf(1, 2, 3),
74+
stringList = stringList,
75+
boolList = listOf(true, false),
76+
enumList = listOf(AnEnum.ONE, AnEnum.TWO),
77+
intList = listOf(1, 2),
78+
doubleList = listOf(1.1, 2.2),
79+
objectList = listOf(1, 2, 3),
80+
listList = listOf(stringList, stringList.toList()),
81+
mapList = listOf(mapOf("hello" to 1234), mapOf("hello" to 1234)),
82+
map = mapOf("hello" to 1234),
83+
stringMap = mapOf("hello" to "you"),
84+
intMap = mapOf(1L to 0L),
85+
objectMap = mapOf("hello" to 1234),
86+
enumMap =
87+
mapOf(AnEnum.ONE to AnEnum.FORTY_TWO, AnEnum.TWO to AnEnum.FOUR_HUNDRED_TWENTY_TWO),
88+
listMap = mapOf(1L to stringList),
89+
mapMap = mapOf(1L to mapOf()))
90+
}
91+
92+
@Test
93+
fun testHasValues() {
94+
val everything = getFullyPopulatedAllNullableTypes()
7695
val binaryMessenger = mockk<BinaryMessenger>()
7796
val api = FlutterIntegrationCoreApi(binaryMessenger)
7897

@@ -97,6 +116,16 @@ internal class AllDatatypesTest {
97116
assertTrue(didCall)
98117
}
99118

119+
@Test
120+
fun testRoundtripHasValues() {
121+
val everything = getFullyPopulatedAllNullableTypes()
122+
val codec = FlutterIntegrationCoreApi.codec
123+
val encoded = codec.encodeMessage(everything)
124+
encoded?.rewind()
125+
val decoded = codec.decodeMessage(encoded)
126+
assertEquals(everything, decoded)
127+
}
128+
100129
private val correctList = listOf<Any?>("a", 2, "three")
101130
private val matchingList = correctList.toMutableList()
102131
private val differentList = listOf<Any?>("a", 2, "three", 4.0)

packages/pigeon/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: pigeon
22
description: Code generator tool to make communication between Flutter and the host platform type-safe and easier.
33
repository: https://github.com/flutter/packages/tree/main/packages/pigeon
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+pigeon%22
5-
version: 26.0.4 # This must match the version in lib/src/generator_tools.dart
5+
version: 26.0.5 # This must match the version in lib/src/generator_tools.dart
66

77
environment:
88
sdk: ^3.7.0

0 commit comments

Comments
 (0)