Jackson用法詳解



@

目錄


Spring MVC 默認采用Jackson解析Json,盡管還有一些其它同樣優秀的json解析工具,例如Fast Json、GSON,但是出於最小依賴的考慮,也許Json解析第一選擇就應該是Jackson。


一、簡介

Jackson 是當前用的比較廣泛的,用來序列化和反序列化 json 的 Java 的開源框架。Jackson 社區相對比較活躍,更新速度也比較快, 從 Github 中的統計來看,Jackson 是最流行的 json 解析器之一 。 Spring MVC 的默認 json 解析器便是 Jackson。 Jackson 優點很多。 Jackson 所依賴的 jar 包較少 ,簡單易用。與其他 Java 的 json 的框架 Gson 等相比, Jackson 解析大的 json 文件速度比較快;Jackson 運行時占用內存比較低,性能比較好;Jackson 有靈活的 API,可以很容易進行擴展和定制。

Jackson 的 1.x 版本的包名是 org.codehaus.jackson ,當升級到 2.x 版本時,包名變為 com.fasterxml.jackson。

Jackson 的核心模塊由三部分組成。

  • jackson-core,核心包,提供基於"流模式"解析的相關 API,它包括 JsonPaser 和 JsonGenerator。 Jackson 內部實現正是通過高性能的流模式 API 的 JsonGenerator 和 JsonParser 來生成和解析 json。
  • jackson-annotations,注解包,提供標准注解功能;
  • jackson-databind ,數據綁定包, 提供基於"對象綁定" 解析的相關 API ( ObjectMapper ) 和"樹模型" 解析的相關 API (JsonNode);基於"對象綁定" 解析的 API 和"樹模型"解析的 API 依賴基於"流模式"解析的 API。

源碼地址:FasterXML/jackson


二、依賴

使用Maven構建項目,需要添加依賴:

<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>

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.6</version>
</dependency>

當然了,jackson-databind 依賴 jackson-core 和 jackson-annotations,所以可以只顯示地添加jackson-databind依賴,jackson-core 和 jackson-annotations 也隨之添加到 Java 項目工程中。

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.6</version>
</dependency>

下面是Jackson的用法。


三、 ObjectMapper

Jackson 最常用的 API 就是基於"對象綁定" 的 ObjectMapper:

  • ObjectMapper可以從字符串,流或文件中解析JSON,並創建表示已解析的JSON的Java對象。 將JSON解析為Java對象也稱為從JSON反序列化Java對象。

  • ObjectMapper也可以從Java對象創建JSON。 從Java對象生成JSON也稱為將Java對象序列化為JSON。

  • Object映射器可以將JSON解析為自定義的類的對象,也可以解析置JSON樹模型的對象。

之所以稱為ObjectMapper是因為它將JSON映射到Java對象(反序列化),或者將Java對象映射到JSON(序列化)。


一)、從JSON中獲取Java對象

1、簡單示例

一個簡單的例子:

Car類:

public class Car {
	private String brand = null;
    private int doors = 0;

    public String getBrand() { return this.brand; }
    public void   setBrand(String brand){ this.brand = brand;}

    public int  getDoors() { return this.doors; }
    public void setDoors (int doors) { this.doors = doors; }
}

將Json轉換為Car類對象:

        ObjectMapper objectMapper = new ObjectMapper();

		String carJson ="{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

		try {
		    Car car = objectMapper.readValue(carJson, Car.class);

		    System.out.println("car brand = " + car.getBrand());
		    System.out.println("car doors = " + car.getDoors());
		} catch (IOException e) {
		    e.printStackTrace();
		}

2、 ObjectMapper如何匹配JSON對象的字段和Java對象的屬性

默認情況下,Jackson通過將JSON字段的名稱與Java對象中的getter和setter方法進行匹配,將JSON對象的字段映射到Java對象中的屬性。 Jackson刪除了getter和setter方法名稱的“ get”和“ set”部分,並將其余名稱的第一個字符轉換為小寫。

例如,名為brand的JSON字段與名為getBrand()和setBrand()的Java getter和setter方法匹配。 名為engineNumber的JSON字段將與名為getEngineNumber()和setEngineNumber()的getter和setter匹配。

如果需要以其他方式將JSON對象字段與Java對象字段匹配,則需要使用自定義序列化器和反序列化器,或者使用一些Jackson注解。


3、JSON字符串-->Java對象

從JSON字符串讀取Java對象非常容易。 上面已經有了一個示例——JSON字符串作為第一個參數傳遞給ObjectMapper的readValue()方法。 這是另一個簡單的示例:

ObjectMapper objectMapper = new ObjectMapper();

String carJson =
    "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

Car car = objectMapper.readValue(carJson, Car.class);

3、JSON 字符輸入流-->Java對象

還可以從通過Reader實例加載的JSON中讀取對象。示例如下:

ObjectMapper objectMapper = new ObjectMapper();

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 4 }";
Reader reader = new StringReader(carJson);

Car car = objectMapper.readValue(reader, Car.class);

4、JSON文件-->Java對象

從文件讀取JSON當然可以通過FileReader(而不是StringReader)來完成,也可以通過File對象來完成。 這是從文件讀取JSON的示例:

ObjectMapper objectMapper = new ObjectMapper();

File file = new File("data/car.json");

Car car = objectMapper.readValue(file, Car.class);

5、JSON via URL--->Java對象

可以通過URL(java.net.URL)從JSON讀取對象,如下所示:

ObjectMapper objectMapper = new ObjectMapper();

URL url = new URL("file:data/car.json");

Car car = objectMapper.readValue(url, Car.class);

