Skip to content

[ECO-5458][LiveObjects] Implement object subscriptions#1139

Merged
sacOO7 merged 10 commits intomainfrom
feature/object-subscriptions-refactored
Aug 8, 2025
Merged

[ECO-5458][LiveObjects] Implement object subscriptions#1139
sacOO7 merged 10 commits intomainfrom
feature/object-subscriptions-refactored

Conversation

@sacOO7
Copy link
Collaborator

@sacOO7 sacOO7 commented Aug 6, 2025

Fixed #1123

Summary by CodeRabbit

  • New Features

    • Introduced real-time subscription and notification capabilities for LiveMap and LiveCounter objects, allowing clients to receive updates when map entries or counter values change.
    • Added structured update types for LiveMap and LiveCounter changes, providing clearer and more consistent update information.
  • Bug Fixes

    • Improved type specificity in update handling to prevent ambiguity and enhance reliability.
  • Tests

    • Added and updated integration and unit tests to verify subscription, notification, and update propagation for LiveMap and LiveCounter objects.
  • Refactor

    • Refactored internal update handling to use dedicated update types instead of generic maps or strings.
    • Enhanced helper and fixture functions for test data creation and improved code organization.

sacOO7 added 10 commits July 21, 2025 14:30
- Introduced LiveObjectUpdate interface as foundation for subscription system
- Provides common contract for all live object change notifications
- Added LiveCounterChange interface for counter change notifications
- Created LiveCounterUpdate interface extending LiveObjectUpdate
- Defined comprehensive change event structure for counter subscriptions
- Added LiveMapChange interface for map change notifications
- Created LiveMapUpdate interface extending LiveObjectUpdate
- Defined comprehensive change event structure for map subscriptions
- Moved LiveCounter.java to type/counter package for better organization
- Moved LiveMap.java to type/map package for better organization
- Updated import references in LiveObjects and ObjectsSubscription
- Added LiveCounterChangeCoordinator for counter subscription events
- Added LiveMapChangeCoordinator for map subscription events
- Provides centralized coordination for change notifications and listeners
- Updated BaseLiveObject with subscription coordination capabilities
- Modified DefaultLiveCounter to integrate with LiveCounterChangeCoordinator
- Enhanced LiveCounterManager to return LiveCounterUpdate objects
- Modified DefaultLiveMap to integrate with LiveMapChangeCoordinator
- Enhanced LiveMapManager to return LiveMapUpdate objects
- Implemented comprehensive map change notification system
- Modified DefaultLiveObjects to support subscription integration
- Enhanced Helpers with subscription-related utilities
- Updated ObjectsManager and ObjectsPool for subscription context
- Enhanced DefaultLiveCounterTest with subscription test scenarios
- Updated DefaultLiveMapTest with subscription functionality tests
- Added subscription tests to DefaultLiveObjectsTest and helper utilities
…port

- Updated CounterFixtures and MapFixtures with subscription test data
- Enhanced IntegrationTest setup for subscription scenarios
- Added comprehensive unit tests for LiveCounterManager and LiveMapManager
@coderabbitai
Copy link

coderabbitai bot commented Aug 6, 2025

Walkthrough

This change introduces a comprehensive subscription mechanism for live object data updates, specifically for LiveMap and LiveCounter types. It formalizes update handling using dedicated update classes, adds subscription and notification APIs, and refactors both implementation and test code to use these new abstractions. Extensive new tests verify the subscription flows.

Changes

