Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[protobuf] How to encode/decode map with null value? #2760

Open
xiaozhikang0916 opened this issue Aug 6, 2024 · 0 comments
Open

[protobuf] How to encode/decode map with null value? #2760

xiaozhikang0916 opened this issue Aug 6, 2024 · 0 comments

Comments

@xiaozhikang0916
Copy link
Contributor

xiaozhikang0916 commented Aug 6, 2024

Describe the bug

Giving a simple proto message:

message ProtoMap {
  map<string, TypeValue> map = 1;
}

message TypeValue {
  int32 value = 1;
}

Our backend server in go may assign the map as key to null and send data like 0a050a036b6579 (1: {1: {"key"}} in readable string) with value absent.

But I found it impossible to define a valid class in represent to this message.

I tried:

@Serializable
data class ProtoMap(@ProtoNumber(1) val map: Map<String, TypeValue>)

to see if parser will give a default 0 in map, but failed to parse, and

@Serializable
data class ProtoMapNullable(@ProtoNumber(1) val map: Map<String, TypeValue?>)

This is good for decoding, but failing in encoding.

Is there any suggestion for such message, or it is a bug of map encoding?

PS I believe it is valid data to have null value in map, as described in Proto Spec.

To Reproduce

Run the test code below

package kotlinx.serialization

import kotlinx.serialization.protobuf.ProtoBuf
import kotlinx.serialization.protobuf.ProtoNumber
import kotlin.test.Test
import kotlin.test.assertEquals

@Serializable
data class TypeValue(@ProtoNumber(1) val int: Int = 0)
@Serializable
data class ProtoMap(@ProtoNumber(1) val map: Map<String, TypeValue>)
@Serializable
data class ProtoMapNullable(@ProtoNumber(1) val map: Map<String, TypeValue?>)

const val hexWithoutValue = "0a050a036b6579"

class MapTest {
    @Test
    fun testDecodeNullValueToNullableMap() {
        val value = hexWithoutValue
        val decoded = ProtoBuf.decodeFromHexString<ProtoMapNullable>(value)
        assertEquals(ProtoMapNullable(mapOf("key" to null)), decoded)
        val encode = ProtoBuf.encodeToHexString(decoded)
        println(encode)
    }

    @Test
    fun testDecodeNullValueToMap() {
        val value = hexWithoutValue
        val decoded = ProtoBuf.decodeFromHexString<ProtoMap>(value)
        assertEquals(ProtoMap(mapOf("key" to TypeValue(0))), decoded)
        val encode = ProtoBuf.encodeToHexString(decoded)
        println(encode)
    }
}

Expected behavior

One of the test should be passed, maybe?

Environment

  • Kotlin version: 2.0.0 and 1.9.23
  • Library version: 1.7.1 and 1.6.3
  • Kotlin platforms: JVM, JS, iOS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant