欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java整合Jackson實現(xiàn)反序列化器流程

 更新時間:2023年01月14日 09:18:47   作者:何憶清風(fēng)  
Jackson是一個開源的Java序列化和反序列化工具,可以將Java對象序列化為XML或JSON格式的字符串,以及將XML或JSON格式的字符串反序列化為Java對象。由于其使用簡單,速度較快,且不依靠除JDK外的其他庫,被眾多用戶所使用

在使用 Jackson 時很多時候在自定義的數(shù)據(jù)結(jié)構(gòu)時通過本身自帶的序列化器可能實現(xiàn)不了自定義的結(jié)構(gòu)轉(zhuǎn)換,比如:需要從Json 字符串中讀取某個字段,根據(jù)某個字段轉(zhuǎn)換為對應(yīng)的實體類,例如下面的結(jié)構(gòu),我需要根據(jù) Json 字符串中的 messageType 字段轉(zhuǎn)換為對應(yīng)的實體,這時候我們可以通過自定義序列化器來進(jìn)行轉(zhuǎn)換

{
    "messageId": "1665709790068",
    "timestamp": 1665709790068,
    "point": "123.33, 123.555",
    "messageType": "MODEL",
    "payload": {
        "method": "POST",
        "modelType": "EVENT",
        "output": {
            "ouaaa": "name"
        },
        "timestamp": 1665709790068
    }
}

1. 實體類

這里 payload 可以使用成泛型通過指定對應(yīng)的類型來轉(zhuǎn)換為對應(yīng)的實體類型

public class UniversalMessage<T extends Payload> {
    /** PAYLOAD */
    public static final String PAYLOAD = "payload";
    /** MESSAGE_ID */
    public static final String MESSAGE_ID = "messageId";
    /** TIMESTAMP */
    public static final String TIMESTAMP = "timestamp";
    /** POINT */
    public static final String POINT = "point";
    /** MESSAGETYPE */
    public static final String MESSAGE_TYPE = "messageType";
    private static final long serialVersionUID = -3703724430631400996L;
    protected String messageId;
    protected Long timestamp;
    protected String point;
    protected MessageType messageType;
    private T payload;
}

下面是定義好的 Payload 實現(xiàn)類,這里我們定義一個就行了 ModelType 定義的枚舉類型,隨便寫就行了,只要跟后面獲取序列化器對應(yīng)就好

@Type(value = "MODEL") //填寫消息類型
public class ModelEventPayload implements Payload {
    /** serialVersionUID */
    private static final long serialVersionUID = -4371712921890795815L;
    private Map<String, Object> output;
    private Long timestamp;
    protected ModelType modelType;
    protected String method;
}

2. 反序列化器

反序列化器的整體結(jié)構(gòu)

PayloadDeserialize 實現(xiàn)了 JacksonStdDeserializer 序列化器

  • 其中用到了 parser 里面的 ObjectCodec 對象編碼,用于將對應(yīng)的 Json 格式轉(zhuǎn)換為實體
  • Jackon會將 Json 字符串中每個結(jié)構(gòu)都會轉(zhuǎn)換對應(yīng)的類型添加到樹結(jié)構(gòu)中,例如:字符串就會轉(zhuǎn)換為 TextNode,對象就會轉(zhuǎn)換為 ObjectNode

其中根據(jù)每個轉(zhuǎn)換類型,我這里封裝了一個 DeserializeForType<Payload> 接口類型,用于根據(jù)自定的類型獲取序列化器,用于替換寫多個 If else 代碼不美觀

  • 接口里面定義一個 type() 方法,實現(xiàn)類用于實現(xiàn),當(dāng)前類用于什么類型的轉(zhuǎn)換
  • 上面 Json 接口中,通過 messageType 轉(zhuǎn)換了之后可能還需要通過實體中的 modelType 來進(jìn)行轉(zhuǎn)換,這里我又通過實現(xiàn) DeserializeForType<Payload> 創(chuàng)建了兩個匿名類 event()other() 方法返回,先根據(jù) messageType 轉(zhuǎn)換了,然后再根據(jù) modelType 獲取對應(yīng)的反序列化器進(jìn)行轉(zhuǎn)換
