Java序列化篇之Json解析工具Jackson

json 的解析包:

<!--核心類 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.6</version>
</dependency>
<!--注解-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.6</version>
</dependency>
<!--數(shù)據(jù)綁定-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.6</version>
</dependency>

Jackson的基本應(yīng)用:

JsonNode 類是 Jackson 的一個將 Json 內(nèi)容反序列到內(nèi)存的一種內(nèi)存數(shù)據(jù)結(jié)構(gòu)表達(dá)方式放祟。
例如對于一個測試的Json內(nèi)容:

{
  "name" : "test",
  "value" : 20,
  "address" : [
    {
     "addressId" : "0001" 
    },
    {
    "addressId" : "0002"
    }
  ]
}

當(dāng)我們把json內(nèi)容反序列化到內(nèi)存中的時(shí)候,便可以如同操作一個樹結(jié)構(gòu)讀取json內(nèi)容:

String name = node.get("name").asText();
Integer value = node.get("value").asInt();
Iterator<JsonNode> addressNodes = node.get("address").elements();
String address = addressNodes.next().get("addressId").asText();

從上我們可以發(fā)現(xiàn)跪妥, jackson 可以方便的進(jìn)行節(jié)點(diǎn)定位跟類型轉(zhuǎn)換。

如何才能將json內(nèi)容轉(zhuǎn)換成 JsonNode 呢 眉撵?

  • 文件字符串解析
public static JsonNode str2JsonNode(String str) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    return objectMapper.readTree(str);
}

  • stream 解析
public static JsonNode str2JsonNode(InputStream stream) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    return objectMapper.readTree(stream);
}
  • file 解析
public static JsonNode str2JsonNode(File file) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    return objectMapper.readTree(file);
}
  • reader 解析
public static JsonNode str2JsonNode(Reader reader) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    return objectMapper.readTree(reader);
}
  • bytes 解析
public static JsonNode str2JsonNode(byte[] datas) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    return objectMapper.readTree(datas);
}

Json 與 基本類型的相互轉(zhuǎn)化:

readValue 方法能夠幫助我們將字符串序列化成指定的

 public static Object json2Object(String str) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    JsonNode node = objectMapper.readTree(str);
    if(node.isObject()){
        return objectMapper.readValue(str, Map.class);
    }else if(node.isArray()){
        return objectMapper.readValue(str, List.class);
    }else{
        if (node.isInt()) {
            return node.asInt();
        } else if (node.isLong()) {
            return node.asLong();
        } else if (node.isDouble()) {
            return node.asDouble();
        } else if(node.isTextual()) {
            return node.asText();
        } else if (node.isNull()){
            return null;
        }
        else {
            throw new IOException("Json node exception type :  " + node.numberType());
        }
    }
}

例如上面的字符串我們將其解析為 常見的Map結(jié)構(gòu):

Map map = JsonUtil.json2Bean(str, Map.class);
System.out.println(map.get("address"));
List<Map<String, String>> list = (List<Map<String, String>>)map.get("address");
System.out.println(list.get(1).get("addressId"));

當(dāng)然我們也可以通過 writeValue的方式將普通類型轉(zhuǎn)換成 String 打印出來:

public static String object2Str(Object object, boolean prettyPrint) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();

    // 美化方式打印
    if(prettyPrint){
        ObjectWriter write = objectMapper.writerWithDefaultPrettyPrinter();
        return write.writeValueAsString(object);
    }
    // 單行打印
    return objectMapper.writeValueAsString(object);
}

String 與 Bean 的相互轉(zhuǎn)化

  • 轉(zhuǎn)換工具方法為:
public static <T> T str2Bean(String str, Class<T> beanClass) throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    return mapper.readValue(str, beanClass);
}

要將 string -> bean , 對于每一個 jsonStr, 我們都需要創(chuàng)建一個與之對應(yīng)的 bean class.

例如 :

{
  "name" : "test",
  "value" : 20
}

對應(yīng)的 Bean 為 :

public class Persion {
    private String name;
    private int value;

    public void setName(String name) {
        this.name = name;
    }

    public void setValue(int value) {
        this.value = value;
    }
    
}

我們通過 Persion persion = JsonUtil.str2Bean(str, Persion.class); 這時(shí)候會通過 setter 方法將json內(nèi)容注入到 Persion類的對應(yīng)字段中。

如果 json 中的 key 與 Bean 中的字段名稱不對應(yīng)芜赌,我們可以通過 @JsonProperty 注解為其聲明對應(yīng)關(guān)系仰挣。
@JsonProperty 注解可以用于 getter,setter,或者構(gòu)造函數(shù)參數(shù)中。
例如 :

public class Persion {
    private String name;
    private int value;

    @JsonProperty("v-name")
    public void setName(String name) {
        this.name = name;
    }

    @JsonProperty("v-value")
    public void setValue(int value) {
        this.value = value;
    }
}
  • 排除未知的字段@JsonIgnoreProperties(ignoreUnknown = true)

有時(shí)候json中出了具有bean聲明的字段以外膘壶,有時(shí)候還會有其他信息,但這些信息并不是我們所關(guān)系的颓芭,我們這時(shí)候就需要舍棄這部分內(nèi)容, 我們可以在類開始處使用 @JsonIgnoreProperties(ignoreUnknown = true) 注解亡问,忽略掉不匹配或者轉(zhuǎn)換失敗的字段。

@JsonIgnoreProperties(ignoreUnknown = true)
public class Persion {
    private String name;
    private int value;

