Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Caching Java 8 Optional with Spring Cache

I have a method:

@Cacheable(key = "#jobId")
public Optional<JobInfo> getJobById(String jobId) {
    log.info("Querying for job " + jobId);
    counterService.increment("queryJobById");
    Job job = jobsRepository.findOne(jobId);
    if (job != null) {
        return Optional.of(createDTOFromJob(job));
    }
    return Optional.empty();
}

When I am trying to retrieve the cached item I am getting the following exception:

2016-01-18 00:01:10 ERROR [trace=,span=] http-nio-8021-exec-2 [dispatcherServlet]:182 - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [java.util.Optional]] with root cause java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [java.util.Optional]

like image 366
Roi Ezra Avatar asked Jan 17 '16 22:01

Roi Ezra


People also ask

How do you caching in spring?

If we want to enable a cache mechanism in a Spring Boot application, we need to add cache dependency in the pom. xml file. It enables caching and configures a CacheManager.

How do I enable caching in spring boot?

To enable the Spring Boot caching feature, you need to add the @EnableCaching annotation to any of your classes annotated with @Configuration or to the boot application class annotated with @SpringBootApplication .


2 Answers

Just implement the Serializable interface in your DTO

@Document(collection = "document_name")
public class Document implements Serializable {

    private static final long serialVersionUID = 7156526077883281623L;
like image 102
Ishan Ojha Avatar answered Oct 24 '22 01:10

Ishan Ojha


Spring supports caching Optional. The issue is your Redis serializer (JdkSerializationRedisSerializer probably). It uses Java based serialization which requires the classes to be Serializable. You can solve this by configuring the RedisCacheManager to use another serializer that doesn't have this limitation. For example you can use Kryo (com.esotericsoftware:kryo:3.0.3):

@Bean
RedisCacheManager redisCacheManager (RedisTemplate<Object, Object> redisOperations) {
    // redisOperations will be injected if it is configured as a bean or create it: new RedisTemplate()...
    redisOperations.setDefaultSerializer(new RedisSerializer<Object>() {
        //use a pool because kryo instances are not thread safe
        KryoPool kryoPool = new KryoPool.Builder(Kryo::new).build();

        @Override
        public byte[] serialize(Object o) throws SerializationException {
            ByteBufferOutput output = new ByteBufferOutput();
            Kryo kryo = kryoPool.borrow();
            try {
                kryo.writeClassAndObject(output, o);
            } finally {
                kryoPool.release(kryo);
                output.close();
            }

            return output.toBytes();
        }

        @Override
        public Object deserialize(byte[] bytes) throws SerializationException {
            if(bytes.length == 0) return null;

            Kryo kryo = kryoPool.borrow();
            Object o;
            try {
                o = kryo.readClassAndObject(new ByteBufferInput(bytes));
            } finally {
                kryoPool.release(kryo);
            }
            return o;
        }
    });

    RedisCacheManager redisCacheManager = new RedisCacheManager(redisOperations);
    redisCacheManager.setCachePrefix(new DefaultRedisCachePrefix("app"));
    redisCacheManager.setTransactionAware(true);
    return redisCacheManager;
}

Note that this is just an example, I didn't test this imeplementation. But I use the Kryo serializer in production in the same manner for redis caching with Spring.

like image 22
Cyril Avatar answered Oct 23 '22 23:10

Cyril