public class PayloadDeserialize extends StdDeserializer<UniversalMessage<Payload>> {
    /** serialVersionUID */
    private static final long serialVersionUID = 7922419965896101563L;
    /** MESSAGE_TYPE */
    public static final String MESSAGE_TYPE = "messageType";
    /** PAYLOAD */
    public static final String PAYLOAD = "payload";
    /**
     * Payload deserialize
     */
    protected PayloadDeserialize() {
        this(null);
    }
    /**
     * Payload deserialize
     */
    protected PayloadDeserialize(Class<?> vc) {
        super(vc);
    }
    /**
     * 實現(xiàn)jackson序列化器的方法
     */
    @Override
    public UniversalMessage<Payload> deserialize(JsonParser jsonParser,
    DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
    	//獲取到對象編碼對象,用當(dāng)前對應(yīng)可以對字符串進(jìn)行轉(zhuǎn)換
        ObjectCodec codec = jsonParser.getCodec();
        //讀取出整個消息體的樹型結(jié)構(gòu)
        TreeNode treeNode = codec.readTree(jsonParser);
        //解析出的節(jié)點樹結(jié)構(gòu),消息字段是處于第一層結(jié)構(gòu),所以這里可以直接通過get進(jìn)行獲取,jackson會將字符串不同的結(jié)構(gòu)解析為不同的 TreeNode類型,例如字符串就會解析成 TextNode
        TreeNode messageTypeNode = Objects.requireNonNull(treeNode.get(MESSAGE_TYPE), "消息類型不能為空");
        Class<? extends TreeNode> messageTypeNodeClass = messageTypeNode.getClass();
        boolean assignableFrom = TextNode.class.isAssignableFrom(messageTypeNodeClass);
        Assertions.isTrue(assignableFrom, "消息類型字段類型錯誤:" + messageTypeNodeClass + "需要 TextNode");
        String messageTypeStr = ((TextNode) messageTypeNode).asText();
        //構(gòu)建外層實體消息
        UniversalMessage<Payload> universalMessage = getPayloadUniversalMessage(treeNode, codec);
        //獲取到j(luò)son字符串中的 payload
        TreeNode payloadNode = treeNode.get(PAYLOAD);
        DeserializeForType<Payload> deserializeForType = DeserializeTypeContext.get(messageTypeStr);
        Objects.requireNonNull(deserializeForType, "不支持當(dāng)前消息類型:" + messageTypeStr);
        //對 payload進(jìn)行解析
        Payload payload = deserializeForType.deserialize(codec, payloadNode);
        universalMessage.setPayload(payload);
        return universalMessage;
    }
    /**
     * 創(chuàng)建最外層的消息體
     */
    private UniversalMessage<Payload> getPayloadUniversalMessage(TreeNode treeNode, ObjectCodec codec) throws IOException {
        ObjectNode node = (ObjectNode) treeNode;
        String messageId = Objects.requireNonNull(node.get(UniversalMessage.MESSAGE_ID), "消息ID不能為空").asText();
        String messageType = Objects.requireNonNull(node.get(UniversalMessage.MESSAGE_TYPE), "消息類型不能為空").asText();
        long timestamp = Objects.requireNonNull(node.get(UniversalMessage.TIMESTAMP), "時間戳不能為空").asLong();
        String point = Objects.requireNonNull(node.get(UniversalMessage.POINT), "Point不能為空").asText();
        return UniversalMessage.builder()
            .messageId(messageId)
            //枚舉轉(zhuǎn)換的工具,這里可以自己封裝一個,根據(jù)名稱進(jìn)行轉(zhuǎn)換
            .messageType(EnumUtils.nameOf(MessageType.class, messageType.toUpperCase()))
            .timestamp(timestamp)
            .point(point).build();
    }
    /**
     * 保存序列化器的上下文,為防止反復(fù)的創(chuàng)建序列化器,這里我們提前加載上對類型的序列化器
     */
    static class DeserializeTypeContext {
        /** Deserialize for type map */
        private static Map<String, DeserializeForType<Payload>> deserializeForTypeMap = new HashMap<>(4);
        static {
            add(new ModelDeserialize());
            //如果有新的類型,直接在這里添加,這里也可以做成 spring容器管理進(jìn)行注入
        }
        /**
         * Add
         */
        public static void add(DeserializeForType deserializeForType) {
            Assertions.notNull(deserializeForType, "序列化器不能為空");
            deserializeForTypeMap.putIfAbsent(deserializeForType.getType(), deserializeForType);
        }
        /**
         * Get
         */
        public static DeserializeForType<Payload> get(String type) {
            Assertions.notBlank(type, "消息類型不能為空");
            return deserializeForTypeMap.get(type);
        }
    }
    /**
     * 定義的序列化器頂級接口
     */
    interface DeserializeForType<T extends Payload> {
        /**
         * 反序列化方法,這里的 ObjectCodec對象是上面最外層的方法傳遞進(jìn)來的,TreeNode則是對應(yīng)的消息結(jié)構(gòu)體
         */
        T deserialize(ObjectCodec codec,  TreeNode node) throws IOException;
        /**
         * Gets type
         */
        String getType();
    }
    /**
     * 封裝一個抽象的父級類,主要用于實現(xiàn)接口的 Type 方法,獲取當(dāng)前類是什么類型的
     */
    public abstract static class AbstractDeserialize<T extends Payload> implements DeserializeForType<T> {
        /** Type */
        private final String type;
        /**
         * Abstract deserialize
         */
        public AbstractDeserialize(String type) {
            this.type = type;
        }
        /**
         * Gets type *
         */
        @Override
        public String getType() {
            return this.type;
        }
    }
    /**
     * 自定義model類型的序列化器
     */
    public static class ModelDeserialize extends AbstractDeserialize<Payload> {
        /** TYPE */
        public static final String TYPE = "MODEL";
        /** MODEL_TYPE */
        public static final String MODEL_TYPE = "modelType";
        /** MODEL_TYPE_MAP */
        private static final Map<String, DeserializeForType<Payload>> MODEL_TYPE_MAP = new HashMap<>(4);
        static {
        	//這里根據(jù) MODEL 類型又封裝了幾個子類型的方法進(jìn)行轉(zhuǎn)換
            add(other());
            add(event());
        }
        /**
         * Model deserialize
         */
        public ModelDeserialize() {
            super(TYPE);
        }
        /**
         * Deserialize
         */
        @Override
        public Payload deserialize(ObjectCodec codec, TreeNode node) throws IOException {
            TreeNode modelTypeNode = Objects.requireNonNull(node.get(MODEL_TYPE), "消息類型不能為空");
            Class<? extends TreeNode> modelTypeNodeClass = modelTypeNode.getClass();
            boolean assignableFrom = TextNode.class.isAssignableFrom(modelTypeNodeClass);
            Assertions.isTrue(assignableFrom, "模型消息類型字段類型錯誤:" + modelTypeNodeClass + "需要 TextNode");
            //string 類型的字段會被轉(zhuǎn)換成 TextNode的節(jié)點
            String messageTypeStr = ((TextNode) modelTypeNode).asText();
            DeserializeForType<Payload> deserializeForType = MODEL_TYPE_MAP.get(messageTypeStr);
            Assertions.notNull(deserializeForType, "模型:" + messageTypeStr + ",序列化器為空");
            return deserializeForType.deserialize(codec, node);
        }
        /**
         * Add
         */
        public static void add(DeserializeForType<Payload> deserializeForType) {
            Assertions.notNull(deserializeForType, "對應(yīng)類型的序列化器不能為空");
            MODEL_TYPE_MAP.putIfAbsent(deserializeForType.getType(), deserializeForType);
        }
        /**
         * OTHER
         */
        private static DeserializeForType<Payload> other() {
            return new DeserializeForType<Payload>() {
                @Override
                public Payload deserialize(ObjectCodec codec, TreeNode node) throws IOException {
                    return node.traverse(codec).readValueAs(ModelOtherPayload.class);
                }
                @Override
                public String getType() {
                    return "OTHER";
                }
            };
        }
        /**
         * Event
         */
        private static DeserializeForType<Payload> event() {
            return new DeserializeForType<Payload>() {
                @Override
                public Payload deserialize(ObjectCodec codec, TreeNode node) throws IOException {
                    return node.traverse(codec).readValueAs(ModelEventPayload.class);
                }
                @Override
                public String getType() {
                    return "EVENT";
                }
            };
        }
    }
}

