2

In my test project, I build my cache system by spring-data-redis and jedis. And the valueSerializer of RedisTemplate is GenericJackson2JsonRedisSerializer. But here is a question, when I range a list from cache of type java.lang.Long, there is an java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long. Anyone knows the reason, it confused me a long time;

Redis config detail is as below:

<bean id="objRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="redisConnectionFactory" />
    <property name="keySerializer">
        <bean
            class="org.springframework.data.redis.serializer.StringRedisSerializer" />
    </property>
    <property name="valueSerializer">
        <bean
            class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
    </property>
</bean>

Code detail is as below:

public List<Long> findByProductId(Long productId) {
    String key = ThemeRedisKeyGenerator.genProductThemeKey(productId);
    List<Long> themeIdList = redisService.range(key, Long.class);
    if (themeIdList == null) {
        themeIdList = themeProductMapper
                .selectThemeIdByProductId(productId);
        if (!redisService.containKey(key)) {
            redisService.rightPush(key,
                    ThemeRedisKeyGenerator.PRODUCT_THEME_KEY_EXPIRE_HOURS,
                    TimeUnit.HOURS, themeIdList.toArray());
        }
    }
    return themeIdList;
}

And redis service method is as below:

public <T> List<T> range(String key, Class<T> clazz) {
    return range(key, 0L, -1L, clazz);
}
public <T> List<T> range(String key, Long start, Long end, Class<T> clazz) {
    if (StringUtil.isEmpty(key) || !objRedisTemplate.hasKey(key)) {
        return null;
    }

    if (start < 0) {
        start = 0L;
    }

    List<T> list = (List<T>) (objRedisTemplate.opsForList().range(key,
            start, end));

    if(list == null) {
        list = new ArrayList<T>();
    }

    return list;
}

1 Answer 1

9

In short

By default, Jackson returns int when the number is smaller than 231-1

Explanation

JSON is limited in the number of data types. There's also no type information attached:

{
    "number": 42
}

The 42 could be originally a short, int or long, but you can't tell from JSON. The default setting is to use int if the number is smaller than Integer.MAX_INT.

You have multiple options to fix the issue:

  1. Use Number as interface to the data which comes back
  2. Configure the GenericJackson2JsonRedisSerializer by providing a configured ObjectMapper
  3. Use a different serializer that uses type details (such as JdkSerializationRedisSerializer)

You can find more details on JSON deserialization here.

Sign up to request clarification or add additional context in comments.

4 Comments

Cause data is from database big int, so 1st is not capable. Sometimes, I need to check data I redis server, if I use Jdk, the result in redis is meaningless. I don't quite understand the 2nd suggestion, is there any sample?
Number is the super-type of Long, Integer, etc. The quick variant is List<Number> themeIdList = redisService.range(key, Number.class); List<Long> result = new ArrayList<Long>; for(Number n:themeIdList) result.add(n.longValue());
Oh, that's a good idea. I will try it. Thanks! In addition, I found when the number is larger than Integer.MAX_INT, the value will be convert to BigInteger instead of Long. Thanks a lot, you make me think outside of my box.
This helped me: ObjectMapper objectMapper = new ObjectMapper(); objectMapper.enable(DeserializationFeature.USE_LONG_FOR_INTS); GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(objectMapper); RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.