天天看點

json、Jackson專題

文章目錄

    • json說明
      • JSON 文法規則
      • JSON 值
      • JSON 對象
      • JSON 數組
    • Jackson的使用
      • Jackson的注解使用
        • 序列化注解
          • @JsonAnyGetter
          • @JsonGetter
          • @JsonPropertyOrder
          • @JsonRawValue
          • @JsonValue
          • @JsonRootName
          • @JsonSerialize
        • 反序列化注解
          • @JsonCreator
          • @JacksonInject
          • @JsonAnySetter
          • @JsonSetter
          • @JsonDeserialize
          • @JsonAlias
        • Jackson 屬性包含有關的注釋
          • @JsonIgnoreProperties
          • @JsonIgnore
          • @JsonIgnoreType
          • @JsonInclude
          • @JsonAutoDetect
        • Jackson 多态類型處理注解
        • Jackson 一般注釋
          • @JsonProperty
          • @JsonFormat
          • @JsonUnwrapped
          • @JsonView
      • 三種方式處理JSON
      • Jackson ObjectMapper
        • 使用ObjectMapper讀寫
        • Java 對象到 JSON
          • writeValue
          • writeValueAsString
          • writeValueAsBytes
        • JSON 到 Java 對象
          • readValue
        • JSON 到 Jackson JsonNode
        • 從 JSON 數組字元串建立 Java List
        • 從 JSON 字元串建立 Java Map
        • 進階功能
          • 配置序列化或反序列化功能
          • 建立自定義序列化程式或反序列化程式
          • 處理日期格式

json說明

JSON(JavaScript Object Notation)是一種輕量級的、 完全獨立于語言的文本格式。

JSON 的兩種結構:

  • 名稱/值對的集合。在各種語言中,這被實作為對象、記錄、結構、字典、哈希表、鍵控清單或關聯數組。
  • 值的有序清單。在大多數語言中,這被實作為數組、向量、清單或序列。

JSON 文法規則

JSON 文法是 JavaScript 對象表示文法的子集。

  • 大括号 {} 儲存對象
  • 中括号 [] 儲存數組,數組可以包含多個對象

JSON 值

JSON 值可以是:

  • 數字(整數或浮點數)
  • 字元串(在雙引号中)
  • 邏輯值(true 或 false)
  • 數組(在中括号中)
  • 對象(在大括号中)
  • null

JSON 對象

key 必須是字元串,value 可以是合法的 JSON 資料類型(字元串, 數字, 對象, 數組, 布爾值或 null)。

JSON 數組

[
    { key1 : value1-1 , key2:value1-2 }, 
    { key1 : value2-1 , key2:value2-2 }, 
    { key1 : value3-1 , key2:value3-2 }, 
    ...
    { keyN : valueN-1 , keyN:valueN-2 }, 
]
           

Jackson的使用

jackson序列化對象時,隻序列化非私有字段和帶有getter\setter的私有字段。

Jackson的注解使用

序列化注解

@JsonAnyGetter

該注釋允許靈活地使用 Map 字段作為标準屬性。

實體類:

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.annotation.JsonAnyGetter;

import java.util.HashMap;
import java.util.Map;

public class ExtendableBean {


  private String name;
   protected Map<String, String> properties = new HashMap<>();

    public ExtendableBean(String name) {
        this.name = name;
    }

    @JsonAnyGetter
    public Map<String, String> getProperties() {
        return properties;
    }

    public String getName() {
        return name;
    }

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


}
           

測試類:

public void whenSerializingUsingJsonAnyGetter_thenCorrect()
            throws JsonProcessingException {

        ExtendableBean bean = new ExtendableBean("My bean");
        Map<String, String> map = bean.getProperties();
        map.put("attr1", "val1");
        map.put("attr2", "val2");
        ObjectMapper objectMapper = new ObjectMapper();

        String result = objectMapper.writeValueAsString(bean);
        System.out.println(result);
    }
           

使用@JsonAnyGetter的結果

不使用的結果:

@JsonGetter