示例使用文件URL,也可以使用HTTP URL(類似於http://jenkov.com/some-data.json)。


6、JSON字節輸入流-->Java對象

也可以使用ObjectMapper通過InputStream從JSON讀取對象。 這是一個從InputStream讀取JSON的示例:

ObjectMapper objectMapper = new ObjectMapper();

InputStream input = new FileInputStream("data/car.json");

Car car = objectMapper.readValue(input, Car.class);

7、JSON二進制數組-->Java對象

Jackson還支持從JSON字節數組讀取對象。 這是從JSON字節數組讀取對象的示例:

ObjectMapper objectMapper = new ObjectMapper();

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

byte[] bytes = carJson.getBytes("UTF-8");

Car car = objectMapper.readValue(bytes, Car.class);

8、JSON數組字符串-->Java對象數組

Jackson ObjectMapper也可以從JSON數組字符串讀取對象數組。 這是從JSON數組字符串讀取對象數組的示例:

String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";

ObjectMapper objectMapper = new ObjectMapper();

Car[] cars2 = objectMapper.readValue(jsonArray, Car[].class);

需要將Car數組類作為第二個參數傳遞給readValue()方法。

讀取對象數組還可以與字符串以外的其他JSON源一起使用。 例如,文件,URL,InputStream,Reader等。


9、JSON數組字符串-->List

Jackson ObjectMapper還可以從JSON數組字符串讀取對象的Java List。 這是從JSON數組字符串讀取對象列表的示例:

    String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";

	ObjectMapper objectMapper = new ObjectMapper();

	List<Car> cars1 = objectMapper.readValue(jsonArray, new TypeReference<List<Car>>(){});

10、JSON字符串-->Map

Jackson ObjectMapper還可以從JSON字符串讀取Java Map。 如果事先不知道將要解析的確切JSON結構,這種方法是很有用的。 通常,會將JSON對象讀入Java Map。 JSON對象中的每個字段都將成為Java Map中的鍵,值對。

這是一個使用Jackson ObjectMapper從JSON字符串讀取Java Map的示例:

String jsonObject = "{\"brand\":\"ford\", \"doors\":5}";

ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> jsonMap = objectMapper.readValue(jsonObject,
    new TypeReference<Map<String,Object>>(){});

11、忽略未知的JSON字段

有時候,與要從JSON讀取的Java對象相比,JSON中的字段更多。 默認情況下,Jackson在這種情況下會拋出異常,報不知道XYZ字段異常,因為在Java對象中找不到該字段。

但是,有時應該允許JSON中的字段多於相應的Java對象中的字段。 例如,要從REST服務解析JSON,而該REST服務包含的數據遠遠超出所需的。 在這種情況下,可以使用Jackson配置忽略這些額外的字段。 以下是配置Jackson ObjectMapper忽略未知字段的示例:

objectMapper.configure(
    DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

12、不允許基本類型為null

如果JSON字符串包含其值設置為null的字段(對於在相應的Java對象中是基本數據類型(int,long,float,double等)的字段),Jackson ObjectMapper默認會處理基本數據類型為null的情況,我們可以可以將Jackson ObjectMapper默認配置為失效,這樣基本數據為null就會轉換失敗。 例如以下Car類:

public class Car {
    private String brand = null;
    private int doors = 0;

    public String getBrand() { return this.brand; }
    public void   setBrand(String brand){ this.brand = brand;}

    public int  getDoors(){ return this.doors; }
    public void setDoors (int doors) { this.doors = doors; }
}

doors字段是一個int類型,它是Java中的基本數據類型。

現在,假設有一個與Car對象相對應的JSON字符串,如下所示:

{ "brand":"Toyota", "doors":null }

請注意,doors字段值為null。 Java中的基本數據類型不能為null值。 默認情況下,Jackson ObjectMapper會忽略原始字段的空值。 但是,可以將Jackson ObjectMapper配置設置為失敗。

ObjectMapper objectMapper = new ObjectMapper();

objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);

在FAIL_ON_NULL_FOR_PRIMITIVES配置值設置為true的情況下,嘗試將空JSON字段解析為基本類型Java字段時會遇到異常。 這是一個Java Jackson ObjectMapper示例,該示例將失敗,因為JSON字段包含原始Java字段的空值:

		ObjectMapper objectMapper = new ObjectMapper();

		objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);

		String carJson = "{ \"brand\":\"Toyota\", \"doors\":null }";

		Car car = objectMapper.readValue(carJson, Car.class);

結果:

在這里插入圖片描述

13、自定義反序列化

有時,可能希望以不同於Jackson ObjectMapper缺省方式的方式將JSON字符串讀入Java對象。 可以將自定義反序列化器添加到ObjectMapper,可以按需要執行反序列化。

這是在Jackson的ObjectMapper中注冊和使用自定義反序列化器的方式:

		String json = "{ \"brand\" : \"Ford\", \"doors\" : 6 }";

		SimpleModule module =
		        new SimpleModule("CarDeserializer", new Version(3, 1, 8, null, null, null));
		module.addDeserializer(Car.class, new CarDeserializer(Car.class));

		ObjectMapper mapper = new ObjectMapper();
		mapper.registerModule(module);

		Car car = mapper.readValue(json, Car.class);

自定義反序列化器CarDeserializer類:

public class CarDeserializer extends StdDeserializer<Car> {

    public CarDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public Car deserialize(JsonParser parser, DeserializationContext deserializer) throws IOException {
        Car car = new Car();
        while(!parser.isClosed()){
            JsonToken jsonToken = parser.nextToken();

            if(JsonToken.FIELD_NAME.equals(jsonToken)){
                String fieldName = parser.getCurrentName();
                System.out.println(fieldName);

                jsonToken = parser.nextToken();

                if("brand".equals(fieldName)){
                    car.setBrand(parser.getValueAsString());
                } else if ("doors".equals(fieldName)){
                    car.setDoors(parser.getValueAsInt());
                }
            }
        }
        return car;
    }
}

二)、將對象寫入JSON


1、Java對象-->JSON

Jackson ObjectMapper也可以用於從對象生成JSON。 可以使用以下方法之一進行操作:

  • writeValue()
  • writeValueAsString()
  • writeValueAsBytes()

這是一個從Car對象生成JSON的示例,和上面的實例相反:

ObjectMapper objectMapper = new ObjectMapper();

		Car car = new Car();
		car.setBrand("BMW");
		car.setDoors(4);

		objectMapper.writeValue(
		    new FileOutputStream("data/output-2.json"), car);

此示例首先創建一個ObjectMapper,然后創建一個Car實例,最后調用ObjectMapper的writeValue()方法,該方法將Car對象轉換為JSON並將其寫入給定的FileOutputStream。

ObjectMapper的writeValueAsString()和writeValueAsBytes()都從一個對象生成JSON,並將生成的JSON作為String或字節數組返回。 示例如下:

		ObjectMapper objectMapper = new ObjectMapper();

		Car car = new Car();
		car.setBrand("寶馬");
		car.setDoors(4);

		String json = objectMapper.writeValueAsString(car);
		System.out.println(json);

運行結果:
在這里插入圖片描述