    @JsonProperty("v-name")
    public void setName(String name) {
        this.name = name;
    }

    @JsonProperty("v-value")
    public void setValue(int value) {
        this.value = value;
    }
}
  • 自定義序列號與反序列化方式:

有時(shí)候 json 與 bean 并不是簡單的對應(yīng)關(guān)系州藕, 反序列化過程往往存在困難, 例如對于開始處這個 json 內(nèi)容 :

{
  "name" : "test",
  "value" : 20,
  "address" : [
    {
     "addressId" : "0001" 
    },
    {
    "addressId" : "0002"
    }
  ]
}

我們的對應(yīng) bean 為:

public class Persion {
    private String name;
    private int value;
    private List<Address> address;
}
public class Address {
    private String addressId;

    public void setAddressId(String addressId) {
        this.addressId = addressId;
    }
}

正常情況下床玻, 對于 address 字段會映射為 List<Map> 類型, 但是此處我們需要讓他自動轉(zhuǎn)換為 List<Address>
這時(shí)候就需要我們自定義反序列化過程:

反序列化類需要繼承 JsonDeserializer<T> 泛型對應(yīng)反序列化的返回類型 :

反序列化工具類

public class AddressDeserde extends JsonDeserializer<List> {
    public List deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode nodes = mapper.readTree(jsonParser);

        List<Address> addresses = new LinkedList<Address>();

        for(JsonNode node :  Lists.newArrayList(nodes.elements())){
            System.out.println(node.toString());
            addresses.add(JsonUtil.str2Bean(node.toString(), Address.class));
        }
        return addresses;
    }
}

然后便可以再 bean 中字段指名反序列化工具:

@JsonIgnoreProperties(ignoreUnknown = true)
public class Persion {
    private String name;
    private int value;
    private List<Address> address;

    @JsonProperty("v-name")
    public void setName(String name) {
        this.name = name;
    }

    @JsonProperty("v-value")
    public void setValue(int value) {
        this.value = value;
    }


    @JsonProperty("address")
    @JsonDeserialize(using = bean.AddressDeserde.class)
    public void setAddress(List<Address> address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Persion{" +
                "name='" + name + '\'' +
                ", value=" + value +
                ", addresses=" + address +
                '}';
    }
}

這時(shí)候便可以用了。

同樣的锈死,我們要自定義序列化方式需要繼承 JsonSerializer<T> 抽象方法

例如對于 address 的字段,的序列化過程:

public class AddressSerde extends JsonSerializer<List<Address>> {
    @Override
    public void serialize(List<Address> addresses, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {

        jsonGenerator.writeStartArray();
        for(Address address : addresses){
            jsonGenerator.writeObject(address);
        }
        jsonGenerator.writeEndArray();


    }
}

我們可以在 getter 方法中加入序列化方式:

@JsonProperty("v-address")
@JsonSerialize(using = bean.AddressSerde.class)
public List<Address> getAddress() {
    return address;
}

然后便能夠成功的解析出 List<Address>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末其屏,一起剝皮案震驚了整個濱河市窿克,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瞳遍,老刑警劉巖睦优,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異汗盘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)询一,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門癌椿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來菱阵,“玉大人踢俄,你說我怎么就攤上這事晴及《及欤” “怎么了虑稼?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蛛倦。 經(jīng)常有香客問我歌懒,道長溯壶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任且改,我火速辦了婚禮,結(jié)果婚禮上钾虐,老公的妹妹穿的比我還像新娘噪窘。我一直安慰自己效扫,他們只是感情好倔监,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布菌仁。 她就那樣靜靜地躺著,像睡著了一般济丘。 火紅的嫁衣襯著肌膚如雪谱秽。 梳的紋絲不亂的頭發(fā)上摹迷,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機(jī)與錄音峡碉,去河邊找鬼。 笑死鲫寄,一個胖子當(dāng)著我的面吹牛吉执,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播戳玫,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼咕宿,長吁一口氣:“原來是場噩夢啊……” “哼币绩!你這毒婦竟也來了类浪?” 一聲冷哼從身側(cè)響起肌似,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤诉瓦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后睬澡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斗躏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年啄糙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片云稚。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖静陈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拐格,我是刑警寧澤捏浊,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布角撞,位于F島的核電站,受9級特大地震影響热康,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜铁材,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一著觉、第九天 我趴在偏房一處隱蔽的房頂上張望惊暴。 院中可真熱鬧辽话,春花似錦、人聲如沸油啤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽梅鹦。三九已至评腺,卻和暖如春蒿讥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背芋绸。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工廷蓉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留马昙,地道東北人刹悴。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓土匀,卻偏偏與公主長得像形用,于是被迫代替她去往敵國和親田度。 傳聞我的和親對象是個殘疾皇子妒御,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)兰怠,斷路器揭保,智...
    卡卡羅2017閱讀 134,652評論 18 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架秸侣,建立于...
    Hsinwong閱讀 22,394評論 1 92
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,806評論 6 342
  • 1.1 spring IoC容器和beans的簡介 Spring 框架的最核心基礎(chǔ)的功能是IoC(控制反轉(zhuǎn))容器,...
    simoscode閱讀 6,713評論 2 22
  • 感恩陳斯載我去工地見客戶搏色,還請吃飯、下午茶哈哈,還學(xué)到很多東西 感恩東莞的秋天還是夏天~短袖好舒服 感恩朋友請吃玉...
    愛眉小札夏大寶閱讀 165評論 0 0