該注解是 @JsonProperty 替代方法,用于将方法标記為 getter 方法

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.annotation.JsonGetter;

public class MyBean {
    public int id;
    private String name ;

    @JsonGetter("name")
    public String getTheName() {
        return name;
    }
    public MyBean(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

           

測試類:

@Test
    public void whenSerializingUsingJsonGetter_thenCorrect()
            throws JsonProcessingException {

        MyBean bean = new MyBean(1, "My bean");

        String result = new ObjectMapper().writeValueAsString(bean);
        System.out.println(result);
    }
           

測試結果

@JsonPropertyOrder

我們可以使用@JsonPropertyOrder 注釋來指定序列化屬性的順序。

實體類:

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonPropertyOrder({ "name", "id" })
public class MyBean2 {
    public int id;
    public String name;

    public MyBean2(int id, String name) {
        this.id = id;
        this.name = name;
    }
}
           

測試方法:

@Test
    void whenSerializingUsingJsonPropertyOrder_thenCorrect() throws JsonProcessingException {
        MyBean2 bean = new MyBean2(1, "My bean");
        String result = new ObjectMapper().writeValueAsString(bean);
        System.out.println(result);
    }
           

使用注解測試結果:

不使用,測試結果:

@JsonRawValue

該@JsonRawValue注釋可以訓示傑克遜序列化的屬性完全一樣的

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.annotation.JsonRawValue;

public class RawBean {
    public String name;
    @JsonRawValue
    public String json;

    public RawBean(String name, String json) {
        this.name = name;
        this.json = json;
    }
}
           

測試方法:

@Test
    public void whenSerializingUsingJsonRawValue_thenCorrect()
            throws JsonProcessingException {

        RawBean bean = new RawBean("My bean", "{\"attr\":false}");

        String result = new ObjectMapper().writeValueAsString(bean);
        System.out.println(result);
    }
           

使用注解結果:

不用的結果:

@JsonValue

@JsonValue訓示序列化所有執行個體使用的單個方法。

實體類:

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.annotation.JsonValue;

public enum TypeEnumWithValue {
    TYPE1(1, "Type A"), TYPE2(2, "Type 2");

    private Integer id;
    private String name;

    // standard constructors

    TypeEnumWithValue(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    @JsonValue
    public String getName() {
        return name;
    }
}
           

測試:

@Test
    public void whenSerializingUsingJsonValue_thenCorrect()
            throws JsonParseException, IOException {

        String enumAsString = new ObjectMapper()
                .writeValueAsString(TypeEnumWithValue.TYPE1);

        System.out.println(enumAsString);
    }
           

使用結果:

不使用,則直接輸出Enum執行個體的名稱

@JsonRootName

使用@JsonRootName 注釋,如果啟用了包裝

mapper.enable(SerializationFeature.WRAP_ROOT_VALUE)

——會将實體序列化對象包裝在指定的對象中

實體類:

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.annotation.JsonRootName;

@JsonRootName(value = "yongren")
public class UserWithRoot {
    public int id;
    public String name;

    public UserWithRoot(int id, String name) {
        this.id = id;
        this.name = name;
    }
}
           

測試方法:

@Test
    public void whenSerializingUsingJsonRootName_thenCorrect()
            throws JsonProcessingException {

        UserWithRoot user = new UserWithRoot(1, "John");

        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
        String result = mapper.writeValueAsString(user);
        System.out.println(result);
    }
           

使用,結果:

@JsonSerialize

@JsonSerialize表示在編組實體時使用自定義序列化程式。

jackson在序列化時間Date類型時,會序列化成毫秒,指定自定義序列器,來指定時間格式。

實體:

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class EventWithSerializer {
    public String name;

    @JsonSerialize(using = CustomDateSerializer.class)
    public Date eventDate;

    public EventWithSerializer(String name, Date eventDate) {
        this.name = name;
        this.eventDate = eventDate;
    }
}
 class CustomDateSerializer extends StdSerializer<Date> {

    private static SimpleDateFormat formatter
            = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

    public CustomDateSerializer() {
        this(null);
    }

    public CustomDateSerializer(Class<Date> t) {
        super(t);
    }

    @Override
    public void serialize(
            Date value, JsonGenerator gen, SerializerProvider arg2)
            throws IOException, JsonProcessingException {
        gen.writeString(formatter.format(value));
    }
}
           

測試:

@Test
    public void whenSerializingUsingJsonSerialize_thenCorrect()
            throws JsonProcessingException, ParseException {

        SimpleDateFormat df
                = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

        String toParse = "20-12-2014 02:30:00";
        Date date = df.parse(toParse);
        EventWithSerializer event = new EventWithSerializer("party", date);

        String result = new ObjectMapper().writeValueAsString(event);
        System.out.println(result);
    }
           

不使用注解:

使用注解:

反序列化注解

@JsonCreator

我們可以使用 @JsonCreator 注釋來調整反序列化中使用的構造函數/工廠。

實體:

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class BeanWithCreator {
    public int id;
    public String name;

    @JsonCreator
    public BeanWithCreator(
            @JsonProperty("id") int id,
            @JsonProperty("theName") String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "BeanWithCreator{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
           

測試:

@Test
    public void whenDeserializingUsingJsonCreator_thenCorrect()
            throws IOException {

        String json = "{\"id\":1,\"theName\":\"My bean\"}";

        BeanWithCreator bean = new ObjectMapper()
                .readerFor(BeanWithCreator.class)
                .readValue(json);
        System.out.println(bean);
    }
           

使用注解,結果:

不使用注解,結果:

  • 僅使用@JsonProperty,正常使用
  • 不存在@JsonProperty,報錯
  • 不使用任何注解,報錯
@JacksonInject

@JacksonInject表示屬性将從注入中擷取其值,而不是從 JSON 資料中擷取。根據類型推斷的,是以同一類型注入,隻能有一個;每個屬性注入都必須有值。

實體:

public class BeanWithInject {
    @JacksonInject
    public int id;
    
    public String name;
       @Override
    public String toString() {
        return "BeanWithInject{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
           

測試:

@Test
    public void whenDeserializingUsingJsonInject_thenCorrect()
            throws IOException {

        String json = "{\"name\":\"My bean\"}";

        InjectableValues inject = new InjectableValues.Std()
                .addValue(int.class, 1);
        BeanWithInject bean = new ObjectMapper().reader(inject)
                .forType(BeanWithInject.class)
                .readValue(json);
        System.out.println(bean);

    }
           

結果:

@JsonAnySetter

@JsonAnySetter允許我們靈活地使用Map作為标準屬性。在反序列化時,來自 JSON 的屬性将簡單地添加到映射中。

實體:

public class ExtendableBean {
    public String name;
    private Map<String, String> properties;

    @JsonAnySetter
    public void add(String key, String value) {
        properties.put(key, value);
    }
}
           

測試:

@Test
public void whenDeserializingUsingJsonAnySetter_thenCorrect()
  throws IOException {
    String json
      = "{\"name\":\"My bean\",\"attr2\":\"val2\",\"attr1\":\"val1\"}";

    ExtendableBean bean = new ObjectMapper()
      .readerFor(ExtendableBean.class)
      .readValue(json);
    
    assertEquals("My bean", bean.name);
    assertEquals("val2", bean.getProperties().get("attr2"));
}
           

測試結果:

使用注解:

不使用注解,将因屬性不比對爆錯。

@JsonSetter

@JsonSetter是@JsonProperty的替代方法,它将方法标記為 setter 方法。

當我們需要讀取一些 JSON 資料時,這非常有用,但目标實體類與該資料不完全比對,是以我們需要調整過程以使其适合。

@JsonGetter、@JsonSetter、@JsonProperty在各自作用範圍上使用,效果一樣。

@JsonDeserialize

@JsonDeserialize表示使用自定義反序列化器。

實體:

public class EventWithSerializer {

public String name;

@JsonDeserialize(using = CustomDateDeserializer.class)
public Date eventDate;
           

}

@JsonAlias

@JsonAlias定義反序列化過程為屬性的一個或多個的替代名稱。

實體:

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.annotation.JsonAlias;

public class AliasBean {

    @JsonAlias({"fName", "f_name"})
    private String firstName;
    private String lastName;


    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return "AliasBean{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                '}';
    }
}

           

測試:

@Test
    public void whenDeserializingUsingJsonAlias_thenCorrect() throws IOException {
        String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}";
        AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json);
        String json2 = "{\"f_name\": \"John\", \"lastName\": \"Green\"}";
        AliasBean aliasBean2 = new ObjectMapper().readerFor(AliasBean.class).readValue(json2);
        System.out.println(aliasBean);
        System.out.println(aliasBean2);
    }
           

結果:

AliasBean{firstName='John', lastName='Green'}
AliasBean{firstName='John', lastName='Green'}
           

Jackson 屬性包含有關的注釋

@JsonIgnoreProperties

@JsonIgnoreProperties是一個類級别的注釋,用于标記 Jackson 将忽略的屬性或屬性清單。

實體:

@JsonIgnoreProperties({ "id" })
public class BeanWithIgnore {
    public int id;
    public String name;
}
           

測試:

@Test
    public void whenSerializingUsingJsonIgnoreProperties_thenCorrect()
            throws JsonProcessingException {

        BeanWithIgnore bean = new BeanWithIgnore(1, "My bean");

        String result = new ObjectMapper()
                .writeValueAsString(bean);

        System.out.println(result);
    }

           

結果:

@JsonIgnore

JsonIgnore注解用于在字段級别标記要忽略的屬性。

@JsonIgnoreType

@JsonIgnoreType将注釋類型的所有屬性标記為被忽略。

例如:

public class User {
    public int id;
    public Name name;

    @JsonIgnoreType
    public static class Name {
        public String firstName;
        public String lastName;
    }
}
           
@JsonInclude

我們可以使用@JsonInclude排除具有null/空/預設值的屬性。

實體:

@JsonInclude(Include.NON_NULL)
public class MyBean {
    public int id;
    public String name;
}
           

測試:

@Test
    public void whenSerializingUsingJsonInclude_thenCorrect()
            throws JsonProcessingException {

        MyBean bean = new MyBean(1, null);

        String result = new ObjectMapper()
                .writeValueAsString(bean);
        System.out.println(result);
    }
           

結果:

@JsonAutoDetect

@JsonAutoDetect可以覆寫哪些屬性可見和哪些屬性不可見的預設語義。

實體:

package com.yongren.jsonAnnotation;


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;

@JsonAutoDetect(fieldVisibility = Visibility.PUBLIC_ONLY)
public class PrivateBean {
    private int id;
    private String name;

    public PrivateBean() {

    }

    public PrivateBean(final int id, final String name) {
        this.id = id;
        this.name = name;
    }
}
           

測試:

@Test
    public void whenSerializingUsingJsonAutoDetect_thenCorrect()
            throws JsonProcessingException {

        PrivateBean bean = new PrivateBean(1, "My bean");

        String result = new ObjectMapper()
                .writeValueAsString(bean);
        System.out.println(result);
    }
           

結果:

Jackson 多态類型處理注解

接下來我們來看看Jackson多态類型處理注解:

  • @JsonTypeInfo – 訓示序列化中包含哪些類型資訊的詳細資訊
  • @JsonSubTypes – 表示注釋類型的子類型
  • @JsonTypeName – 定義用于帶注釋的類的邏輯類型名稱

實體:

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;

public class Zoo {
    public Animal animal;

    public Zoo() {

    }

    @Override
    public String toString() {
        return "Zoo{" +
                "animal=" + animal +
                '}';
    }

    public Zoo(final Animal animal) {
        this.animal = animal;
    }

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

        @Override
        public String toString() {
            return "Animal{" +
                    "name='" + name + '\'' +
                    '}';
        }

        public Animal() {
        }

        public Animal(final String name) {
            this.name = name;
        }

    }

    @JsonTypeName("dog")
    public static class Dog extends Animal {
        public double barkVolume;

        @Override
        public String toString() {
            return "Dog{" +
                    "name='" + name + '\'' +
                    ", barkVolume=" + barkVolume +
                    '}';
        }

        public Dog() {
        }

        public Dog(final String name) {
            this.name = name;
        }
    }

    @JsonTypeName("cat")
    public static class Cat extends Animal {
        boolean likesCream;
        public int lives;

        @Override
        public String toString() {
            return "Cat{" +
                    "name='" + name + '\'' +
                    ", likesCream=" + likesCream +
                    ", lives=" + lives +
                    '}';
        }

        public Cat() {
        }

        public Cat(final String name) {
            this.name = name;
        }
    }
}
           

測試:

@Test
    public void whenSerializingPolymorphic_thenCorrect()
            throws JsonProcessingException {
        Zoo.Dog dog = new Zoo.Dog("lacy");
        Zoo zoo = new Zoo(dog);

        String result = new ObjectMapper()
                .writeValueAsString(zoo);
        System.out.println(result);


        Zoo deserializeZoo = new ObjectMapper()
                .readerFor(Zoo.class)
                .readValue(result);
        System.out.println(deserializeZoo);
    }
           

結果:

{"animal":{"type":"dog","name":"lacy","barkVolume":0.0}}
Zoo{animal=Dog{name='lacy', barkVolume=0.0}}
           

Jackson 一般注釋

@JsonProperty

通過添加的@JsonProperty注釋,指明在JSON屬性名。

@JsonFormat

序列化日期/時間值時,用該@JsonFormat注解指定格式。

實體:

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.annotation.JsonFormat;

import java.util.Date;

public class EventWithFormat {

        public String name;

        @JsonFormat(
                shape = JsonFormat.Shape.STRING,
                pattern = "yyyy-MM-dd hh:mm:ss")
        public Date eventDate;

        public EventWithFormat(String name, Date eventDate) {
                this.name = name;
                this.eventDate = eventDate;
        }
}

           

測試:

@Test
    public void whenSerializingUsingJsonFormat_thenCorrect()
            throws JsonProcessingException, ParseException {
        Date date=new Date();
        System.out.println(date);
        SimpleDateFormat df = new SimpleDateFormat("MM-dd-yyyy hh:mm:ss");
        String format = df.format(date);
        System.out.println(format);
         date = df.parse(format);
        EventWithFormat event = new EventWithFormat("party", date);

        String result = new ObjectMapper().writeValueAsString(event);
        System.out.println(result);
    }
           

結果:

Thu Sep 16 10:46:53 CST 2021
09-16-2021 10:46:53
{"name":"party","eventDate":"2021-09-16 02:46:53"}
           
@JsonUnwrapped

@JsonUnwrapped定義了在序列化/反序列化時應該解包/展平的值。

實體:

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.annotation.JsonUnwrapped;

public class UnwrappedUser {
    public int id;

    @JsonUnwrapped
    public Name name;

    public UnwrappedUser(int id, Name name) {
        this.id = id;
        this.name = name;
    }

    public static class Name {
        public String firstName;
        public String lastName;

        public Name(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
    }
}
           

測試:

@Test
    public void whenSerializingUsingJsonUnwrapped_thenCorrect()
            throws JsonProcessingException, ParseException {
        UnwrappedUser.Name name = new UnwrappedUser.Name("John", "Doe");
        UnwrappedUser user = new UnwrappedUser(1, name);

        String result = new ObjectMapper().writeValueAsString(user);
        System.out.println(result);

    }
           

結果:

@JsonView

@JsonView用于在序列化/反序列化時指定一個視圖類(視圖就是java類),僅有視圖對應的屬性被序列化/反序列化。

視圖:

public class Views {

}
class view1 {}
class view2 {}
class view3 {}
           

實體:

package com.yongren.jsonAnnotation;

import com.fasterxml.jackson.annotation.JsonView;

public class Item {
    @JsonView(view1.class)
    public int id;

    @JsonView(view2.class)
    public String itemName;

    @JsonView(view3.class)
    public String ownerName;

    public Item(int id, String itemName, String ownerName) {
        this.id = id;
        this.itemName = itemName;
        this.ownerName = ownerName;
    }
}
           

結果:

{"id":2}
{"itemName":"book"}
           

三種方式處理JSON

  • 流式API - -讀取并将JSON内容寫入作為離散事件。 JsonParser讀取資料,而JsonGenerator寫入資料。它是三者中最有效的方法,是最低的開銷和最快的讀/寫操作。它類似于Stax解析器XML。
  • 樹模型 - - 準備JSON檔案在記憶體裡以樹形式表示。 ObjectMapper建構JsonNode節點樹。這是最靈活的方法。它類似于XML的DOM解析器。
  • 資料綁定 – 轉換JSON并從POJO(普通Java對象)使用屬性通路或使用注釋。ObjectMapper讀/寫JSON兩種類型的資料綁定。資料綁定是最友善的方式是類似XML的JAXB解析器。它有兩個類型。
    • 簡單的資料綁定 - -轉換JSON和Java Maps, Lists, Strings, Numbers, Booleans 和null 對象。
    • 全部資料綁定 - -從任何JAVA類型轉換為JSON。

Jackson ObjectMapper

使用ObjectMapper類将 Java 對象序列化為 JSON 并将 JSON 字元串反序列化為 Java 對象。

使用ObjectMapper讀寫

  • 使用

    readValue

    API将 JSON 内容解析或反序列化為 Java 對象。
  • 使用

    writeValue

    API 将任何 Java 對象序列化為 JSON 輸出。

    示例實體:

package com.yongren.objectMapper;

public class Car {

    private String color;
    private String type;

    public Car() {
    }

    public Car(String color, String type) {
        this.color = color;
        this.type = type;
    }
// standard getters setters

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "Car{" +
                "color='" + color + '\'' +
                ", type='" + type + '\'' +
                '}';
    }
}
           

Java 對象到 JSON

writeValue

使用ObjectMapper類的writeValue方法将 Java 對象序列化為 JSON 的示例:

@Test
    public void usingWriteValue() {
        ObjectMapper objectMapper = new ObjectMapper();
        Car car = new Car("yellow", "renault");
        try {
            objectMapper.writeValue(new File("target/car.json"), car);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
           

檔案中的結果:

writeValueAsString

測試:

@Test
    public void usingWriteValueAsString() {
        ObjectMapper objectMapper = new ObjectMapper();
        Car car = new Car("yellow", "renault");
        try {
            String carAsString = objectMapper.writeValueAsString(car);
            System.out.println(carAsString);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
           

輸出:

writeValueAsBytes

測試:

@Test
    public void usingWriteValueAsBytes() {
        ObjectMapper objectMapper = new ObjectMapper();
        Car car = new Car("yellow", "renault");

        byte[] carAsString = null;
        try {
            carAsString = objectMapper.writeValueAsBytes(car);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        System.out.println(carAsString);

    }
           

輸出:

JSON 到 Java 對象

readValue

測試:

@Test
    public void usingReadValue() {
        String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
        try {
            Car car = objectMapper.readValue(json, Car.class);
            System.out.println(car);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

    }

           

輸出:

readValue()函數還接受其他形式的輸入,諸如包含JSON字元串檔案:

或網址:

Car car = 
  objectMapper.readValue(new URL("file:src/test/resources/json_car.json"), Car.class);
           

JSON 到 Jackson JsonNode

可以将 JSON 解析為JsonNode對象并用于從特定節點檢索資料:

String json = "{ \"color\" : \"Black\", \"type\" : \"FIAT\" }";
JsonNode jsonNode = objectMapper.readTree(json);
String color = jsonNode.get("color").asText();
           

從 JSON 數組字元串建立 Java List

可以使用TypeReference将數組形式的 JSON 解析為 Java 對象清單:

String jsonCarArray = 
  "[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
List<Car> listCar = objectMapper.readValue(jsonCarArray, new TypeReference<List<Car>>(){});
           

輸出:

從 JSON 字元串建立 Java Map

可以使用TypeReference将數組形式的 JSON 解析為 Java Map:

String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
Map<String, Object> map 
  = objectMapper.readValue(json, new TypeReference<Map<String,Object>>(){});
           

輸出:

進階功能

配置序列化或反序列化功能

在将 JSON 對象轉換為 Java 類時,如果 JSON 字元串有一些新字段,預設過程将導緻異常:

示例:

String jsonString 
  = "{ \"color\" : \"Black\", \"type\" : \"Fiat\", \"year\" : \"1970\" }";
           

上例中的 JSON 字元串在預設解析為類 Car的 Java 對象的過程中将導緻

UnrecognizedPropertyException

異常。

通過

configure

方法,我們可以擴充預設流程來忽略新字段:

@Test
    public void usingConfigure(){
         String jsonString
                 = "{ \"color\" : \"Black\", \"type\" : \"Fiat\", \"year\" : \"1970\" }";
         objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
         try {
             Car car = objectMapper.readValue(jsonString, Car.class);
             System.out.println(car);
         } catch (JsonProcessingException e) {
             e.printStackTrace();
         }

         JsonNode jsonNodeRoot = null;
         try {
             jsonNodeRoot = objectMapper.readTree(jsonString);
         } catch (JsonProcessingException e) {
             e.printStackTrace();
         }
         JsonNode jsonNodeYear = jsonNodeRoot.get("year");
         String year = jsonNodeYear.asText();
         System.out.println(year);
     }
           

輸出:

Car{color='Black', type='Fiat'}
1970

           

另一個選項基于FAIL_ON_NULL_FOR_PRIMITIVES,它定義是否允許原始值的空值;

FAIL_ON_NUMBERS_FOR_ENUM控制是否允許将枚舉值序列化/反序列化為數字;

建立自定義序列化程式或反序列化程式

ObjectMapper類的另一個基本特性是能夠注冊自定義序列化器和反序列化器。

自定義序列化器和反序列化器在輸入或輸出 JSON 響應的結構與必須對其進行序列化或反序列化的 Java 類不同的情況下非常有用。

以下是自定義 JSON 序列化程式的示例:

public class CustomCarSerializer extends StdSerializer<Car> {
    
    public CustomCarSerializer() {
        this(null);
    }

    public CustomCarSerializer(Class<Car> t) {
        super(t);
    }

    @Override
    public void serialize(
      Car car, JsonGenerator jsonGenerator, SerializerProvider serializer) {
        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("car_brand", car.getType());
        jsonGenerator.writeEndObject();
    }
}
           

這個自定義序列化器可以這樣調用:

@Test
    public void usingCustomCarSerializer(){
         ObjectMapper mapper = new ObjectMapper();
         SimpleModule module =
                 new SimpleModule("CustomCarSerializer", new Version(1, 0, 0, null, null, null));
         module.addSerializer(Car.class, new CustomCarSerializer());
         mapper.registerModule(module);
         Car car = new Car("yellow", "renault");
         try {
             String carJson = mapper.writeValueAsString(car);
             System.out.println(carJson);
         } catch (JsonProcessingException e) {
             e.printStackTrace();
         }
     }
           

輸出:

處理日期格式

java.util.Date的預設序列化會産生一個數字,即紀元時間戳(自 1970 年 1 月 1 日起的毫秒數,UTC)。但這不是人類可讀的,需要進一步轉換才能以人類可讀的格式顯示。

實體:

public class Request 
{
    private Car car;
    private Date datePurchased;

    // standard getters setters
}
           

測試:

ObjectMapper objectMapper = new ObjectMapper();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
objectMapper.setDateFormat(df);
String carAsString = objectMapper.writeValueAsString(request);
// output: {"car":{"color":"yellow","type":"renault"},"datePurchased":"2016-07-03 11:43 AM CEST"}