23

I am using Spring Redis support to save my objects in Redis.

I have several DAOs which handle different Model classes:

For example, ShopperHistoryDao save/retrieve objects of ShopperHistoryModel, ShopperItemHistoryDao save/retrieve objects of ItemHistoryModel.

I want to use JacksonJsonRedisSerializer to serialise/deserialize my objects to/from json.

But in the constructor of JacksonJsonRedisSerializer, it takes one specific Model class.

JacksonJsonRedisSerializer(Class<T> type)

Does that mean, I have to configure separate RedisTemplates for each different Model class and use them in appropriate DAO implementation?

Something like:

<bean id="redisTemplateForShopperHistoryModel" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory" />
    <property name="valueSerializer">
        <bean id="redisJsonSerializer" 
                        class="org.springframework.data.redis.serializer.JacksonJsonRedisSerializer">
            <constructor-arg type="java.lang.Class" value="ShopperHistoryModel.class"/>
        </bean>   
    </property>
</bean>


<bean id="redisTemplateForItemHistoryModel" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory" />
    <property name="valueSerializer">
        <bean id="redisJsonSerializer" 
                        class="org.springframework.data.redis.serializer.JacksonJsonRedisSerializer">
            <constructor-arg type="java.lang.Class" value="ItemHistoryModel.class"/>
        </bean>   
    </property>
</bean>
Jason Law
  • 965
  • 1
  • 9
  • 21
Ashika Umanga Umagiliya
  • 8,988
  • 28
  • 102
  • 185
  • old, but maybe one can extend `redisJson Serializer` and make the use of `fasterxml.jackson` in order to make it more generic. i.e not forcing it to be bound to a single class definition? – oak Sep 30 '15 at 11:08

3 Answers3

25

GenericJackson2JsonRedisSerializer should do the job

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(jedisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());                                           
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }

This will add @Class property to the JSON to understand the type, which helps Jackson to deserialize, so no need to explicitly map the model on the configuration class.

"{\"@class\":\"com.prnv.model.WhitePaper\",\"title\":\"Hey\",\"author\":{\"@class\":\"com.prnv.model.Author\",\"name\":\"Hello\"},\"description\":\"Description\"}"

In the service you can cache the model using

    @Cacheable(value = "whitePaper", key = "#title")
    public WhitePaper findWhitePaperByTitle(String title) 
    {
        WhitePaper whitePaper = repository.findByTitle(title);
        return whitePaper;
    }

Check this article: http://blog.pranavek.com/2016/12/25/integrating-redis-with-spring-application

Pranav
  • 952
  • 9
  • 20
  • what about public List findWhitePapersByTitle(String title) ?? – Sachin Sharma Sep 28 '17 at 07:40
  • Can you share the source code ? Am getting the following error "Cannot handle managed/back reference 'defaultReference': back reference type (java.util.List) not compatible with managed type " – Vignesh_A Oct 04 '19 at 08:32
5

Yes, the RedisTemplate seems to be designed to have a single instance of the value serializer.

I was going to suggest the possible workaround of having a RedisSerializer which contains a Map of inner serializers so you can use one RedisTemplate with a serializer that can handle multiple types - but since RedisSerializer does not offer methods like boolean canDeserialize(..) (as the HTTP MessageConverters in Spring MVC have) this doesn't seem possible.

So it seems that you are stuck with having multiple RedisTemplate instances.

matt b
  • 138,234
  • 66
  • 282
  • 345
-1

A bit of old thread, but you can do something like this:

<bean id="RedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory" />
    <property name="valueSerializer">
        <bean id="jackson2JsonRedisSerializer" 
                        class="org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer">
            <constructor-arg type="java.lang.Class" value="Object.class" />
        </bean>   
    </property>
</bean>

Then in your Java class

@Autowire
private RedisTemplate redisTemplate;

public void save(Model model) {
    ObjectMapper obmap = new ObjectMapper();
    redisTemplate.opsForHash().putAll(mode.getId(), obmap.convertValue(model, Map.class));
}
Zeta
  • 534
  • 6
  • 17
  • This is an manual to get as string then convert it using an ObjectMapper. You can benefit from Redis serializer like above answer – kidnan1991 May 18 '21 at 10:56