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

利用Jackson解決Json序列化和反序列化問(wèn)題

 更新時(shí)間:2023年05月26日 14:20:16   作者:衍志  
Jackson是一個(gè)用于處理Json數(shù)據(jù)的Java庫(kù),它提供了一系列功能,包括Json序列化和反序列化,所以本文就來(lái)講講如何利用利用Jackson解決Json序列化和反序列化的問(wèn)題吧

前言

在前后端分離的應(yīng)用中,前端往往需要向后端發(fā)送命令請(qǐng)求,并將請(qǐng)求中的數(shù)據(jù)以Json格式傳遞。后端需要將Json格式的數(shù)據(jù)反序列化成Java對(duì)象,以便進(jìn)行處理。但是,在實(shí)際應(yīng)用中,我們會(huì)遇到一些挑戰(zhàn),比如多態(tài)類型處理的需求,以及需要將多個(gè)API壓縮成一個(gè)API等。本文將介紹如何使用Jackson庫(kù)解決這些問(wèn)題。

Jackson庫(kù)簡(jiǎn)介

Jackson庫(kù)概述

Jackson是一個(gè)用于處理Json數(shù)據(jù)的Java庫(kù),由FasterXML開(kāi)發(fā)和維護(hù)。它提供了一系列功能,包括Json序列化和反序列化、Json樹(shù)模型、流式API等。

Jackson主要特性

  • 支持Java對(duì)象與Json之間的轉(zhuǎn)換
  • 支持Json樹(shù)模型
  • 支持流式API
  • 支持注解,靈活地控制序列化和反序列化過(guò)程
  • 支持多態(tài)類型處理

JsonTypeInfo和JsonSubTypes的基本概念

JsonTypeInfo的作用與使用場(chǎng)景

在進(jìn)行Json序列化和反序列化時(shí),我們需要考慮Java對(duì)象的類型信息,以便正確地將Json數(shù)據(jù)轉(zhuǎn)換成Java對(duì)象。JsonTypeInfo提供了一種機(jī)制,用于在序列化和反序列化時(shí)處理Java對(duì)象的類型信息。

JsonSubTypes的作用與使用場(chǎng)景

JsonSubTypes是JsonTypeInfo的一個(gè)子注解,用于指定Java類的子類。當(dāng)我們需要序列化和反序列化一個(gè)包含多態(tài)類型的Java對(duì)象時(shí),我們可以使用@JsonTypeInfo和@JsonSubTypes注解來(lái)指定子類的類型信息。

實(shí)際應(yīng)用案例

代碼示例:動(dòng)物園

假設(shè)我們有一個(gè)動(dòng)物園,里面有各種動(dòng)物,包括狗、貓、魚(yú)等。我們需要將動(dòng)物園中的動(dòng)物序列化成Json格式,并將其發(fā)送到前端。我們定義一個(gè)Animal類作為父類,然后定義三個(gè)子類:Dog、Cat和Fish。具體代碼如下:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "dog"),
    @JsonSubTypes.Type(value = Cat.class, name = "cat"),
    @JsonSubTypes.Type(value = Fish.class, name = "fish")
})
public abstract class Animal {
    private String name;
    public Animal(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
public class Dog extends Animal {
    private String breed;
    public Dog(String name, String breed) {
        super(name);
        this.breed = breed;
    }
    public String getBreed() {
        return breed;
    }
    public void setBreed(String breed) {
        this.breed = breed;
    }
}
public class Cat extends Animal {
    private String color;
    public Cat(String name, String color) {
        super(name);
        this.color = color;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
}
public class Fish extends Animal {
    private String species;
    public Fish(String name, String species) {
        super(name);
        this.species = species;
    }
    public String getSpecies() {
        return species;
    }
    public void setSpecies(String species) {
        this.species = species;
    }
}

從父類到子類的序列化和反序列化

現(xiàn)在我們需要將動(dòng)物園中的所有動(dòng)物序列化成Json格式。我們可以使用ObjectMapper類的writeValueAsString()方法來(lái)實(shí)現(xiàn)。具體代碼如下:

List<Animal> animals = new ArrayList<>();
animals.add(new Dog("旺財(cái)", "金毛"));
animals.add(new Cat("小花", "黑白"));
animals.add(new Fish("尼莫", "小丑魚(yú)"));
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(animals);

反之,我們可以使用ObjectMapper類的readValue()方法將Json數(shù)據(jù)反序列化成Java對(duì)象。具體代碼如下:

List<Animal> animals = objectMapper.readValue(json, new TypeReference<List<Animal>>() {});

自定義類型信息屬性

我們可以通過(guò)@JsonTypeInfo注解的property屬性來(lái)自定義類型信息的屬性名。例如,我們將property屬性的值設(shè)置為"animalType",則Json數(shù)據(jù)中的類型信息屬性名也會(huì)變?yōu)?quot;animalType"。具體代碼如下:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "animalType")
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "dog"),
    @JsonSubTypes.Type(value = Cat.class, name = "cat"),
    @JsonSubTypes.Type(value = Fish.class, name = "fish")
})
public abstract class Animal {
    ...
}

