json 綁定多態

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:用作類型標識的子類邏輯名
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章