[ECO-5482][LiveObjects] Implement realtime write API#1141
Conversation
- Enhanced LiveObjects interface with realtime write operations and spec annotations - Extended Adapter and LiveObjectsAdapter with realtime write support - Implemented foundational API structure for realtime object modifications
…perations - Updated LiveCounter interface with realtime write methods and spec references - Modified LiveMap interface to support realtime write capabilities - Added comprehensive API documentation for realtime operations
…me operations - Implemented comprehensive LiveMapValue class for map value handling - Added ServerTime utility for server timestamp management - Provided foundational support classes for realtime write operations
- Enhanced DefaultLiveObjects with realtime write operation implementations - Updated Helpers with realtime write support utilities - Modified Utils to support realtime operation context and validation
- Updated ObjectId with realtime operation support - Modified ErrorCodes for realtime write error handling - Enhanced MsgpackSerialization for realtime operation serialization - Updated BaseLiveObject with realtime write base functionality
…r and DefaultLiveMap - Added runBlocking synchronous wrappers for increment/decrement in DefaultLiveCounter - Updated DefaultLiveMap.get() to return LiveMapValue instead of Any? - Integrated asyncScope for coroutine-based realtime operations - Added kotlinx.coroutines.runBlocking import for synchronous API support
… operations - Added imports for LiveCounter, LiveMap, LiveMapValue types - Extended imports for BaseLiveObject and ObjectType support - Updated LiveMapEntry to support enhanced type system for realtime write operations
- Updated DefaultLiveCounterTest with realtime write test scenarios - Enhanced DefaultLiveMapTest with comprehensive realtime operation tests - Added LiveMapValue import and removed unused type imports - Expanded test coverage for realtime increment/decrement and map operations
- Removed unused imports from DefaultLiveObjectsTest (JsonArray, JsonObject, Binary) - Updated PayloadBuilder helper for realtime write operation support - Streamlined import statements for better code organization
WalkthroughThis update implements the realtime write API for LiveObjects, including LiveMap and LiveCounter. It introduces type-safe value handling with a new Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant LiveObjects
participant Adapter
participant AblyRealtime
Client->>LiveObjects: createMap()/createCounter()
LiveObjects->>Adapter: getClientOptions(), getConnectionManager(), getTime()
Adapter->>AblyRealtime: (delegates)
LiveObjects->>AblyRealtime: Publish ObjectMessage (MapCreate/CounterCreate)
AblyRealtime-->>LiveObjects: Ack/Result
LiveObjects-->>Client: Return LiveMap/LiveCounter instance
Client->>LiveMap/LiveCounter: set()/increment()/decrement()
LiveMap/LiveCounter->>LiveObjects: Publish mutation ObjectMessage
LiveObjects->>AblyRealtime: Publish mutation
AblyRealtime-->>LiveObjects: Ack/Result
LiveObjects-->>Client: Operation result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
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 (
|
1d6add2 to
b32c283
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt (1)
114-117: Consider using cryptographically secure random for nonce generation.The current implementation uses Kotlin's
random()which relies onjava.util.Random, which is not cryptographically secure. For object creation nonces that may be used in security-sensitive contexts, consider usingSecureRandom.-/** - * Generates a random nonce string for object creation. - */ -internal fun generateNonce(): String { - val chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" // avoid calculation using range - return (1..16).map { chars.random() }.joinToString("") -} +/** + * Generates a random nonce string for object creation. + */ +internal fun generateNonce(): String { + val chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + val secureRandom = java.security.SecureRandom() + return (1..16).map { chars[secureRandom.nextInt(chars.length)] }.joinToString("") +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (24)
lib/src/main/java/io/ably/lib/objects/Adapter.java(2 hunks)lib/src/main/java/io/ably/lib/objects/LiveObjects.java(5 hunks)lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java(2 hunks)lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.java(1 hunks)lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java(4 hunks)lib/src/main/java/io/ably/lib/objects/type/map/LiveMapValue.java(1 hunks)live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt(3 hunks)live-objects/src/main/kotlin/io/ably/lib/objects/ErrorCodes.kt(1 hunks)live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt(5 hunks)live-objects/src/main/kotlin/io/ably/lib/objects/ObjectId.kt(2 hunks)live-objects/src/main/kotlin/io/ably/lib/objects/ServerTime.kt(1 hunks)live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt(3 hunks)live-objects/src/main/kotlin/io/ably/lib/objects/serialization/MsgpackSerialization.kt(0 hunks)live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt(1 hunks)live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt(4 hunks)live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt(7 hunks)live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.kt(3 hunks)live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt(5 hunks)live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt(10 hunks)live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt(4 hunks)live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/PayloadBuilder.kt(3 hunks)live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectIdTest.kt(1 hunks)live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.kt(1 hunks)live-objects/src/test/kotlin/io/ably/lib/objects/unit/UtilsTest.kt(1 hunks)
💤 Files with no reviewable changes (1)
- live-objects/src/main/kotlin/io/ably/lib/objects/serialization/MsgpackSerialization.kt
🧰 Additional context used
🧠 Learnings (18)
📓 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#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.
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#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.
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#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.
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#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.
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 in the `shouldCalculateMapDifferenceCorrectly` test method to test the `calculateUpdateFromDataDiff` functionality, 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 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:
live-objects/src/test/kotlin/io/ably/lib/objects/unit/UtilsTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectIdTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Helpers.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ObjectId.ktlib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapValue.javalive-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ServerTime.ktlib/src/main/java/io/ably/lib/objects/LiveObjects.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/PayloadBuilder.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.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/unit/ObjectIdTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.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/LiveObjects.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/PayloadBuilder.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
📚 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:
live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectIdTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.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/LiveObjects.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/PayloadBuilder.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
📚 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:
live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectIdTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Helpers.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapValue.javalib/src/main/java/io/ably/lib/objects/LiveObjects.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
📚 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:
live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectIdTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Helpers.ktlib/src/main/java/io/ably/lib/objects/Adapter.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapValue.javalive-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.ktlib/src/main/java/io/ably/lib/objects/LiveObjects.javalive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/PayloadBuilder.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Utils.ktlib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.javalive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.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:
live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlib/src/main/java/io/ably/lib/objects/LiveObjects.javalib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.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:
live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Helpers.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapValue.javalive-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ServerTime.ktlib/src/main/java/io/ably/lib/objects/LiveObjects.javalib/src/main/java/io/ably/lib/objects/type/map/LiveMap.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.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:
live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Helpers.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlib/src/main/java/io/ably/lib/objects/type/map/LiveMapValue.javalive-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.ktlib/src/main/java/io/ably/lib/objects/LiveObjects.javalive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.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/integration/DefaultLiveObjectsTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.kt
📚 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:
live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ServerTime.ktlive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.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/DefaultLiveObjectsTest.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Helpers.ktlive-objects/src/main/kotlin/io/ably/lib/objects/ServerTime.ktlive-objects/src/main/kotlin/io/ably/lib/objects/Utils.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.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:
live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.ktlib/src/main/java/io/ably/lib/objects/Adapter.javalib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.ktlib/src/main/java/io/ably/lib/objects/LiveObjects.javalive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.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/Helpers.ktlive-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/PayloadBuilder.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.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
📚 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/LiveObjectsAdapter.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.ktlib/src/main/java/io/ably/lib/objects/LiveObjects.javalive-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.ktlive-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.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:
live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.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/PayloadBuilder.kt
🧬 Code Graph Analysis (7)
live-objects/src/test/kotlin/io/ably/lib/objects/unit/UtilsTest.kt (1)
live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt (1)
generateNonce(114-117)
live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt (1)
live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt (3)
ablyException(10-18)ablyException(20-23)clientError(37-37)
live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt (1)
live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt (1)
invalidInputError(45-47)
live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt (1)
live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt (1)
invalidInputError(45-47)
live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/PayloadBuilder.kt (1)
live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt (1)
generateNonce(114-117)
lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java (1)
live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt (2)
entries(60-71)values(82-89)
lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.java (2)
live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt (3)
increment(44-44)decrement(46-46)decrementAsync(52-54)live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt (1)
amount(90-96)
🔇 Additional comments (61)
lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounter.java (5)
17-27: LGTM! Well-documented method signature change.The increment method now properly accepts a
Numberparameter with clear documentation about the operation behavior and spec reference.
29-37: LGTM! Consistent decrement method design.The decrement method correctly mirrors the increment signature and clearly documents that it's an alias for negative increment, which aligns with the implementation in
DefaultLiveCounter.kt.
40-51: LGTM! Proper async method signature.The asynchronous increment method maintains consistency with the synchronous version while properly handling the callback pattern.
54-62: LGTM! Consistent async decrement method.The asynchronous decrement method properly mirrors the increment async method with clear documentation about being an alias.
67-71: LGTM! Appropriate return type change.Changing the return type from
LongtoDoubleis consistent with the internal representation and theObjectCounterOp.amountfield beingDouble. The@Contract(pure = true)annotation correctly indicates this method doesn't modify object state.live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.kt (1)
171-171: LGTM! Correct pluralization in error message.The change from "ObjectMessage" to "ObjectMessages" properly reflects that the error occurs when multiple messages collectively exceed the size limit, aligning with the implementation in
Helpers.kt.live-objects/src/main/kotlin/io/ably/lib/objects/ErrorCodes.kt (1)
9-9: LGTM! Improved error code naming.Renaming
MapKeyShouldBeStringtoInvalidInputParamsmakes the error code more generic and reusable for various input validation scenarios while maintaining the same code value.live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt (1)
30-30: LGTM! Appropriate visibility change.Changing
objectTypefromprivatetointernalenables module-level access needed for type-safe operations likeLiveMapValuewrapping and object ID generation while maintaining encapsulation outside the module.live-objects/src/test/kotlin/io/ably/lib/objects/unit/UtilsTest.kt (1)
15-31: LGTM! Comprehensive test coverage for generateNonce.The test thoroughly validates the
generateNonce()function by checking:
- Correct length (16 characters)
- Randomness (different nonces generated)
- Character set compliance (only alphanumeric characters)
The test structure is well-organized and covers all important aspects of the nonce generation functionality.
live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/PayloadBuilder.kt (1)
6-6: LGTM! Good refactoring to use centralized nonce generation.The replacement of the local
nonce()function with the centralizedgenerateNonce()utility improves code consistency and eliminates duplication. The new function generates a 16-character alphanumeric string instead of UUID-based nonces, which aligns with the deterministic object ID generation requirements.Also applies to: 44-44, 111-111
live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectIdTest.kt (1)
56-74: LGTM! Comprehensive test coverage for the new factory method.The test properly validates the
fromInitialValuemethod by checking:
- String format compliance (
type:hash@timestamp)- Deterministic hash generation with expected output
- Proper timestamp handling
The use of fixed inputs with pre-calculated expected hash ensures test repeatability and validates the SHA-256 + Base64 URL-safe encoding implementation.
live-objects/src/main/kotlin/io/ably/lib/objects/ObjectId.kt (2)
26-33: LGTM! Correct implementation of RTO14 specification.The
fromInitialValuemethod properly implements the specification requirements:
- Concatenates initial value and nonce with colon separator
- Uses SHA-256 for cryptographic hashing (RTO14b)
- Applies Base64 URL-safe encoding without padding, suitable for identifiers
- Returns deterministic object IDs for given inputs
The implementation is secure and follows cryptographic best practices.
38-38: LGTM! Appropriate visibility change to internal.Making
fromStringinternal is consistent with the codebase patterns and properly restricts access to this parsing method.live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt (1)
76-76: Excellent type safety improvements with nullable accessors.The refactoring from unsafe casts (
as Type) to safe nullable property accessors (?.asType) significantly improves code safety by:
- Eliminating
ClassCastExceptionrisks- Making null handling explicit with
assertNotNullchecks- Aligning with the new
LiveMapValuetype systemThis change properly reflects the API evolution toward type-safe live object handling.
Also applies to: 81-81, 86-86, 92-92, 97-97, 100-100, 105-105, 110-111, 114-115, 119-122, 124-131, 134-135, 139-140, 147-148, 150-150, 173-173, 190-190, 211-211
live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt (2)
45-47: LGTM!The
invalidInputErrorfunction follows the established pattern of other error creation functions and correctly uses the updatedErrorCode.InvalidInputParams.
55-55: LGTM!The change from
Charsets.UTF_8toStandardCharsets.UTF_8is correct and aligns with the import statement. Both are functionally equivalent.lib/src/main/java/io/ably/lib/objects/Adapter.java (3)
71-74: LGTM!The implementation correctly delegates to the underlying AblyRealtime instance's options property.
76-79: LGTM!The implementation correctly delegates to the connection manager from the AblyRealtime instance.
81-84: LGTM!The implementation correctly delegates to the AblyRealtime's
time()method and properly declares theAblyExceptionin the throws clause.live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.kt (3)
45-59: LGTM!The updated
getResolvedValuefunction correctly implements type-safe conversion from internal representations toLiveMapValue. The logic flow is preserved while adding proper type safety.
69-78: LGTM!The
fromObjectValuefunction comprehensively handles allObjectValuesubtypes and correctly maps them to correspondingLiveMapValueinstances.
80-85: LGTM!The
fromLiveObjectfunction correctly handles the conversion ofBaseLiveObjectinstances toLiveMapValuewith proper type casting based onObjectType.lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java (3)
60-67: LGTM!The
getClientOptions()method declaration is well-documented and correctly annotated with@NotNull.
69-76: LGTM!The
getConnectionManager()method declaration is well-documented and correctly annotated with@NotNull.
78-83: LGTM!The
getTime()method declaration is properly documented with spec reference (RTO16), correctly annotated with@Blocking, and properly declares theAblyException.live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveCounterTest.kt (3)
31-31: LGTM!The updates to use safe nullable accessors (
?.asLiveCounterand?.asLiveMap) improve type safety and prevent potentialClassCastExceptions. This aligns with the broader type safety improvements in the PR.Also applies to: 37-37, 42-42, 47-47, 52-52, 57-57, 62-62, 67-67, 73-73, 78-78, 83-83, 88-88, 132-132, 203-206
208-297: LGTM!The new test
testLiveCounterOperationsUsingRealtimeprovides comprehensive coverage of the realtime API for counter operations. The test properly:
- Creates counters using the realtime API
- Tests increment/decrement operations with proper waiting
- Verifies values after each operation
- Uses proper async testing patterns with
assertWaiter
308-312: LGTM!The safe accessor pattern is consistently applied throughout the test, improving robustness and type safety.
live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt (6)
12-29: LGTM!The
sendAsyncimplementation correctly wraps the adapter's callback-basedsendmethod into a suspend function using proper coroutine patterns.
31-41: Good grammar fix!The error message correctly uses plural "ObjectMessages" since the function validates an array of messages.
56-60: LGTM!The validation function properly enforces all requirements for write operations: echo messages enabled, correct channel mode, and valid channel state.
62-67: LGTM!Proper validation of connection and channel states before publishing, with appropriate error information from the connection manager.
85-89: LGTM!Clear validation that echo messages must be enabled, with an appropriate client error message.
107-113: LGTM!Well-structured data classes for encapsulating creation payloads for counters and maps.
lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java (1)
33-33: Excellent type safety improvements!The migration from generic
Objectto the specificLiveMapValuetype throughout the interface provides:
- Compile-time type safety
- Better API clarity
- Consistent typing across all map operations
The added specification references (RTLM20, RTLM21) properly document the requirements.
Also applies to: 43-43, 63-63, 71-77, 85-85, 108-115, 123-123
live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveMapTest.kt (4)
34-98: Great type safety improvements in tests!The consistent use of safe nullable access (
?.) followed by explicit type conversions (.asLiveMap,.asLiveCounter,.asString, etc.) makes the tests more robust and clearer about expected types.
126-216: LGTM!Consistent application of type-safe accessors throughout the test. The value extraction at lines 214-215 correctly handles the
LiveMapValuewrapper for set comparison.
218-333: Excellent addition of realtime API test coverage!The new
testLiveMapOperationsUsingRealtimetest effectively validates the realtime write API implementation. It properly:
- Uses
LiveMapValue.of()factory methods for type-safe value creation- Tests both
set()andremove()operations via the realtime API- Maintains consistency with the REST API test for comparison
- Follows the same type-safe accessor patterns
345-411: LGTM!The subscription test correctly uses type-safe accessors, maintaining consistency with the rest of the test suite.
live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt (3)
42-54: Well-structured implementation!Good application of DRY principle by delegating all increment/decrement operations to a single
incrementAsyncfunction. The use of negative amounts for decrement operations is clean and correct.
72-92: Robust implementation with proper validation!The
incrementAsyncimplementation correctly:
- Validates write API configuration before operations
- Rejects invalid numeric values (NaN, Infinite)
- Constructs the
ObjectMessagewith appropriate operation details- Delegates publishing to the
liveObjectsinstanceAll specification requirements (RTLC12b-f) are properly addressed.
128-136: LGTM!Clean factory method for creating initial counter payloads, properly converting the
Numberparameter toDouble.live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (5)
55-55: LGTM!The public API methods are well-structured:
- Proper delegation pattern from sync to async methods
- Reasonable defaults (empty map, zero counter)
- Consistent use of
asyncScopefor callback-based operationsAlso applies to: 63-85
100-134: Well-implemented map creation with proper synchronization!The implementation correctly:
- Validates input (no empty keys)
- Generates unique object IDs with nonce and server timestamp
- Constructs the MAP_CREATE operation message properly
- Ensures thread-safe object creation using the sequential scope
The pattern of checking the pool first, then creating in sequential scope, is thread-safe as confirmed by the single-threaded execution context.
136-170: Consistent implementation with map creation!The counter creation properly:
- Validates numeric input (rejects NaN/Infinite)
- Follows the same ID generation pattern as maps
- Constructs the COUNTER_CREATE operation correctly
- Uses the same thread-safe object pool pattern
175-179: LGTM!Clean helper method that properly encapsulates object ID generation with server timestamp and nonce.
184-193: Well-structured publish implementation!The method properly enforces all requirements:
- Channel/connection state validation (RTO15b, RTL6c)
- Message size limit enforcement (RTO15d)
- Correct ProtocolMessage construction (RTO15e)
- Asynchronous sending with proper error propagation
lib/src/main/java/io/ably/lib/objects/type/map/LiveMapValue.java (5)
13-21: Well-designed abstract base classThe abstract class structure with the abstract
getValue()method provides a solid foundation for the union type implementation. The@NotNullannotation correctly indicates that all implementations must return non-null values.
27-81: Type checking methods follow good design patternThe default implementations returning
falsewith subclasses overriding only the relevant method is an elegant approach that follows the template method pattern well.
87-172: Getter methods correctly implement fail-fast behaviorThe default implementations throwing
IllegalStateExceptionwith clear error messages ensure type safety at runtime. The@NotNullannotations are appropriate since valid type conversions should never return null.
178-264: Factory methods provide clean, type-safe APIThe static factory methods follow the factory method pattern effectively, providing a clean API for creating type-safe
LiveMapValueinstances. The@NotNullannotations on both parameters and return types ensure null safety.
268-442: Implementation classes are well-structured and thread-safeThe private static final implementation classes with final fields ensure immutability and thread safety. Each class correctly overrides only the relevant type checking and getter methods, maintaining a clean separation of concerns.
live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt (6)
49-58: get() method correctly implements type-safe value retrievalThe method properly validates access configuration, checks for tombstoned state, and converts the internal representation to
LiveMapValueusinggetResolvedValue(). The nullable return type appropriately handles missing keys.
60-89: Collection methods efficiently handle type conversionThe use of sequences for lazy evaluation is efficient. Filtering out null values from
getResolvedValue()correctly excludes tombstoned entries. The updated return types properly integrate with theLiveMapValuetype system.
96-98: Synchronous methods correctly delegate to async implementationsUsing
runBlockingto implement synchronous versions ensures consistency between sync and async behavior. This is a standard pattern in Kotlin for bridging coroutine and blocking APIs.
100-106: Async callback methods properly integrate with coroutine scopeThe methods correctly use
asyncScope.launchWithVoidCallbackto execute suspend functions and handle callbacks, maintaining consistency with the async patterns in the codebase.
119-164: Write operations correctly implement spec requirementsThe implementations properly validate write API configuration (RTLM20b-d, RTLM21b-d), check for empty keys, construct appropriate
ObjectMessageinstances with MAP_SET/MAP_REMOVE operations (RTLM20e, RTLM21e), and publish them (RTLM20f, RTLM21f). The error handling for empty keys is appropriate.
200-248: Companion object functions correctly handle type conversionThe
initialValuefunction properly creates the payload structure for map creation. ThefromLiveMapValuefunction (RTLM20e5) exhaustively handles allLiveMapValuetypes with appropriate conversions. TheIllegalArgumentExceptionin the else clause ensures fail-fast behavior if new types are added without updating this conversion logic.lib/src/main/java/io/ably/lib/objects/LiveObjects.java (3)
36-76: Type-safe map creation API with excellent documentationThe transition from
Map<String, Object>toMap<String, LiveMapValue>enforces compile-time type safety, preventing runtime errors. The comprehensive example (lines 57-69) clearly demonstrates all supported value types, making the API easy to understand and use. The parameterlesscreateMap()provides a convenient way to create empty maps.
79-103: Counter creation API properly generalizedChanging the initial value parameter from
LongtoNumberprovides greater flexibility, allowing various numeric types (Integer, Double, etc.). The parameterlesscreateCounter()with a default value of 0 offers a convenient option for the common use case.
117-165: Async methods maintain API consistencyThe asynchronous methods perfectly mirror their synchronous counterparts, maintaining API consistency. The use of
ObjectsCallbackfor result handling follows established patterns in the codebase.
live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
Outdated
Show resolved
Hide resolved
b32c283 to
e6cf876
Compare
- Enhanced ObjectIdTest with testFromInitialValue test for object initialization - Added new test methods to UtilsTest for realtime operation utilities - Updated ObjectMessageSizeTest with realtime write operation size calculations
e6cf876 to
c4f1f1c
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.kt (1)
150-150: Update variable name to match object type.The object creation was correctly changed from
DefaultLiveMaptoDefaultLiveCounterwith appropriate object ID prefix, but the variable nameliveMapis now misleading since it contains aLiveCounterinstance.- val liveMap: BaseLiveObject = DefaultLiveCounter.zeroValue("counter:testObject@1", defaultLiveObjects) + val liveCounter: BaseLiveObject = DefaultLiveCounter.zeroValue("counter:testObject@1", defaultLiveObjects)And update the subsequent variable references throughout the test method.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt(4 hunks)live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt(5 hunks)live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectIdTest.kt(1 hunks)live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.kt(1 hunks)live-objects/src/test/kotlin/io/ably/lib/objects/unit/UtilsTest.kt(1 hunks)live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.kt(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.kt
🚧 Files skipped from review as they are similar to previous changes (4)
- live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectIdTest.kt
- live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt
- live-objects/src/test/kotlin/io/ably/lib/objects/unit/UtilsTest.kt
- live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt
🧰 Additional context used
🧠 Learnings (11)
📓 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#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.
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#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.
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#1139
File: live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt:86-92
Timestamp: 2025-08-07T07:19:59.951Z
Learning: In DefaultLiveCounter.notifyUpdated method, sacOO7 prefers to keep the unchecked cast `update as LiveCounterUpdate` without type safety checks, as they are confident the type system guarantees the correct type will always be passed.
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.
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#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.
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#1137
File: live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt:6-6
Timestamp: 2025-08-07T07:17:33.286Z
Learning: In the ably-java LiveObjects test code, there are extension properties defined in TestHelpers.kt that provide access to private fields of classes for testing purposes. For example, `internal var DefaultLiveMap.LiveMapManager: LiveMapManager` allows tests to access the private `liveMapManager` field. These extension imports (like `import io.ably.lib.objects.unit.LiveMapManager`) should not be removed as they are necessary for test functionality and are not conflicting imports.
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.
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 liveobjects test code, there are extension properties defined in testhelpers.kt tha...
Learnt from: sacOO7
PR: ably/ably-java#1137
File: live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt:6-6
Timestamp: 2025-08-07T07:17:33.286Z
Learning: In the ably-java LiveObjects test code, there are extension properties defined in TestHelpers.kt that provide access to private fields of classes for testing purposes. For example, `internal var DefaultLiveMap.LiveMapManager: LiveMapManager` allows tests to access the private `liveMapManager` field. These extension imports (like `import io.ably.lib.objects.unit.LiveMapManager`) should not be removed as they are necessary for test functionality and are not conflicting imports.
Applied to files:
live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.kt
📚 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:
live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.kt
📚 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:
live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.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:
live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.kt
📚 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:
live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.kt
📚 Learning: in the ably-java liveobjects test code, there is a `findmethod` extension function defined on `class...
Learnt from: sacOO7
PR: ably/ably-java#1137
File: live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.kt:48-67
Timestamp: 2025-08-07T07:14:23.327Z
Learning: In the ably-java LiveObjects test code, there is a `findMethod` extension function defined on `Class<*>` in TestUtils.kt that searches the class's public methods for one whose name contains the given substring and returns it. This extension method should not be replaced with standard reflection methods like `getDeclaredMethod()` when used in tests.
Applied to files:
live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.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/BaseLiveObjectTest.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/unit/type/BaseLiveObjectTest.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:
live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.kt
📚 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:
live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: build
- GitHub Check: check-realtime-okhttp
- GitHub Check: check-liveobjects
- GitHub Check: check-rest-okhttp
- GitHub Check: check (21)
- GitHub Check: check (24)
- GitHub Check: check (29)
- GitHub Check: check (19)
- GitHub Check: check-realtime
- GitHub Check: check-rest
- GitHub Check: check
LiveMapValueas a concrete type representing a map valueReason to choose
of()methods return immutable objectsSummary by CodeRabbit
New Features
LiveMapValueabstraction.Improvements
Bug Fixes
Tests
Chores