For the latest stable version, please use Spring Data Redis 3.4.0! |
Object-to-Hash Mapping
The Redis Repository support persists Objects to Hashes.
This requires an Object-to-Hash conversion which is done by a RedisConverter
.
The default implementation uses Converter
for mapping property values to and from Redis native byte[]
.
Given the Person
type from the previous sections, the default mapping looks like the following:
_class = org.example.Person (1)
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand (2)
lastname = al’thor
address.city = emond's field (3)
address.country = andor
1 | The _class attribute is included on the root level as well as on any nested interface or abstract types. |
2 | Simple property values are mapped by path. |
3 | Properties of complex types are mapped by their dot path. |
Data Mapping and Type Conversion
This section explains how types are mapped to and from a Hash representation:
Type | Sample | Mapped Value |
---|---|---|
Simple Type |
String firstname = "rand"; |
firstname = "rand" |
Byte array ( |
byte[] image = "rand".getBytes(); |
image = "rand" |
Complex Type |
Address address = new Address("emond’s field"); |
address.city = "emond’s field" |
List |
List<String> nicknames = asList("dragon reborn", "lews therin"); |
nicknames.[0] = "dragon reborn", |
Map |
Map<String, String> atts = asMap({"eye-color", "grey"}, {"… |
atts.[eye-color] = "grey", |
List |
List<Address> addresses = asList(new Address("em… |
addresses.[0].city = "emond’s field", |
Map |
Map<String, Address> addresses = asMap({"home", new Address("em… |
addresses.[home].city = "emond’s field", |
Due to the flat representation structure, Map keys need to be simple types, such as String or Number .
|
Mapping behavior can be customized by registering the corresponding Converter
in RedisCustomConversions
.
Those converters can take care of converting from and to a single byte[]
as well as Map<String, byte[]>
.
The first one is suitable for (for example) converting a complex type to (for example) a binary JSON representation that still uses the default mappings hash structure.
The second option offers full control over the resulting hash.
Writing objects to a Redis hash deletes the content from the hash and re-creates the whole hash, so data that has not been mapped is lost. |
The following example shows two sample byte array converters:
@WritingConverter
public class AddressToBytesConverter implements Converter<Address, byte[]> {
private final Jackson2JsonRedisSerializer<Address> serializer;
public AddressToBytesConverter() {
serializer = new Jackson2JsonRedisSerializer<Address>(Address.class);
serializer.setObjectMapper(new ObjectMapper());
}
@Override
public byte[] convert(Address value) {
return serializer.serialize(value);
}
}
@ReadingConverter
public class BytesToAddressConverter implements Converter<byte[], Address> {
private final Jackson2JsonRedisSerializer<Address> serializer;
public BytesToAddressConverter() {
serializer = new Jackson2JsonRedisSerializer<Address>(Address.class);
serializer.setObjectMapper(new ObjectMapper());
}
@Override
public Address convert(byte[] value) {
return serializer.deserialize(value);
}
}
Using the preceding byte array Converter
produces output similar to the following:
_class = org.example.Person
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand
lastname = al’thor
address = { city : "emond's field", country : "andor" }
The following example shows two examples of Map
converters:
@WritingConverter
public class AddressToMapConverter implements Converter<Address, Map<String, byte[]>> {
@Override
public Map<String, byte[]> convert(Address source) {
return singletonMap("ciudad", source.getCity().getBytes());
}
}
@ReadingConverter
public class MapToAddressConverter implements Converter<Map<String, byte[]>, Address> {
@Override
public Address convert(Map<String, byte[]> source) {
return new Address(new String(source.get("ciudad")));
}
}
Using the preceding Map Converter
produces output similar to the following:
_class = org.example.Person
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand
lastname = al’thor
ciudad = "emond's field"
Custom conversions have no effect on index resolution. Secondary Indexes are still created, even for custom converted types. |
Customizing Type Mapping
If you want to avoid writing the entire Java class name as type information and would rather like to use a key, you can use the @TypeAlias
annotation on the entity class being persisted.
If you need to customize the mapping even more, look at the TypeInformationMapper
interface.
An instance of that interface can be configured at the DefaultRedisTypeMapper
, which can be configured on MappingRedisConverter
.
The following example shows how to define a type alias for an entity:
@TypeAlias
for an entity@TypeAlias("pers")
class Person {
}
The resulting document contains pers
as the value in a _class
field.
Configuring Custom Type Mapping
The following example demonstrates how to configure a custom RedisTypeMapper
in MappingRedisConverter
:
RedisTypeMapper
via Spring Java Configclass CustomRedisTypeMapper extends DefaultRedisTypeMapper {
//implement custom type mapping here
}
@Configuration
class SampleRedisConfiguration {
@Bean
public MappingRedisConverter redisConverter(RedisMappingContext mappingContext,
RedisCustomConversions customConversions, ReferenceResolver referenceResolver) {
MappingRedisConverter mappingRedisConverter = new MappingRedisConverter(mappingContext, null, referenceResolver,
customTypeMapper());
mappingRedisConverter.setCustomConversions(customConversions);
return mappingRedisConverter;
}
@Bean
public RedisTypeMapper customTypeMapper() {
return new CustomRedisTypeMapper();
}
}