2、自定義序列化

有時,想要將Java對象序列化為JSON的方式與使用Jackson的默認方式不同。 例如,可能想要在JSON中使用與Java對象中不同的字段名稱,或者希望完全省略某些字段。

Jackson可以在ObjectMapper上設置自定義序列化器。 該序列化器已為某個類注冊,然后在每次要求ObjectMapper序列化Car對象時將調用該序列化器。

這是為Car類注冊自定義序列化器的示例:

		CarSerializer carSerializer = new CarSerializer(Car.class);
		ObjectMapper objectMapper = new ObjectMapper();

		SimpleModule module =
		        new SimpleModule("CarSerializer", new Version(2, 1, 3, null, null, null));
		module.addSerializer(Car.class, carSerializer);

		objectMapper.registerModule(module);

		Car car = new Car();
		car.setBrand("Mercedes");
		car.setDoors(5);

		String carJson = objectMapper.writeValueAsString(car);

自定義序列化器CarSerializer類:

public class CarSerializer extends StdSerializer<Car> {

    protected CarSerializer(Class<Car> t) {
        super(t);
    }

    public void serialize(Car car, JsonGenerator jsonGenerator,
                          SerializerProvider serializerProvider)
            throws IOException {

        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("producer", car.getBrand());
        jsonGenerator.writeNumberField("doorCount", car.getDoors());
        jsonGenerator.writeEndObject();
    }
}

運行結果:

在這里插入圖片描述


三)、Jackson 日期轉化

默認情況下,Jackson會將java.util.Date對象序列化為其long型的值,該值是自1970年1月1日以來的毫秒數。但是,Jackson還支持將日期格式化為字符串。

1、Date-->long

默認的Jackson日期格式,該格式將Date序列化為自1970年1月1日以來的毫秒數(long類型)。

這是一個包含Date字段的Java類示例:

    private String type = null;
    private Date date = null;

    public Transaction() {
    }

    public Transaction(String type, Date date) {
        this.type = type;
        this.date = date;
    }

    public String getType() {
        return type;
    }

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

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

就像使用其他Java對象進行序列化一樣,代碼如下:

		Transaction transaction = new Transaction("transfer", new Date());

		ObjectMapper objectMapper = new ObjectMapper();
		String output = objectMapper.writeValueAsString(transaction);

		System.out.println(output);

運行結果:

在這里插入圖片描述

2、Date-->String

日期的long序列化格式不符合人類的時間查看格式。 因此,Jackson也支持文本日期格式。 可以通過在ObjectMapper上設置SimpleDateFormat來指定要使用的確切Jackson日期格式。 這是在Jackson的ObjectMapper上設置SimpleDateFormat的示例:

		Transaction transaction = new Transaction("transfer", new Date());

		ObjectMapper objectMapper = new ObjectMapper();
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		objectMapper.setDateFormat(dateFormat);

		String output2 = objectMapper.writeValueAsString(transaction);
		System.out.println(output2);

運行結果:

在這里插入圖片描述

四)、Jackson JSON 樹模型

Jackson具有內置的樹模型,可用於表示JSON對象。 如果不知道接收到的JSON的格式,或者由於某種原因而不能(或者只是不想)創建一個類來表示它,那么就要用到Jackson的樹模型。 如果需要在使用或轉化JSON之前對其進行操作,也需要被用到Jackson樹模型。 所有這些情況在數據流場景中都很常見。

Jackson樹模型由JsonNode類表示。 您可以使用Jackson ObjectMapper將JSON解析為JsonNode樹模型,就像使用您自己的類一樣。

以下將展示如何使用Jackson ObjectMapper讀寫JsonNode實例。

1、Jackson Tree Model簡單例子

下面是一個簡單的例子:

		String carJson =
		        "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

		ObjectMapper objectMapper = new ObjectMapper();

		try {

		    JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);

		} catch (IOException e) {
		    e.printStackTrace();
		}

只需將JsonNode.class作為第二個參數傳遞給readValue()方法,而不是本教程前面的示例中使用的Car.class,就可以將JSON字符串解析為JsonNode對象而不是Car對象。 。

ObjectMapper類還具有一個特殊的readTree()方法,該方法返回JsonNode。 這是使用ObjectMapper readTree()方法將JSON解析為JsonNode的示例:

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

ObjectMapper objectMapper = new ObjectMapper();

try {

    JsonNode jsonNode = objectMapper.readTree(carJson);

} catch (IOException e) {
    e.printStackTrace();
}

2、Jackson JsonNode類

通過JsonNode類,可以以非常靈活和動態的方式將JSON作為Java對象導航。這里了解一些如何使用它的基礎知識。

將JSON解析為JsonNode(或JsonNode實例樹)后,就可以瀏覽JsonNode樹模型。 這是一個JsonNode示例,顯示了如何訪問JSON字段,數組和嵌套對象:

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 5," +
        "  \"owners\" : [\"John\", \"Jack\", \"Jill\"]," +
        "  \"nestedObject\" : { \"field\" : \"value\" } }";

ObjectMapper objectMapper = new ObjectMapper();


try {

    JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);

    JsonNode brandNode = jsonNode.get("brand");
    String brand = brandNode.asText();
    System.out.println("brand = " + brand);

    JsonNode doorsNode = jsonNode.get("doors");
    int doors = doorsNode.asInt();
    System.out.println("doors = " + doors);

    JsonNode array = jsonNode.get("owners");
    JsonNode jsonNode = array.get(0);
    String john = jsonNode.asText();
    System.out.println("john  = " + john);

    JsonNode child = jsonNode.get("nestedObject");
    JsonNode childField = child.get("field");
    String field = childField.asText();
    System.out.println("field = " + field);

} catch (IOException e) {
    e.printStackTrace();
}

請注意,JSON字符串現在包含一個稱為owners的數組字段和一個稱為nestedObject的嵌套對象字段。

無論訪問的是字段,數組還是嵌套對象,都可以使用JsonNode類的get()方法。 通過將字符串作為參數提供給get()方法,可以訪問JsonNode的字段。 如果JsonNode表示數組,則需要將索引傳遞給get()方法。 索引指定要獲取的數組元素。


3、Java對象-->JsonNode

可以使用Jackson ObjectMapper將Java對象轉換為JsonNode,而JsonNode是轉換后的Java對象的JSON表示形式。 可以通過Jackson ObjectMapper valueToTree()方法將Java對象轉換為JsonNode。 這是一個使用ObjectMapper valueToTree()方法將Java對象轉換為JsonNode的示例:

ObjectMapper objectMapper = new ObjectMapper();

Car car = new Car();
car.brand = "Cadillac";
car.doors = 4;

JsonNode carJsonNode = objectMapper.valueToTree(car);

4、JsonNode-->Java對象

可以使用Jackson ObjectMapper treeToValue()方法將JsonNode轉換為Java對象。 這類似於使用Jackson Jackson的ObjectMapper將JSON字符串(或其他來源)解析為Java對象。 唯一的區別是,JSON源是JsonNode。 這是一個使用Jackson ObjectMapper treeToValue()方法將JsonNode轉換為Java對象的示例:

ObjectMapper objectMapper = new ObjectMapper();

String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

JsonNode carJsonNode = objectMapper.readTree(carJson);

Car car = objectMapper.treeToValue(carJsonNode);

上面的示例有點“人為”,因為我們首先將JSON字符串轉換為JsonNode,然后將JsonNode轉換為Car對象。 顯然,如果我們有對原始JSON字符串的引用,則最好將其直接轉換為Car對象,而無需先將其轉換為JsonNode。


四、JsonNode

Jackson JsonNode類com.fasterxml.jackson.databind.JsonNode是Jackson的JSON樹形模型(對象圖模型)。 Jackson可以將JSON讀取到JsonNode實例中,然后將JsonNode寫入JSON。 因此,這一節將說明如何將JSON反序列化為JsonNode以及將JsonNode序列化為JSON。 此Jackson JsonNode教程還將說明如何從頭開始構建JsonNode對象圖,因此以后可以將它們序列化為JSON。


1、JsonNode vs ObjectNode

Jackson JsonNode類是不可變的。 這意味着,實際上不能直接構建JsonNode實例的對象圖。 而是創建JsonNode子類ObjectNode的對象圖。 作為JsonNode的子類,可以在可以使用JsonNode的任何地方使用ObjectNode。


2、JSON-->JsonNode

要使用Jackson將JSON讀取到JsonNode中,首先需要創建一個Jackson ObjectMapper實例。 在ObjectMapper實例上,調用readTree()並將JSON源作為參數傳遞。 這是將JSON反序列化為JsonNode的示例:

String json = "{ \"f1\" : \"v1\" } ";

ObjectMapper objectMapper = new ObjectMapper();

JsonNode jsonNode = objectMapper.readTree(json);

System.out.println(jsonNode.get("f1").asText());

3、JsonNode-->JSON

要將Jackson的JsonNode寫入JSON,還需要一個Jackson ObjectMapper實例。 在ObjectMapper上,調用writeValueAsString()方法或任何適合需要的寫入方法。 這是將JsonNode寫入JSON的示例:

ObjectMapper objectMapper = new ObjectMapper();

JsonNode jsonNode = readJsonIntoJsonNode();

String json = objectMapper.writeValueAsString(jsonNode);

4、獲取JsonNode字段

JsonNode可以像JSON對象一樣具有字段。 假設已將以下JSON解析為JsonNode:

{
    "field1" : "value1",
    "field2" : 999
}

此JSON對象具有兩個名為field1和field2的字段。 如果有一個表示上述JSON對象的Jackson JsonNode,則可以這樣獲得兩個字段:

JsonNode jsonNode = ... //parse above JSON into a JsonNode

JsonNode field1 = jsonNode.get("field1");
JsonNode field2 = jsonNode.get("field2");

請注意,即使兩個字段都是String字段,get()方法也始終返回JsonNode來表示該字段。


5、在路徑中獲取JsonNode字段

Jackson JsonNode有一個稱為at()的特殊方法。 at()方法可以從JSON圖中以給定JsonNode為根的任何位置訪問JSON字段。 假設JSON結構如下所示:

{
  "identification" :  {
        "name" : "James",
        "ssn: "ABC123552"
    }
}

如果將此JSON解析為JsonNode,則可以使用at()方法訪問名稱字段,如下所示:

JsonNode nameNode = jsonNode.at("/identification/name");

注意傳遞給at()方法的參數:字符串/ identification / name。 這是一個JSON路徑表達式。 此路徑表達式指定從根JsonNode到您要訪問其值的字段的完整路徑。 這類似於從文件系統根目錄到Unix文件系統中文件的路徑。

請注意,JSON路徑表達式必須以斜杠字符(/字符)開頭。

at()方法返回一個JsonNode,它表示請求的JSON字段。 要獲取該字段的實際值,需要調用下一部分介紹的方法之一。 如果沒有節點與給定的路徑表達式匹配,則將返回null。


6、轉換JsonNode字段

Jackson JsonNode類包含一組可以將字段值轉換為另一種數據類型的方法。 例如,將String字段值轉換為long或相反。 這是將JsonNode字段轉換為一些更常見的數據類型的示例:

String f2Str = jsonNode.get("f2").asText();
double f2Dbl = jsonNode.get("f2").asDouble();
int    f2Int = jsonNode.get("f2").asInt();
long   f2Lng = jsonNode.get("f2").asLong();

使用默認值轉換:
如果JsonNode中的字段可以為null,則在嘗試轉換它時可以提供默認值。 這是使用默認值調用轉換方法的示例:

ObjectMapper objectMapper = new ObjectMapper();

String json = "{ \"f1\":\"Hello\", \"f2\":null }";

JsonNode jsonNode = objectMapper.readTree(json);

String f2Value = jsonNode.get("f2").asText("Default");

在示例的JSON字符串中可以看到,聲明了f2字段,但將其設置為null。 在這種情況下,調用jsonNode.get(“ f2”)。asText(“ Default”)將返回默認值,在此示例中為字符串Default。

asDouble(),asInt()和asLong()方法還可以采用默認參數值,如果嘗試從中獲取值的字段為null,則將返回默認參數值。

請注意,如果該字段在JSON中未顯式設置為null,但在JSON中丟失,則調用jsonNode.get(“ fieldName”)將返回Java null值,您無法在該Java值上調用asInt() ,asDouble(),asLong()或asText()。 如果嘗試這樣做,將會導致NullPointerException。 這是說明這種情況的示例:

 ObjectMapper objectMapper = new ObjectMapper();

String json = "{ \"f1\":\"Hello\" }";

