java:jackson 二:Custom Deserialization in Jackson

如果你不相信努力和时光,那么成果就会是第一个选择辜负你的。不要去否定你自己的过去,也不要用你的过去牵扯你现在的努力和对未来的展望。不是因为拥有希望你才去努力,而是去努力了,你才有可能看到希望的光芒。java:jackson 二:Custom Deserialization in Jackson,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

java:jackson 二:Custom Deserialization in Jackson

1 前言

jackson支持自定义反序列化器,参考文档地址如下:

https://www.baeldung.com/jackson

https://www.baeldung.com/jackson-deserialization

依赖如下(这里使用jackson-databind的2.14.1版本):

<properties>
    <jackson.version>2.14.1</jackson.version>
</properties>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${jackson.version}</version>
</dependency>

2 使用

2.1 Standard Deserialization

Let’s start by defining two entities and see how Jackson will deserialize a JSON representation to these entities without any customization:

package com.xiaoxu.test.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.Data;
import lombok.ToString;

/**
 * @author xiaoxu
 * @date 2022-12-22
 * spring_boot:com.xiaoxu.test.jackson.TestCustomizeJackson
 */
public class TestCustomizeJackson {
    private static ObjectMapper objectMapper = new ObjectMapper();
    static {
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
    }

    public static void testStandard() throws Exception{
        Good g = new Good();
        g.setId(1);
        g.setGoodName("苹果");

        VIPUser vipUser = new VIPUser();
        vipUser.setUid(999L);
        vipUser.setUserName("xiaoxu");
        g.setVipUser(vipUser);

        String s = objectMapper.writeValueAsString(g);
        System.out.println(s);
        String msg = "{\n" +
                "  \"id\" : 1,\n" +
                "  \"goodName\" : \"苹果\",\n" +
                "  \"vipUser\" : {\n" +
                "    \"uid\" : 999,\n" +
                "    \"userName\" : \"xiaoxu\"\n" +
                "  }\n" +
                "}";
        Good good = objectMapper.readValue(msg, Good.class);
        System.out.println(good);
    }

    public static void main(String[] args) throws Exception{
        testStandard();
    }
}

@Data
@ToString
class Good{
    public int id;
    public String goodName;
    public VIPUser vipUser;
}

@Data
@ToString
class VIPUser{
    long uid;
    String userName;
}

执行如下:

{
  "id" : 1,
  "goodName" : "苹果",
  "vipUser" : {
    "uid" : 999,
    "userName" : "xiaoxu"
  }
}
Good(id=1, goodName=苹果, vipUser=VIPUser(uid=999, userName=xiaoxu))

上述场景不需要自定义反序列化器

2.2 Custom Deserializer on ObjectMapper

this will of course fail

package com.xiaoxu.test.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

/**
 * @author xiaoxu
 * @date 2022-12-22
 * spring_boot:com.xiaoxu.test.jackson.TestCustomizeJackson2
 */
public class TestCustomizeJackson2 {
    private static ObjectMapper objectMapper = new ObjectMapper();
    static {
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
    }

    public static void testStandard2() throws Exception{
        String msg = "{\n" +
                "  \"id\" : 1,\n" +
                "  \"goodName\" : \"苹果\",\n" +
                "  \"vipUser\" : {\n" +
                "  }\n" +
                "}";
        Good good = objectMapper.readValue(msg, Good.class);
        System.out.println(good);
        /* 将反序列化的字符串的key vipUser 改为  normalUser,
        * 反序列化将报错*/
        String msg2 = "{\n" +
                "  \"id\" : 1,\n" +
                "  \"goodName\" : \"苹果\",\n" +
                "  \"normalUser\" : {\n" +
                "    \"userName\" : \"tellMe\"\n" +
                "  }\n" +
                "}";
        Good good2 = objectMapper.readValue(msg2, Good.class);
        System.out.println(good2);
    }

    public static void main(String[] args) throws Exception{
        testStandard2();
    }
}

执行将报错,因为反序列化的json中含有实体类不存在的属性:

在这里插入图片描述

We’ll solve this by doing our own deserialization with a custom Deserializer:

package com.xiaoxu.test.jackson;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;

import java.io.IOException;

/**
 * @author xiaoxu
 * @date 2022-12-22
 * spring_boot:com.xiaoxu.test.jackson.TestCustomizeJackson2
 */
