SpringBoot項目中Jackson反序列化時的多態配置

需求描述:
項目中可能有這麼一種情況,我們對外提供一個http接口服務,但是這個接口需要接收某一類具有共同特徵的參數(父類 – 子類)。比如一個消息服務接口去提供發送郵件,短信,根據傳入的消息類型不同而調用不同的發送邏輯,即接口接收父類類型,傳入的參數需要反序列化爲實際的子類類型。

接口示例


/**
 * 暴露http接口,供feign調用
 *
 * @author [email protected]
 * @date 2019/9/10
 */
@RestController
public class MessageController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostMapping("/api/v1/send")
    public void send(@RequestBody MessageContext messageContext) {
        rabbitTemplate.convertAndSend("t_message", messageContext);
    }

}

類圖結構

接口接收一個父類類型,但是實際上傳入的類型爲子類類型。
在這裏插入圖片描述

根據類型反序列化(多態支持)

父類


/**
 * 消息體父類
 *
 * @author [email protected]
 * @date 2019/9/10
 */
@Data
// 根據字段值進行反序列化態判斷,字段 MessageContext.messageType,並在子類中攜帶此字段值
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "messageType", visible = true)
@JsonSubTypes({
        // 值-->子類映射
        @JsonSubTypes.Type(value = SimpleEmailContext.class, name = MessageType.StringType.SIMPLE_EMAIL),
        @JsonSubTypes.Type(value = SecretEmailContext.class, name = MessageType.StringType.SECRET_EMAIL),
        @JsonSubTypes.Type(value = SMSContext.class, name = MessageType.StringType.SMS)
})
public class MessageContext {

    /**
     * 消息類型
     */
    protected MessageType messageType;
    /**
     * 消息發送者
     */
    protected String from;
    /**
     * 消息接受者
     */
    protected List<String> to;
    /**
     * 消息內容
     */
    protected String content;
    /**
     * 消息ID
     */
    private String messageId = UUID.randomUUID().toString();

    public MessageContext(MessageType messageType, String from, List<String> to, String content) {
        this.messageType = messageType;
        this.from = from;
        this.to = to;
        this.content = content;
    }

}

注:在父類配置反序列化規則,此配置雖然可用,但是如果子類非常多,此方式就不太優美了,並且這樣做也違反了開閉原則。

子類

/**
 * 簡單郵件消息體
 *
 * @author [email protected]
 * @date 2019/9/10
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class SimpleEmailContext extends MessageContext {

    private String subject;
    private List<String> cc;
    private List<String> bcc;

    @Builder
    public SimpleEmailContext(String from, List<String> to, String subject, String content, List<String> cc, List<String> bcc) {
        super(MessageType.SIMPLE_EMAIL, from, to, content);
        this.subject = subject;
        this.cc = cc;
        this.bcc = bcc;
    }

}

不違反開閉原則的方式

之前看過有貌似另一種方式可以只新增不修改,不違反開閉原則,但沒有深究,有興趣的話可自行Google。

示例代碼

可以在 https://gitee.com/tangjizhou/message 查看完整版本代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章