JsonNode jsonNode = objectMapper.readTree(json);

JsonNode f2FieldNode = jsonNode.get("f2");

7、創建一個ObjectNode

如前所述,JsonNode類是不可變的。 要創建JsonNode對象圖,必須能夠更改圖中的JsonNode實例,例如 設置屬性值和子JsonNode實例等。由於是不可變的,因此無法直接使用JsonNode來實現。

而是創建一個ObjectNode實例,該實例是JsonNode的子類。 這是一個通過Jackson ObjectMapper createObjectNode()方法創建ObjectNode的示例:

ObjectMapper objectMapper = new ObjectMapper();

ObjectNode objectNode = objectMapper.createObjectNode();

8、Set ObjectNode字段

要在Jackson ObjectNode上設置字段,可以調用其set()方法,並將字段名稱String和JsonNode作為參數傳遞。 這是在Jackson的ObjectNode上設置字段的示例:

ObjectMapper objectMapper = new ObjectMapper();
ObjectNode parentNode = objectMapper.createObjectNode();

JsonNode childNode = readJsonIntoJsonNode();

parentNode.set("child1", childNode);

9、Put ObjectNode字段

ObjectNode類還具有一組方法,可以直接為字段put(設置)值。 這比嘗試將原始值轉換為JsonNode並使用set()進行設置要容易得多。 以下是使用put()方法為ObjectNode上的字段設置字符串值的示例:

objectNode.put("field1", "value1");
objectNode.put("field2", 123);
objectNode.put("field3", 999.999);

10、刪除字段

ObjectNode類具有一個稱為remove()的方法,該方法可用於從ObjectNode中刪除字段。 這是一個通過其remove()方法從Jackson ObjectNode刪除字段的示例:

objectNode.remove("fieldName");

11、循環JsonNode字段

JsonNode類具有一個名為fieldNames()的方法,該方法返回一個Iterator,可以迭代JsonNode的所有字段名稱。 我們可以使用字段名稱來獲取字段值。 這是一個迭代Jackson JsonNode的所有字段名稱和值的示例:

Iterator<String> fieldNames = jsonNode.fieldNames();

while(fieldNames.hasNext()) {
    String fieldName = fieldNames.next();

    JsonNode field = jsonNode.get(fieldName);
}

五、JsonParser

Jackson JsonParser類是一個底層一些的JSON解析器。 它類似於XML的Java StAX解析器,差別是JsonParser解析JSON而不解析XML。

Jackson JsonParser的運行層級低於Jackson ObjectMapper。 這使得JsonParser比ObjectMapper更快,但使用起來也比較麻煩。

1、創建一個JsonParser

為了創建Jackson JsonParser,首先需要創建一個JsonFactory。 JsonFactory用於創建JsonParser實例。 JsonFactory類包含幾個createParser()方法,每個方法都使用不同的JSON源作為參數。

這是創建一個JsonParser來從字符串中解析JSON的示例:

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

JsonFactory factory = new JsonFactory();
JsonParser  parser  = factory.createParser(carJson);

2、用JsonParser轉化JSON

一旦創建了Jackson JsonParser,就可以使用它來解析JSON。 JsonParser的工作方式是將JSON分解為一系列令牌,可以一個一個地迭代令牌。

這是一個JsonParser示例,它簡單地循環遍歷所有標記並將它們輸出到System.out。 這是一個實際上很少用示例,只是展示了將JSON分解成的令牌,以及如何遍歷令牌的基礎知識。

tring carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

JsonFactory factory = new JsonFactory();
JsonParser  parser  = factory.createParser(carJson);

while(!parser.isClosed()){
    JsonToken jsonToken = parser.nextToken();

    System.out.println("jsonToken = " + jsonToken);
}

只要JsonParser的isClosed()方法返回false,那么JSON源中仍然會有更多的令牌。

可以使用JsonParser的nextToken()獲得一個JsonToken。 您可以使用此JsonToken實例檢查給定的令牌。 令牌類型由JsonToken類中的一組常量表示。 這些常量是:

START_OBJECT
END_OBJECT
START_ARRAY
END_ARRAY
FIELD_NAME
VALUE_EMBEDDED_OBJECT
VALUE_FALSE
VALUE_TRUE
VALUE_NULL
VALUE_STRING
VALUE_NUMBER_INT
VALUE_NUMBER_FLOAT

可以使用這些常量來找出當前JsonToken是什么類型的令牌。 可以通過這些常量的equals()方法進行操作。 這是一個例子:

String carJson =
        "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";

JsonFactory factory = new JsonFactory();
JsonParser  parser  = factory.createParser(carJson);

Car car = new Car();
while(!parser.isClosed()){
    JsonToken jsonToken = parser.nextToken();

    if(JsonToken.FIELD_NAME.equals(jsonToken)){
        String fieldName = parser.getCurrentName();
        System.out.println(fieldName);

        jsonToken = parser.nextToken();

        if("brand".equals(fieldName)){
            car.brand = parser.getValueAsString();
        } else if ("doors".equals(fieldName)){
            car.doors = parser.getValueAsInt();
        }
    }
}

System.out.println("car.brand = " + car.brand);
System.out.println("car.doors = " + car.doors);

如果指向的標記是字段名稱,則JsonParser的getCurrentName()方法將返回當前字段名稱。

如果指向的令牌是字符串字段值,則getValueAsString()返回當前令牌值作為字符串。 如果指向的令牌是整數字段值,則getValueAsInt()返回當前令牌值作為int值。 JsonParser具有更多類似的方法來獲取不同類型的curren令牌值(例如boolean,short,long,float,double等)。


六、JsonGenerator

Jackson JsonGenerator用於從Java對象(或代碼從中生成JSON的任何數據結構)生成JSON。

1、創建一個JsonGenerator

為了創建Jackson JsonGenerator,必須首先創建JsonFactory實例。 這是創建JsonFactory的方法:

JsonFactory factory = new JsonFactory();

一旦創建了JsonFactory,就可以使用JsonFactory的createGenerator()方法創建JsonGenerator。 這是創建JsonGenerator的示例:

JsonFactory factory = new JsonFactory();

JsonGenerator generator = factory.createGenerator(
    new File("data/output.json"), JsonEncoding.UTF8);