Cohort / File(s) Change Summary
API & Interface Refactors
lib/src/main/java/io/ably/lib/objects/LiveObjects.java, lib/src/main/java/io/ably/lib/objects/ObjectsSubscription.java, lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.java, lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java
Added imports and updated package structure; extended LiveCounter and LiveMap to support new subscription interfaces; updated documentation with spec references.
Core Update & Subscription Types
lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java, lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterChange.java, lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java, lib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.java, lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java
Introduced new update and change interfaces/classes for LiveObject, LiveCounter, and LiveMap, with structured update representations and subscription mechanisms.
Kotlin Implementation: Base & Core
live-objects/src/main/kotlin/io/ably/lib/objects/BaseLiveObject.kt, live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt, live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsPool.kt, live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt, live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
Refactored to use new update types, replaced generic maps with structured updates, added or updated notify/subscribe/unsubscribe methods, added inline spec comments, and updated imports.
LiveCounter Implementation
live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt, live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterChangeCoordinator.kt, live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt
Added subscription management and notification logic; refactored update handling to use LiveCounterUpdate; introduced coordinator and emitter for event dispatching.
LiveMap Implementation
live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt, live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapChangeCoordinator.kt, live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt
Added subscription management and notification logic; refactored update handling to use LiveMapUpdate; introduced coordinator and emitter for event dispatching; improved diff calculation and update merging.
Integration & Unit Tests for LiveCounter
live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt, live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt
Added/updated tests to verify subscription, update notification, and correct update structure for LiveCounter; adjusted assertions for new types.
Integration & Unit Tests for LiveMap
live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt, live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt
Added/updated tests to verify subscription, update notification, and correct update structure for LiveMap; adjusted assertions for new types and enums.
Test Utilities & Fixtures
live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt, live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.kt, live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt, live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/CounterFixtures.kt, live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/MapFixtures.kt, live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt
Updated imports, refactored helper functions, improved fixture modularity, and increased test timeouts for reliability.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant LiveMap/LiveCounter
    participant ChangeCoordinator
    participant Listener

    Client->>LiveMap/LiveCounter: subscribe(listener)
    LiveMap/LiveCounter->>ChangeCoordinator: subscribe(listener)
    ChangeCoordinator->>Listener: (register)

    Note over LiveMap/LiveCounter: Data changes (e.g., set, inc)
    LiveMap/LiveCounter->>ChangeCoordinator: notify(update)
    ChangeCoordinator->>Listener: onUpdated(update)
    Listener-->>Client: (callback invoked)

    Client->>LiveMap/LiveCounter: unsubscribe(listener)
    LiveMap/LiveCounter->>ChangeCoordinator: unsubscribe(listener)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Assessment against linked issues

