Skip to content

Commit ef65124

Browse files
committed
[ECO-5386] Updated unit tests for ObjectMesssage serialization
1. Updated test for testOmitNullsInObjectMessageSerialization 2. Added test HandleNullsInObjectMessageDeserialization
1 parent 7e4f5d6 commit ef65124

File tree

3 files changed

+102
-24
lines changed

3 files changed

+102
-24
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ turbine = "1.2.0"
2626
ktor = "3.1.3"
2727
jetbrains-annoations = "26.0.2"
2828
jackson-msgpack = "0.8.11" # Compatible with msgpack-core 0.8.11
29-
jackson-param = "2.18.0" # Compatible with jackson-msgpack
29+
jackson-param = "2.19.1" # Compatible with jackson-msgpack
3030

3131
[libraries]
3232
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }

live-objects/src/main/kotlin/io/ably/lib/objects/Serialization.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ internal class DefaultLiveObjectSerializer : LiveObjectSerializer {
8787
}
8888

8989
internal class ObjectDataJsonSerializer : JsonSerializer<ObjectData>, JsonDeserializer<ObjectData> {
90-
override fun serialize(src: ObjectData?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement {
90+
override fun serialize(src: ObjectData, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement {
9191
val obj = JsonObject()
92-
src?.objectId?.let { obj.addProperty("objectId", it) }
92+
src.objectId?.let { obj.addProperty("objectId", it) }
9393

94-
src?.value?.let { value ->
94+
src.value?.let { value ->
9595
when (val v = value.value) {
9696
is Boolean -> obj.addProperty("boolean", v)
9797
is String -> obj.addProperty("string", v)
@@ -107,8 +107,8 @@ internal class ObjectDataJsonSerializer : JsonSerializer<ObjectData>, JsonDeseri
107107
return obj
108108
}
109109

110-
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): ObjectData {
111-
val obj = if (json?.isJsonObject == true) json.asJsonObject else throw JsonParseException("Expected JsonObject")
110+
override fun deserialize(json: JsonElement, typeOfT: Type?, context: JsonDeserializationContext?): ObjectData {
111+
val obj = if (json.isJsonObject) json.asJsonObject else throw JsonParseException("Expected JsonObject")
112112
val objectId = if (obj.has("objectId")) obj.get("objectId").asString else null
113113
val encoding = if (obj.has("encoding")) obj.get("encoding").asString else null
114114
val value = when {
@@ -135,10 +135,10 @@ internal class ObjectDataJsonSerializer : JsonSerializer<ObjectData>, JsonDeseri
135135
}
136136

137137
internal class ObjectDataMsgpackSerializer : com.fasterxml.jackson.databind.JsonSerializer<ObjectData>() {
138-
override fun serialize(value: ObjectData?, gen: JsonGenerator, serializers: SerializerProvider) {
138+
override fun serialize(value: ObjectData, gen: JsonGenerator, serializers: SerializerProvider) {
139139
gen.writeStartObject()
140-
value?.objectId?.let { gen.writeStringField("objectId", it) }
141-
value?.value?.let { v ->
140+
value.objectId?.let { gen.writeStringField("objectId", it) }
141+
value.value?.let { v ->
142142
when (val data = v.value) {
143143
is Boolean -> gen.writeBooleanField("boolean", data)
144144
is String -> gen.writeStringField("string", data)
@@ -192,8 +192,8 @@ internal class InitialValueJsonSerializer : JsonSerializer<Binary>, JsonDeserial
192192
}
193193

194194
internal class InitialValueMsgpackSerializer : com.fasterxml.jackson.databind.JsonSerializer<Binary>() {
195-
override fun serialize(value: Binary?, gen: JsonGenerator, serializers: SerializerProvider) {
196-
gen.writeBinary(value?.data)
195+
override fun serialize(value: Binary, gen: JsonGenerator, serializers: SerializerProvider) {
196+
gen.writeBinary(value.data)
197197
}
198198
}
199199

live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSerializationTest.kt

Lines changed: 91 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
package io.ably.lib.objects.unit
22

3-
import io.ably.lib.objects.gson
4-
import io.ably.lib.objects.msgpackMapper
3+
import com.google.gson.Gson
4+
import com.google.gson.GsonBuilder
5+
import com.google.gson.JsonElement
6+
import com.google.gson.JsonNull
57
import io.ably.lib.objects.unit.fixtures.*
68
import io.ably.lib.types.ProtocolMessage
9+
import io.ably.lib.types.ProtocolMessage.ActionSerializer
710
import io.ably.lib.types.ProtocolSerializer
811
import io.ably.lib.util.Serialisation
912
import kotlinx.coroutines.test.runTest
1013
import org.junit.Assert.assertEquals
1114
import org.junit.Test
1215
import kotlin.test.assertNotNull
16+
import kotlin.test.assertNull
17+
import kotlin.test.assertTrue
1318

1419
class ObjectMessageSerializationTest {
1520

@@ -61,18 +66,91 @@ class ObjectMessageSerializationTest {
6166
}
6267

6368
@Test
64-
fun testOmitNullInSerialization() = runTest {
65-
val nullableObject = object {
66-
val name = "Test Object"
67-
val description: String? = null // This will be omitted if using Gson with excludeNulls
68-
val value = 42
69+
fun testOmitNullsInObjectMessageSerialization() = runTest {
70+
val objectMessage = dummyObjectMessageWithStringData()
71+
val objectMessageWithNullFields = objectMessage.copy(
72+
id = null,
73+
timestamp = null,
74+
clientId = "test-client",
75+
connectionId = "test-connection",
76+
extras = null,
77+
operation = null,
78+
objectState = null,
79+
serial = null,
80+
siteCode = null
81+
)
82+
val protocolMessage = ProtocolMessage()
83+
protocolMessage.action = ProtocolMessage.Action.`object`
84+
protocolMessage.state = arrayOf(objectMessageWithNullFields)
85+
86+
// check if Gson/Msgpack serialization omits null fields
87+
fun assertSerializedObjectMessage(serializedProtoMsg: String) {
88+
val deserializedProtoMsg = Gson().fromJson(serializedProtoMsg, JsonElement::class.java).asJsonObject
89+
val serializedObjectMessage = deserializedProtoMsg.get("state").asJsonArray[0].asJsonObject.toString()
90+
assertEquals("""{"clientId":"test-client","connectionId":"test-connection"}""", serializedObjectMessage)
6991
}
70-
val serializedJsonString = gson.toJson(nullableObject)
71-
// check serializedObject does not contain the null field
72-
assertEquals("""{"name":"Test Object","value":42}""", serializedJsonString)
7392

74-
val serializedMsgpackBytes = msgpackMapper.writeValueAsBytes(nullableObject)
75-
// check serializedObject does not contain the null field
76-
assertEquals("""{"name":"Test Object","value":42}""", Serialisation.msgpackToGson(serializedMsgpackBytes).toString())
93+
// Serialize using Gson
94+
val serializedProtoMsg = ProtocolSerializer.writeJSON(protocolMessage).toString(Charsets.UTF_8)
95+
assertSerializedObjectMessage(serializedProtoMsg)
96+
97+
// Serialize using MsgPack
98+
val serializedMsgpackBytes = ProtocolSerializer.writeMsgpack(protocolMessage)
99+
val serializedJsonStringFromMsgpackBytes = Serialisation.msgpackToGson(serializedMsgpackBytes).toString()
100+
assertSerializedObjectMessage(serializedJsonStringFromMsgpackBytes)
101+
}
102+
103+
@Test
104+
fun testHandleNullsInObjectMessageDeserialization() = runTest {
105+
val protocolMessage = ProtocolMessage()
106+
protocolMessage.id = "id"
107+
protocolMessage.action = ProtocolMessage.Action.`object`
108+
protocolMessage.state = null
109+
110+
// Serialize using Gson with serializeNulls enabled
111+
val gsonBuilderCreatingNulls = GsonBuilder()
112+
.registerTypeAdapter(ProtocolMessage.Action::class.java, ActionSerializer())
113+
.serializeNulls().create()
114+
115+
var protoMsgJsonObject = gsonBuilderCreatingNulls.toJsonTree(protocolMessage).asJsonObject
116+
assertTrue(protoMsgJsonObject.has("state"))
117+
assertEquals(JsonNull.INSTANCE, protoMsgJsonObject.get("state"))
118+
119+
var deserializedProtoMsg = ProtocolSerializer.fromJSON(protoMsgJsonObject.toString())
120+
assertNull(deserializedProtoMsg.state)
121+
122+
var serializedMsgpackBytes = Serialisation.gsonToMsgpack(protoMsgJsonObject)
123+
deserializedProtoMsg = ProtocolSerializer.readMsgpack(serializedMsgpackBytes)
124+
assertNull(deserializedProtoMsg.state)
125+
126+
// Create ObjectMessage and serialize in a way that resulting string/bytes include null fields
127+
val objectMessage = dummyObjectMessageWithStringData()
128+
val objectMessageWithNullFields = objectMessage.copy(
129+
id = null,
130+
timestamp = null,
131+
clientId = "test-client",
132+
connectionId = "test-connection",
133+
extras = null,
134+
operation = objectMessage.operation?.copy(
135+
initialValue = null, // initialValue set to null
136+
mapOp = objectMessage.operation.mapOp?.copy(
137+
data = null // objectData set to null
138+
)
139+
),
140+
objectState = null,
141+
serial = null,
142+
siteCode = null
143+
)
144+
protocolMessage.state = arrayOf(objectMessageWithNullFields)
145+
protoMsgJsonObject = gsonBuilderCreatingNulls.toJsonTree(protocolMessage).asJsonObject
146+
147+
// Check if gson deserialization works correctly
148+
deserializedProtoMsg = ProtocolSerializer.fromJSON(protoMsgJsonObject.toString())
149+
assertEquals(objectMessageWithNullFields, deserializedProtoMsg.state[0] as? io.ably.lib.objects.ObjectMessage)
150+
151+
// Check if msgpack deserialization works correctly
152+
serializedMsgpackBytes = Serialisation.gsonToMsgpack(protoMsgJsonObject)
153+
deserializedProtoMsg = ProtocolSerializer.readMsgpack(serializedMsgpackBytes)
154+
assertEquals(objectMessageWithNullFields, deserializedProtoMsg.state[0] as? io.ably.lib.objects.ObjectMessage)
77155
}
78156
}

0 commit comments

Comments
 (0)