为什么Jackson redis serializer启用 USE_LONG_FOR_INTS 不起作用?

我最近才知道Jackson通过开启配置USE_LONG_FOR_INTS可以将整型数据默认转换为Long类型,于是我将我的redisTemplate配置如下:

    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory)
    {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        ObjectMapper objectMapper = new ObjectMapper();
        // 开启默认转换Long类型配置
        objectMapper.enable(DeserializationFeature.USE_LONG_FOR_INTS);

        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());

        template.setDefaultSerializer(jackson2JsonRedisSerializer);

        return template;
    }

但是并没有像我预想的一样:

    @Test
    void test() throws JsonProcessingException {
        redisTemplate.opsForValue().set("key", 11);
        System.out.println(redisTemplate.opsForValue().get("key").getClass());
    }

上面测试代码会打印Integer而非Long。

我仔细跟踪了下源码,发现大概是因为反序列化时执行的是这个函数com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer.Vanilla#deserializeWithType,这个函数中并没有判断当前是否开启了USE_LONG_FOR_INTS,只会判断是否开启了USE_BIG_INTEGER_FOR_INTS

我想知道咋样才能让Jackson默认返回Long类型,还是说没有办法了,只能写一个工具类每个取到返回值时自己做类型转换。

阅读 2.7k
2 个回答

你可以创建一个自定义的反序列化器,然后在反序列化时将整数值转换为 Long 类型。

public class CustomDeserializer extends JsonDeserializer<Object> {
    private final UntypedObjectDeserializer delegate;

    public CustomDeserializer() {
        this.delegate = new UntypedObjectDeserializer(null, null);
    }

    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        Object value = delegate.deserialize(p, ctxt);
        if (value instanceof Integer) {
            return ((Integer) value).longValue();
        }
        return value;
    }
}

然后把你创建的自定义反序列化器添加到 Jackson 的配置中:


@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(connectionFactory);

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new SimpleModule().addDeserializer(Object.class, new CustomDeserializer()));

    Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
    jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

    template.setKeySerializer(RedisSerializer.string());
    template.setHashKeySerializer(RedisSerializer.string());

    template.setDefaultSerializer(jackson2JsonRedisSerializer);

    return template;
}

我测了下 这样是可以的

@Configuration
public class Redis {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @PostConstruct
    public void init() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 开启默认转换Long类型配置
        objectMapper.enable(DeserializationFeature.USE_LONG_FOR_INTS);

        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题