22
33package io.ably.lib.objects
44
5+ import com.fasterxml.jackson.annotation.JsonCreator
6+ import com.fasterxml.jackson.annotation.JsonInclude
57import com.fasterxml.jackson.core.JsonGenerator
68import com.fasterxml.jackson.databind.DeserializationContext
79import com.fasterxml.jackson.databind.ObjectMapper
810import com.fasterxml.jackson.databind.SerializerProvider
11+ import com.fasterxml.jackson.module.paramnames.ParameterNamesModule
912import com.google.gson.*
1013import org.msgpack.core.MessagePack
1114import org.msgpack.core.MessagePacker
1215import org.msgpack.core.MessageUnpacker
1316import org.msgpack.jackson.dataformat.MessagePackFactory
17+ import org.msgpack.value.ImmutableMapValue
1418import java.lang.reflect.Type
1519import java.util.*
1620
@@ -19,7 +23,11 @@ internal val gson: Gson = GsonBuilder().create()
1923
2024// Jackson ObjectMapper for MessagePack serialization (respects @JsonProperty annotations)
2125// Caches type metadata and serializers for ObjectMessage class after first use, so next time it's super fast 🚀
22- private val msgpackMapper = ObjectMapper (MessagePackFactory ())
26+ // https://github.com/FasterXML/jackson-modules-java8/tree/3.x/parameter-names
27+ internal val msgpackMapper = ObjectMapper (MessagePackFactory ()).apply {
28+ registerModule(ParameterNamesModule (JsonCreator .Mode .PROPERTIES ))
29+ setSerializationInclusion(JsonInclude .Include .NON_NULL )
30+ }
2331
2432internal fun ObjectMessage.toJsonObject (): JsonObject {
2533 return gson.toJsonTree(this ).asJsonObject
@@ -30,29 +38,15 @@ internal fun JsonObject.toObjectMessage(): ObjectMessage {
3038}
3139
3240internal fun ObjectMessage.writeTo (packer : MessagePacker ) {
33- // Jackson automatically creates the correct msgpack map structure
34- val msgpackBytes = msgpackMapper.writeValueAsBytes(this )
35-
36- // Parse the msgpack bytes to get the structured value
37- val tempUnpacker = MessagePack .newDefaultUnpacker(msgpackBytes)
38- val msgpackValue = tempUnpacker.unpackValue()
39- tempUnpacker.close()
40-
41- // Pack the structured value using the provided packer
42- packer.packValue(msgpackValue)
41+ val msgpackBytes = msgpackMapper.writeValueAsBytes(this ) // returns correct msgpack map structure
42+ packer.writePayload(msgpackBytes)
4343}
4444
45- internal fun MessageUnpacker.readObjectMessage (): ObjectMessage {
46- // Read the msgpack value from the unpacker
47- val msgpackValue = this .unpackValue()
48-
49- // Convert the msgpack value back to bytes
50- val tempPacker = MessagePack .newDefaultBufferPacker()
51- tempPacker.packValue(msgpackValue)
52- val msgpackBytes = tempPacker.toByteArray()
53- tempPacker.close()
54-
55- // Let Jackson deserialize the msgpack bytes back to ObjectMessage
45+ internal fun ImmutableMapValue.toObjectMessage (): ObjectMessage {
46+ val msgpackBytes = MessagePack .newDefaultBufferPacker().use { packer ->
47+ packer.packValue(this )
48+ packer.toByteArray()
49+ }
5650 return msgpackMapper.readValue(msgpackBytes, ObjectMessage ::class .java)
5751}
5852
@@ -66,7 +60,7 @@ internal class DefaultLiveObjectSerializer : LiveObjectSerializer {
6660
6761 override fun readMsgpackArray (unpacker : MessageUnpacker ): Array <Any > {
6862 val objectMessagesCount = unpacker.unpackArrayHeader()
69- return Array (objectMessagesCount) { unpacker.readObjectMessage () }
63+ return Array (objectMessagesCount) { unpacker.unpackValue().asMapValue().toObjectMessage () }
7064 }
7165
7266 override fun writeMsgpackArray (objects : Array <out Any >? , packer : MessagePacker ) {
@@ -101,7 +95,7 @@ internal class ObjectDataJsonSerializer : JsonSerializer<ObjectData>, JsonDeseri
10195 when (val v = value.value) {
10296 is Boolean -> obj.addProperty(" boolean" , v)
10397 is String -> obj.addProperty(" string" , v)
104- is Number -> obj.addProperty(" number" , v)
98+ is Number -> obj.addProperty(" number" , v.toDouble() )
10599 is Binary -> obj.addProperty(" bytes" , Base64 .getEncoder().encodeToString(v.data))
106100 // Spec: OD4c5
107101 is JsonObject , is JsonArray -> {
@@ -132,7 +126,7 @@ internal class ObjectDataJsonSerializer : JsonSerializer<ObjectData>, JsonDeseri
132126 )
133127 }
134128 obj.has(" string" ) -> ObjectValue (obj.get(" string" ).asString)
135- obj.has(" number" ) -> ObjectValue (obj.get(" number" ).asNumber )
129+ obj.has(" number" ) -> ObjectValue (obj.get(" number" ).asDouble )
136130 obj.has(" bytes" ) -> ObjectValue (Binary (Base64 .getDecoder().decode(obj.get(" bytes" ).asString)))
137131 else -> throw JsonParseException (" ObjectData must have one of the fields: boolean, string, number, or bytes" )
138132 }
@@ -179,10 +173,32 @@ internal class ObjectDataMsgpackDeserializer : com.fasterxml.jackson.databind.Js
179173 )
180174 }
181175 node.has(" string" ) -> ObjectValue (node.get(" string" ).asText())
182- node.has(" number" ) -> ObjectValue (node.get(" number" ).numberValue ())
176+ node.has(" number" ) -> ObjectValue (node.get(" number" ).doubleValue ())
183177 node.has(" bytes" ) -> ObjectValue (Binary (node.get(" bytes" ).binaryValue()))
184178 else -> throw IllegalArgumentException (" ObjectData must have one of the fields: boolean, string, number, or bytes" )
185179 }
186180 return ObjectData (objectId, value)
187181 }
188182}
183+
184+ internal class InitialValueJsonSerializer : JsonSerializer <Binary >, JsonDeserializer <Binary > {
185+ override fun serialize (src : Binary , typeOfSrc : Type ? , context : JsonSerializationContext ? ): JsonElement {
186+ return JsonPrimitive (Base64 .getEncoder().encodeToString(src.data))
187+ }
188+
189+ override fun deserialize (json : JsonElement , typeOfT : Type ? , context : JsonDeserializationContext ? ): Binary {
190+ return Binary (Base64 .getDecoder().decode(json.asString))
191+ }
192+ }
193+
194+ internal class InitialValueMsgpackSerializer : com.fasterxml.jackson.databind.JsonSerializer <Binary >() {
195+ override fun serialize (value : Binary ? , gen : JsonGenerator , serializers : SerializerProvider ) {
196+ gen.writeBinary(value?.data)
197+ }
198+ }
199+
200+ internal class InitialValueMsgpackDeserializer : com.fasterxml.jackson.databind.JsonDeserializer <Binary >() {
201+ override fun deserialize (p : com.fasterxml.jackson.core.JsonParser , ctxt : DeserializationContext ): Binary {
202+ return Binary (p.binaryValue)
203+ }
204+ }
0 commit comments