public class TestCustomizeJackson2 {
    private static ObjectMapper objectMapper = new ObjectMapper();
    static {
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);

        /* 注册自定义的反序列化器 */
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addDeserializer(Good.class, new GoodDeserializer());
        objectMapper.registerModule(simpleModule);
    }

    public static void testStandard2() throws Exception{
        String msg = "{\n" +
                "  \"id\" : 1,\n" +
                "  \"goodName\" : \"苹果\",\n" +
                "  \"vipUser\" : {\n" +
                "  }\n" +
                "}";
        Good good = objectMapper.readValue(msg, Good.class);
        System.out.println("实体类:"+good+"\n");
        /* 将反序列化的字符串的key vipUser 改为  normalUser,
        * 反序列化将报错*/
        String msg2 = "{\n" +
                "  \"id\" : 1,\n" +
                "  \"goodName\" : \"苹果\",\n" +
                "  \"normalUser\" : {\n" +
                "    \"userName\" : \"tellMe\"\n" +
                "  }\n" +
                "}";
        Good good2 = objectMapper.readValue(msg2, Good.class);
        System.out.println("实体类2:"+good2+"\n");
    }

    public static void main(String[] args) throws Exception{
        testStandard2();
    }
}


class GoodDeserializer extends StdDeserializer<Good>{

    protected GoodDeserializer(){
        this(null);
    }

    protected GoodDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public Good deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
        JsonNode jNode = jsonParser.getCodec().readTree(jsonParser);
        System.out.println("node: "+jNode);

        int id = jNode.get("id").intValue();
        String goodName = jNode.get("goodName").asText();
        JsonNode normalUser = jNode.get("normalUser");

        Good good = new Good();
        good.setId(id);
        good.setGoodName(goodName);
        good.setVipUser(null);
        if(null != normalUser){
            String normalUserName = jNode.get("normalUser").get("userName").asText();

            VIPUser vipUser = new VIPUser();
            vipUser.setUid(1000000L);
            vipUser.setUserName(normalUserName);
            good.setVipUser(vipUser);
            return good;
        }

        return good;
    }
}

执行自定义反序列化器,结果如下:

node: {"id":1,"goodName":"苹果","vipUser":{}}
实体类:Good(id=1, goodName=苹果, vipUser=null)

node: {"id":1,"goodName":"苹果","normalUser":{"userName":"tellMe"}}
实体类2Good(id=1, goodName=苹果, vipUser=VIPUser(uid=1000000, userName=tellMe))

2.3 Custom Deserializer on the Class

区别于2.2的全部配置,可使用注解单独配置。

Alternatively, we can also register the deserializer directly on the class:

在这里插入图片描述
在这里插入图片描述

再次执行效果一致:

在这里插入图片描述

2.4 Custom Deserializer for a Generic Type

Let’s now create a Wrapper class that only contains a unique argument of the generic type T,The User attribute of our Item will now be of type Wrapper< User > instead.

Let’s implement a custom deserializer for this case.

First, we need to implement the ContextualDeserializer interface so that we’ll be able to get the type of the entity inside the Wrapper. We’ll do this by overriding the createContextual() method. When this method is called, the context is resolved and the actual content of the Wrapper can be retrieved via the BeanProperty argument.

We also have to extend JsonDeserializer. Thus, we can set the concrete type of the Wrapper‘s value inside deserialize():

package com.xiaoxu.test.jackson;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import lombok.Data;
import lombok.ToString;

import java.io.IOException;
import java.lang.annotation.*;

/**
 * @author xiaoxu
 * @date 2022-12-22
 * spring_boot:com.xiaoxu.test.jackson.TestCustomizeJackson3
 */
public class TestCustomizeJackson3 {

    private static ObjectMapper objectMapper = new ObjectMapper();
    static {
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);

