Skip to content

Add MessageExtras support to PresenceMessage#1191

Open
AndyTWF wants to merge 4 commits intomainfrom
claude/add-extras-presence-message-3bEeo
Open

Add MessageExtras support to PresenceMessage#1191
AndyTWF wants to merge 4 commits intomainfrom
claude/add-extras-presence-message-3bEeo

Conversation

@AndyTWF
Copy link
Contributor

@AndyTWF AndyTWF commented Feb 12, 2026

Summary

This change adds full support for MessageExtras on presence messages:

  1. PresenceMessage.extras field (TP3i) — allows presence messages to carry arbitrary metadata and ancillary payloads, with serialization support in both MessagePack and JSON formats.
  2. Extras parameter on convenience methods — adds MessageExtras overloads to enter(), update(), leave() and their *Client variants so callers can pass extras without dropping down to updatePresence(PresenceMessage, CompletionListener).
  3. Kotlin wrappers — updates the RealtimePresence interface and RealtimePresenceAdapter with the extras parameter (defaulting to null).
  4. JSON null tolerancePresenceMessage.read() now handles "extras": null gracefully instead of throwing.

CHA-1243

Prerequisite to ably/ably-chat-kotlin#193

Closes #736
Closes #753

Key Changes

PresenceMessage.java

  • Added extras field of type MessageExtras (TP3i)
  • Added 4-arg constructor: PresenceMessage(Action, String, Object, MessageExtras); existing 3-arg constructor delegates to it with extras = null
  • Updated clone() to copy the extras field
  • Serialization support for extras in both MessagePack (writeMsgpack/readMsgpack) and JSON (read/Serializer) formats
  • JSON deserialization handles null extras gracefully and type-checks for valid JSON object

Presence.java

  • 6 new overloaded public methods with MessageExtras extras parameter:
    • enter(Object data, MessageExtras extras, CompletionListener listener) — RTP8
    • update(Object data, MessageExtras extras, CompletionListener listener) — RTP9
    • leave(Object data, MessageExtras extras, CompletionListener listener) — RTP10
    • enterClient(String clientId, Object data, MessageExtras extras, CompletionListener listener) — RTP15
    • updateClient(String clientId, Object data, MessageExtras extras, CompletionListener listener) — RTP15
    • leaveClient(String clientId, Object data, MessageExtras extras, CompletionListener listener) — RTP15
  • Existing methods delegate to the new overloads with null extras (fully backward-compatible, no ambiguity — different arity)

RealtimePresence.kt / RealtimePresenceAdapter.kt

  • Added extras: MessageExtras? = null parameter to all 6 presence methods in the Kotlin interface and adapter

RealtimePresenceTest.java

  • presence_enter_with_extras — existing test for extras via updatePresence() directly
  • presence_enter_with_extras_convenience — new: tests enter(data, extras, listener)
  • presence_update_with_extras — new: tests update(data, extras, listener)
  • presence_leave_with_extras — new: tests leave(data, extras, listener)
  • presence_enterClient_with_extras — new: tests enterClient(clientId, data, extras, listener)

Backward Compatibility

All changes are fully backward-compatible. No existing method signatures change. Java overload resolution is clean since the new methods differ in arity from the existing ones.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Presence operations now support attaching optional metadata ("extras") to enter, update, and leave actions, including for specific client IDs; presence messages carry and return extras and are serialized/deserialized accordingly.
  • Tests
    • Added tests verifying extras are sent, received, included in presence payloads, and exposed in completion callbacks.
  • Compatibility
    • Backward compatible: existing presence methods continue to work and delegate to the extras-enabled variants.

@coderabbitai
Copy link

coderabbitai bot commented Feb 12, 2026

Walkthrough

Adds support for MessageExtras across Presence APIs and PresenceMessage: new overloads for enter/update/leave (including clientId variants), PresenceMessage gains an extras field with serialization/deserialization, tests added, and Kotlin interface/adapter updated to accept and forward extras.

Changes

