# Getting started: LiveObjects in Java This guide shows how to integrate Ably LiveObjects into your Java application. You will learn how to: * Create an Ably account and get an API key for authentication. * Install the Ably Pub/Sub SDK. * Create a channel with LiveObjects functionality enabled. * Use the [PathObject API](https://ably.com/docs/liveobjects/concepts/path-object.md) to access objects on a channel. * Create, update and subscribe to changes on LiveObjects data structures: [LiveMap](https://ably.com/docs/liveobjects/map.md) and [LiveCounter](https://ably.com/docs/liveobjects/counter.md). ## Authentication An [API key](https://ably.com/docs/auth.md#api-keys) is required to authenticate with Ably. API keys are used either to authenticate directly with Ably using [basic authentication](https://ably.com/docs/auth/basic.md), or to generate tokens for untrusted clients using [token authentication](https://ably.com/docs/auth/token.md). [Sign up](https://ably.com/sign-up) for a free account and create your own API key in the [dashboard](https://ably.com/dashboard) or use the [Control API](https://ably.com/docs/platform/account/control-api.md) to create an API key programmatically. API keys and tokens have a set of [capabilities](https://ably.com/docs/auth/capabilities.md) assigned to them that specify which operations can be performed on which resources. The following capabilities are available for LiveObjects: * `object-subscribe` - grants clients read access to LiveObjects, allowing them to get the channel object and subscribe to updates. * `object-publish` - grants clients write access to LiveObjects, allowing them to perform mutation operations on objects. To use LiveObjects, an API key must have at least the `object-subscribe` capability. With only this capability, clients will have read-only access, preventing them from calling mutation methods on LiveObjects. For the purposes of this guide, make sure your API key includes both `object-subscribe` and `object-publish` [capabilities](https://ably.com/docs/auth/capabilities.md) to allow full read and write access. ## Install Ably Pub/Sub SDK LiveObjects is available as part of the Ably Pub/Sub SDK via the dedicated Objects plugin. The plugin is discovered from the classpath at runtime. No code registration is needed; adding the dependency is enough. ### Install for Maven ```xml io.ably ably-java 1.8.1 io.ably liveobjects 1.8.1 runtime ``` ### Install for Gradle ```java implementation 'io.ably:ably-java:1.8.1' runtimeOnly 'io.ably:liveobjects:1.8.1' ``` For `Android` platform, use `ably-android` instead of `ably-java` ```java implementation 'io.ably:ably-android:1.8.1' runtimeOnly 'io.ably:liveobjects:1.8.1' ``` ## Instantiate a client Instantiate an Ably Realtime client from the Pub/Sub SDK: ### Java ``` AblyRealtime realtime = new AblyRealtime(new ClientOptions("your-api-key")); ``` A [`ClientOptions`](https://ably.com/docs/api/realtime-sdk.md#client-options) object may be passed to the Pub/Sub SDK instance to further customize the connection, however at a minimum you must set an API key. The LiveObjects plugin is picked up automatically when `io.ably:liveobjects` is on the runtime classpath. If the plugin is missing, reading the `channel.object` field is still safe, but calling any method on it (for example `channel.object.get()`) fails with error code `40019` and a message telling you which dependency to add. ## Create a channel LiveObjects is managed and persisted on [channels](https://ably.com/docs/channels.md). To use LiveObjects, you must first create a channel with the correct [channel mode flags](https://ably.com/docs/channels/options.md#modes): * `OBJECT_SUBSCRIBE` - required to access objects on a channel. * `OBJECT_PUBLISH` - required to create and modify objects on a channel. ### Java ``` ChannelOptions opts = new ChannelOptions(); opts.modes = new ChannelMode[] { ChannelMode.object_publish, ChannelMode.object_subscribe }; Channel channel = realtime.channels.get("test-channel", opts); ``` ## Get the channel object The [`channel.object`](https://ably.com/docs/api/realtime-sdk/channels.md#object) field gives access to the LiveObjects API for a channel. Use `channel.object.get()` to obtain the channel object. The channel object is a [`LiveMap`](https://ably.com/docs/liveobjects/map.md) that always exists on a channel and acts as the top-level entry point for accessing and persisting objects. It is returned as a [`LiveMapPathObject`](https://ably.com/docs/liveobjects/concepts/path-object.md#get), which provides a path-based API for accessing and manipulating the object hierarchy. Every LiveObjects mutation is asynchronous: `channel.object.get()` returns a `CompletableFuture` that completes once the LiveObjects state is synchronized with the Ably system; reads are synchronous and local. The **recommended** pattern is to compose these futures rather than block on them: hold the future returned by `get()` and chain each step onto it: ### Java ``` // Recommended: keep the future reference explicit and compose it CompletableFuture objectFuture = channel.object.get(); // Get the object, then create your first object - without blocking. // thenCompose sequences dependent operations (each returns its own future); // finish with thenRun/exceptionally. objectFuture .thenCompose(rootObject -> rootObject.set("visits", LiveMapValue.of(LiveCounter.create(0)))) .thenRun(() -> System.out.println("Channel object ready and counter created")) .exceptionally(err -> { System.err.println("Failed to set up objects: " + err); return null; }); ``` The remaining steps in this guide call `.join()` to keep each example short and focused on the LiveObjects API. It blocks until the operation completes and returns the result directly: ### Java ``` // For brevity, the rest of this guide blocks with join() LiveMapPathObject rootObject = channel.object.get().join(); ``` ## Create and assign objects You can create and assign objects using the `LiveMap.create()` and `LiveCounter.create()` static methods. These methods return a description of the object to create; the actual object is created when you assign it to a key with `set()`. Every value passed to `set()` is wrapped in `LiveMapValue.of(...)`: ### Java ``` // Create a LiveCounter with initial value 0 LiveCounter visits = LiveCounter.create(0); // Assign it to the 'visits' key on the channel object rootObject.set("visits", LiveMapValue.of(visits)).join(); // Create a LiveMap with initial entries LiveMap reactions = LiveMap.create(Map.of( "likes", LiveMapValue.of(0), "hearts", LiveMapValue.of(0))); // Assign it to the 'reactions' key on the channel object rootObject.set("reactions", LiveMapValue.of(reactions)).join(); // Infer types for the assigned objects LiveCounterPathObject visitsCounter = rootObject.get("visits").asLiveCounter(); LiveMapPathObject reactionsMap = rootObject.get("reactions").asLiveMap(); ``` `rootObject.get(key)` returns a general [`PathObject`](https://ably.com/docs/liveobjects/concepts/path-object.md) that doesn't yet know the type of the value it points to. Call one of the `as*` methods, such as `asLiveCounter()` or `asLiveMap()`, to work with the value as a specific type. These casts are always safe to call: they never throw an exception, even if the value at the path has a different type. Learn more about [Type inference](https://ably.com/docs/liveobjects/typing.md#type-inference). ## Subscribe to updates Subscribe to realtime updates using the `subscribe()` method on a `PathObject`. You will be notified when the object at that path is updated by other clients or by you: ### Java ``` // Subscribe to counter updates visitsCounter.subscribe(event -> System.out.println("Visits counter updated: " + event.getObject().asLiveCounter().value())); // Subscribe to map updates reactionsMap.subscribe(event -> System.out.println("Reactions updated: " + event.getObject().compactJson())); ``` The subscription callback receives an event that exposes: - `getObject()`: A `PathObject` pointing to the path where the change occurred - `getMessage()`: The `ObjectMessage` that carried the operation that led to the change (nullable) The `subscribe()` method also returns a `Subscription` object. When you no longer want to receive updates, call `subscription.unsubscribe()` on it: ### Java ``` // Keep the Subscription returned by subscribe() Subscription subscription = visitsCounter.subscribe(event -> System.out.println("Visits counter updated: " + event.getObject().asLiveCounter().value())); // Later, stop receiving updates subscription.unsubscribe(); ``` ## Update objects Update objects using mutation methods on `PathObject`. All subscribers (including you) will be notified of the changes: ### Java ``` // Update counter visitsCounter.increment(5).join(); // console: Visits counter updated: 5.0 visitsCounter.decrement(2).join(); // console: Visits counter updated: 3.0 // Update map reactionsMap.set("likes", LiveMapValue.of(10)).join(); // console: Reactions updated: {"likes":10.0,"hearts":0.0} reactionsMap.set("hearts", LiveMapValue.of(5)).join(); // console: Reactions updated: {"likes":10.0,"hearts":5.0} reactionsMap.remove("likes").join(); // console: Reactions updated: {"hearts":5.0} ``` ## Next steps This quickstart introduced the basic concepts of LiveObjects and demonstrated how the path-based API works. The next steps are to: * Learn about the [PathObject](https://ably.com/docs/liveobjects/concepts/path-object.md) and [Instance](https://ably.com/docs/liveobjects/concepts/instance.md) APIs. * Read more about [LiveCounter](https://ably.com/docs/liveobjects/counter.md) and [LiveMap](https://ably.com/docs/liveobjects/map.md). * Learn about [Objects Lifecycle Events](https://ably.com/docs/liveobjects/lifecycle.md). * Learn about [Type inference](https://ably.com/docs/liveobjects/typing.md) for your LiveObjects. ## Related Topics - [JavaScript](https://ably.com/docs/liveobjects/quickstart/javascript.md): A getting started guide to learn the basics of integrating the Ably LiveObjects product into your JavaScript application. - [Swift](https://ably.com/docs/liveobjects/quickstart/swift.md): A quickstart guide to learn the basics of integrating the Ably LiveObjects product into your Swift application. ## Documentation Index To discover additional Ably documentation: 1. Fetch [llms.txt](https://ably.com/llms.txt) for the canonical list of available pages. 2. Identify relevant URLs from that index. 3. Fetch target pages as needed. Avoid using assumed or outdated documentation paths.