Noel
Noel

Reputation: 83

How to serialize Java Instant type using redis

I'm using spring boot 2.0.3 and spring-boot-starter-data-redis. Also using jackson-datatype-jsr310.

I want to store Object into redis.

the object(MyObj):

String text;
Instant instant;

Here's my code:

@Test
public void test() {

    ListOperations<String, MyObj> listOps = redisTemplate.opsForList();

    MyObj o1 = new MyObj();
    o1.setText("foo");
    o1.setInstant(Instant.now());

    listOps.leftPush("foo", o1);

    MyObj o2 = new MyObj();
    o2.setText("bar");
    o2.setInstant(Instant.now());

    listOps.leftPush("foo", o2);

    List<MyObj> list = listOps.range("foo", 0, -1);

    for (MyObj o : list) {
        System.out.println(o.getText());
        System.out.println(o.getInstant());
    }

}

in my RedisConfig:

redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

But when I'm pushing into redis, the error occurs below:

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of java.time.Instant (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

How to serialize java instant type with Redis?

Any opinion would be appreciated.

Upvotes: 5

Views: 2431

Answers (1)

Jeffrey Wills
Jeffrey Wills

Reputation: 1

While this is quite an old post, I ran into this problem recently and did the lazy man search and found this before deciding to read the class file. I found that you can easily override the default ObjectMapper with a custom one. Use the setObjectMapper(ObjectMapper objectMapper) method on the Serializer to override the default.

// Taken from Jackson library
public class Jackson2JsonRedisSerializer<T> implements RedisSerializer<T> {

    public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

    private final JavaType javaType;

    private ObjectMapper objectMapper = new ObjectMapper();
    
    // truncated
    
    public void setObjectMapper(ObjectMapper objectMapper) {

        Assert.notNull(objectMapper, "'objectMapper' must not be null");
        this.objectMapper = objectMapper;
    }


You just need to create an ObjectMapper with the JavaTime.Module registered like below

public static ObjectMapper dateMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        return mapper;

     Jackson2JsonRedisSerializer<MyObj> valueSerializer = new 
         Jackson2JsonRedisSerializer<>(MyObj.class);
     valueSerializer.setObjectMapper(dateMapper());
    }

disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) turns of default behavior.

Upvotes: 0

Related Questions