Objective Addressed Explanation
Implement BaseLiveObject#data-subscriptions for LiveObject, LiveMap, and LiveCounter (#1123, ECO-5458)
Provide structured update types and subscription APIs for live object changes (#1123, ECO-5458)
Ensure correct notification and update propagation via subscription mechanism (#1123, ECO-5458)
Add comprehensive tests for subscription and update flows (#1123, ECO-5458)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes detected.

Possibly related PRs

  • Setup : LiveObject plugin #1085: Introduces the LiveObjects interface and plugin integration, which is closely related to the subscription and update mechanisms established in this PR.

Suggested reviewers

  • ttypic

Poem

In fields of code where objects thrive,
Subscriptions bloom, updates arrive.
Maps and counters now can sing,
Notifying listeners of everything.
With tests that hop and fixtures neat,
This rabbit’s work is quite complete!
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/object-subscriptions-refactored

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sacOO7 sacOO7 changed the title Feature/object subscriptions refactored [ECO-5458][LiveObjects] Implement object subscriptions Aug 6, 2025
@sacOO7 sacOO7 marked this pull request as ready for review August 7, 2025 02:58
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: 2

🧹 Nitpick comments (3)
live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt (1)

25-25: Timeout increased to 15 s – double-check necessity
If the new subscription workflow occasionally needs >10 s this is fine, but we should make sure the increase masks no latent performance regression in the objects sync path. Consider profiling the longest-running integration to confirm.

live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterChangeCoordinator.kt (1)

23-51: LGTM! Solid implementation with consistent patterns.

The coordinator and emitter classes follow the same robust patterns as the map implementation with proper error handling and resource management.

Consider introducing a generic base coordinator class to reduce code duplication between LiveCounterChangeCoordinator and LiveMapChangeCoordinator, though the current type-safe approach is also valid:

internal abstract class LiveObjectChangeCoordinator<TUpdate, TListener> {
  // Common coordination logic
}
live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt (1)

58-63: Consider using a when expression for better readability.

The if-else pattern can be replaced with a more idiomatic Kotlin when expression.

-      if (objectType == ObjectType.Map) {
-        return noOpMapUpdate
-      }
-      return noOpCounterUpdate
+      return when (objectType) {
+        ObjectType.Map -> noOpMapUpdate
+        ObjectType.Counter -> noOpCounterUpdate
+      }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b1c9e47 and 4f1fc2d.

📒 Files selected for processing (30)
  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/ObjectsSubscription.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.java (2 hunks)
  • lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterChange.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java (2 hunks)
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (2 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt (3 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsPool.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt (7 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt (2 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterChangeCoordinator.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt (6 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt (2 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapChangeCoordinator.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt (14 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt (2 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt (2 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt (1 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.kt (2 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt (1 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/CounterFixtures.kt (2 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/MapFixtures.kt (2 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt (1 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt (2 hunks)
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt (16 hunks)
🧰 Additional context used
🧠 Learnings (19)
📓 Common learnings
Learnt from: sacOO7
PR: ably/ably-java#1106
File: live-objects/src/main/kotlin/io/ably/lib/objects/serialization/Serialization.kt:25-29
Timestamp: 2025-06-23T14:18:25.315Z
Learning: In the ably-java codebase, the DefaultLiveObjectSerializer class methods like writeMsgpackArray will have their type signatures updated to be non-nullable since the calling sites ensure objects are never null when passed to these methods.
Learnt from: sacOO7
PR: ably/ably-java#1087
File: lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java:32-34
Timestamp: 2025-05-27T12:11:25.084Z
Learning: In LiveObjects implementation (lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java), the send method intentionally hardcodes queueEvents to true rather than respecting ably.options.queueMessages. This is because LiveObjects requires reliable message delivery to ensure proper state synchronization and acknowledgment, unlike other realtime components that may allow configurable queuing behavior.
Learnt from: sacOO7
PR: ably/ably-java#1130
File: live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt:241-241
Timestamp: 2025-08-01T10:30:27.049Z
Learning: In DefaultLiveMapTest.kt integration tests, operations are performed sequentially one after another, and subscription callback list updates happen one at a time, so thread-safe collections are not needed for collecting updates in test scenarios.
Learnt from: sacOO7
PR: ably/ably-java#1085
File: lib/src/main/java/io/ably/lib/objects/LiveObjects.java:0-0
Timestamp: 2025-05-20T13:12:19.013Z
Learning: The LiveObjects interface does not currently include public API methods for resource management (dispose) or change listeners, as these features are not yet implemented.
Learnt from: sacOO7
PR: ably/ably-java#1113
File: live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt:16-16
Timestamp: 2025-08-01T05:50:33.039Z
Learning: In LiveMapManagerTest.kt, the private field `livemapManager` is used extensively in the `shouldCalculateMapDifferenceCorrectly` test method to test the `calculateUpdateFromDataDiff` functionality across multiple test scenarios, so it should not be removed as unused.
Learnt from: sacOO7
PR: ably/ably-java#1092
File: live-objects/src/test/kotlin/io/ably/lib/objects/TestUtils.kt:48-61
Timestamp: 2025-06-03T09:15:18.827Z
Learning: User sacOO7 prefers simple test utilities without extensive error handling, believing tests should fail fast if incorrect field/method names are used rather than having defensive programming.
📚 Learning: in the ably-java codebase, the defaultliveobjectserializer class methods like writemsgpackarray will...
Learnt from: sacOO7
PR: ably/ably-java#1106
File: live-objects/src/main/kotlin/io/ably/lib/objects/serialization/Serialization.kt:25-29
Timestamp: 2025-06-23T14:18:25.315Z
Learning: In the ably-java codebase, the DefaultLiveObjectSerializer class methods like writeMsgpackArray will have their type signatures updated to be non-nullable since the calling sites ensure objects are never null when passed to these methods.

Applied to files:

  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • lib/src/main/java/io/ably/lib/objects/ObjectsSubscription.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt
  • lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt
  • lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
  • lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java
📚 Learning: in the ably-java liveobjects test code, extension properties with capital letter names (like `state`...
Learnt from: sacOO7
PR: ably/ably-java#1120
File: live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt:0-0
Timestamp: 2025-08-01T09:53:16.730Z
Learning: In the ably-java LiveObjects test code, extension properties with capital letter names (like `State`, `ObjectId`) are defined in live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt to provide access to internal fields of concrete implementations through their public interfaces. For example, `LiveObjects.State` casts to `DefaultLiveObjects` to access the internal `state` field for testing purposes.

Applied to files:

  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt
  • lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/MapFixtures.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterChangeCoordinator.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt
  • lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
  • lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapChangeCoordinator.kt
📚 Learning: in test utility code for the ably java live objects module, the team prefers to keep reflection-base...
Learnt from: sacOO7
PR: ably/ably-java#1092
File: live-objects/src/test/kotlin/io/ably/lib/objects/TestUtils.kt:21-32
Timestamp: 2025-06-03T09:15:15.338Z
Learning: In test utility code for the Ably Java Live Objects module, the team prefers to keep reflection-based field access utilities simple without additional error handling, allowing tests to fail fast if incorrect field names are used.

Applied to files:

  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
  • lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java
📚 Learning: in the ably-java liveobjects test code, an extension property `state` (capital s) is defined on the ...
Learnt from: sacOO7
PR: ably/ably-java#1120
File: live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt:0-0
Timestamp: 2025-08-01T09:53:16.730Z
Learning: In the ably-java LiveObjects test code, an extension property `State` (capital S) is defined on the `LiveObjects` interface in live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt to provide access to the internal `state` field by casting to `DefaultLiveObjects`. This allows tests to access internal state for verification purposes.

Applied to files:

  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt
  • lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt
  • lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
  • lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapChangeCoordinator.kt
📚 Learning: the liveobjects interface does not currently include public api methods for resource management (dis...
Learnt from: sacOO7
PR: ably/ably-java#1085
File: lib/src/main/java/io/ably/lib/objects/LiveObjects.java:0-0
Timestamp: 2025-05-20T13:12:19.013Z
Learning: The LiveObjects interface does not currently include public API methods for resource management (dispose) or change listeners, as these features are not yet implemented.

Applied to files:

  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • lib/src/main/java/io/ably/lib/objects/ObjectsSubscription.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterChangeCoordinator.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt
  • lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterChange.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt
  • lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapChangeCoordinator.kt
📚 Learning: in kotlin/java codebases, when referencing types (classes, enums, interfaces) that are defined in th...
Learnt from: sacOO7
PR: ably/ably-java#1087
File: live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt:198-198
Timestamp: 2025-05-27T12:12:10.782Z
Learning: In Kotlin/Java codebases, when referencing types (classes, enums, interfaces) that are defined in the same package, no import statement is required as they are automatically accessible due to package-private visibility.

Applied to files:

  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
📚 Learning: in defaultlivemaptest.kt integration tests, operations are performed sequentially one after another,...
Learnt from: sacOO7
PR: ably/ably-java#1130
File: live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt:241-241
Timestamp: 2025-08-01T10:30:27.049Z
Learning: In DefaultLiveMapTest.kt integration tests, operations are performed sequentially one after another, and subscription callback list updates happen one at a time, so thread-safe collections are not needed for collecting updates in test scenarios.

Applied to files:

  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/CounterFixtures.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/MapFixtures.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterChangeCoordinator.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapChangeCoordinator.kt
📚 Learning: in liveobjects implementation (lib/src/main/java/io/ably/lib/objects/liveobjectsadapter.java), the s...
Learnt from: sacOO7
PR: ably/ably-java#1087
File: lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java:32-34
Timestamp: 2025-05-27T12:11:25.084Z
Learning: In LiveObjects implementation (lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java), the send method intentionally hardcodes queueEvents to true rather than respecting ably.options.queueMessages. This is because LiveObjects requires reliable message delivery to ensure proper state synchronization and acknowledgment, unlike other realtime components that may allow configurable queuing behavior.

Applied to files:

  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt
  • lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterChange.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt
  • lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java
📚 Learning: in defaultliveobjects.kt, the object creation pattern using objectspool.get() followed by withcontex...
Learnt from: sacOO7
PR: ably/ably-java#1135
File: live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt:100-134
Timestamp: 2025-08-06T09:22:40.964Z
Learning: In DefaultLiveObjects.kt, the object creation pattern using objectsPool.get() followed by withContext(sequentialScope.coroutineContext) { objectsPool.createZeroValueObjectIfNotExists() } is thread-safe because sequentialScope uses limitedParallelism(1) ensuring sequential execution, and createZeroValueObjectIfNotExists() performs an internal get() check before creating, preventing duplicate object creation even when multiple coroutines initially see null from the first get() call.

Applied to files:

  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsPool.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt
📚 Learning: in the ably-java codebase, the defaultliveobjectserializer class uses intentional unsafe casting (`o...
Learnt from: sacOO7
PR: ably/ably-java#1106
File: live-objects/src/main/kotlin/io/ably/lib/objects/serialization/Serialization.kt:38-46
Timestamp: 2025-06-23T14:14:17.847Z
Learning: In the ably-java codebase, the DefaultLiveObjectSerializer class uses intentional unsafe casting (`objects as Array<ObjectMessage>`) without type validation in both writeMsgpackArray and asJsonArray methods. This is a deliberate design decision to keep the dynamically-loaded class simple and let ClassCastException occur naturally for type mismatches.

Applied to files:

  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt
  • lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java
📚 Learning: in livemapmanagertest.kt, the private field `livemapmanager` is used extensively in the `shouldcalcu...
Learnt from: sacOO7
PR: ably/ably-java#1113
File: live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt:16-16
Timestamp: 2025-08-01T05:50:33.039Z
Learning: In LiveMapManagerTest.kt, the private field `livemapManager` is used extensively in the `shouldCalculateMapDifferenceCorrectly` test method to test the `calculateUpdateFromDataDiff` functionality across multiple test scenarios, so it should not be removed as unused.

Applied to files:

  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/CounterFixtures.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/MapFixtures.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
  • lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapChangeCoordinator.kt
📚 Learning: the sandbox.kt file in ably-java live-objects module already has comprehensive http retry mechanism ...
Learnt from: sacOO7
PR: ably/ably-java#1095
File: live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt:87-89
Timestamp: 2025-06-06T09:28:12.298Z
Learning: The Sandbox.kt file in ably-java live-objects module already has comprehensive HTTP retry mechanism using HttpRequestRetry with 5 retries, exponential backoff, and automatic retry on non-success responses and timeout exceptions.

Applied to files:

  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.kt
📚 Learning: in livemapmanagertest.kt, the private field `livemapmanager` is used in the `shouldcalculatemapdiffe...
Learnt from: sacOO7
PR: ably/ably-java#1113
File: live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt:16-16
Timestamp: 2025-08-01T05:50:33.039Z
Learning: In LiveMapManagerTest.kt, the private field `livemapManager` is used in the `shouldCalculateMapDifferenceCorrectly` test method to test the `calculateUpdateFromDataDiff` functionality, so it should not be removed as unused.

Applied to files:

  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/CounterFixtures.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/MapFixtures.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt
  • lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
  • lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapChangeCoordinator.kt
📚 Learning: in kotlin, functions, classes, and other declarations within the same package are automatically acce...
Learnt from: sacOO7
PR: ably/ably-java#1095
File: live-objects/src/test/kotlin/io/ably/lib/objects/unit/LiveObjectTest.kt:1-6
Timestamp: 2025-06-05T10:24:28.789Z
Learning: In Kotlin, functions, classes, and other declarations within the same package are automatically accessible without explicit import statements. Do not suggest adding imports for functions/classes that are already in the same package.

Applied to files:

  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
📚 Learning: in the ably-java codebase test files, junit's assert.assertequals method is used which has the signa...
Learnt from: sacOO7
PR: ably/ably-java#1113
File: live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt:640-640
Timestamp: 2025-08-01T05:54:07.024Z
Learning: In the ably-java codebase test files, JUnit's Assert.assertEquals method is used which has the signature assertEquals(String message, Object expected, Object actual) where the message parameter comes first, not last like in Kotlin test's assertEquals method.

Applied to files:

  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
📚 Learning: in the ably java liveobjects messagepack deserialization code, the `action` field in objectoperation...
Learnt from: sacOO7
PR: ably/ably-java#1106
File: live-objects/src/main/kotlin/io/ably/lib/objects/serialization/MsgpackSerialization.kt:207-211
Timestamp: 2025-06-23T14:28:23.301Z
Learning: In the Ably Java LiveObjects MessagePack deserialization code, the `action` field in ObjectOperation is guaranteed to always be present in the protocol, so using a default value during deserialization is acceptable and won't mask real protocol errors.

Applied to files:

  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt
  • lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java
📚 Learning: in kotlin dsl, the `beforetest` method requires a groovy closure and cannot be replaced with a lambd...
Learnt from: ttypic
PR: ably/ably-java#1034
File: java/build.gradle.kts:55-55
Timestamp: 2024-09-25T09:08:30.472Z
Learning: In Kotlin DSL, the `beforeTest` method requires a Groovy closure and cannot be replaced with a lambda expression.

Applied to files:

  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt
  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
📚 Learning: user sacoo7 prefers simple test utilities without extensive error handling, believing tests should f...
Learnt from: sacOO7
PR: ably/ably-java#1092
File: live-objects/src/test/kotlin/io/ably/lib/objects/TestUtils.kt:48-61
Timestamp: 2025-06-03T09:15:18.827Z
Learning: User sacOO7 prefers simple test utilities without extensive error handling, believing tests should fail fast if incorrect field/method names are used rather than having defensive programming.

Applied to files:

  • live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt
🧬 Code Graph Analysis (8)
live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/CounterFixtures.kt (1)
live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.kt (2)
  • createMap (22-26)
  • createCounter (57-61)
live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/MapFixtures.kt (1)
live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.kt (2)
  • setMapRef (40-43)
  • createMap (22-26)
live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterChangeCoordinator.kt (1)
lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java (1)
  • LiveCounterUpdate (13-80)
live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt (1)
lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java (1)
  • LiveCounterUpdate (13-80)
lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterChange.java (1)
live-objects/src/main/kotlin/io/ably/lib/objects/ObjectId.kt (1)
  • type (5-62)
live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt (1)
lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java (1)
  • LiveMapUpdate (14-66)
live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt (1)
lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java (1)
  • LiveCounterUpdate (13-80)
live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapChangeCoordinator.kt (1)
lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java (1)
  • LiveMapUpdate (14-66)
🔇 Additional comments (57)
live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsPool.kt (1)

79-79: Spec-link comment is clear and helpful

The added RTO4b2a reference neatly ties the call to the spec without altering behaviour. No concerns.

lib/src/main/java/io/ably/lib/objects/LiveObjects.java (1)

4-5: Imports correctly updated to new package locations
LiveCounter and LiveMap are now referenced from their new type.counter / type.map sub-packages, keeping this interface compilable after the refactor. No further action required.

live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt (1)

12-13: Test imports aligned with refactor
The test now pulls LiveCounter / LiveMap from the relocated packages, maintaining compile-time correctness. ✅

live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt (1)

44-44: Spec reference added – good traceability
Linking the helper to RTLO4b1/4b2 clarifies why the pre-flight checks exist. No code impact.

live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt (1)

4-5: Helper imports updated and consistent
Keeps the extension utilities compiling after package move. Nothing else to address.

lib/src/main/java/io/ably/lib/objects/ObjectsSubscription.java (1)

14-14: LGTM! Documentation enhancement with specification references.

The addition of specification tags (RTLO4b5 and RTLO4b5a) improves traceability between the implementation and the LiveObjects specification requirements.

Also applies to: 21-21

live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (2)

5-6: LGTM! Import updates reflect the new package structure.

The imports correctly reference LiveCounter and LiveMap from their new package locations, supporting the subscription functionality implementation.


130-130: LGTM! Minor formatting improvement.

The return statement formatting is improved for better code style consistency.

lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java (3)

1-1: LGTM! Package reorganization improves code structure.

Moving LiveMap to the io.ably.lib.objects.type.map package provides better organization by grouping map-related types together.


3-3: LGTM! Import supports existing async API methods.

The ObjectsCallback import is correctly added to support the existing asynchronous method signatures in the interface.


17-17: LGTM! Interface extension adds subscription capabilities.

Extending LiveMapChange adds subscription functionality to LiveMap while maintaining backward compatibility with all existing methods.

lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.java (3)

1-1: LGTM! Package reorganization improves code structure.

Moving LiveCounter to the io.ably.lib.objects.type.counter package provides better organization by grouping counter-related types together.


3-3: LGTM! Import supports existing async API methods.

The ObjectsCallback import is correctly added to support the existing asynchronous method signatures in the interface.


14-14: LGTM! Interface extension adds subscription capabilities.

Extending LiveCounterChange adds subscription functionality to LiveCounter while maintaining backward compatibility with all existing methods.

live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt (3)

4-4: LGTM! Import supports the new typed update system.

The LiveObjectUpdate import enables the transition from generic Any types to strongly typed update objects.


129-130: LGTM! Type safety improvement with better documentation.

The type change from MutableList<Pair<BaseLiveObject, Any>> to MutableList<Pair<BaseLiveObject, LiveObjectUpdate>> provides better type safety and compile-time guarantees. The clarifying comment improves code readability.


153-156: LGTM! Proper integration of typed subscription callbacks.

The subscription callback mechanism is correctly implemented using the strongly typed LiveObjectUpdate objects, ensuring type safety throughout the update notification pipeline.

live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.kt (1)

8-8: LGTM! Good refactoring to improve consistency.

The replacement of manual ObjectData construction with the DataFixtures.mapRef() helper function improves code consistency and maintainability. This aligns well with the broader effort to centralize test fixture creation throughout the codebase.

Also applies to: 41-41

live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt (1)

31-31: LGTM! Improved type safety with structured updates.

The changes from update["amount"] to update.update.amount correctly reflect the refactoring from generic map-based updates to typed LiveCounterUpdate objects. This improves type safety and eliminates the potential for runtime errors from incorrect string keys.

Also applies to: 61-61

lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java (1)

1-27: LGTM! Well-designed abstract base class.

This abstract base class provides a clean foundation for typed update notifications across different live object types. Key strengths:

  • Proper encapsulation with protected field visibility for subclass access
  • Nullable update field handles no-op updates gracefully
  • Clear documentation with spec references (RTLO4b4, RTLO4b4a)
  • Follows good OOP inheritance principles

The design enables type-safe update handling while maintaining flexibility for different live object implementations.

live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt (3)

6-6: LGTM! Import added for structured updates.

The import of LiveMapUpdate enables the use of typed update structures throughout the test file.


59-62: LGTM! Excellent type safety improvement.

Replacing magic strings ("updated", "removed") with strongly-typed enum values (LiveMapUpdate.Change.UPDATED, LiveMapUpdate.Change.REMOVED) provides several benefits:

  • Eliminates potential runtime errors from typos in string literals
  • Makes the code self-documenting and more readable
  • Enables compile-time validation of update types
  • Aligns with the broader refactoring to structured update types

The consistent pattern of accessing updates through .update property reflects the new typed update structure.

Also applies to: 93-94, 122-123, 181-184


641-641: LGTM! Comprehensive update to typed enums.

The systematic replacement of string-based change indicators with LiveMapUpdate.Change enum values throughout the comprehensive test suite demonstrates excellent consistency. This improves maintainability and type safety across all test scenarios covering map difference calculations.

Also applies to: 653-653, 665-665, 683-683, 701-701, 719-719, 737-737, 749-749, 782-782, 800-800, 818-818

live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/MapFixtures.kt (2)

137-139: LGTM! Good separation of concerns.

The refactoring to extract user profile map creation into a separate function and set map references afterward improves modularity and follows the single responsibility principle. This makes the code more maintainable and allows the user profile creation logic to be reused independently.


151-184: LGTM! Well-designed helper function.

The new createUserProfileMapObject function demonstrates excellent design:

  • Clear separation of basic user data creation from reference setup
  • Comprehensive documentation describing structure and purpose
  • Consistent data types covering common user profile scenarios
  • Focused responsibility making it easily testable and reusable

The function creates a solid foundation for testing map operations on user profile data while maintaining clean abstraction boundaries.

live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/CounterFixtures.kt (2)

45-45: LGTM! Good refactoring for reusability.

Extracting the engagement metrics map creation into a dedicated helper function improves modularity and allows the nested map fixture to be used independently in other tests.


59-88: Excellent documentation and clear structure.

The new helper function is well-documented with detailed KDoc comments including the object tree structure, making it easy to understand what fixtures are being created for testing purposes.

live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt (2)

3-4: Package relocation handled correctly.

The imports correctly reference the relocated LiveCounter and LiveMap interfaces from their new type-specific packages.


209-276: Comprehensive subscription test implementation.

This test thoroughly validates the new subscription mechanism:

  • Tests subscription lifecycle (subscribe → receive updates → unsubscribe)
  • Verifies update amounts are correctly propagated through LiveCounterUpdate.amount
  • Confirms no updates are received after unsubscribing
  • Uses appropriate non-thread-safe collections for sequential test execution

The test structure aligns well with the existing test patterns and provides good coverage of the new subscription functionality.

live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt (2)

7-11: Import updates reflect package restructuring.

The imports correctly reference the new type-specific packages and include the necessary LiveMapUpdate class for the subscription test.


219-307: Thorough LiveMap subscription test coverage.

This integration test provides excellent validation of the LiveMap subscription mechanism:

  • Tests different update types: field updates (UPDATED) and removals (REMOVED)
  • Verifies the LiveMapUpdate.Change enum values are correctly set
  • Confirms subscription lifecycle works as expected
  • Uses sequential operations with appropriate collection types based on retrieved learnings

The test structure is consistent with the LiveCounter subscription test and provides comprehensive coverage of the map-specific subscription features.

lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java (1)

1-66: Well-designed update class with comprehensive functionality.

This LiveMapUpdate class provides excellent type safety and structure for LiveMap change notifications:

Strengths:

  • Extends LiveObjectUpdate base class appropriately
  • Clear separation between no-op updates and actual changes
  • Type-safe Change enum with UPDATED/REMOVED values
  • Comprehensive JavaDoc with specification references (RTLM18, RTLM18a, RTLM18b)
  • Proper null handling and defensive programming
  • Useful toString() implementation for debugging

Design consistency:

  • Follows established patterns for update classes in the codebase
  • Uses @NotNull annotations appropriately for type safety
  • Constructor overloading provides flexibility for different use cases

The implementation is clean, well-documented, and provides the structured update information needed for the subscription system.

lib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.java (1)

1-56: Excellent subscription interface design with proper abstractions.

This LiveMapChange interface provides a clean and well-designed API for LiveMap subscriptions:

API Design Strengths:

  • Multiple independent listener support via subscribe() returning ObjectsSubscription
  • Proper resource management with individual and bulk unsubscribe methods
  • Clear separation of concerns with nested Listener interface
  • Non-blocking operations marked with @NonBlocking annotation

Documentation Quality:

  • Comprehensive JavaDoc with specification references (RTLO4b, RTLO4c, RTLO4d, RTLO4b3)
  • Clear threading guidance for listener callbacks
  • Explicit mention of last-write-wins conflict resolution
  • Performance expectations documented (quick execution requirement)

Technical Implementation:

  • Uses LiveMapUpdate for type-safe change notifications
  • Proper null safety with @NotNull annotations
  • Interface design supports multiple concurrent subscribers

This interface establishes a solid foundation for the LiveMap subscription system and aligns well with reactive programming patterns.

lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterChange.java (1)

12-56: LGTM! Well-designed subscription interface.

The LiveCounterChange interface provides a clean and consistent API for managing LiveCounter update subscriptions. The design follows established patterns with proper documentation, spec references, and appropriate annotations.

live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapChangeCoordinator.kt (4)

9-9: LGTM! Good use of constant for no-op updates.

The noOpMapUpdate constant provides a clean way to represent no-change scenarios, improving consistency across the codebase.


11-21: LGTM! Clean interface design.

The HandlesLiveMapChange interface provides a clear contract for map change notification with good documentation.


23-38: LGTM! Solid coordinator implementation.

The LiveMapChangeCoordinator provides a clean abstraction for managing LiveMap subscriptions using the established EventEmitter pattern. The ObjectsSubscription return type enables proper resource management.


40-51: LGTM! Robust error handling in emitter.

The LiveMapChangeEmitter includes appropriate error handling with logging for both null events and listener exceptions, ensuring system stability.

live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterChangeCoordinator.kt (2)

9-9: LGTM! Consistent no-op pattern.

The noOpCounterUpdate constant maintains consistency with the map implementation for representing no-change scenarios.


11-21: LGTM! Consistent interface design.

The HandlesLiveCounterChange interface follows the same clean design pattern as the map version.

lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java (3)

13-29: LGTM! Well-structured update class.

The LiveCounterUpdate class provides a clean abstraction for counter changes with proper inheritance from LiveObjectUpdate and clear constructor overloads for different scenarios.


31-52: LGTM! Good accessor and utility methods.

The getUpdate() and toString() methods provide proper access to update data with helpful debugging information and appropriate null handling.


54-79: LGTM! Well-designed immutable update data container.

The nested Update class provides proper encapsulation of counter change data with immutable design and clear documentation.

live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt (3)

11-11: LGTM! Proper integration with subscription system.

Extending LiveCounterChangeCoordinator correctly integrates the manager with the new subscription and notification infrastructure.


20-20: LGTM! Consistent transition to structured updates.

The return type changes from Map<String, Double> to LiveCounterUpdate provide better structure while maintaining the same calculation logic. The use of noOpCounterUpdate for no-change scenarios is consistent and clear.

Also applies to: 36-36, 62-62, 72-72, 81-81, 85-85, 91-91, 100-100


56-56: LGTM! Proper update notification integration.

The notifyUpdated() call correctly propagates updates to subscribers, enabling the subscription system to function as designed.

live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt (3)

8-18: LGTM!

The extension property noOp provides a clean way to check for no-op updates by examining if the update field is null. This follows Kotlin conventions and improves code readability.


125-131: Good type safety improvements!

The method signature changes from generic maps to LiveObjectUpdate improve type safety and make the update handling more explicit and structured.

Also applies to: 156-156, 182-182


184-189: Well-designed abstract method for update notifications.

The abstract notifyUpdated method provides a clear contract for subclasses to implement update notifications using the structured LiveObjectUpdate type. The documentation properly references the specification.

live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt (2)

112-119: Clean subscription management implementation.

The delegation pattern to liveMapManager is well-structured. The API validation in subscribe ensures proper configuration before allowing subscriptions.


121-132: Correct update handling with proper diff calculation.

The methods correctly return LiveMapUpdate types, and clearData properly calculates the diff before clearing the data, ensuring accurate change tracking.

live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt (2)

63-70: Consistent subscription management implementation.

The subscription methods follow the same clean delegation pattern as DefaultLiveMap, maintaining consistency across live object types.


82-84: Incorrect sign for counter clear operation.

When clearing a counter from a positive value to zero, the update amount should be negative to represent the decrement. Currently it returns the positive value which incorrectly suggests an increment.

 override fun clearData(): LiveCounterUpdate {
-  return LiveCounterUpdate(data.get()).apply { data.set(0.0) }
+  val currentValue = data.get()
+  data.set(0.0)
+  return if (currentValue == 0.0) LiveCounterUpdate() else LiveCounterUpdate(-currentValue)
 }

Likely an incorrect or invalid review comment.

live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt (4)

10-14: Clean inheritance from coordinator class.

Extending LiveMapChangeCoordinator properly integrates subscription management capabilities into the manager.


75-75: Proper delegation of update notifications.

The change correctly delegates update notification to the LiveMap instance, maintaining proper separation of concerns.


148-148: Well-structured update aggregation logic.

The update building correctly uses LiveMapUpdate with proper change types, and the aggregation logic in mergeInitialDataFromCreateOperation efficiently combines multiple updates.

Also applies to: 188-188, 217-245


248-300: Comprehensive diff calculation with proper change types.

The calculateUpdateFromDataDiff method correctly identifies all types of changes (additions, updates, removals) and properly uses the LiveMapUpdate.Change enum for type safety.

@sacOO7 sacOO7 requested a review from ttypic August 7, 2025 08:04
Base automatically changed from feature/objects-getroot-refactored to main August 8, 2025 14:23
@sacOO7 sacOO7 merged commit e8bba9e into main Aug 8, 2025
13 checks passed
@sacOO7 sacOO7 deleted the feature/object-subscriptions-refactored branch August 8, 2025 14:23
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.

LiveObject: implement BaseLiveObject#data-subscriptions

2 participants