Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
refactor: simplify MessageVersion and MessageAnnotations parsing,…
… improve readability

Make parsing methods static and refactor to use local variables, reducing reliance on instance-level mutation. Introduce `LEGACY_API_PROTOCOL_V2` constant for consistent versioning in legacy endpoints calls.
  • Loading branch information
ttypic committed Sep 24, 2025
commit d05b4dd758bad3d0360ce50301f1299bd44654af
22 changes: 19 additions & 3 deletions lib/src/main/java/io/ably/lib/rest/AblyBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@
*/
public abstract class AblyBase implements AutoCloseable {

/**
* Some REST endpoints (e.g., stats and batch) changed in protocol v3.
* To preserve backward compatibility for those specific endpoints, we
* explicitly request protocol v2 when calling them.
* <p>
* Use this only for legacy endpoints that must remain on v2; all other
* calls should use the default protocol version.
*/
private static final int LEGACY_API_PROTOCOL_V2 = 2;

public final ClientOptions options;
public final Http http;
public final HttpCore httpCore;
Expand Down Expand Up @@ -254,7 +264,10 @@ PaginatedResult<Stats> stats(Http http, Param[] params) throws AblyException {
http,
"/stats",
// Stats api uses protocol v2 format for now
Param.set(HttpUtils.defaultAcceptHeaders(false), new Param(Defaults.ABLY_PROTOCOL_VERSION_HEADER, 2)),
Param.set(
HttpUtils.defaultAcceptHeaders(false),
new Param(Defaults.ABLY_PROTOCOL_VERSION_HEADER, LEGACY_API_PROTOCOL_V2)
),
params,
StatsReader.statsResponseHandler
).get();
Expand Down Expand Up @@ -289,7 +302,10 @@ void statsAsync(Http http, Param[] params, Callback<AsyncPaginatedResult<Stats>>
http,
"/stats",
// Stats api uses protocol v2 format for now
Param.set(HttpUtils.defaultAcceptHeaders(false), new Param(Defaults.ABLY_PROTOCOL_VERSION_HEADER, 2)),
Param.set(
HttpUtils.defaultAcceptHeaders(false),
new Param(Defaults.ABLY_PROTOCOL_VERSION_HEADER, LEGACY_API_PROTOCOL_V2)
),
params,
StatsReader.statsResponseHandler
)).get(callback);
Expand Down Expand Up @@ -451,7 +467,7 @@ public void execute(HttpScheduler http, final Callback<PublishResponse[]> callba
// This method uses an old batch format from protocol v2
Param[] headers = Param.set(
HttpUtils.defaultAcceptHeaders(options.useBinaryProtocol),
new Param(Defaults.ABLY_PROTOCOL_VERSION_HEADER, 2)
new Param(Defaults.ABLY_PROTOCOL_VERSION_HEADER, LEGACY_API_PROTOCOL_V2)
);
http.post("/messages", headers, params, requestBody, new HttpCore.ResponseHandler<PublishResponse[]>() {
@Override
Expand Down
4 changes: 2 additions & 2 deletions lib/src/main/java/io/ably/lib/types/Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,11 @@ Message readMsgpack(MessageUnpacker unpacker) throws IOException {
} else if (fieldName.equals(SERIAL)) {
serial = unpacker.unpackString();
} else if (fieldName.equals(VERSION)) {
version = MessageVersion.fromMsgpack(unpacker);
version = MessageVersion.read(unpacker);
} else if (fieldName.equals(ACTION)) {
Comment thread
ttypic marked this conversation as resolved.
action = MessageAction.tryFindByOrdinal(unpacker.unpackInt());
} else if (fieldName.equals(ANNOTATIONS)) {
annotations = MessageAnnotations.fromMsgpack(unpacker);
annotations = MessageAnnotations.read(unpacker);
}
else {
Log.v(TAG, "Unexpected field: " + fieldName);
Expand Down
30 changes: 13 additions & 17 deletions lib/src/main/java/io/ably/lib/types/MessageAnnotations.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ void writeMsgpack(MessagePacker packer) throws IOException {
}
}

MessageAnnotations readMsgpack(MessageUnpacker unpacker) throws IOException {
static MessageAnnotations read(MessageUnpacker unpacker) throws IOException {
MessageAnnotations annotations = new MessageAnnotations();

int fieldCount = unpacker.unpackMapHeader();
for (int i = 0; i < fieldCount; i++) {
String fieldName = unpacker.unpackString().intern();
Expand All @@ -68,37 +70,31 @@ MessageAnnotations readMsgpack(MessageUnpacker unpacker) throws IOException {
}

if (fieldName.equals(SUMMARY)) {
summary = Summary.read(unpacker);
annotations.summary = Summary.read(unpacker);
} else {
Log.v(TAG, "Unexpected field: " + fieldName);
unpacker.skipValue();
}
}

return this;
return annotations;
}

static MessageAnnotations fromMsgpack(MessageUnpacker unpacker) throws IOException {
return (new MessageAnnotations()).readMsgpack(unpacker);
}
static MessageAnnotations read(JsonElement json) throws MessageDecodeException {
if (!json.isJsonObject()) {
throw MessageDecodeException.fromDescription("Message annotations is of type \"" + json.getClass() + "\" when expected a JSON object.");
}

protected void read(final JsonObject map) throws MessageDecodeException {
final JsonElement summaryElement = map.get(SUMMARY);
MessageAnnotations annotations = new MessageAnnotations();

final JsonElement summaryElement = json.getAsJsonObject().get(SUMMARY);
if (summaryElement != null) {
if (!summaryElement.isJsonObject()) {
throw MessageDecodeException.fromDescription("MessageAnnotations summary is of type \"" + summaryElement.getClass() + "\" when expected a JSON object.");
}
summary = Summary.read(summaryElement.getAsJsonObject());
annotations.summary = Summary.read(summaryElement.getAsJsonObject());
}
}

static MessageAnnotations read(JsonElement json) throws MessageDecodeException {
if (!json.isJsonObject()) {
Log.w(TAG, "Message annotations is of type \"" + json.getClass() + "\" when expected a JSON object.");
}

MessageAnnotations annotations = new MessageAnnotations();
annotations.read(json.getAsJsonObject());
return annotations;
}

Expand Down
53 changes: 25 additions & 28 deletions lib/src/main/java/io/ably/lib/types/MessageVersion.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ void writeMsgpack(MessagePacker packer) throws IOException {
}
}

MessageVersion readMsgpack(MessageUnpacker unpacker) throws IOException {
static MessageVersion read(MessageUnpacker unpacker) throws IOException {
MessageVersion version = new MessageVersion();
int fieldCount = unpacker.unpackMapHeader();
for (int i = 0; i < fieldCount; i++) {
String fieldName = unpacker.unpackString().intern();
Expand All @@ -120,24 +121,24 @@ MessageVersion readMsgpack(MessageUnpacker unpacker) throws IOException {

switch (fieldName) {
case SERIAL:
serial = unpacker.unpackString();
version.serial = unpacker.unpackString();
break;
case TIMESTAMP:
timestamp = unpacker.unpackLong();
version.timestamp = unpacker.unpackLong();
break;
case CLIENT_ID:
clientId = unpacker.unpackString();
version.clientId = unpacker.unpackString();
break;
case DESCRIPTION:
description = unpacker.unpackString();
version.description = unpacker.unpackString();
break;
case METADATA:
int mapSize = unpacker.unpackMapHeader();
metadata = new HashMap<>(mapSize);
version.metadata = new HashMap<>(mapSize);
for (int j = 0; j < mapSize; j++) {
String key = unpacker.unpackString();
String value = unpacker.unpackString();
metadata.put(key, value);
version.metadata.put(key, value);
}
break;
default:
Expand All @@ -146,43 +147,39 @@ MessageVersion readMsgpack(MessageUnpacker unpacker) throws IOException {
break;
}
}
return this;
return version;
}

static MessageVersion fromMsgpack(MessageUnpacker unpacker) throws IOException {
return (new MessageVersion()).readMsgpack(unpacker);
}

protected void read(final JsonObject map) throws MessageDecodeException {
serial = readString(map, SERIAL);
timestamp = readLong(map, TIMESTAMP);;
clientId = readString(map, CLIENT_ID);;
description = readString(map, DESCRIPTION);;
if (map.has(METADATA)) {
JsonObject metadataObject = map.getAsJsonObject(METADATA);
metadata = new HashMap<>();
for (Map.Entry<String, JsonElement> entry : metadataObject.entrySet()) {
metadata.put(entry.getKey(), entry.getValue().getAsString());
}
}
}

static MessageVersion read(JsonElement json) throws MessageDecodeException {
if (!json.isJsonObject()) {
throw MessageDecodeException.fromDescription("Expected an object but got \"" + json.getClass() + "\".");
}

MessageVersion version = new MessageVersion();
version.read(json.getAsJsonObject());
JsonObject map = json.getAsJsonObject();

version.serial = readString(map, SERIAL);
version.timestamp = readLong(map, TIMESTAMP);;
version.clientId = readString(map, CLIENT_ID);;
version.description = readString(map, DESCRIPTION);;
if (map.has(METADATA)) {
JsonObject metadataObject = map.getAsJsonObject(METADATA);
version.metadata = new HashMap<>();
for (Map.Entry<String, JsonElement> entry : metadataObject.entrySet()) {
version.metadata.put(entry.getKey(), entry.getValue().getAsString());
}
}

return version;
}

private String readString(JsonObject map, String key) {
private static String readString(JsonObject map, String key) {
JsonElement element = map.get(key);
return (element != null && !element.isJsonNull()) ? element.getAsString() : null;
}

private long readLong(JsonObject map, String key) {
private static long readLong(JsonObject map, String key) {
JsonElement element = map.get(key);
return (element != null && !element.isJsonNull()) ? element.getAsLong() : 0;
}
Expand Down
Loading