借助Jackson的JsonTypeInfo注解实现抽象类的序列化和反序列化

一、问题背景

Jackson框架对json字段的序列化和反序列化默认策略是根据getter和setter方法,去掉get和set,再把首字母小写,便找到了对应的字段。通常情况,我们都是对普通的POJO进行serialization/deserialization。那么如果遇到了解析抽象类呢?如何定位到对应的实现类?实现类都找不到,谈何匹配到对应的字段反序列化。

二、JsonTypeInfo 注解简单介绍

作用于类或接口,被用来处理多态类型的序列化及反序列化。

This is necessarily for polymorphic types, and may also be needed to link abstract declared types and matching concrete implementation.

三、demo

抽象类

package jackson;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Data;

@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
@JsonSubTypes({@JsonSubTypes.Type(value = InputPageModel.class, name = "input")
                      , @JsonSubTypes.Type(value = NumberPageModel.class, name = "number")})
public abstract class PageModel {

    private String type;
    private String name;
    private String uiType;
    private String label;
}

注解里的visible字段:如果为false,那么反序列化时,类型id字段(这里是type字段)的值将不会被反序列化到POJO中。

实现类1

package jackson;

import lombok.Data;

@Data
public class InputPageModel extends PageModel {

    private String input;
}

实现类2

package jackson;

import lombok.Data;

@Data
public class NumberPageModel extends PageModel {

    private Integer number;
}

测试类

package jackson;

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

import java.io.IOException;

public class JsonTypeInfoTest {

    public static void main(String[] args) {
        String inputJson = " {\n" +
                "        \"type\": \"input\",\n" +
                "        \"label\": \"标题\",\n" +
                "        \"uiType\": \"input\",\n" +
                "        \"input\" : \"lvsheng\"\n" +
                "        \n" +
                "      }";
        ObjectMapper mapper = new ObjectMapper();
        try {
            InputPageModel inputPageModel = mapper.readValue(inputJson, InputPageModel.class);
            System.out.println(inputPageModel.getInput());
        } catch (IOException e) {
            e.printStackTrace();
        }

        String numberJson = " {\n" +
                "        \"type\": \"number\",\n" +
                "        \"label\": \"价格\",\n" +
                "        \"uiType\": \"input\",\n" +
                "        \"number\" : 110\n" +
                "        \n" +
                "      }";
        try {
            NumberPageModel inputPageModel = mapper.readValue(numberJson, NumberPageModel.class);
            System.out.println(inputPageModel.getNumber());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

测试类输出

lvsheng
110

四、 优化

这个demo里JsonTypeInfo借助JsonSubTypes注解来感知抽象类的有哪些实现类,并且是如何匹配的。如果子类很多,那么JsonSubTypes注解就十分臃肿了。而且这种写法是违反开闭原则的。有两种方式可以将JsonSubTypes剔除掉,达到相同的效果。

1. 注解方式

使用JsonTypeName注解

package jackson;

import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Data;

@Data
@JsonTypeName(value = "input")
public class InputPageModel extends PageModel {

    private String input;
}

2. 非注解, api方式

ObjectMapper提供手工注册的方法

public void registerSubtypes(NamedType... types) {
        getSubtypeResolver().registerSubtypes(types);
}

NamedType 有两个参数,一个是类的class对象,另一个是匹配子类的字段名。

猜你喜欢

转载自blog.csdn.net/bruce128/article/details/80298808