-
Notifications
You must be signed in to change notification settings - Fork 624
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
Fix serializing nulls for a property of a parameterized type with a nullable upper bound with Protobuf #2561
Fix serializing nulls for a property of a parameterized type with a nullable upper bound with Protobuf #2561
Conversation
… a nullable upper bound but break some existing tests This is done by setting `nullableMode` depending on `serializer.descriptor.isNullable` in `encodeSerializableElement`. Some common test functions are extracted to `TestFunctions.kt` to eliminate duplicate code. This breaks some existing tests in `ProtobufCollectionsTest`.
…mit 16fc6de A common `isMapOrList` function is extracted and the `elementKind` local variables is removed with this function so its value is evaluated only when needed.
The checks on Linux failed because "Gradle build daemon disappeared unexpectedly (it may have been killed or may have crashed)". Is there a way to rerun it? |
Here is some brief information for this PR. See such a class definition with a type parameter @Serializable
data class Box<T>(val value: T)
While for JSON, |
It looks like what you are trying to do is to omit the box if the member is empty. Is that not more of a case for either a custom serializer or a value class (which formats can handle specially). In terms of your tests, you at least need to test for correct behaviour if there are more members than just 1. |
No I don't think this is what I am doing. I mean it's probably a bug that, when the upper bound of a type of a property is nullable instead of the type itself, serializing a |
I was looking at the test data. The data is empty when the member is null, and not empty if there is a member. This looks like what happens for inline structs. Looking back it may be because you directly serialize the struct so the box is not tagged (as it is the outer type). |
I think this is the correct behavior of Protobuf here. In the Protobuf Java library, If you run the code below on the class NullableIntBox(val value: Int?)
println(ProtoBuf.encodeToHexString(NullableIntBox(null)).length) |
I came across the same exception, and also another very similar one in org.mongodb:bson-kotlinx. But I hadn't seen this PR. I actually think the root cause is in the kotlinx.serialization compiler plugin. Because the default upper bound for a type parameter is Any?, they are nullable. Therefore I would expect that the write$Self$main static method generated by the kotlinx.serialization compiler plugin would invoke CompositeEncoder.encodeNullableSerializableElement, but instead it invokes CompositeEncoder.encodeSerializableElement. I've created JetBrains/kotlin#5271 to address this. This will also automatically fix this problem with the Protobuf encoder. |
@cliffred Cool. I also played with the compiler plugin for a while and later found that this could be resolved without changing the code in the compiler plugin. I think both are viable solutions. |
Me too, it's indeed a good idea to also deal with this within the individual encoders, therefore I also submitted a PR to the MongoDB BSON kotlinx encoder to fix it also within that encoder. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your PR! I believe this is the correct way to fix this in the encoder.
data class ExplicitNullableUpperBoundBox<T : Any?>(val value: T) | ||
|
||
@Serializable | ||
data class ExplicitNullableUpperNullablePropertyBoundBox<T : Any?>(val value: T?) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mind also adding test for class Foo<T: Any>(val t: T)
to check that non-nullable type parameters still reject null
s?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry I am not sure how to do this. I could add some tests for class Foo<T: Any>(val t: T)
but it's impossible to set a null
for the member t
, unless I go for some hacks like calling the constructor in Java and passing a null
argument (I am not completely sure this works though).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you're right, that's impossible for Kotlin's type system. Never mind :)
I've also taken a look at the PR by @cliffred. It seems to be the correct approach to my intuition, but I should re-check if it doesn't break anything. |
No description provided.