question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

@SerialId does not affect enum members

See original GitHub issue

There appears to be an incorrect enum index/value check during protobuf enum decoding (kotlin: 1.3.20, kotlinx.serialization: 0.10.0)

For example using the following .proto definition to generate the incoming serialized message:

syntax = "proto3";
package example;

option java_package = "example.java";
option java_multiple_files = true;

enum EnumA {
    reserved 2 to 9;
    A_ZERO = 0;
    A_ONE = 1;
    A_TEN = 10;
}

enum EnumB {
    B_ZERO = 0;
    B_ONE = 1;
    B_TWO = 2;
}

message ExampleEnumMessage {
    EnumA a = 1;
    EnumB b = 2;
}

Deserializing to the following data class:

enum class EnumA {
    @SerialId(0) A_ZERO,
    @SerialId(1) A_ONE,
    @SerialId(10) A_TEN;

    companion object {
        val defaultValue: EnumA = EnumA.values()[0]
    }
}

enum class EnumB {
    @SerialId(0) B_ZERO,
    @SerialId(1) B_ONE,
    @SerialId(2) B_TWO;

    companion object {
        val defaultValue: EnumB = EnumB.values()[0]
    }
}

@Serializable
data class ExampleEnumMessage(
    @SerialId(1) @Optional val a: EnumA = EnumA.defaultValue,
    @SerialId(2) @Optional val b: EnumB = EnumB.defaultValue) {
}

The following example uses protobuf-java runtime to generate the encoded data to be decoded by kotlinx.serialization:

fun example() {
    val parser = ExampleEnumMessageJava.parser()
    val serializer = ExampleEnumMessage.serializer()

    val message = ExampleEnumMessageJava.newBuilder().setA(EnumAJava.A_TEN).build()
    // Replacing previous line with the following will not have an error.
    // val message = ExampleEnumMessageJava.newBuilder().setB(EnumBJava.B_TWO).build()
    val encodedWithJava = message.toByteArray()
    val decodedWithKotlin = ProtoBuf.load(serializer, encodedWithJava)
}

will fail with:

java.lang.IllegalStateException: 10 is not among valid example.EnumA choices, choices size is 3

	at kotlinx.serialization.internal.CommonEnumSerializer.deserialize(Enums.kt:46)
	at kotlinx.serialization.protobuf.ProtoBuf$ProtobufReader.decodeSerializableValue(ProtoBuf.kt:204)
	at kotlinx.serialization.TaggedDecoder$decodeSerializableElement$1.invoke(Tagged.kt:254)
	at kotlinx.serialization.TaggedDecoder.tagBlock(Tagged.kt:267)
	at kotlinx.serialization.TaggedDecoder.decodeSerializableElement(Tagged.kt:254)

It looks like the decoded value is directly used as the index value into an enum-value choice array, which is causing the range-check condition to fail.

What is the correct way to pass in enum constant information such that it matches the analogous protobuf IDL declaration?

Edited:

  • Removed red-herring information on a application-supplied ‘value’ property in the enum class definitions. The example now attempts to tag each enum value with a @SerialId (though probably incorrectly used).

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
sandwwraithcommented, Feb 4, 2019

This is the current enums limitation: no serial annotation has any effect on them. We are going to fix this at some point in the future.

1reaction
rickygaocommented, Apr 30, 2019

Looking forward it. Actually, values in enums should be easier to be customized any way you like, instead of just in sequence.

I noticed that Int may replace the enum type, however, to make a workaround.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to ensure consistency of enums in Java serialization?
The serialized form of an enum constant consists solely of its name; field values of the constant are not present in the form....
Read more >
Serialization Rules - CodeNarc
The process by which enum constants are serialized cannot be customized; ... declaring class–serialVersionUID fields are not useful as inherited members.
Read more >
"serialVersionUID" should not be declared blindly
Providing a serialVersionUID field on Serializable classes is strongly recommended by the Serializable documentation but blindly following that recommendation ...
Read more >
Java Object Serialization Specification: 1 - System Architecture
The serialized form of an enum constant consists solely of its name; field values of the constant are not present in the form....
Read more >
ALWAYS assign enum values (at least, if you serialize them)
With that little change, they've broken the whole UnityAds integration. No ads will show up anymore, because it uses the wrong AdNetwork that ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found