How To Store JSON with Redis on Java
JSON (JavaScript Object Notation) is a fast, lightweight, text-based format for representing information based on a subset of the JavaScript programming language. JSON is intended to be both simple for humans to read and write and easy for machines to parse and generate. Because JSON is supported by most modern programming languages and computing environments, it is a popular choice when building web services and APIs (application programming interfaces) that need to exchange data.
Redis is an open-source, in-memory data structure store that can be used to implement databases, caches, and message brokers. Like JSON, Redis is a popular choice for building web applications that require fast data storage and retrieval, thanks to its ability to process requests in real time.
Users can obtain JSON support in Redis by installing the RedisJSON module or using AWS Elasticache. RedisJSON offers full JSON support, letting users store, update, and retrieve JSON values inside a Redis database. In addition, RedisJSON can be used with other Redis modules such as RediSearch to index and query JSON documents.
Storing JSON in Redis with the Java RJsonBucket
Despite the many advantages of Redis, it also comes with a drawback for Java developers: Redis is written in the C programming language and doesn’t support Java out of the box. Instead, Java programmers can install third-party Redis Java frameworks such as Redisson.
Redisson is a Redis Java client for Redis that provides implementations of dozens of distributed Java objects and services. Developers familiar with these Java constructs, classes, and interfaces can use Redisson to start working with Redis immediately, dramatically lowering the learning curve.
One of the Java constructs offered by Redisson is the RJsonBucket interface. As the name suggests, RJsonBucket holds information with the JSON datatype inside a Redis database. RJsonBucket is an extension of the RBucket interface, which is also extended by the RBinaryStream interface for storing binary data.
Below are some of the most essential methods of the RJsonBucket interface:
-
set(Object value): Stores the given object into the JSON container.
-
compareAndSet(V expect, V update): Atomically sets the value to the given updated value if the current value is equal to the given expected value.
-
setIfAbsent(String path, Object value): Sets the given object at the given path only if the previous value at that path is empty.
-
setIfExists(String path, Object value): Sets the given object at the given path only if the previous value at that path is non-empty.
-
get(JsonCodec codec, String... paths): Gets the object(s) stored at the given path(s) and decodes them using the given codec.
-
getAndSet(V newValue): Replaces the current value inside the JSON container with the given new value.
-
delete(String path): Deletes the object at the given path.
-
getKeys(): Returns the list of keys of the JSON container.
-
clear(): Clears the JSON container.
JSON documents inside an RJsonBucket can be a maximum of 512 megabytes. RJsonBucket also implements methods for working with special datatypes, such as arrays and strings. This mirrors the original RedisJSON module, which includes commands such as JSON.ARRAPPEND, JSON.ARRINSERT, and JSON.ARRTRIM (for appending to, inserting to, and trimming an array, respectively).
Redisson automatically handles the task of encoding and decoding JSON data with the codec org.redisson.codec.JacksonCodec. Below is a code example of how to store JSON with Redis in Java using the RJsonBucket interface:
class AnyObject { private String name; private Integer num; private List<String> values; public AnyObject(String name, Integer num) { this.name = name; this.num = num; } public getName() { return name; } public getNum() { return num; } public List<String> getValues() { return values; } } RJsonBucket<AnyObject> bucket = redisson.getJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class)); bucket.set(new AnyObject("Sara", 1)); AnyObject obj = bucket.get(); bucket.trySet(new AnyObject("Connor", 3)); bucket.compareAndSet(new AnyObject("Aviant", 4), new AnyObject("Jack", 5)); bucket.getAndSet(new AnyObject("Michael", 6)); List<String> values = bucket.get(new JacksonCodec<>(new TypeReference<List<String>>() {}), "obj.values"); long arraySize = bucket.arrayAppend("$.obj.values", "t3", "t4");
Redisson allows RJsonBucket to be implemented using a local cache or “near cache,” which can speed up read operations and avoid network round trips. The entire JSON object is cached on the Redisson side, allowing read operations to be executed up to 45 times faster than in the standard RJsonBucket implementation. Local cache instances that have the same name are connected via the same pub/sub channel. The local cache functionality is available with the getJsonBucket and getLocalCachedJsonBucket() functions in Redisson PRO.
Finally, RJsonBucket can be used with the asynchronous, reactive, and RxJava2 programming models. These models require the RJsonBucketAsync, RJsonBucketReactive, and RJsonBucketRx interfaces, respectively.
For example, the code snippet below shows how to use RJsonBucket with the asynchronous programming model. Note how the interface methods also change to denote that we are using the async model:
RJsonBucket<AnyObject> bucket = redisson.getJsonBucket("anyObject", new JacksonCodec<>(AnyObject.class)); RFuture<Void> future = bucket.setAsync(new AnyObject(1)); RFuture<AnyObject> objfuture = bucket.getAsync(); RFuture<Boolean> tsFuture = bucket.trySetAsync(new AnyObject(3)); RFuture<Boolean> csFuture = bucket.compareAndSetAsync(new AnyObject(4), new AnyObject(5)); RFuture<AnyObject> gsFuture = bucket.getAndSetAsync(new AnyObject(6)); RFuture<String> gFuture = bucket.getAsync(new JacksonCodec<>(new TypeReference<List<String>>() {}), "obj.values"); RFuture<Long> aaFuture = bucket.arrayAppendAsync("$.obj.values", "t3", "t4");Getting Started With Redisson