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:用作類型標識的子類邏輯名