好的,以下是使用markdown的翻譯和例子:

JsonTypeInfo類

JsonTypeInfo類是一個(gè)注解,用于配置在JSON序列化和反序列化中使用類型信息的詳細(xì)信息,以保留有關(guān)對(duì)象實(shí)例的實(shí)際類的信息。這對(duì)于多態(tài)類型是必需的,并且還可能需要鏈接抽象聲明類型和匹配的具體實(shí)現(xiàn)。

參數(shù)方法

JsonTypeInfo類的參數(shù)方法如下:

use:定義如何使用類型信息。有三個(gè)選項(xiàng):Id.CLASS,Id.NAMEId.MINIMAL_CLASS。默認(rèn)值為Id.CLASS。

include:定義類型信息的包含方式。有四個(gè)選項(xiàng):As.PROPERTY,As.WRAPPER_OBJECTAs.EXISTING_PROPERTYAs.EXTERNAL_PROPERTY。默認(rèn)值為As.PROPERTY。

property:定義包含類型信息的屬性的名稱。默認(rèn)值為"$type"

例子

以下是使用JsonTypeInfo類的一些例子:

// 將Java類名("com.myempl.ImplClass")包含在JSON屬性"class"中
@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "class")
// 將邏輯類型名稱(在實(shí)現(xiàn)類中定義)作為包裝器包含;2個(gè)注釋
@JsonTypeInfo(use = Id.NAME, include = As.WRAPPER_OBJECT)
@JsonSubTypes({
    @JsonSubTypes.Type(value = com.myemp.Impl1.class, name = "impl1"),
    @JsonSubTypes.Type(value = com.myempl.Impl2.class, name = "impl2")
})

在第一個(gè)例子中,use參數(shù)設(shè)置為Id.CLASS,這意味著使用Java類名作為類型信息。include參數(shù)設(shè)置為As.PROPERTY,這意味著類型信息將包含在JSON屬性"class"中。property參數(shù)設(shè)置為"class",這是包含類型信息的屬性的名稱。

在第二個(gè)例子中,use參數(shù)設(shè)置為Id.NAME,這意味著使用邏輯類型名稱作為類型信息。include參數(shù)設(shè)置為As.WRAPPER_OBJECT,這意味著類型信息將作為包裝器包含。@JsonSubTypes注解用于指定實(shí)現(xiàn)類,并將它們的邏輯類型名稱與之關(guān)聯(lián)。

JsonSubTypes Annotation

@JsonSubTypes 是一個(gè)用于與 @JsonTypeInfo 一起使用的注解,用于指定可序列化的多態(tài)類型的子類型,并將邏輯名稱與 JSON 內(nèi)容中使用的名稱關(guān)聯(lián)起來(lái)。

注意,僅注釋屬性或基本類型不會(huì)啟用多態(tài)類型處理:此外,需要使用 @JsonTypeInfo 或等效注釋(例如啟用所謂的“默認(rèn)鍵入”)注釋,并且僅在這種情況下才使用子類型信息。

可用的元素

@JsonSubTypes 注解具有以下元素:

元素類型描述
valueType[]注釋類型的子類型(注釋類或關(guān)聯(lián)到注釋方法的屬性值類型)。這些將被遞歸檢查,以便可以僅通過(guò)包含直接子類型來(lái)定義類型
@Type注解子類型的定義和可選名稱。如果未定義名稱(空字符串將被忽略),類型的類將被檢查是否有 @JsonTypeName 注解;如果也缺少或?yàn)榭?,則將通過(guò)類型 id 機(jī)制構(gòu)造默認(rèn)名稱。默認(rèn)名稱通?;陬惷?/td>

Type

@Type 是 @JsonSubTypes 中的一個(gè)注解,用于聲明子類型。

@Type 注解具有以下元素:

元素類型描述
valueClass<?>子類型的類
nameString類型標(biāo)識(shí)符所使用的邏輯類型名稱,如果定義了,則為空字符串。除非 names 定義為非空。默認(rèn)情況下使用,如果類沒(méi)有 @JsonTypeName 注解的話,會(huì)使用默認(rèn)名稱構(gòu)造類型 id 機(jī)制
namesString[](可選)用于類的類型標(biāo)識(shí)符的邏輯類型名稱:如果應(yīng)將多個(gè)類型名稱與同一類型關(guān)聯(lián),則使用

