Skip to content

Codecs (3.x)

Mark Paluch edited this page Jun 13, 2020 · 2 revisions

❗️Documentation page for Lettuce 3.x. Find the recent documentation for Lettuce 4.x here: Codecs


Codecs are a pluggable mechanism for transcoding keys and values between your application and Redis. The default codec supports UTF-8 encoded String keys and values.

Each connection may have its codec passed to the extended RedisClient.connect methods:

RedisConnection<K, V> connect(RedisCodec<K, V> codec)
RedisAsyncConnection<K, V> connectAsync(RedisCodec<K, V> codec)
RedisPubSubConnection<K, V> connectPubSub(RedisCodec<K, V> codec)

Lettuce ships with two predefined codecs:

  • com.lambdaworks.redis.codec.ByteArrayCodec - use byte[] for keys and values
  • com.lambdaworks.redis.codec.Utf8StringCodec - use Strings for keys and values and convert Strings using UTF-8 to store them within Redis

Publish/Subscribe connections use channel names and patterns for keys, messages are treated as values.

Keys and values can be encoded independently from each other which means the key can be a java.lang.String while the value is a byte[]. Many other constellations are possible like:

  • Representing your data as JSON if your data is mapped to a particular Java type. Different types are hard to map since the codec applies to all operations.
  • Serialize your data using the Java Serializer (ObjectInputStream/ObjectOutputStream). Allows type-safe conversions but is less interoperable with other languages
  • Serializing your data using Kryo for improved type-safe serialization.
  • Any specialized codecs like the BitStringCodec (see below)

Diversity in Codecs

Like in every other segment of technology, there is no one-fits-it-all solution when it comes to Codecs. Redis data structures provide a variety of The key and value limitation of codecs is intentionally and a balance amongst convenience and simplicity. The Redis API allows much more variance in encoding and decoding particular data elements. A good example is Redis hashes. A hash is identified by its key but stores another key/value pairs. The keys of the key-value pairs could be encoded using a different approach than the key of the hash. Another different approach might be to use different encodings between lists and sets. Using a base codec (such as UTF-8 or byte array) and performing an own conversion on top of the base codec is often the better idea.

Multi-Threading

A key point in Codecs is that Codecs are shared resources and can be used by multiple threads. Your Codec needs to be thread-safe (by shared-nothing, pooling or synchronization). Every logical Lettuce connection uses its codec instance. Codec instances are shared as soon as multiple threads are issuing commands or if you use Redis Cluster.

Examples

BitString codec

public class BitStringCodec extends Utf8StringCodec {
    @Override
    public String decodeValue(ByteBuffer bytes) {
        StringBuilder bits = new StringBuilder(bytes.remaining() * 8);
        while (bytes.remaining() > 0) {
            byte b = bytes.get();
            for (int i = 0; i < 8; i++) {
                bits.append(Integer.valueOf(b >>> i & 1));
            }
        }
        return bits.toString();
    }
}

RedisConnection<String, String> redis = client.connect(new BitStringCodec());

redis.setbit(key, 0, 1);
redis.setbit(key, 1, 1);
redis.setbit(key, 2, 0);
redis.setbit(key, 3, 0);
redis.setbit(key, 4, 0);
redis.setbit(key, 5, 1);

redis.get(key) == "00100011"

Java serialized object

public class SerializedObjectCodec extends RedisCodec<String, Object> {
    private Charset charset = Charset.forName("UTF-8");

    @Override
    public String decodeKey(ByteBuffer bytes) {
        return charset.decode(bytes).toString();
    }

    @Override
    public Object decodeValue(ByteBuffer bytes) {
        try {
            byte[] array = new byte[bytes.remaining()];
            bytes.get(array);
            ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(array));
            return is.readObject();
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public byte[] encodeKey(String key) {
        return charset.encode(key).array();
    }

    @Override
    public byte[] encodeValue(Object value) {
        try {
            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
            ObjectOutputStream os = new ObjectOutputStream(bytes);
            os.writeObject(value);
            return bytes.toByteArray();
        } catch (IOException e) {
            return null;
        }
    }
}
Clone this wiki locally