Cohort / File(s) Summary
Presence API (Java)
lib/src/main/java/io/ably/lib/realtime/Presence.java
Added public overloads accepting MessageExtras for enter, update, leave and clientId variants; existing overloads delegate to the new extras-enabled signatures; internals construct PresenceMessage with extras.
PresenceMessage model (Java)
lib/src/main/java/io/ably/lib/types/PresenceMessage.java
Added public MessageExtras extras field and EXTRAS key; new constructor PresenceMessage(Action,String,Object,MessageExtras); updated clone, msgpack read/write, JSON read/serialize, and added JSON deserializer to preserve extras.
Tests (Java)
lib/src/test/java/io/ably/lib/test/realtime/RealtimePresenceTest.java
Added tests verifying extras propagation for enter/update/leave and enterClient flows; duplicated test block present in diff.
Kotlin public API (pubsub-adapter)
pubsub-adapter/src/main/kotlin/com/ably/pubsub/RealtimePresence.kt
Interface method signatures updated to accept optional extras: MessageExtras? for enter, update, leave and clientId variants; documentation comments updated.
Kotlin adapter implementations
pubsub-adapter/src/main/kotlin/io/ably/lib/realtime/RealtimePresenceAdapter.kt
Adapter overrides updated to accept extras: MessageExtras? and forward it to the underlying Java presence methods.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Presence
    participant PresenceMessage
    participant Network

    Client->>Presence: enter(data, extras, listener)
    Presence->>PresenceMessage: new PresenceMessage(action, clientId, data, extras)
    PresenceMessage-->>Presence: constructed (includes extras)
    Presence->>Network: serialize PresenceMessage (JSON/msgpack includes extras)
    Network-->>Presence: deliver PresenceMessage payload
    Presence->>PresenceMessage: deserialize/read (extract extras)
    Presence-->>Client: emit PresenceMessage (with extras)
    Client->>Client: listener.onSuccess()
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I hop in with extras snug and bright,
Tucking small claims into presence light.
Enter, update, leave — I carry more cheer,
Messages richer, now extras appear,
A joyful thump — presence holds what’s dear.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: adding MessageExtras support to PresenceMessage. It is clear, concise, and directly related to the primary objective of the changeset.
Linked Issues check ✅ Passed The PR implements all requirements from linked issues: adds extras field to PresenceMessage (#736), adds extras parameter to all six presence methods (#753), and enables extras exposure for Chat SDK use cases (CHA-1243).
Out of Scope Changes check ✅ Passed All changes are scoped to presence extras support across PresenceMessage, Presence API, and related adapters. One minor issue noted: test duplication (5 tests appear duplicated in RealtimePresenceTest) which may be unintended, though not strictly out-of-scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/add-extras-presence-message-3bEeo

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot temporarily deployed to staging/pull/1191/features February 12, 2026 15:33 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1191/javadoc February 12, 2026 15:35 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1191/features February 12, 2026 15:37 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1191/javadoc February 12, 2026 15:39 Inactive
Add extras field to PresenceMessage type with support for both
msgpack and JSON serialization/deserialization. Includes end-to-end
test verifying extras round-trip through presence enter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@AndyTWF AndyTWF force-pushed the claude/add-extras-presence-message-3bEeo branch from dabc3d8 to 8e5acc4 Compare February 12, 2026 17:31
@github-actions github-actions bot temporarily deployed to staging/pull/1191/features February 12, 2026 17:31 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1191/javadoc February 12, 2026 17:34 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1191/features February 12, 2026 19:14 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1191/javadoc February 12, 2026 19:17 Inactive
@AndyTWF AndyTWF requested review from sacOO7 and ttypic February 12, 2026 23:15
@AndyTWF AndyTWF marked this pull request as ready for review February 12, 2026 23:15
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@lib/src/main/java/io/ably/lib/types/PresenceMessage.java`:
- Around line 293-309: The read method in PresenceMessage currently throws when
extras is the JSON literal null; update PresenceMessage.read to treat JsonNull
as absent by checking extrasElement.isJsonNull() (or instanceof JsonNull) and
skipping the extras parsing instead of erroring, so only non-null JsonObject
values are passed to MessageExtras.read; reference the EXTRAS lookup, the
extrasElement variable, and MessageExtras.read when making this change.

@github-actions github-actions bot temporarily deployed to staging/pull/1191/features February 12, 2026 23:20 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1191/javadoc February 12, 2026 23:22 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1191/features February 12, 2026 23:25 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1191/javadoc February 12, 2026 23:28 Inactive
AndyTWF and others added 3 commits February 17, 2026 09:43
Add MessageExtras overloads to enter(), update(), leave() and their
*Client variants so callers can pass extras without dropping down to
updatePresence(PresenceMessage, CompletionListener). Existing methods
delegate to the new overloads with null extras (fully backward-compatible).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update RealtimePresence interface and RealtimePresenceAdapter to accept
MessageExtras on enter, update, leave and their *Client variants,
matching the new Java overloads. The extras parameter defaults to null
so existing callers are unaffected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Treat `"extras": null` as absent rather than throwing a
MessageDecodeException. This avoids a hard failure when incoming JSON
explicitly sets extras to null.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/src/main/java/io/ably/lib/realtime/Presence.java (1)

675-688: ⚠️ Potential issue | 🟠 Major

Preserve extras when re-entering internal members after reconnect.
enterInternalMembers() replays presence via enterClientWithId, which currently drops extras. This breaks RTP17g and loses per-message metadata on reconnect.

🔧 Proposed fix
-    private void enterClientWithId(String id, String clientId, Object data, CompletionListener listener) throws AblyException {
+    private void enterClientWithId(String id, String clientId, Object data, MessageExtras extras, CompletionListener listener) throws AblyException {
         if(clientId == null) {
             String errorMessage = String.format(Locale.ROOT, "Channel %s: unable to enter presence channel (null clientId specified)", channel.name);
             Log.v(TAG, errorMessage);
             if(listener != null) {
                 listener.onError(new ErrorInfo(errorMessage, 40000));
                 return;
             }
         }
-        PresenceMessage presenceMsg = new PresenceMessage(PresenceMessage.Action.enter, clientId, data);
+        PresenceMessage presenceMsg = new PresenceMessage(PresenceMessage.Action.enter, clientId, data, extras);
         presenceMsg.id = id;
         Log.v(TAG, "enterClient(); channel = " + channel.name + "; clientId = " + clientId);
         updatePresence(presenceMsg, listener);
     }
-                enterClientWithId(item.id, item.clientId, item.data, new CompletionListener() {
+                enterClientWithId(item.id, item.clientId, item.data, item.extras, new CompletionListener() {

Also applies to: 1049-1064

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/src/main/java/io/ably/lib/realtime/Presence.java` around lines 675 - 688,
enterClientWithId currently drops per-message metadata (extras) when rebuilding
PresenceMessage, breaking RTP17g; modify the replay path so the original
PresenceMessage.extras are preserved: update enterClientWithId and its callers
(notably enterInternalMembers and the other replay location around the 1049-1064
area) to accept or obtain the original PresenceMessage.extras and set
presenceMsg.extras = originalExtras before calling updatePresence; reference
Presence.enterClientWithId, Presence.enterInternalMembers, and the
PresenceMessage.extras field so all replayed messages carry the same extras as
the original.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@lib/src/main/java/io/ably/lib/realtime/Presence.java`:
- Around line 675-688: enterClientWithId currently drops per-message metadata
(extras) when rebuilding PresenceMessage, breaking RTP17g; modify the replay
path so the original PresenceMessage.extras are preserved: update
enterClientWithId and its callers (notably enterInternalMembers and the other
replay location around the 1049-1064 area) to accept or obtain the original
PresenceMessage.extras and set presenceMsg.extras = originalExtras before
calling updatePresence; reference Presence.enterClientWithId,
Presence.enterInternalMembers, and the PresenceMessage.extras field so all
replayed messages carry the same extras as the original.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Spec alignement for presence message extras Missing extras property at PresenceMessage object

1 participant

Comments