William Lei
William Lei

Reputation: 68

spring-data-redis java.lang.ClassCastException

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;
}

Upvotes: 2

Views: 9471

Answers (1)

mp911de
mp911de

Reputation: 18119

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.

Upvotes: 9

Related Questions