Skip to content

Commit 0592f72

Browse files
committed
[ECO-5386] Defined LiveObjectSerializer interface
1. Added LiveObjectsHelper for initializing LiveObjects plugin and related serializer 2. Updated ProtocolMessage to handle msgpack serialization/deserialization
1 parent 6c8a793 commit 0592f72

File tree

6 files changed

+143
-15
lines changed

6 files changed

+143
-15
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package io.ably.lib.objects;
2+
3+
import com.google.gson.JsonArray;
4+
import org.jetbrains.annotations.NotNull;
5+
import org.msgpack.core.MessagePacker;
6+
import org.msgpack.core.MessageUnpacker;
7+
8+
import java.io.IOException;
9+
10+
/**
11+
* Serializer interface for converting between LiveObject arrays and their
12+
* MessagePack or JSON representations.
13+
*/
14+
public interface LiveObjectSerializer {
15+
/**
16+
* Reads a MessagePack array from the given unpacker and deserializes it into an Object array.
17+
*
18+
* @param unpacker the MessageUnpacker to read from
19+
* @return the deserialized Object array
20+
* @throws IOException if an I/O error occurs during unpacking
21+
*/
22+
@NotNull
23+
Object[] readMsgpackArray(@NotNull MessageUnpacker unpacker) throws IOException;
24+
25+
/**
26+
* Serializes the given Object array as a MessagePack array using the provided packer.
27+
*
28+
* @param objects the Object array to serialize
29+
* @param packer the MessagePacker to write to
30+
* @throws IOException if an I/O error occurs during packing
31+
*/
32+
void writeMsgpackArray(@NotNull Object[] objects, @NotNull MessagePacker packer) throws IOException;
33+
34+
/**
35+
* Reads a JSON array from the given {@link JsonArray} and deserializes it into an Object array.
36+
*
37+
* @param json the {@link JsonArray} representing the array to deserialize
38+
* @return the deserialized Object array
39+
* @throws IOException if an error occurs during parsing
40+
*/
41+
@NotNull
42+
Object[] readFromJsonArray(@NotNull JsonArray json) throws IOException;
43+
44+
/**
45+
* Serializes the given Object array as a JSON array.
46+
*
47+
* @param objects the Object array to serialize
48+
* @return the resulting JsonArray
49+
* @throws IOException if an error occurs during serialization
50+
*/
51+
@NotNull
52+
JsonArray writeAsJsonArray(@NotNull Object[] objects) throws IOException;
53+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package io.ably.lib.objects;
2+
3+
import io.ably.lib.realtime.AblyRealtime;
4+
import io.ably.lib.util.Log;
5+
6+
import java.lang.reflect.InvocationTargetException;
7+
8+
public class LiveObjectsHelper {
9+
10+
private static final String TAG = LiveObjectsHelper.class.getName();
11+
private static LiveObjectSerializer liveObjectSerializer;
12+
13+
public static LiveObjectsPlugin tryInitializeLiveObjectsPlugin(AblyRealtime ablyRealtime) {
14+
try {
15+
Class<?> liveObjectsImplementation = Class.forName("io.ably.lib.objects.DefaultLiveObjectsPlugin");
16+
LiveObjectsAdapter adapter = new Adapter(ablyRealtime);
17+
return (LiveObjectsPlugin) liveObjectsImplementation
18+
.getDeclaredConstructor(LiveObjectsAdapter.class)
19+
.newInstance(adapter);
20+
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException |
21+
InvocationTargetException e) {
22+
Log.i(TAG, "LiveObjects plugin not found in classpath. LiveObjects functionality will not be available.", e);
23+
return null;
24+
}
25+
}
26+
27+
public static LiveObjectSerializer getLiveObjectSerializer() {
28+
if (liveObjectSerializer == null) {
29+
try {
30+
Class<?> serializerClass = Class.forName("io.ably.lib.objects.DefaultLiveObjectSerializer");
31+
liveObjectSerializer = (LiveObjectSerializer) serializerClass.getDeclaredConstructor().newInstance();
32+
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException |
33+
InvocationTargetException e) {
34+
Log.e(TAG, "Failed to initialize LiveObjectSerializer", e);
35+
}
36+
}
37+
return liveObjectSerializer;
38+
}
39+
}

lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import io.ably.lib.objects.Adapter;
1010
import io.ably.lib.objects.LiveObjectsAdapter;
11+
import io.ably.lib.objects.LiveObjectsHelper;
1112
import io.ably.lib.objects.LiveObjectsPlugin;
1213
import io.ably.lib.rest.AblyRest;
1314
import io.ably.lib.rest.Auth;
@@ -74,7 +75,7 @@ public AblyRealtime(ClientOptions options) throws AblyException {
7475
final InternalChannels channels = new InternalChannels();
7576
this.channels = channels;
7677

77-
liveObjectsPlugin = tryInitializeLiveObjectsPlugin();
78+
liveObjectsPlugin = LiveObjectsHelper.tryInitializeLiveObjectsPlugin(this);
7879

7980
connection = new Connection(this, channels, platformAgentProvider, liveObjectsPlugin);
8081

@@ -185,20 +186,6 @@ public interface Channels extends ReadOnlyMap<String, Channel> {
185186
void release(String channelName);
186187
}
187188

188-
private LiveObjectsPlugin tryInitializeLiveObjectsPlugin() {
189-
try {
190-
Class<?> liveObjectsImplementation = Class.forName("io.ably.lib.objects.DefaultLiveObjectsPlugin");
191-
LiveObjectsAdapter adapter = new Adapter(this);
192-
return (LiveObjectsPlugin) liveObjectsImplementation
193-
.getDeclaredConstructor(LiveObjectsAdapter.class)
194-
.newInstance(adapter);
195-
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException |
196-
InvocationTargetException e) {
197-
Log.i(TAG, "LiveObjects plugin not found in classpath. LiveObjects functionality will not be available.", e);
198-
return null;
199-
}
200-
}
201-
202189
private class InternalChannels extends InternalMap<String, Channel> implements Channels, ConnectionManager.Channels {
203190
/**
204191
* Get the named channel; if it does not already exist,

lib/src/main/java/io/ably/lib/types/ProtocolMessage.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import java.lang.reflect.Type;
55
import java.util.Map;
66

7+
import io.ably.lib.objects.LiveObjectSerializer;
8+
import io.ably.lib.objects.LiveObjectsHelper;
9+
import org.jetbrains.annotations.Nullable;
710
import org.msgpack.core.MessageFormat;
811
import org.msgpack.core.MessagePacker;
912
import org.msgpack.core.MessageUnpacker;
@@ -123,6 +126,11 @@ public ProtocolMessage(Action action, String channel) {
123126
public AuthDetails auth;
124127
public Map<String, String> params;
125128
public Annotation[] annotations;
129+
/**
130+
* This will be null if we skipped decoding this property due to user not requesting Objects functionality
131+
*/
132+
@Nullable
133+
public Object[] state;
126134

127135
public boolean hasFlag(final Flag flag) {
128136
return (flags & flag.getMask()) == flag.getMask();
@@ -147,6 +155,7 @@ void writeMsgpack(MessagePacker packer) throws IOException {
147155
if(params != null) ++fieldCount;
148156
if(channelSerial != null) ++fieldCount;
149157
if(annotations != null) ++fieldCount;
158+
if(state != null) ++fieldCount;
150159
packer.packMapHeader(fieldCount);
151160
packer.packString("action");
152161
packer.packInt(action.getValue());
@@ -186,6 +195,15 @@ void writeMsgpack(MessagePacker packer) throws IOException {
186195
packer.packString("annotations");
187196
AnnotationSerializer.writeMsgpackArray(annotations, packer);
188197
}
198+
if(state != null) {
199+
LiveObjectSerializer liveObjectsSerializer = LiveObjectsHelper.getLiveObjectSerializer();
200+
if (liveObjectsSerializer != null) {
201+
packer.packString("state");
202+
liveObjectsSerializer.writeMsgpackArray(state, packer);
203+
} else {
204+
Log.w(TAG, "Skipping 'state' field serialization because LiveObjectsSerializer is not set");
205+
}
206+
}
189207
}
190208

191209
ProtocolMessage readMsgpack(MessageUnpacker unpacker) throws IOException {
@@ -248,6 +266,15 @@ ProtocolMessage readMsgpack(MessageUnpacker unpacker) throws IOException {
248266
case "annotations":
249267
annotations = AnnotationSerializer.readMsgpackArray(unpacker);
250268
break;
269+
case "state":
270+
LiveObjectSerializer liveObjectsSerializer = LiveObjectsHelper.getLiveObjectSerializer();
271+
if (liveObjectsSerializer != null) {
272+
state = liveObjectsSerializer.readMsgpackArray(unpacker);
273+
} else {
274+
Log.w(TAG, "Skipping 'state' field deserialization because LiveObjectsSerializer is not set");
275+
unpacker.skipValue();
276+
}
277+
break;
251278
default:
252279
Log.v(TAG, "Unexpected field: " + fieldName);
253280
unpacker.skipValue();

live-objects/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ repositories {
1111

1212
dependencies {
1313
implementation(project(":java"))
14+
implementation(libs.bundles.common)
1415
implementation(libs.coroutine.core)
1516

1617
testImplementation(kotlin("test"))

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,30 @@ package io.ably.lib.objects
22

33
import com.google.gson.Gson
44
import com.google.gson.GsonBuilder
5+
import com.google.gson.JsonArray
6+
import org.msgpack.core.MessagePacker
7+
import org.msgpack.core.MessageUnpacker
58

69
internal val gson: Gson = createGsonSerializer()
710

811
private fun createGsonSerializer(): Gson {
912
return GsonBuilder().create() // Do not call serializeNulls() to omit null values
1013
}
14+
15+
internal class DefaultLiveObjectSerializer : LiveObjectSerializer {
16+
override fun readMsgpackArray(unpacker: MessageUnpacker): Array<Any> {
17+
TODO("Not yet implemented")
18+
}
19+
20+
override fun writeMsgpackArray(objects: Array<out Any>?, packer: MessagePacker) {
21+
TODO("Not yet implemented")
22+
}
23+
24+
override fun readFromJsonArray(json: JsonArray): Array<Any> {
25+
TODO("Not yet implemented")
26+
}
27+
28+
override fun writeAsJsonArray(objects: Array<out Any>?): JsonArray {
29+
TODO("Not yet implemented")
30+
}
31+
}

0 commit comments

Comments
 (0)