GenericJackson2JsonRedisSerializer 反序列化问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_38278330/article/details/82150879

在使用Spring-data-redis 时, 很多文章都推荐使用GenericJackson2JsonRedisSerializer 作为redisTemplate 的序列化执行器,

然而,在遇到类中有 LocalDateTime 等类型时, 反序列化会有问题,大概错误提示为:

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of `java.time.LocalDateTime` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

比如这个类:

存在redis 里面的值大概长这样,可以看到 LocalDateTime的内部字段都当作json数据存起来了,反序列化时肯定找不到

构造器。

解决办法:

1、先添加依赖,(注意:在设置了spring boot的parent的情况下不需要指定具体的版本,也不建议指定某个具体版本)

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310 -->
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>

</dependency>

2、然后我们依赖GenericJackson2JsonRedisSerializer 新写一个类:

package com.example.demoredis.util;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.cache.support.NullValue;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.io.IOException;

public class GenericJackson2JsonRedisSerializerEx implements RedisSerializer<Object> {

    protected GenericJackson2JsonRedisSerializer serializer = null;
    
    public GenericJackson2JsonRedisSerializerEx() {
        ObjectMapper om = new ObjectMapper();
        om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        om.registerModule(new JavaTimeModule());
        om.registerModule((new SimpleModule())
            .addSerializer(new NullValueSerializer()));
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        this.serializer = new GenericJackson2JsonRedisSerializer(om);
    }

    public GenericJackson2JsonRedisSerializerEx(ObjectMapper om) {
        this.serializer = new GenericJackson2JsonRedisSerializer(om);
    }

    @Override
    public byte[] serialize(Object o) throws SerializationException {
        return serializer.serialize(o);
    }

    @Override
    public Object deserialize(byte[] bytes) throws SerializationException {
        return serializer.deserialize(bytes);
    }


    protected class NullValueSerializer extends StdSerializer<NullValue> {
        private static final long serialVersionUID = 1999052150548658807L;
        private final String classIdentifier="@class";

        NullValueSerializer() {
            super(NullValue.class);
        }

        public void serialize(NullValue value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
            jgen.writeStartObject();
            jgen.writeStringField(this.classIdentifier, NullValue.class.getName());
            jgen.writeEndObject();
        }
    }
}

3、最后这么使用:

@Bean
    RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
        def template = new RedisTemplate()
        template.setConnectionFactory(redisConnectionFactory)
        template.setDefaultSerializer(new GenericJackson2JsonRedisSerializerEx())
        template.setEnableDefaultSerializer(true)
        return template
    }

4、运行成功,redis里面的值长这样:

这里不得不吐槽一下GenericJackson2JsonRedisSerializer 的作者,

里面的内部类和域都是private 的,改源码限制颇多,虽然原始类很简单,copy一份源码出来稍加改造就行

但是对于懒人来说,连代码都懒得copy (虽然万不得已还是考了他的内部类,万恶的private)

参考:

https://www.2cto.com/net/201806/755322.html

猜你喜欢

转载自blog.csdn.net/sinat_38278330/article/details/82150879
今日推荐