Sviatlana
Sviatlana

Reputation: 1888

Redis caching Map<Integer, String>

I an using redis cache and faced the problem: map with integer key is serialized as String like this:

 "1":"AAAA","2":"BBB","3":"CCC"

This is how my config looks like:

@Bean
    public RedisCacheConfiguration myCacheConfiguration()
    {
        return RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ZERO)
                .disableCachingNullValues()
                .serializeValuesWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(new Jackson2JsonRedisSerializer<>(Map.class)));
    }

  @Bean
    public CacheManager myCacheManager(RedisConnectionFactory redisConnectionFactory)
    {
        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(myCacheConfiguration())
                .transactionAware()
                .build();
    }

I tried to pass GenericJackson2JsonRedisSerializer to serializeValuesWith(), but is doesn't work. Is there any way to serialize\deserialize Integer keys of map as number?

Upvotes: 0

Views: 4014

Answers (2)

Sviatlana
Sviatlana

Reputation: 1888

The issue is easily solved by adding overriding of method JavaType getJavaType(Class clazz) in Jackson2JsonRedisSerializer. Documentation says:

/**
     * Returns the Jackson {@link JavaType} for the specific class.
     * <p>
     * Default implementation returns {@link TypeFactory#constructType(java.lang.reflect.Type)}, but this can be
     * overridden in subclasses, to allow for custom generic collection handling. For instance:
     *
     * <pre class="code">
     * protected JavaType getJavaType(Class&lt;?&gt; clazz) {
     *  if (List.class.isAssignableFrom(clazz)) {
     *      return TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, MyBean.class);
     *  } else {
     *      return super.getJavaType(clazz);
     *  }
     * }
     * </pre>
     *
     * @param clazz the class to return the java type for
     * @return the java type
     */
    protected JavaType getJavaType(Class<?> clazz) {
        return TypeFactory.defaultInstance().constructType(clazz);
    }

So, I just overriding this method like this:

public class CustomSerializer extends Jackson2JsonRedisSerializer
{
    public JurisdictionsSerializer(Class type)
    {
        super(type);
    }


    @Override
    protected JavaType getJavaType(Class clazz)
    {
        return TypeFactory.defaultInstance()
                .constructMapType(Map.class, Integer.class, String.class);
    }
}

And then add this serializer to redis configuration like this:

@Bean
    public RedisCacheConfiguration myCacheConfiguration()
    {
        return RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ZERO)
                .disableCachingNullValues()
                .serializeValuesWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(new CustomSerializer(Map.class)));
    }

Upvotes: 0

devmind
devmind

Reputation: 364

Jackson2JsonRedisSerializer and GenericJackson2JsonRedisSerializer both allow to use custom ObjectMapper.

No familiar with Redis, but seems that's designed way for custom serialization according to the doc:

Setting a custom-configured ObjectMapper is one way to take further control of the JSON serialization process. For example, an extended SerializerFactory can be configured that provides custom serializers for specific types. The other option for refining the serialization process is to use Jackson's provided annotations on the types to be serialized, in which case a custom-configured ObjectMapper is unnecessary.

Upvotes: 1

Related Questions