json 绑定多态

本文探讨了在JSON绑定中处理多子类的需求,重点介绍了两种解决方案:在每个子类中添加数量字段或在父类定义数量字段并由子类继承。通过这两种方式,可以灵活地创建具有不同数据类型(如时间、数值和文本)且数量可变的对象,并讨论了方案二在拓展性和维护性上的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

json 绑定多子类

假设存在如下需求:

  • 自动创建用户指定的数量的多数据类型的数据
  • 用户指定的数量应用于所有数据类型
  • 数据类型包括:时间、数值和文本等
  • 时间类型可指定具体的时间格式(如yyyy-MM-dd,HH:mm:ss yyyy/MM/dd等)、单位(年、月、日、时、分、秒)、最大最小值以及值间隔等内容
  • 数值类型可指定最大最小值和值间隔等
  • 文本无需指定特殊字段

根据需求可得到如下pojo:

  • 时间
// 时间
public class TimeData {
    private final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private final Unit DEFAULT_UNIT = Unit.DAY;
    private final Date DEFAULT_MIN = new Date();

    private String unit;
    private String format;
    private Date min;
    private Date max;
    private Integer step;
}

// 数值
public class IntAmountData {
    private final Integer DEFAULT_MIN = 0;
    private final Integer DEFAULT_MAX = 100;
    private final Integer DEFAULT_STEP = 1;

    private Integer min;
    private Integer max;
    private Integer step;
}

// 文本
public class StringData {

    private final String[] names = {"梦琪", "忆柳", "之桃", "慕青", "问兰", "尔岚", "元香",
            "初夏", "沛菡", "傲珊", "曼文", "乐菱", "痴珊", "恨玉", "惜文", "香寒", "新柔", "语蓉",
            "海安", "夜蓉", "涵柏", "水桃", "醉蓝", "春儿", "语琴", "从彤", "傲晴", "语兰", "又菱"};

关键的地方在于,如何体现出用户指定的数量?

此时有两种解决方案:

  • 方案一:在每种数据类型中添加数量字段
// 时间
public class TimeData {
    private final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private final Unit DEFAULT_UNIT = Unit.DAY;
    private final Date DEFAULT_MIN = new Date();

    private String unit;
    private String format;
    private Date min;
    private Date max;
    private Integer step;
    // 为时间类添加数量字段
    private Integer limit;
}

// 数值
public class IntAmountData {
    private final Integer DEFAULT_MIN = 0;
    private final Integer DEFAULT_MAX = 100;
    private final Integer DEFAULT_STEP = 1;

    private Integer min;
    private Integer max;
    private Integer step;
    // 为数值类添加数量字段
    private Integer limit;
}

// 文本
public class StringData {
    private final String[] names = {"梦琪", "忆柳", "之桃", "慕青", "问兰", "尔岚", "元香",
            "初夏", "沛菡", "傲珊", "曼文", "乐菱", "痴珊", "恨玉", "惜文", "香寒", "新柔", "语蓉",
            "海安", "夜蓉", "涵柏", "水桃", "醉蓝", "春儿", "语琴", "从彤", "傲晴", "语兰", "又菱"};
    // 为文本类添加数量字段
    private Integer limit;
}

此方案下的json请求如下:

curl -XPOST '/create' -d '
{
    "timeData": {
        "unit": "",
        "format": "",
        "min": "",
        "max": "",
        "step": 1,
        "limit": 10
    },
    "intAmountData": {
        "min": "",
        "max": "",
        "step": 1,
        "limit": 10
    },
    "stringData": {
        "limit": 10
    }
}
  • 方案二:在父类中定义数量字段,每种子类型通过继承的方式获得数量字段
// 父类
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes(
        {
            @JsonSubTypes.Type(value = TimeData.class, name = "time"),
            @JsonSubTypes.Type(value = StringData.class, name = "string"),
            @JsonSubTypes.Type(value = IntAmountData.class, name = "int")
        }
)
public class BaseData {
    // 用于指定每种子类的类型名
    private String type;
    // 只在父类中添加数量字段
    private Integer limit;
}

// 时间
public class TimeData extends BaseData {
    private final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private final Unit DEFAULT_UNIT = Unit.DAY;
    private final Date DEFAULT_MIN = new Date();

    private String unit;
    private String format;
    private Date min;
    private Date max;
    private Integer step;
}

// 数值
public class IntAmountData extends BaseData {
    private final Integer DEFAULT_MIN = 0;
    private final Integer DEFAULT_MAX = 100;
    private final Integer DEFAULT_STEP = 1;

    private Integer min;
    private Integer max;
    private Integer step;
}

// 文本
public class StringData extends BaseData {

    private final String[] names = {"梦琪", "忆柳", "之桃", "慕青", "问兰", "尔岚", "元香",
            "初夏", "沛菡", "傲珊", "曼文", "乐菱", "痴珊", "恨玉", "惜文", "香寒", "新柔", "语蓉",
            "海安", "夜蓉", "涵柏", "水桃", "醉蓝", "春儿", "语琴", "从彤", "傲晴", "语兰", "又菱"};

此方案下的json请求如下:

// 时间
curl -XPOST '/create' -d '
{
    "baseData": {
        // 指定子类类型为时间
        "type": "time",
        "unit": "",
        "format": "",
        "min": "",
        "max": "",
        "step": 1,
        "limit": 10
    }
}

// 数值
curl -XPOST '/create' -d '
{
    "baseData": {
        // 指定子类类型为数值
        "type": "int",
        "min": "",
        "max": "",
        "step": 1,
        "limit": 10
    }
}

// 文本
curl -XPOST '/create' -d '
{
    "baseData": {
        // 指定子类类型为文本
        "type": "string",
        "limit": 10
    }
}

通过此方式,可实现多子类的统一,相比方案一更容易拓展和维护。

方案二相关注解说明

JsonTypeInfo
    use:指定类型元数据的形式,用于序列化和反序列化具体实例(接受一个JsonTypeInfo.Id的枚举值)
        JsonTypeInfo.Id:定义序列化和反序列化中的类型标识
            - NONE:不明确指定类型标识类型,需根据上下文判断类型信息
            - CLASS:使用全限定名作为类型标识
            - MINIMAL_CLASS:采用类名作为类型标识
            - NAME:使用逻辑类型名作为类型标识
            - CUSTOM:采用自定义的方式定义类型标识
    include:指定如何包含类型元数据(接受一个JsonTypeInfo.As的枚举值)
        JsonTypeInfo.As:枚举类,包含以下值:
            - PROPERTY:以成员变量的形式包含类型元数据
            - WRAPPER_OBJECT:以包装类的形式包含类型元数据
            - WRAPPER_ARRAY:以成员变量的形式包含类型元数据
            - EXTERNAL_PROPERTY:以成员变量的形式包含类型元数据
    property:当include的值为JsonTypeInfo.As.PROPERTY时,指定作为类型元数据的变量名
    defaultImpl:指定默认实现
    visible:用于定义类型标识符值是作为JSON流的一部分传递给反序列化器(true),还是由TypeDeserializer(false)处理和删除。默认false
JsonSubTypes:接受JsonSubTypes.Type数组参数,用于指定多个子类信息
    JsonSubTypes.Type:指定具体的子类信息
        value:子类全限定名
        name:用作类型标识的子类逻辑名
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值