使用示例

下面是一個(gè)示例,展示了如何使用 @JsonSubTypes 注解:

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "type"
)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "dog"),
    @JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public abstract class Animal {
    // ...
}

在上面的示例中,Animal 是一個(gè)抽象類,它被注釋為可以有子類型。@JsonTypeInfo 注解指定了要使用名稱作為類型標(biāo)識(shí)符,并將類型標(biāo)識(shí)符作為 JSON 屬性的一部分包含在 JSON 中。@JsonSubTypes 注解指定了 DogCat 作為 Animal 的子類型,分別使用名稱 "dog" 和 "cat" 作為它們的類型標(biāo)識(shí)符。

高級(jí)用法

解決循環(huán)引用問(wèn)題

在進(jìn)行Json序列化時(shí),如果Java對(duì)象之間存在循環(huán)引用,就會(huì)導(dǎo)致序列化失敗。為了解決這個(gè)問(wèn)題,我們可以使用@JsonIdentityInfo注解來(lái)指定對(duì)象的標(biāo)識(shí)信息。具體代碼如下:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Employee {
    private int id;
    private String name;
    private Employee manager;
    public Employee(int id, String name, Employee manager) {
        this.id = id;
        this.name = name;
        this.manager = manager;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Employee getManager() {
        return manager;
    }
    public void setManager(Employee manager) {
        this.manager = manager;
    }
}

自定義類型解析器

有時(shí)候,我們需要對(duì)一些特殊類型的數(shù)據(jù)進(jìn)行特殊處理,比如將日期字符串轉(zhuǎn)換成Date對(duì)象。我們可以使用JsonDeserializer和JsonSerializer來(lái)自定義類型的解析和序列化過(guò)程。具體代碼如下:

public class DateDeserializer extends JsonDeserializer<Date> {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Override
    public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        String dateStr = jsonParser.getText();
        try {
            return dateFormat.parse(dateStr);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}
public class DateSerializer extends JsonSerializer<Date> {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Override
    public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
        jsonGenerator.writeString(dateFormat.format(date));
    }
}
@JsonDeserialize(using = DateDeserializer.class)
@JsonSerialize(using = DateSerializer.class)
public class Event {
    private String name;
    private Date date;
    public Event(String name, Date date) {
        this.name = name;
        this.date = date;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
}

使用@JsonTypeName自定義類型名稱

有時(shí)候,我們希望在Json數(shù)據(jù)中使用自定義的類型名稱,而不是Java類的名稱??梢允褂聾JsonTypeName注解來(lái)實(shí)現(xiàn)。具體代碼如下:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "dog"),
    @JsonSubTypes.Type(value = Cat.class, name = "cat"),
    @JsonSubTypes.Type(value = Fish.class, name = "fish")
})
public abstract class Animal {
    ...
}
@JsonTypeName("dog")
public class Dog extends Animal {
    ...
}

性能優(yōu)化

避免重復(fù)解析

在進(jìn)行Json序列化和反序列化時(shí),我們可能會(huì)重復(fù)解析同一個(gè)Json數(shù)據(jù)。為了提高性能,我們可以使用ObjectMapper類的readTree()方法將Json數(shù)據(jù)解析成JsonNode對(duì)象,并在需要的時(shí)候?qū)ζ溥M(jìn)行操作。具體代碼如下:

JsonNode root = objectMapper.readTree(json);
JsonNode nameNode = root.path("name");
String name = nameNode.asText();

使用緩存機(jī)制

在進(jìn)行Json序列化和反序列化時(shí),我們可以使用緩存機(jī)制來(lái)提高性能。Jackson庫(kù)提供了一個(gè)ObjectReader類,它可以緩存Json數(shù)據(jù)的解析結(jié)果,并在下次解析相同的Json數(shù)據(jù)時(shí)直接返回緩存結(jié)果,從而避免重復(fù)解析。具體代碼如下:

ObjectReader reader = objectMapper.readerFor(new TypeReference<List<Animal>>() {});
List<Animal> animals = reader.readValue(json);

注意事項(xiàng)與最佳實(shí)踐

處理不同版本的數(shù)據(jù)結(jié)構(gòu)

在進(jìn)行Json序列化和反序列化時(shí),我們需要考慮到數(shù)據(jù)結(jié)構(gòu)的版本變化。如果數(shù)據(jù)結(jié)構(gòu)發(fā)生變化,我們需要進(jìn)行相應(yīng)的兼容處理,以確保新版本的程序能夠正確地處理舊版本的數(shù)據(jù)。為了處理不同版本的數(shù)據(jù)結(jié)構(gòu),我們可以使用@JsonCreator和@JsonValue注解來(lái)自定義對(duì)象的構(gòu)造函數(shù)和toString()方法。

