Skip to content

Commit f08de7b

Browse files
committed
[ECO-5386] Implemented custom ObjectDataJsonSerializer for ObjectData type
1 parent 7a4873e commit f08de7b

3 files changed

Lines changed: 58 additions & 19 deletions

File tree

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

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.google.gson.JsonArray
44
import com.google.gson.JsonObject
55

66
import com.fasterxml.jackson.annotation.JsonProperty
7+
import com.google.gson.annotations.JsonAdapter
78
import com.google.gson.annotations.SerializedName
89

910
/**
@@ -31,19 +32,14 @@ internal enum class MapSemantics(val code: Int) {
3132
* An ObjectData represents a value in an object on a channel.
3233
* Spec: OD1
3334
*/
35+
@JsonAdapter(ObjectDataJsonSerializer::class)
3436
internal data class ObjectData(
3537
/**
3638
* A reference to another object, used to support composable object structures.
3739
* Spec: OD2a
3840
*/
3941
val objectId: String? = null,
4042

41-
/**
42-
* Can be set by the client to indicate that value in `string` or `bytes` field have an encoding.
43-
* Spec: OD2b
44-
*/
45-
val encoding: String? = null,
46-
4743
/**
4844
* String, number, boolean or binary - a concrete value of the object
4945
* Spec: OD2c
@@ -214,18 +210,13 @@ internal data class ObjectOperation(
214210
val nonce: String? = null,
215211

216212
/**
217-
* The initial value bytes for the object. These bytes should be used along with the nonce
218-
* and timestamp to create the object ID. Frontdoor will use this to verify the object ID.
219-
* After verification the bytes will be decoded into the Map or Counter objects and
220-
* the initialValue, nonce, and initialValueEncoding will be removed.
213+
* The initial value for the object, encoded as a JSON string.
214+
* This value should be used along with the nonce and timestamp to create the object ID.
215+
* Frontdoor will use this to verify the object ID. After verification, the value will be
216+
* decoded into the Map or Counter objects and the initialValue, nonce, and initialValueEncoding will be removed.
221217
* Spec: OOP3h
222218
*/
223-
val initialValue: Binary? = null,
224-
225-
/** The initial value encoding defines how the initialValue should be interpreted.
226-
* Spec: OOP3i
227-
*/
228-
val initialValueEncoding: ProtocolMessageFormat? = null
219+
val initialValue: String? = null,
229220
)
230221

231222
/**

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import org.msgpack.core.MessagePack
88
import org.msgpack.core.MessagePacker
99
import org.msgpack.core.MessageUnpacker
1010
import org.msgpack.jackson.dataformat.MessagePackFactory
11+
import java.lang.reflect.Type
12+
import java.util.*
1113

1214
// Gson instance for JSON serialization/deserialization
1315
internal val gson: Gson = GsonBuilder().create()
@@ -86,3 +88,51 @@ internal class DefaultLiveObjectSerializer : LiveObjectSerializer {
8688
return jsonArray
8789
}
8890
}
91+
92+
internal class ObjectDataJsonSerializer : JsonSerializer<ObjectData>, JsonDeserializer<ObjectData> {
93+
override fun serialize(src: ObjectData?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement {
94+
val obj = JsonObject()
95+
src?.objectId?.let { obj.addProperty("objectId", it) }
96+
97+
src?.value?.let { value ->
98+
when (val v = value.value) {
99+
is Boolean -> obj.addProperty("boolean", v)
100+
is String -> obj.addProperty("string", v)
101+
is Number -> obj.addProperty("number", v)
102+
is Binary -> obj.addProperty("bytes", Base64.getEncoder().encodeToString(v.data))
103+
// Spec: OD4c5
104+
is JsonObject, is JsonArray -> {
105+
obj.addProperty("string", v.toString())
106+
obj.addProperty("encoding", "json")
107+
}
108+
}
109+
}
110+
return obj
111+
}
112+
113+
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): ObjectData {
114+
val obj = json?.asJsonObject ?: throw JsonParseException("Expected JsonObject")
115+
val objectId = if (obj.has("objectId")) obj.get("objectId").asString else null
116+
val encoding = if (obj.has("encoding")) obj.get("encoding").asString else null
117+
val value = when {
118+
obj.has("boolean") -> ObjectValue(obj.get("boolean").asBoolean)
119+
// Spec: OD5b3
120+
obj.has("string") && encoding == "json" -> {
121+
val jsonStr = obj.get("string").asString
122+
val parsed = JsonParser.parseString(jsonStr)
123+
ObjectValue(
124+
when {
125+
parsed.isJsonObject -> parsed.asJsonObject
126+
parsed.isJsonArray -> parsed.asJsonArray
127+
else -> throw JsonParseException("Invalid JSON string for encoding=json")
128+
}
129+
)
130+
}
131+
obj.has("string") -> ObjectValue(obj.get("string").asString)
132+
obj.has("number") -> ObjectValue(obj.get("number").asNumber)
133+
obj.has("bytes") -> ObjectValue(Binary(Base64.getDecoder().decode(obj.get("bytes").asString)))
134+
else -> null
135+
}
136+
return ObjectData(objectId, value)
137+
}
138+
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ class ObjectMessageSizeTest {
4545
key = "mapKey", // Size: 6 bytes (UTF-8 byte length)
4646
data = ObjectData(
4747
objectId = "ref_obj", // Not counted in data size
48-
encoding = "utf-8", // Not counted in data size
4948
value = ObjectValue("sample") // Size: 6 bytes (UTF-8 byte length)
5049
) // Total ObjectData size: 6 bytes
5150
), // Total ObjectMapOp size: 6 + 6 = 12 bytes
@@ -80,8 +79,7 @@ class ObjectMessageSizeTest {
8079
), // Total ObjectCounter size: 8 bytes
8180

8281
nonce = "nonce123", // Not counted in operation size
83-
initialValue = Binary("initial".toByteArray()), // Not counted in operation size
84-
initialValueEncoding = ProtocolMessageFormat.Json // Not counted in operation size
82+
initialValue = "some-value", // Not counted in operation size
8583
), // Total ObjectOperation size: 12 + 8 + 26 + 8 = 54 bytes
8684

8785
objectState = ObjectState(

0 commit comments

Comments
 (0)