createGenerator()方法的第一個參數是生成的JSON的目標。 在上面的示例中,參數是File對象。 這意味着生成的JSON將被寫入給定文件。 createGenerator()方法已重載,因此還有其他版本的createGenerator()方法采用例如OutputStream等,提供了有關將生成的JSON寫入何處的不同選項。

createGenerator()方法的第二個參數是生成JSON時使用的字符編碼。 上面的示例使用UTF-8。


2、使用JsonGenerator生成JSON

一旦創建了JsonGenerator,就可以開始生成JSON。 JsonGenerator包含一組write ...()方法,可以使用這些方法來編寫JSON對象的各個部分。 這是一個使用Jackson JsonGenerator生成JSON的簡單示例:

JsonFactory factory = new JsonFactory();

JsonGenerator generator = factory.createGenerator(
    new File("data/output.json"), JsonEncoding.UTF8);

generator.writeStartObject();
generator.writeStringField("brand", "Mercedes");
generator.writeNumberField("doors", 5);
generator.writeEndObject();

generator.close();

此示例首先調用writeStartObject(),將{寫入輸出。 然后,該示例調用writeStringField(),將品牌字段名稱+值寫入輸出。 之后,將調用writeNumberField()方法,此方法會將Doors字段名稱+值寫入輸出。 最后,調用writeEndObject(),將}寫入輸出。

JsonGenerator還可以使用許多其他寫入方法。 這個例子只顯示了其中一些。

3、關閉JsonGenerator

完成生成JSON后,應關閉JsonGenerator。 您可以通過調用其close()方法來實現。 這是關閉JsonGenerator的樣子:

generator.close();

七、Jackson注解

Jackson JSON工具包包含一組Java注解,可以使用這些注解來設置將JSON讀入對象的方式或從對象生成什么JSON的方式。 此Jackson注解教程介紹了如何使用Jackson的注解。

下面是一些常用的注解:

下面是一些注解的詳細說明。

一)、Read + Write注解

Jackson包含一組注解,這些注解會影響從JSON讀取Java對象以及將Java對象寫入JSON。 我將這些注解稱為“讀+寫注解”。 以下各節將更詳細地介紹Jackson的讀寫注解。

1、@JsonIgnore

Jackson注解@JsonIgnore用於告訴Jackson忽略Java對象的某個屬性(字段)。 在將JSON讀取到Java對象中以及將Java對象寫入JSON時,都將忽略該屬性。

這是使用@JsonIgnore注解的示例:

import com.fasterxml.jackson.annotation.JsonIgnore;

public class PersonIgnore {

    @JsonIgnore
    public long  personId = 0;

    public String name = null;
}

在上面的類中,不會從JSON讀取或寫入JSON屬性personId。


2、@JsonIgnoreProperties

@JsonIgnoreProperties Jackson注解用於指定要忽略的類的屬性列表。 @JsonIgnoreProperties注解放置在類聲明上方,而不是要忽略的各個屬性(字段)上方。

這是如何使用@JsonIgnoreProperties注解的示例:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties({"firstName", "lastName"})
public class PersonIgnoreProperties {

    public long   personId = 0;

    public String  firstName = null;
    public String  lastName  = null;

}

在此示例中,屬性firstName和lastName都將被忽略,因為它們的名稱在類聲明上方的@JsonIgnoreProperties注解聲明內列出。


3、@JsonIgnoreType

@JsonIgnoreType Jackson注解用於將整個類型(類)標記為在使用該類型的任何地方都將被忽略。

這是一個示例,展示如何使用@JsonIgnoreType注解:

import com.fasterxml.jackson.annotation.JsonIgnoreType;

public class PersonIgnoreType {

    @JsonIgnoreType
    public static class Address {
        public String streetName  = null;
        public String houseNumber = null;
        public String zipCode     = null;
        public String city        = null;
        public String country     = null;
    }

    public long    personId = 0;

    public String  name = null;

    public Address address = null;
}

在上面的示例中,所有Address實例將被忽略。


4、@JsonAutoDetect

Jackson注解@JsonAutoDetect用於告訴Jackson在讀寫對象時包括非public修飾的屬性。

這是一個示例類,展示如何使用@JsonAutoDetect注解:

import com.fasterxml.jackson.annotation.JsonAutoDetect;

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY )
public class PersonAutoDetect {

    private long  personId = 123;
    public String name     = null;

}

JsonAutoDetect.Visibility類包含與Java中的可見性級別匹配的常量,表示ANY,DEFAULT,NON_PRIVATE,NONE,PROTECTED_AND_PRIVATE和PUBLIC_ONLY。


二)、Read注解

Jackson包含一組注解,這些注解僅影響Jackson將JSON解析為對象的方式-意味着它們影響Jackson對JSON的讀取。 我稱這些為“讀注解”。 以下各節介紹了Jackson的讀注解。


1、@JsonSetter

Jackson注解@JsonSetter用於告訴Jackson,當將JSON讀入對象時,應將此setter方法的名稱與JSON數據中的屬性名稱匹配。 如果Java類內部使用的屬性名稱與JSON文件中使用的屬性名稱不同,這個注解就很有用了。

以下Person類用personId名稱對應JSON中名為id的字段:

public class Person {

    private long   personId = 0;
    private String name     = null;

    public long getPersonId() { return this.personId; }
    public void setPersonId(long personId) { this.personId = personId; }

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

但是在此JSON對象中,使用名稱id代替personId:

{
  "id"   : 1234,
  "name" : "John"
}

Jackson無法將id屬性從JSON對象映射到Java類的personId字段。

@JsonSetter注解指示Jackson為給定的JSON字段使用setter方法。 在我們的示例中,我們在setPersonId()方法上方添加@JsonSetter注解。

這是添加@JsonSetter注解的實例:

public class Person {

    private long   personId = 0;
    private String name     = null;

    public long getPersonId() { return this.personId; }
    @JsonSetter("id")
    public void setPersonId(long personId) { this.personId = personId; }

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

@JsonSetter注解中指定的值是要與此setter方法匹配的JSON字段的名稱。 在這種情況下,名稱為id,因為這是我們要映射到setPersonId()setter方法的JSON對象中字段的名稱。

2、@JsonAnySetter

Jackson注解@JsonAnySetter表示Jackson為JSON對象中所有無法識別的字段調用相同的setter方法。 “無法識別”是指尚未映射到Java對象中的屬性或設置方法的所有字段。

看一下這個Bag類:

public class Bag {

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