3. 序列化器

序列化器就比較簡單了,可以先根據(jù) payload 實體獲取到對應(yīng)的類型,寫入一個 string類型 messageType 然后再寫 payload 作為對象進(jìn)行寫成 Json 格式(其他幾個字段我就不寫了,根據(jù)對應(yīng)的類型調(diào)用對應(yīng)類型的 write方法即可)

public class PayloadSerialize extends StdSerializer<UniversalMessage<Payload>> {
    private static final long serialVersionUID = 7679701332948432903L;
    protected PayloadSerialize() {
        this(null);
    }
    protected PayloadSerialize(Class<Payload> t) {
        super(t);
    }
    @Override
    public void serialize(UniversalMessage<Payload> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        Payload payload = value.getPayload();
        gen.writeStartObject();
        if (payload != null) {
            Type type = payload.getClass().getAnnotation(Type.class);
            if (type != null) {
                gen.writeStringField("messageType", type.value());
            }
        }
        gen.writeObjectField("payload", payload);
        gen.writeEndObject();
    }
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Type {
    String value();
}

到此這篇關(guān)于Java整合Jackson實現(xiàn)反序列化器流程的文章就介紹到這了,更多相關(guān)Java Jackson反序列化器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JDK8中Optional類巧用之判空操作

    JDK8中Optional類巧用之判空操作

