[ECO-5458][LiveObjects] Implement object subscriptions#1139
Conversation
- 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
WalkthroughThis 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
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)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changesNo out-of-scope changes detected. Possibly related PRs
Suggested reviewers
Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
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
LiveCounterChangeCoordinatorandLiveMapChangeCoordinator, 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
📒 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.javalib/src/main/java/io/ably/lib/objects/ObjectsSubscription.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Helpers.ktlib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.javalive-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlib/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.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Helpers.ktlib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.javalive-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/MapFixtures.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterChangeCoordinator.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.javalive-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.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Helpers.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlib/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.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.ktlib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.javalive-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.javalive-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.javalib/src/main/java/io/ably/lib/objects/ObjectsSubscription.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterChangeCoordinator.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.ktlib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterChange.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.javalive-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.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.ktlive-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.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/setup/IntegrationTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/CounterFixtures.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/MapFixtures.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterChangeCoordinator.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlive-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.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterChange.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlib/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.javalive-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ObjectsPool.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.ktlive-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.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlib/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.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/CounterFixtures.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/MapFixtures.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.javalive-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.ktlive-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.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/RestObjects.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/CounterFixtures.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/fixtures/MapFixtures.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapChange.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.javalive-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.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Helpers.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.ktlive-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.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlive-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.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlib/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.ktlive-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 helpfulThe added
RTO4b2areference 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
LiveCounterandLiveMapare now referenced from their newtype.counter/type.mapsub-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 pullsLiveCounter/LiveMapfrom 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 (
RTLO4b5andRTLO4b5a) 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
LiveCounterandLiveMapfrom 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.mappackage 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
LiveMapChangeadds 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.counterpackage 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
LiveCounterChangeadds 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>>toMutableList<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
ObjectDataconstruction with theDataFixtures.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"]toupdate.update.amountcorrectly reflect the refactoring from generic map-based updates to typedLiveCounterUpdateobjects. 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
updatefield 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
LiveMapUpdateenables 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
.updateproperty 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.Changeenum 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
createUserProfileMapObjectfunction 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
LiveCounterandLiveMapinterfaces 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
LiveMapUpdateclass 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.Changeenum 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
LiveMapUpdateclass provides excellent type safety and structure for LiveMap change notifications:Strengths:
- Extends
LiveObjectUpdatebase class appropriately- Clear separation between no-op updates and actual changes
- Type-safe
Changeenum withUPDATED/REMOVEDvalues- Comprehensive JavaDoc with specification references (RTLM18, RTLM18a, RTLM18b)
- Proper null handling and defensive programming
- Useful
toString()implementation for debuggingDesign consistency:
- Follows established patterns for update classes in the codebase
- Uses
@NotNullannotations 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
LiveMapChangeinterface provides a clean and well-designed API for LiveMap subscriptions:API Design Strengths:
- Multiple independent listener support via
subscribe()returningObjectsSubscription- Proper resource management with individual and bulk unsubscribe methods
- Clear separation of concerns with nested
Listenerinterface- Non-blocking operations marked with
@NonBlockingannotationDocumentation 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
LiveMapUpdatefor type-safe change notifications- Proper null safety with
@NotNullannotations- 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
LiveCounterChangeinterface 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
noOpMapUpdateconstant provides a clean way to represent no-change scenarios, improving consistency across the codebase.
11-21: LGTM! Clean interface design.The
HandlesLiveMapChangeinterface provides a clear contract for map change notification with good documentation.
23-38: LGTM! Solid coordinator implementation.The
LiveMapChangeCoordinatorprovides a clean abstraction for managing LiveMap subscriptions using the established EventEmitter pattern. TheObjectsSubscriptionreturn type enables proper resource management.
40-51: LGTM! Robust error handling in emitter.The
LiveMapChangeEmitterincludes 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
noOpCounterUpdateconstant maintains consistency with the map implementation for representing no-change scenarios.
11-21: LGTM! Consistent interface design.The
HandlesLiveCounterChangeinterface 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
LiveCounterUpdateclass provides a clean abstraction for counter changes with proper inheritance fromLiveObjectUpdateand clear constructor overloads for different scenarios.
31-52: LGTM! Good accessor and utility methods.The
getUpdate()andtoString()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
Updateclass 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
LiveCounterChangeCoordinatorcorrectly 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>toLiveCounterUpdateprovide better structure while maintaining the same calculation logic. The use ofnoOpCounterUpdatefor 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
noOpprovides 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
LiveObjectUpdateimprove 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
notifyUpdatedmethod provides a clear contract for subclasses to implement update notifications using the structuredLiveObjectUpdatetype. 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
liveMapManageris well-structured. The API validation insubscribeensures proper configuration before allowing subscriptions.
121-132: Correct update handling with proper diff calculation.The methods correctly return
LiveMapUpdatetypes, andclearDataproperly 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
LiveMapChangeCoordinatorproperly 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
LiveMapUpdatewith proper change types, and the aggregation logic inmergeInitialDataFromCreateOperationefficiently combines multiple updates.Also applies to: 188-188, 217-245
248-300: Comprehensive diff calculation with proper change types.The
calculateUpdateFromDataDiffmethod correctly identifies all types of changes (additions, updates, removals) and properly uses theLiveMapUpdate.Changeenum for type safety.
Fixed #1123
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Refactor