    public void set(String fieldName, Object value){
        this.properties.put(fieldName, value);
    }

    public Object get(String fieldName){
        return this.properties.get(fieldName);
    }
}

然后查看此JSON對象:

{
  "id"   : 1234,
  "name" : "John"
}

Jackson無法直接將此JSON對象的id和name屬性映射到Bag類,因為Bag類不包含任何公共字段或setter方法。

可以通過添加@JsonAnySetter注解來告訴Jackson為所有無法識別的字段調用set()方法,如下所示:

public class Bag {

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

    @JsonAnySetter
    public void set(String fieldName, Object value){
        this.properties.put(fieldName, value);
    }

    public Object get(String fieldName){
        return this.properties.get(fieldName);
    }
}

現在,Jackson將使用JSON對象中所有無法識別的字段的名稱和值調用set()方法。

請記住,這僅對無法識別的字段有效。 例如,如果您向Bag Java類添加了公共名稱屬性或setName(String)方法,則JSON對象中的名稱字段將改為映射到該屬性/設置器。


3、@JsonCreator

Jackson注解@JsonCreator用於告訴Jackson該Java對象具有一個構造函數(“創建者”),該構造函數可以將JSON對象的字段與Java對象的字段進行匹配。

@JsonCreator注解在無法使用@JsonSetter注解的情況下很有用。 例如,不可變對象沒有任何設置方法,因此它們需要將其初始值注入到構造函數中。

以這個PersonImmutable類為例:

public class PersonImmutable {

    private long   id   = 0;
    private String name = null;

    public PersonImmutable(long id, String name) {
        this.id = id;
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

}

要告訴Jackson應該調用PersonImmutable的構造函數,我們必須在構造函數中添加@JsonCreator注解。 但是,僅憑這一點還不夠。 我們還必須注解構造函數的參數,以告訴Jackson將JSON對象中的哪些字段傳遞給哪些構造函數參數。

添加了@JsonCreator和@JsonProperty注解的PersonImmutable類的示例如下:

public class PersonImmutable {

    private long   id   = 0;
    private String name = null;

    @JsonCreator
    public PersonImmutable(
            @JsonProperty("id")  long id,
            @JsonProperty("name") String name  ) {

        this.id = id;
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

}

請注意,構造函數上方的注解以及構造函數參數之前的注解。 現在,Jackson能夠從此JSON對象創建PersonImmutable:

{
  "id"   : 1234,
  "name" : "John"
}

4、@JacksonInject

Jackson注解@JacksonInject用於將值注入到解析的對象中,而不是從JSON中讀取這些值。 例如,假設正在從各種不同的源下載Person JSON對象,並且想知道給定Person對象來自哪個源。 源本身可能不包含該信息,但是可以讓Jackson將其注入到根據JSON對象創建的Java對象中。

要將Java類中的字段標記為需要由Jackson注入其值的字段,請在該字段上方添加@JacksonInject注解。

這是一個示例PersonInject類,在屬性上方添加了@JacksonInject注解:

public class PersonInject {

    public long   id   = 0;
    public String name = null;

    @JacksonInject
    public String source = null;

}

為了讓Jackson將值注入屬性,需要在創建Jackson ObjectMapper時做一些額外的工作。

這是讓Jackson將值注入Java對象的過程:

InjectableValues inject = new InjectableValues.Std().addValue(String.class, "jenkov.com");
PersonInject personInject = new ObjectMapper().reader(inject)
                        .forType(PersonInject.class)
                        .readValue(new File("data/person.json"));

請注意,如何在InjectableValues addValue()方法中設置要注入到source屬性中的值。 還要注意,該值僅綁定到字符串類型-而不綁定到任何特定的字段名稱。 @JacksonInject注解指定將值注入到哪個字段。

如果要從多個源下載人員JSON對象,並為每個源注入不同的源值,則必須為每個源重復以上代碼。

5、@JsonDeserialize

Jackson注解@JsonDeserialize用於為Java對象中給定的屬性指定自定義反序列化器類。

例如,假設想優化布爾值false和true的在線格式,使其分別為0和1。

首先,需要將@JsonDeserialize注解添加到要為其使用自定義反序列化器的字段。 這是將@JsonDeserialize注解添加到字段的示例:

public class PersonDeserialize {

    public long    id      = 0;
    public String  name    = null;

    @JsonDeserialize(using = OptimizedBooleanDeserializer.class)
    public boolean enabled = false;
}

其次,這是@JsonDeserialize注解中引用的OptimizedBooleanDeserializer類的實例:

public class OptimizedBooleanDeserializer
    extends JsonDeserializer<Boolean> {

    @Override
    public Boolean deserialize(JsonParser jsonParser,
            DeserializationContext deserializationContext) throws
        IOException, JsonProcessingException {

        String text = jsonParser.getText();
        if("0".equals(text)) return false;
        return true;
    }
}

請注意,OptimizedBooleanDeserializer類使用通用類型Boolean擴展了JsonDeserializer。 這樣做會使deserialize()方法返回一個布爾對象。 如果要反序列化其他類型(例如java.util.Date),則必須在泛型括號內指定該類型。

可以通過調用jsonParser參數的getText()方法來獲取要反序列化的字段的值。 然后,可以將該文本反序列化為任何值,然后輸入反序列化程序所針對的類型(在此示例中為布爾值)。

最后,需要查看使用自定義反序列化器和@JsonDeserializer注解反序列化對象的格式:

PersonDeserialize person = objectMapper
        .reader(PersonDeserialize.class)
        .readValue(new File("data/person-optimized-boolean.json"));

注意,我們首先需要如何使用ObjectMapper的reader()方法為PersonDeserialize類創建一個閱讀器,然后在該方法返回的對象上調用readValue()。


三)、Write注解

Jackson還包含一組注解,這些注解可以影響Jackson將Java對象序列化(寫入)到JSON的方式。 以下各節將介紹這些寫(序列化)注解中的每一個。


1、@JsonInclude

Jackson注解@JsonInclude告訴Jackson僅在某些情況下包括屬性。 例如,僅當屬性為非null,非空或具有非默認值時,才應包括該屬性。 這是顯示如何使用@JsonInclude注解的示例:

import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class PersonInclude {

    public long  personId = 0;
    public String name     = null;

}

如果為該示例設置的值是非空的,則此示例將僅包括name屬性,這意味着不為null且不是空字符串。

@JsonInclude注解的一個更通俗的名稱應該是@JsonIncludeOnlyWhen,但是寫起來會更長。


2、@JsonGetter

@JsonGetter Jackson注解用於告訴Jackson,應該通過調用getter方法而不是通過直接字段訪問來獲取某個字段值。 如果您的Java類使用jQuery樣式的getter和setter名稱,則@JsonGetter注解很有用。

例如,您可能擁有方法personId()和personId(long id),而不是getPersonId()和setPersonId()。

這是一個名為PersonGetter的示例類,它顯示了@JsonGetter注解的用法:

public class PersonGetter {