    善用Optional可以使我們代碼中很多繁瑣、丑陋的設(shè)計變得十分優(yōu)雅,這篇文章主要給大家介紹了JDK8中Optional類巧用之判空的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-08-08
  • idea中創(chuàng)建jsp項目的詳細(xì)實戰(zhàn)步驟

    idea中創(chuàng)建jsp項目的詳細(xì)實戰(zhàn)步驟

    才學(xué)javaWeb,以防自己忘記創(chuàng)建項目的過程,所以淺淺的記錄一下吧,下面這篇文章主要給大家介紹了關(guān)于idea中創(chuàng)建jsp項目的詳細(xì)步驟,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • springboot冪等切片的實現(xiàn)

    springboot冪等切片的實現(xiàn)

    本文主要介紹了springboot冪等切片的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • spring如何使用xml裝配bean

    spring如何使用xml裝配bean

    這篇文章主要介紹了spring如何使用xml裝配bean,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • Java多線程中停止線程遇到線程阻塞的處理方法詳解

    Java多線程中停止線程遇到線程阻塞的處理方法詳解

    這篇文章主要介紹了Java多線程中停止線程遇到線程阻塞的處理方法詳解,在阻塞狀態(tài)下,線程會釋放CPU資源,從而允許其他線程執(zhí)行,線程阻塞是實現(xiàn)多線程編程中重要的概念,可以提高程序的效率和資源利用率,需要的朋友可以參考下
    2023-10-10
  • 一文學(xué)會使用sa-token解決網(wǎng)站權(quán)限驗證

    一文學(xué)會使用sa-token解決網(wǎng)站權(quán)限驗證

    這篇文章主要為大家介紹了使用sa-token解決網(wǎng)站權(quán)限驗證方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • JAVA 根據(jù)Url把多文件打包成ZIP下載實例

    JAVA 根據(jù)Url把多文件打包成ZIP下載實例

    這篇文章主要介紹了JAVA 根據(jù)Url把多文件打包成ZIP下載的相關(guān)資料,需要的朋友可以參考下
    2017-08-08
  • java實現(xiàn)驗證碼類生成中文驗證碼

    java實現(xiàn)驗證碼類生成中文驗證碼

    java實現(xiàn)的漢字輸入驗證碼,主要包含兩個類,一個是生成驗證碼,一個是判斷驗證碼輸入是否正確,實現(xiàn)原理非常簡單,將漢字和干擾線生成圖片并將漢字保存到session,前臺獲取每次生成驗證碼圖片并用文本框值和session值比較,功能就怎么簡單
    2014-01-01
  • 使用maven工具解決jar包沖突或重復(fù)加載的問題

    使用maven工具解決jar包沖突或重復(fù)加載的問題

    這篇文章主要介紹了使用maven工具解決jar包沖突或重復(fù)加載的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Maven學(xué)習(xí)----Maven安裝與環(huán)境變量配置教程

    Maven學(xué)習(xí)----Maven安裝與環(huán)境變量配置教程

    這篇文章主要給大家介紹了關(guān)于如何利用Maven入手Spring Boot第一個程序的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-06-06

最新評論