        /* 注册自定义的序列化器、反序列化器 */
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addDeserializer(WrapClazz.class, new WrapperDeserializer());
        simpleModule.addSerializer(WrapClazz.class, new WrapperSerializer());
        objectMapper.registerModule(simpleModule);
    }

    public static String buildDto() throws JsonProcessingException {
        WrapGood wrapGood = new WrapGood();
        wrapGood.setId(111);
        wrapGood.setGoodName("美味的东西");

        NorUser norUser = new NorUser();
        norUser.setUid(555L);
        norUser.setUserName("xiaoxu");

        WrapClazz<NorUser> wrapClazz = new WrapClazz<>();
        wrapClazz.setVal(norUser);

        wrapGood.setNorUserWrapClazz(wrapClazz);

        /* 因为注册了自定义的序列化器,针对 WrapGood 的 NorUserWrapClazz,
        * 将会精确实施序列化  */
        String s = objectMapper.writeValueAsString(wrapGood);
        System.out.println("序列化的json数据:");
        System.out.println(s);
        return s;
    }

    public static void testCustomizeDeserializer() throws JsonProcessingException {
        String s = buildDto();
        WrapGood wrapGood = objectMapper.readValue(s, WrapGood.class);
        System.out.println("反序列化实体类结果:");
        System.out.println(wrapGood);
        WrapClazz<NorUser> norUserWrapClazz = wrapGood.getNorUserWrapClazz();
        System.out.println(norUserWrapClazz);
    }

    public static void main(String[] args) throws JsonProcessingException {
        testCustomizeDeserializer();
    }
}

/* 自定义序列化器 */
@SuppressWarnings(value = "rawtypes")
class WrapperSerializer extends JsonSerializer<WrapClazz> implements ContextualSerializer {

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        JavaType type = beanProperty.getType();
        System.out.println("序列化type:"+type);
        return this;
    }

    @Override
    public void serialize(WrapClazz wrapClazz, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        System.out.println("自定义序列化:");
        WrapClazz<NorUser> norUserWrapClazz = new WrapClazz<>();
        NorUser norUser = new NorUser();
        norUser.setUid(666L);
        norUser.setUserName("xiaoxuya");
        norUserWrapClazz.setVal(norUser);

        /* 序列化1: */
//        jsonGenerator.writeStartObject();
//        jsonGenerator.writeObjectField("xiaoxu",norUser);
//        jsonGenerator.writeEndObject();

        /* 序列化2:对于泛型对象的序列化,直接使用writeObject,就可以直接写入对象,序列化出来的json,将没有泛型的val这个key */
        jsonGenerator.writeObject(norUser);
    }
}

/* 自定义反序列化器 */
class WrapperDeserializer extends JsonDeserializer<WrapClazz<?>> implements ContextualDeserializer{
//    protected WrapperDeserializer(){
//        super();
//    }

    private JavaType javaType;

    @Override
    public WrapClazz<?> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
        System.out.println("当前的类型:"+this.javaType);
        WrapClazz<?> wrapClazz = new WrapClazz<>();
        wrapClazz.setVal(deserializationContext.readValue(jsonParser, this.javaType));
        return wrapClazz;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext deserializationContext, BeanProperty beanProperty) throws JsonMappingException {
        System.out.println("BeanProperty:"+beanProperty);

        /* 获取 WrapGood实体类的 WrapClazz<NorUser> norUserWrapClazz 属性的注解*/
        TestMe annotation = beanProperty.getAnnotation(TestMe.class);
        if(null != annotation){
            System.out.println(annotation.value());
        }
        JavaType javaType = beanProperty.getType().containedType(0);
        System.out.println("反序列化type:"+javaType);
        this.javaType = javaType;
        return this;
    }
}

@ToString
class WrapClazz<T> {
    T val;

    public T getVal(){
        return val;
    }

    public void setVal(T val){
        this.val = val;
    }
}

@Data
@ToString
class WrapGood{
    public int id;
    public String goodName;
    @TestMe
    WrapClazz<NorUser> norUserWrapClazz;
}

@Data
@ToString
class NorUser{
    long uid;
    String userName;
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface TestMe{
    String value() default "9999";
}

执行结果如下:

序列化type:[simple type, class com.xiaoxu.test.jackson.WrapClazz<com.xiaoxu.test.jackson.NorUser>]
自定义序列化:
序列化的json数据:
{
  "id" : 111,
  "goodName" : "美味的东西",
  "norUserWrapClazz" : {
    "uid" : 666,
    "userName" : "xiaoxuya"
  }
}
BeanProperty:[property 'norUserWrapClazz']
9999
反序列化type:[simple type, class com.xiaoxu.test.jackson.NorUser]
当前的类型:[simple type, class com.xiaoxu.test.jackson.NorUser]
反序列化实体类结果:
WrapGood(id=111, goodName=美味的东西, norUserWrapClazz=WrapClazz(val=NorUser(uid=666, userName=xiaoxuya)))
WrapClazz(val=NorUser(uid=666, userName=xiaoxuya))

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/192102.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!