|
2 | 2 |
|
3 | 3 | package io.ably.lib.objects |
4 | 4 |
|
| 5 | +import com.fasterxml.jackson.core.JsonGenerator |
| 6 | +import com.fasterxml.jackson.databind.DeserializationContext |
5 | 7 | import com.fasterxml.jackson.databind.ObjectMapper |
| 8 | +import com.fasterxml.jackson.databind.SerializerProvider |
6 | 9 | import com.google.gson.* |
7 | 10 | import org.msgpack.core.MessagePack |
8 | 11 | import org.msgpack.core.MessagePacker |
9 | 12 | import org.msgpack.core.MessageUnpacker |
10 | 13 | import org.msgpack.jackson.dataformat.MessagePackFactory |
| 14 | +import java.lang.reflect.Type |
| 15 | +import java.util.* |
11 | 16 |
|
12 | 17 | // Gson instance for JSON serialization/deserialization |
13 | 18 | internal val gson: Gson = GsonBuilder().create() |
@@ -86,3 +91,98 @@ internal class DefaultLiveObjectSerializer : LiveObjectSerializer { |
86 | 91 | return jsonArray |
87 | 92 | } |
88 | 93 | } |
| 94 | + |
| 95 | +internal class ObjectDataJsonSerializer : JsonSerializer<ObjectData>, JsonDeserializer<ObjectData> { |
| 96 | + override fun serialize(src: ObjectData?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement { |
| 97 | + val obj = JsonObject() |
| 98 | + src?.objectId?.let { obj.addProperty("objectId", it) } |
| 99 | + |
| 100 | + src?.value?.let { value -> |
| 101 | + when (val v = value.value) { |
| 102 | + is Boolean -> obj.addProperty("boolean", v) |
| 103 | + is String -> obj.addProperty("string", v) |
| 104 | + is Number -> obj.addProperty("number", v) |
| 105 | + is Binary -> obj.addProperty("bytes", Base64.getEncoder().encodeToString(v.data)) |
| 106 | + // Spec: OD4c5 |
| 107 | + is JsonObject, is JsonArray -> { |
| 108 | + obj.addProperty("string", v.toString()) |
| 109 | + obj.addProperty("encoding", "json") |
| 110 | + } |
| 111 | + } |
| 112 | + } |
| 113 | + return obj |
| 114 | + } |
| 115 | + |
| 116 | + override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): ObjectData { |
| 117 | + val obj = if (json?.isJsonObject == true) json.asJsonObject else throw JsonParseException("Expected JsonObject") |
| 118 | + val objectId = if (obj.has("objectId")) obj.get("objectId").asString else null |
| 119 | + val encoding = if (obj.has("encoding")) obj.get("encoding").asString else null |
| 120 | + val value = when { |
| 121 | + obj.has("boolean") -> ObjectValue(obj.get("boolean").asBoolean) |
| 122 | + // Spec: OD5b3 |
| 123 | + obj.has("string") && encoding == "json" -> { |
| 124 | + val jsonStr = obj.get("string").asString |
| 125 | + val parsed = JsonParser.parseString(jsonStr) |
| 126 | + ObjectValue( |
| 127 | + when { |
| 128 | + parsed.isJsonObject -> parsed.asJsonObject |
| 129 | + parsed.isJsonArray -> parsed.asJsonArray |
| 130 | + else -> throw JsonParseException("Invalid JSON string for encoding=json") |
| 131 | + } |
| 132 | + ) |
| 133 | + } |
| 134 | + obj.has("string") -> ObjectValue(obj.get("string").asString) |
| 135 | + obj.has("number") -> ObjectValue(obj.get("number").asNumber) |
| 136 | + obj.has("bytes") -> ObjectValue(Binary(Base64.getDecoder().decode(obj.get("bytes").asString))) |
| 137 | + else -> throw JsonParseException("ObjectData must have one of the fields: boolean, string, number, or bytes") |
| 138 | + } |
| 139 | + return ObjectData(objectId, value) |
| 140 | + } |
| 141 | +} |
| 142 | + |
| 143 | +internal class ObjectDataMsgpackSerializer : com.fasterxml.jackson.databind.JsonSerializer<ObjectData>() { |
| 144 | + override fun serialize(value: ObjectData?, gen: JsonGenerator, serializers: SerializerProvider) { |
| 145 | + gen.writeStartObject() |
| 146 | + value?.objectId?.let { gen.writeStringField("objectId", it) } |
| 147 | + value?.value?.let { v -> |
| 148 | + when (val data = v.value) { |
| 149 | + is Boolean -> gen.writeBooleanField("boolean", data) |
| 150 | + is String -> gen.writeStringField("string", data) |
| 151 | + is Number -> gen.writeNumberField("number", data.toDouble()) |
| 152 | + is Binary -> gen.writeBinaryField("bytes", data.data) |
| 153 | + is JsonObject, is JsonArray -> { |
| 154 | + gen.writeStringField("string", data.toString()) |
| 155 | + gen.writeStringField("encoding", "json") |
| 156 | + } |
| 157 | + } |
| 158 | + } |
| 159 | + gen.writeEndObject() |
| 160 | + } |
| 161 | +} |
| 162 | + |
| 163 | +internal class ObjectDataMsgpackDeserializer : com.fasterxml.jackson.databind.JsonDeserializer<ObjectData>() { |
| 164 | + override fun deserialize(p: com.fasterxml.jackson.core.JsonParser, ctxt: DeserializationContext): ObjectData { |
| 165 | + val node = p.codec.readTree<com.fasterxml.jackson.databind.JsonNode>(p) |
| 166 | + val objectId = node.get("objectId")?.asText() |
| 167 | + val encoding = node.get("encoding")?.asText() |
| 168 | + val value = when { |
| 169 | + node.has("boolean") -> ObjectValue(node.get("boolean").asBoolean()) |
| 170 | + node.has("string") && encoding == "json" -> { |
| 171 | + val jsonStr = node.get("string").asText() |
| 172 | + val parsed = JsonParser.parseString(jsonStr) |
| 173 | + ObjectValue( |
| 174 | + when { |
| 175 | + parsed.isJsonObject -> parsed.asJsonObject |
| 176 | + parsed.isJsonArray -> parsed.asJsonArray |
| 177 | + else -> throw IllegalArgumentException("Invalid JSON string for encoding=json") |
| 178 | + } |
| 179 | + ) |
| 180 | + } |
| 181 | + node.has("string") -> ObjectValue(node.get("string").asText()) |
| 182 | + node.has("number") -> ObjectValue(node.get("number").numberValue()) |
| 183 | + node.has("bytes") -> ObjectValue(Binary(node.get("bytes").binaryValue())) |
| 184 | + else -> throw IllegalArgumentException("ObjectData must have one of the fields: boolean, string, number, or bytes") |
| 185 | + } |
| 186 | + return ObjectData(objectId, value) |
| 187 | + } |
| 188 | +} |
0 commit comments