# 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. * 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 root 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. ### Install for Maven: ```xml io.ably ably-java 1.3.0 io.ably liveobjects 1.3.0 ``` ### Install for Gradle: ```java implementation 'io.ably:ably-java:1.3.0' implementation 'io.ably:liveobjects:1.3.0' ``` For `Android` platform, use `ably-android` instead of `ably-java` ```java implementation 'io.ably:ably-android:1.3.0' ``` ## Instantiate a client Instantiate an Ably Realtime client from the Pub/Sub SDK, providing the Objects plugin: ```java AblyRealtime realtime = new AblyRealtime(new ClientOptions("ABLY_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 and provide an `Objects` plugin so that the client can use LiveObjects functionality. ## 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 }; ChannelBase channel = realtime.channels.get("test-channel", opts); ``` ## Get root object The [`channel.getObjects`](https://ably.com/docs/api/realtime-sdk/channels.md#objects) method gives access to the LiveObjects API for a channel. Use it to get the root object, which is the entry point for accessing and persisting objects on a channel. The root object is a [`LiveMap`](https://ably.com/docs/liveobjects/map.md) instance that always exists on a channel and acts as the top-level node in your object tree. You can get the root object using the `getRoot()` method of LiveObjects: ```java // The root is returned once the LiveObjects state is synchronized with the Ably system. // `getRoot` Implicitly attaches channel if it's in a INITIALIZED state RealtimeObjects objects = channel.getObjects(); LiveMap root = objects.getRoot(); // blocks current thread till result is returned ``` The above `getRoot()` method is blocking in nature so it's recommended to use `getRootAsync()` instead ```java RealtimeObjects objects = channel.getObjects(); objects.getRootAsync(new ObjectsCallback() { @Override public void onSuccess(LiveMap root) { // Successfully retrieved the root LiveMap System.out.println("Root object retrieved: " + root); // You can now use the root object to create and manage other objects } @Override public void onError(AblyException exception) { // Handle errors (network issues, authentication failures, etc.) System.err.println("Failed to get root object: " + exception.getMessage()); } }); ``` | Blocking Method | Async Method | | --------------- | ------------ | | `RealtimeObjects.getRoot()` | `RealtimeObjects.getRootAsync()` | | `RealtimeObjects.createMap()` | `RealtimeObjects.createMapAsync()` | | `RealtimeObjects.createCounter()` | `RealtimeObjects.createCounterAsync()` | | `LiveMap.set()` | `LiveMap.setAsync()` | | `LiveMap.remove()` | `LiveMap.removeAsync()` | | `LiveCounter.increment()` | `LiveCounter.incrementAsync()` | | `LiveCounter.decrement()` | `LiveCounter.decrementAsync()` | ## Create objects You can create new objects using dedicated methods of the LiveObjects API at [`channel.getObjects()`](https://ably.com/docs/api/realtime-sdk/channels.md#objects). To persist them on a channel and share them between clients, you must assign objects to a parent `LiveMap` instance connected to the root object. The root object itself is a `LiveMap` instance, so you can assign objects to the root and start building your object tree from there. ```java LiveCounter visitsCounter = objects.createCounter(); LiveMap reactionsMap = objects.createMap(); root.set("visits", LiveMapValue.of(visitsCounter)); root.set("reactions", LiveMapValue.of(reactionsMap)); ``` ## Subscribe to updates Subscribe to realtime updates to objects on a channel. You will be notified when an object is updated by other clients or by you. ```java visitsCounter.subscribe((counterUpdate) -> System.out.println("Visits counter updated: " + counterUpdate.getUpdate().getAmount()); ); reactionsMap.subscribe((mapUpdate) -> { System.out.println("Reactions map updated: " + mapUpdate.getUpdate()); System.out.println("Reactions map updated: " + reactionsMap.entries()); }); ``` ## Update objects Update objects using mutation methods. All subscribers (including you) will be notified of the changes when you update an object: ```java visitsCounter.increment(5); // counter updated: 5 visitsCounter.decrement(2); // counter updated: 3 reactionsMap.set("like", LiveMapValue.of(10)); // {"like": 10} reactionsMap.set("love", LiveMapValue.of(5)); // {"like": 10}, {"love": 5} reactionsMap.remove("like"); // {"love": 5} ``` ## Next steps This quickstart introduced the basic concepts of LiveObjects and demonstrated how it works. The next steps are to: * Read more about [LiveCounter](https://ably.com/docs/liveobjects/counter.md) and [LiveMap](https://ably.com/docs/liveobjects/map.md). * Learn about [Batching Operations](https://ably.com/docs/liveobjects/batch.md). * Learn about [Objects Lifecycle Events](https://ably.com/docs/liveobjects/lifecycle.md). * Add [Typings](https://ably.com/docs/liveobjects/typing.md) for your LiveObjects.