0

I found that the annotation @Cacheable cannot work when the method returns a Java Bean type, this is the complete description:

  1. I annotated @Cacheable on a method to use spring cache:
@Cacheable(cacheNames="userCache", key="#userId")
public User getUser(long userId){
    return userRepository.getUserById(userId);
}

And the User class like this:

public class User{
    Long userId;
    String username;
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime birthDateTime;
}

As you can see, I annotated the relating Jackson annotations to make Jackson deserialization for LocalDateTime types work, and this is the related dependency in pom.xml:

        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>2.12.5</version>
        </dependency>
  1. After that, I call the @Cacheable method getUser like this:
User user = userCache.getUser(1L);

and there throws an exception:

org.redisson.client.RedisException: Unexpected exception while processing command at org.redisson.command.CommandAsyncService.convertException(CommandAsyncService.java:326) at org.redisson.command.CommandAsyncService.get(CommandAsyncService.java:123) at org.redisson.RedissonObject.get(RedissonObject.java:82) ...blabla Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type java.time.LocalDateTime not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 101] (through reference chain: com.stackoverflow.domain.User["birthDateTime"]) at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1764) at com.fasterxml.jackson.databind.deser.impl.UnsupportedTypeDeserializer.deserialize(UnsupportedTypeDeserializer.java:36) at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)

3.Before I use the @Cacheable, there is no problem if I get the User from database straightly. But when I begin to use @Cacheable, it always throws the exception above, no matter if I configured those Jackson deserialization for LocalDateTime. Is @Cacheable cannot work well with Java Bean with LocalDateTime property, or just my configuration of Jackson is wrong?

  • By the way, the CacheManager is Redis, as is shown in the exception – when can we play ORI3 Dec 24 '21 at 04:02
  • Welcome to Stack Overflow. From the message the problem seems related to the redisson configuration not including the javatime module, and this seems confirmed by the fact that you can deserialize `LocalDateTime` without problems in your spring project. I don't know redis but I think you have to check if you can add the javatimemodule to its configuration. – dariosicily Dec 25 '21 at 11:26
  • thank you for your comment, I'll check it – when can we play ORI3 Dec 27 '21 at 04:12
  • Right, _Spring's Cache Abstraction_ (for example when using the `@Cacheable` annotation) does not handle any form of serialization of the cache entry to and from the caching provider. That is all caching provider configuration specific. Spring caching is just the "messenger". – John Blum Feb 09 '22 at 21:55

1 Answers1

1

I had the same problem. Spring Cache doesn't use the implicit ObjectMapper used by other Spring components.

  1. Include the module, you already did that.
  2. Create a configuration which will override the default Spring Cache Configuration:
@Configuration
@EnableCaching
public class CacheConfiguration {
    @Bean
    public RedisSerializationContext.SerializationPair<Object> serializationPair() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule())
            .activateDefaultTyping(
                objectMapper.getPolymorphicTypeValidator(),
                ObjectMapper.DefaultTyping.EVERYTHING,
                JsonTypeInfo.As.PROPERTY
            );
        return RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper));
    }

    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(
        @Value("${cache.default-ttl-in-seconds}") Integer ttl,
        RedisSerializationContext.SerializationPair<Object> serializationPair
    ) {
        return RedisCacheConfiguration.defaultCacheConfig()
            .disableCachingNullValues()
            .entryTtl(Duration.ofSeconds(ttl))
            .serializeValuesWith(serializationPair);
    }
}
robi
  • 113
  • 8