-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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 bson-kotlinx encodeNullableSerializableValue
null handling
#1453
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,7 +72,7 @@ internal class DefaultBsonEncoder( | |
private var isPolymorphic = false | ||
private var state = STATE.VALUE | ||
private var mapState = MapState() | ||
private var deferredElementName: String? = null | ||
private val deferredElementHandler: DeferredElementHandler = DeferredElementHandler() | ||
|
||
override fun shouldEncodeElementDefault(descriptor: SerialDescriptor, index: Int): Boolean = | ||
configuration.encodeDefaults | ||
|
@@ -117,7 +117,7 @@ internal class DefaultBsonEncoder( | |
is StructureKind.CLASS -> { | ||
val elementName = descriptor.getElementName(index) | ||
if (descriptor.getElementDescriptor(index).isNullable) { | ||
deferredElementName = elementName | ||
deferredElementHandler.set(elementName) | ||
} else { | ||
encodeName(elementName) | ||
} | ||
|
@@ -140,25 +140,25 @@ internal class DefaultBsonEncoder( | |
} | ||
|
||
override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) { | ||
deferredElementName?.let { | ||
if (value != null || configuration.explicitNulls) { | ||
encodeName(it) | ||
super.encodeSerializableValue(serializer, value) | ||
} else { | ||
deferredElementName = null | ||
} | ||
} | ||
?: super.encodeSerializableValue(serializer, value) | ||
deferredElementHandler.with( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's unclear to me why value is |
||
{ | ||
if (value != null || configuration.explicitNulls) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a point of clarification: It's unclear to me why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this surprised me also. The only test that triggers this is via the use of generics which aren't marked as nullable.
Encoding: Its questionable that this code is reasonable / bug free. However, it appears to be marked as designed: https://youtrack.jetbrains.com/issue/KT-66206 I've added a comment to the code. |
||
encodeName(it) | ||
super.encodeSerializableValue(serializer, value) | ||
} | ||
}, | ||
{ super.encodeSerializableValue(serializer, value) }) | ||
} | ||
|
||
override fun <T : Any> encodeNullableSerializableValue(serializer: SerializationStrategy<T>, value: T?) { | ||
deferredElementName?.let { | ||
if (value != null || configuration.explicitNulls) { | ||
encodeName(it) | ||
super.encodeNullableSerializableValue(serializer, value) | ||
} | ||
} | ||
?: super.encodeNullableSerializableValue(serializer, value) | ||
deferredElementHandler.with( | ||
{ | ||
if (value != null || configuration.explicitNulls) { | ||
encodeName(it) | ||
super.encodeNullableSerializableValue(serializer, value) | ||
} | ||
}, | ||
{ super.encodeNullableSerializableValue(serializer, value) }) | ||
} | ||
|
||
override fun encodeByte(value: Byte) = encodeInt(value.toInt()) | ||
|
@@ -170,14 +170,7 @@ internal class DefaultBsonEncoder( | |
override fun encodeDouble(value: Double) = writer.writeDouble(value) | ||
override fun encodeInt(value: Int) = writer.writeInt32(value) | ||
override fun encodeLong(value: Long) = writer.writeInt64(value) | ||
override fun encodeNull() { | ||
deferredElementName?.let { | ||
if (configuration.explicitNulls) { | ||
encodeName(it) | ||
} | ||
} | ||
writer.writeNull() | ||
} | ||
override fun encodeNull() = writer.writeNull() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure how this was missed in a PR - but encoding null will never require the deferred element name - as |
||
|
||
override fun encodeString(value: String) { | ||
when (state) { | ||
|
@@ -206,7 +199,6 @@ internal class DefaultBsonEncoder( | |
|
||
private fun encodeName(value: Any) { | ||
writer.writeName(value.toString()) | ||
deferredElementName = null | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No longer required - as its cleaned up in the |
||
state = STATE.VALUE | ||
} | ||
|
||
|
@@ -229,4 +221,25 @@ internal class DefaultBsonEncoder( | |
return getState() | ||
} | ||
} | ||
|
||
private class DeferredElementHandler { | ||
private var deferredElementName: String? = null | ||
|
||
fun set(name: String) { | ||
assert(deferredElementName == null) { -> "Overwriting an existing deferred name" } | ||
deferredElementName = name | ||
} | ||
|
||
fun with(actionWithDeferredElement: (String) -> Unit, actionWithoutDeferredElement: () -> Unit): Unit { | ||
deferredElementName?.let { | ||
reset() | ||
actionWithDeferredElement(it) | ||
} | ||
?: actionWithoutDeferredElement() | ||
} | ||
|
||
private fun reset() { | ||
deferredElementName = null | ||
} | ||
} | ||
} |
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.
This is just a copy from
bson-kotlinx
- to ensure thebson-kotlin
library also works as expected.