使用@JsonSubTypes的局限性

使用@JsonSubTypes注解時(shí),需要注意它的局限性。它只能用于序列化和反序列化Java對(duì)象,無(wú)法用于處理基本類型和數(shù)組類型。

安全性考慮

在進(jìn)行Json序列化和反序列化時(shí),我們需要考慮到安全性問(wèn)題。由于Json數(shù)據(jù)是開(kāi)放的,存在被惡意篡改和注入的風(fēng)險(xiǎn)。為了防止這種風(fēng)險(xiǎn),我們可以使用@JsonInclude注解來(lái)控制序列化時(shí)包含的屬性,以及使用@JsonCreator和@JsonValue注解來(lái)限制反序列化的輸入。此外,我們還可以使用JsonNode對(duì)象來(lái)手動(dòng)解析Json數(shù)據(jù),以避免使用反序列化機(jī)制。

以上就是利用Jackson解決Json序列化和反序列化問(wèn)題的詳細(xì)內(nèi)容,更多關(guān)于Jackson Json序列化與反序列化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java struts2框架簡(jiǎn)介

    java struts2框架簡(jiǎn)介

    本文主要介紹了java struts2框架的基礎(chǔ)知識(shí)。具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-01-01
  • Mybatis工具類JdbcTypeInterceptor運(yùn)行時(shí)自動(dòng)添加jdbcType屬性

    Mybatis工具類JdbcTypeInterceptor運(yùn)行時(shí)自動(dòng)添加jdbcType屬性

    今天小編就為大家分享一篇關(guān)于Mybatis工具類JdbcTypeInterceptor運(yùn)行時(shí)自動(dòng)添加jdbcType屬性,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • jdk17+springboot使用webservice的踩坑實(shí)戰(zhàn)記錄

    jdk17+springboot使用webservice的踩坑實(shí)戰(zhàn)記錄

    這篇文章主要給大家介紹了關(guān)于jdk17+springboot使用webservice踩坑的相關(guān)資料,網(wǎng)上很多教程是基于jdk8的,所以很多在17上面跑不起來(lái),折騰兩天,直接給答案,需要的朋友可以參考下
    2024-01-01
  • spring中12種@Transactional的失效場(chǎng)景(小結(jié))

    spring中12種@Transactional的失效場(chǎng)景(小結(jié))

    日常我們進(jìn)行業(yè)務(wù)開(kāi)發(fā)時(shí),基本上使用的都是聲明式事務(wù),即為使用@Transactional注解的方式,本文主要介紹了spring中12種@Transactional的失效場(chǎng)景,感興趣的小伙伴們可以參考一下
    2022-01-01
  • spring?項(xiàng)目實(shí)現(xiàn)限流方法示例

    spring?項(xiàng)目實(shí)現(xiàn)限流方法示例

    這篇文章主要為大家介紹了spring項(xiàng)目實(shí)現(xiàn)限流的方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Java并發(fā)工具之Exchanger線程間交換數(shù)據(jù)詳解

    Java并發(fā)工具之Exchanger線程間交換數(shù)據(jù)詳解

    這篇文章主要介紹了Java并發(fā)工具之Exchanger線程間交換數(shù)據(jù)詳解,Exchanger是一個(gè)用于線程間協(xié)作的工具類,Exchanger用于進(jìn)行線程間的數(shù)據(jù)交 換,它提供一個(gè)同步點(diǎn),在這個(gè)同步點(diǎn),兩個(gè)線程可以交換彼此的數(shù)據(jù),需要的朋友可以參考下
    2023-12-12
  • mybatis 攔截器添加參數(shù)的實(shí)現(xiàn)

    mybatis 攔截器添加參數(shù)的實(shí)現(xiàn)

    本文主要介紹了MyBatis攔截器中添加參數(shù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • 基于Java中UDP的廣播形式(實(shí)例講解)

    基于Java中UDP的廣播形式(實(shí)例講解)

    下面小編就為大家分享一篇基于Java中UDP的廣播形式(實(shí)例講解),具有很好的參考價(jià)值,希望對(duì)大家有所幫助
    2017-12-12
  • mybatis如何批量更新list對(duì)象

    mybatis如何批量更新list對(duì)象

    這篇文章主要介紹了mybatis如何批量更新list對(duì)象問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 淺談同步監(jiān)視器之同步代碼塊、同步方法

    淺談同步監(jiān)視器之同步代碼塊、同步方法

    下面小編就為大家?guī)?lái)一篇淺談同步監(jiān)視器之同步代碼塊、同步方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08

最新評(píng)論