    private long  personId = 0;

    @JsonGetter("id")
    public long personId() { return this.personId; }

    @JsonSetter("id")
    public void personId(long personId) { this.personId = personId; }

}

如您所見,personId()方法帶有@JsonGetter注解。 @JsonGetter注解上設置的值是JSON對象中應使用的名稱。 因此,用於JSON對象中personId的名稱是id。 生成的JSON對象如下所示:

{"id":0}

還要注意,personId(long personId)方法使用@JsonSetter注解進行注解,以使Jackson識別為與JSON對象中的id屬性匹配的設置方法。 從JSON讀取Java對象時使用@JsonSetter注解-將Java對象寫入JSON時不使用。 為了完整起見,僅包含@JsonSetter注解。


3、@JsonAnyGetter

@JsonAnyGetter Jackson注解使您可以將Map用作要序列化為JSON的屬性的容器。 這是在Java類中使用@JsonAnyGetter注解的示例:

public class PersonAnyGetter {

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

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

當看到@JsonAnyGetter注解時,Jackson將從@JsonAnyGetter注解的方法中獲取返回的Map,並將該Map中的每個鍵值對都視為一個屬性。 換句話說,Map中的所有鍵值對都將作為PersonAnyGetter對象的一部分序列化為JSON。


4、@JsonPropertyOrder

@JsonPropertyOrder Jackson注解可用於指定將Java對象的字段序列化為JSON的順序。 這是顯示如何使用@JsonPropertyOrder注解的示例:

@JsonPropertyOrder({"name", "personId"})
public class PersonPropertyOrder {

    public long  personId  = 0;
    public String name     = null;

}

通常,Jackson會按照在類中找到的順序序列化PersonPropertyOrder中的屬性。 但是,@JsonPropertyOrder注解指定了不同的順序,在序列化的JSON輸出中,name屬性將首先出現,personId屬性將隨后出現。


5、@JsonRawValue

@JsonRawValue Jackson注解告訴Jackson該屬性值應直接寫入JSON輸出。 如果該屬性是字符串,Jackson通常會將值括在引號中,但是如果使用@JsonRawValue屬性進行注解,Jackson將不會這樣做。

為了更清楚@JsonRawValue的作用,看看沒有使用@JsonRawValue的此類:

public class PersonRawValue {

    public long   personId = 0;

    public String address  = "$#";
}

Jackson會將其序列化為以下JSON字符串:

{"personId":0,"address":"$#"}

現在,我們將@JsonRawValue添加到address屬性,如下所示:

public class PersonRawValue {

    public long   personId = 0;

    @JsonRawValue
    public String address  = "$#";
}

現在,當對地址屬性進行序列化時,傑克遜將省略引號。 因此,序列化的JSON如下所示:

{"personId":0,"address":$#}

當然它是無效的JSON,那么為什么要這么做呢?

如果address屬性包含一個JSON字符串,那么該JSON字符串將被序列化為最終的JSON對象,作為JSON對象結構的一部分,而不僅是序列化為JSON對象的address字段中的字符串。

要查看其工作原理,讓我們像下面這樣更改address屬性的值:

public class PersonRawValue {

    public long   personId = 0;

    @JsonRawValue
    public String address  =
            "{ \"street\" : \"Wall Street\", \"no\":1}";

}

Jackson會將其序列化為以下JSON:

{"personId":0,"address":{ "street" : "Wall Street", "no":1}}

請注意,JSON字符串現在如何成為序列化JSON結構的一部分。

沒有@JsonRawValue注解,Jackson會將對象序列化為以下JSON:

{"personId":0,"address":"{ \"street\" : \"Wall Street\", \"no\":1}"}

請注意,address屬性的值現在如何用引號引起來,並且值內的所有引號均被轉義。


6、@JsonValue

Jackson注解@JsonValue告訴Jackson,Jackson不應該嘗試序列化對象本身,而應在對象上調用將對象序列化為JSON字符串的方法。 請注意,Jackson將在自定義序列化返回的String內轉義任何引號,因此不能返回例如 完整的JSON對象。 為此,應該改用@JsonRawValue(請參閱上一節)。

@JsonValue注解已添加到Jackson調用的方法中,以將對象序列化為JSON字符串。 這是顯示如何使用@JsonValue注解的示例:

public class PersonValue {

    public long   personId = 0;
    public String name = null;

    @JsonValue
    public String toJson(){
        return this.personId + "," + this.name;
    }

}

要求Jackson序列化PersonValue對象所得到的輸出是:

"0,null"

引號由Jackson添加。 請記住,對象返回的值字符串中的所有引號均會轉義。


7、@JsonSerialize

@JsonSerialize Jackson注解用於為Java對象中的字段指定自定義序列化程序。 這是一個使用@JsonSerialize注解的Java類示例:

public class PersonSerializer {

    public long   personId = 0;
    public String name     = "John";

    @JsonSerialize(using = OptimizedBooleanSerializer.class)
    public boolean enabled = false;
}

注意啟用字段上方的@JsonSerialize注解。

OptimizedBooleanSerializer將序列的真值序列化為1,將假值序列化為0。這是代碼:

public class OptimizedBooleanSerializer extends JsonSerializer<Boolean> {

    @Override
    public void serialize(Boolean aBoolean, JsonGenerator jsonGenerator, 
        SerializerProvider serializerProvider) 
    throws IOException, JsonProcessingException {

        if(aBoolean){
            jsonGenerator.writeNumber(1);
        } else {
            jsonGenerator.writeNumber(0);
        }
    }
}



參考:

【1】:Jackson Installation
【2】:Jackson ObjectMapper
【3】:Jackson 框架的高階應用
【4】:Jackson JsonNode
【5】:Jackson JsonParser
【6】:Jackson JsonGenerator
【7】:Jackson Annotations


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM