Redis - How to configure custom conversions
Asked Answered
P

5

12

In spring-data-redis, How do we need configure custom converters that can be auto-wired/injected from Spring boot application or configuration.

I read about @ReadingConverter and @WritingConverter from spring data redis documentation. From this documentation, it is not clear on how to configure them. https://github.com/spring-projects/spring-data-redis/blob/master/src/main/asciidoc/reference/redis-repositories.adoc#redis.repositories.indexes

Does anyone know how to do it?

Pritchett answered 20/3, 2017 at 23:5 Comment(0)
I
14

Tested with spring-boot-starter-data-redis:2.0.4.RELEASE.

I was facing a problem where my OffsetDateTime properties of my @RedisHash entity were not being stored when using CrudRepository.

The problem was that Jsr310Converters does not have a converter of OffsetDateTime.

To solve this, I created a reading converter:

@Component
@ReadingConverter
public class BytesToOffsetDateTimeConverter implements Converter<byte[], OffsetDateTime> {
    @Override
    public OffsetDateTime convert(final byte[] source) {
        return OffsetDateTime.parse(new String(source), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
    }
}

and writing converter:

@Component
@WritingConverter
public class OffsetDateTimeToBytesConverter implements Converter<OffsetDateTime, byte[]> {
    @Override
    public byte[] convert(final OffsetDateTime source) {
        return source.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME).getBytes();
    }
}

And registered a RedisCustomConversions bean in the configuration:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.convert.RedisCustomConversions;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;

import java.util.Arrays;

@Configuration
@EnableRedisRepositories
public class RedisConfiguration {

    @Bean
    public RedisCustomConversions redisCustomConversions(OffsetDateTimeToBytesConverter offsetToBytes,
                                                         BytesToOffsetDateTimeConverter bytesToOffset) {
        return new RedisCustomConversions(Arrays.asList(offsetToBytes, bytesToOffset));
    }

}
Incogitable answered 12/9, 2018 at 11:14 Comment(0)
K
12

You have to declare CustomConversions bean named "redisCustomConversions" in your application configuration.

@Bean
public CustomConversions redisCustomConversions(){
    return new CustomConversions(Arrays.asList(new YourWritingConverter(), new YourReadingConverter()));
}
Kroo answered 22/3, 2017 at 19:9 Comment(3)
Thanks Mikhail for taking time to respond to my question. I am using @RedisHash. Your solution doesn't seem to work even though the bean gets initialized.Pritchett
I use @RedisHash as well and this works perfectly for me. JFYI it's Spring 4.3.7 and spring-data-redis 1.8.1. I can't guarantee that this or any other approach will work with other versions.Kroo
As indicated in CustomConversions, this class is deprecated. since 2.0, use RedisCustomConversions.Snoddy
P
1

These code may help anyone. Thanks @Mikhail

@Component
public class RedisObjectHelper {

    @Resource
    private RedisTemplate<String, ?> redisTemplate;
    private HashOperations<String, byte[], byte[]> hashOperations;
    private HashMapper<Object, byte[], byte[]> mapper;

    @PostConstruct
    public void init() {
        mapper = new ObjectHashMapper(new CustomConversions(Arrays.asList(new Timestamp2ByteConverter(), new Byte2TimestampConverter())));
        hashOperations = redisTemplate.opsForHash();
    }
    // and any methods
}

tested with spring-data-redis-1.8.4.RELEASE

Paratyphoid answered 25/7, 2017 at 12:39 Comment(0)
N
0

Try to implement this way.

import java.sql.Timestamp;

import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.stereotype.Component;


@Component
@ReadingConverter
public class BytesToDateConverter implements Converter<byte[], Timestamp> {
    @Override
    public Timestamp convert(final byte[] source) {
        String value = new String(source);
        return new Timestamp(Long.parseLong(value));
    }
}

and resister to the Bean.

@Bean
    public MappingRedisConverter redisConverter(RedisMappingContext mappingContext,
            RedisCustomConversions customConversions, ReferenceResolver referenceResolver) {

         MappingRedisConverter mappingRedisConverter = new MappingRedisConverter(mappingContext, null, referenceResolver,
                    customTypeMapper());
        mappingRedisConverter.setCustomConversions(redisCustomConversions());
        return mappingRedisConverter;
    }
    
    @Bean
    public RedisTypeMapper customTypeMapper() {
        return new CustomRedisTypeMapper();
    }
    
    public RedisCustomConversions redisCustomConversions() {
        return new RedisCustomConversions(
                Arrays.asList(new OffsetDateTimeToBytesConverter(), new BytesToOffsetDateTimeConverter(),new BytesToDateConverter()));
    }
     
    class CustomRedisTypeMapper extends DefaultRedisTypeMapper {

    }
Novellanovello answered 27/10, 2020 at 13:42 Comment(0)
C
0

I had the same problem converting Bytes to Timestamp, what worked for me was the following:

@Component @ReadingConverter public class CustomReadingTimestampConverter implements Converter<byte[], Timestamp> { @Override public Timestamp convert(final byte @NonNull [] source) { ByteBuffer buffer = ByteBuffer.wrap(source); long data = buffer.getLong(); return new Timestamp(data); } }

then:

@Component @WritingConverter public class CustomReadingByteConverter implements Converter<Timestamp, byte[]> { @Override public byte[] convert(final Timestamp source) { long timestamp = source.getTime(); ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); buffer.putLong(timestamp); return buffer.array(); } }

Finally, I register the methods in a bean, remember this method goes in the @configuration class

@Bean public RedisCustomConversions redisCustomConversions(CustomReadingTimestampConverter byteToTimestamp, CustomReadingByteConverter timestampToBytes) { return new RedisCustomConversions(Arrays.asList(byteToTimestamp, timestampToBytes)); }

Cheree answered 25/6, 2024 at 14:42 Comment(1)
answer should be properly formattedRefit

© 2022 - 2025 — McMap. All rights reserved.