Jackson系列


 

詳情參閱:Jackson系列

 注:下文涉及到的 jackson 源碼的版本為 2.11.0

Jackson介紹

(對應 Jackson系列 文章1)

Jackson是一個基於JVM平台(所以支持Java、Scala、Kotlin等語言)的數據(不限於JSON格式的數據)序列化、反序列化工具集,包括:JSON解析器(讀)/ JSON生成器(寫)、數據綁定庫(POJOs to and from JSON);並且提供了相關模塊來支持 Avro、BSON、CBOR、CSV、Smile、Properties、Protobuf、XML、YAML等數據格式,甚至還支持大數據格式模塊的設置。

特性

性能且穩定:低內存占用,對大/小JSON串解析、大/小對象的序列化表現均很優秀。
流行度高:是很多流行框架的默認選擇。
易使用:提供高層次的API,極大簡化了日常使用的難度。
無需自己手動創建映射:內置了絕大部分序列化時和Java類型的映射關系。
干凈的JSON:創建的JSON具有干凈、緊湊、體積小等特點。
無三方依賴:僅依賴於JDK。
可擴展性強:與GSON等其他庫相比的另一大特點是具有很強的可擴展性。
Spring生態加持:jackson是Spring家族的默認JSON/XML解析器。

其他:考慮安全性,預防JSON解析時的Dos攻擊(ByteQuadsCanonicalizer)等。

 

模塊

三個核心模塊:(說明:核心模塊的groupId均為:<groupId>com.fasterxml.jackson.core</groupId>,artifactId見下面各模塊所示)

json解析和生成的核心模塊(jackson-core):主要包括JsonParser、JsonGenerator、JsonFactory三個內容,分別用於解析JSON數據、生成JSON數據、配置和構建JsonParser與JsonGenerator。此模塊是jackson其他所有模塊的基礎,屬於low-level API。jackson-core 模塊提供了兩種處理JSON的方式(縱纜整個Jackson共三種):

數據流式API:讀取並將JSON內容寫入作為離散事件 -> JsonParser讀取數據,而JsonGenerator負責寫入數據。

樹模型:JSON文件在內存里以樹形式表示。此種方式也很靈活,它類似於XML的DOM解析,是層層嵌套的。這種模式下無需定義POJO就可以用它快速讀寫JSON數據,同時它也可以達到「模糊掉類型的概念」,做到更抽象和更公用。

Annotations標准注解模塊(jackson-annotations):包含標准的Jackson注解。

Databind數據綁定模塊(jackson-databind):在streaming包上實現數據綁定(和對象序列化)支持,它依賴於上面的兩個模塊,也是Jackson的high-level API(如ObjectMapper)所在的模塊。

實際應用級開發中,我們只會使用到Databind數據綁定模塊。

 

數據類型模塊:這些模塊為Jackson插件模塊(通過ObjectMapper.registerModule()注冊),並通過添加序列化器和反序列化器來支持各種常用的Java庫數據類型,以便Jackson databind包(ObjectMapper / ObjectReader / ObjectWriter)能夠順利讀寫/轉換這些類型。包括官方維護和非官方維護兩類。

官方維護:Guava、HPPC、PCollections、Hibernate、Joda、Java8、JSR310、JSR353 等(groupId統一為:<groupId>com.fasterxml.jackson.datatype</groupId>,且版本號和主版本號保持一致)。

第三方開源維護:jackson-datatype-bolts、jackson-datatype-commons-lang3 等。

 

數據格式模塊:Data format modules(數據格式模塊)提供對JSON之外的數據格式的支持。它們中的大多數只是實現streaming API抽象,以便數據綁定組件可以按原樣使用。兩類(groupId統一為<groupId>com.fasterxml.jackson.dataformat</groupId>,且版本號和主版本號保持一致):

Avro/CBOR/Ion/Protobuf/Smile(binary JSON) :這些均屬於二進制的數據格式,它們的artifactId為:<artifactId>jackson-dataformat-[FORMAT]</artifactId>

CSV/Properties/XML/YAML

 

JVM平台其他語言支持:Jackson是一個JVM平台的解析器,因此語言層面不局限於Java本身,還涵蓋了另外兩大主流JVM語言:Kotlin和Scala。兩類(groupId均為:<groupId>com.fasterxml.jackson.module</groupId>,版本號跟着主版本號走):

jackson-module-kotlin:處理kotlin源生類型

jackson-module-scala_[scala版本號]:處理scala源生類型

 

移動端簡化版(Jackson jr):Jackson databind(如ObjectMapper)是通用數據綁定的良好選擇,但它占用空間(Jar包大小)和啟動開銷在移動端等常見下較為笨重,故官方推出了更簡單、更小的庫——Jackson jr。它仍舊構建在Streaming API之上,但不依賴於databind和annotation。因此,它的大小(jar和運行時內存使用)要小得多,它的API非常緊湊,所以適合APP等移動端

 

2 Java數據轉成JSON數據(jackson-core之 JsonGenerator) 

(對應 Jackson系列 文章2)

JsonGenerator是jackson-core提供的JSON數據生成器,用於將Java數據對象轉成JSON數據。

在應用開發層面一般不推薦直接使用JsonGenerator(而是用ObjectMapper),因為它的API比較底層比較靈活,因此易錯;但如果是框架開發,則很適合用這個(Spring MVC對JSON消息的轉換器 AbstractJackson2HttpMessageConverter 就用到了Jackson底層流式API -> JsonGenerator寫數據),因為它的性能更高,是ObjectMapper等的基礎。

如上圖所示,最終負責生成JSON數據的實現類有 WriterBasedJsonGenerator、UTF8JsonGenerator 兩種

WriterBasedJsonGenerator:基於 java.io.Writer 來輸出JSON內容,由該Writer來處理字符編碼。

UTF8JsonGenerator:該實現類自己對Java數據進行UTF8字符編碼,編碼后的JSON數據內容直接輸出到OutputStream而不是借助Writer輸出。

基本使用:

寫key:JSON中的key只有String一種類型

寫value:Java中的數據類型多種多樣,但JSON中只有 【字符串、數值、布爾、null、數組、對象 】6種。

 

關於JsonGenerator中寫key、寫value的各種API使用示例可參閱本節首的文章。

writeFieldName

writeString、writeNumber、writeBoolean、writeNull、writeStartArray/writeArray、writeStartObject/writeObject

writeRaw、writeRawValue、writeBinary

JsonGenerator的 writeObject/writeTree 方法要求事先給JsonGenerator指定一個編解碼器 ObjectCodec/TreeCodec,否則會報錯。而Jackson里我們最為熟悉的API ObjectMapper 實際上就是一個ObjectCodec 的唯一實現,實現了序列化和反序列化、POJO、Tree Model 等操作。

數JSON數據生成(序列化)的配置項

(對應 Jackson系列 文章3)

JsonGenerator#Feature 枚舉類:

public enum Feature {

 // Low-level I/O
 AUTO_CLOSE_TARGET(true),
 AUTO_CLOSE_JSON_CONTENT(true),
 FLUSH_PASSED_TO_STREAM(true),

 // Quoting-related features
 @Deprecated
 QUOTE_FIELD_NAMES(true),
 @Deprecated
 QUOTE_NON_NUMERIC_NUMBERS(true),
 @Deprecated
 ESCAPE_NON_ASCII(false),
 @Deprecated
 WRITE_NUMBERS_AS_STRINGS(false),

 // Schema/Validity support features
 WRITE_BIGDECIMAL_AS_PLAIN(false),
 STRICT_DUPLICATE_DETECTION(false),
 IGNORE_UNKNOWN(false);
 
 ...
}
View Code

StreamWriterFeature:

2.10版本新增的,用於完全替換上面的Feature,被JsonFactory所使用。目的:完全獨立的屬性配置,不依賴於任何后端格式,因為JsonGenerator並不局限於寫JSON,因此把Feature放在JsonGenerator作為內部類是不太合適的,所以單獨摘出來。

 

3 JSON數據轉成Java數據(jackson-core之 JsonParser

(對應 Jackson系列 文章4)

關於JsonParser的基本使用及配置可參閱該文章。

如上圖所示,最終負責解析JSON數據的實現類有 ReaderBasedJsonParser、UTF8StreamJsonParser、UTF8SDataInputJsonParser、NonBlockingJsonParser 幾種。其中前兩種最常用,這兩種Parser的區別與前述Generator的兩種實現的區別類似。

JSON數據解析(反序列化)的配置項:

JsonParser#Feature 枚舉類:

public enum Feature {
 AUTO_CLOSE_SOURCE(true),
 
 ALLOW_COMMENTS(false),
 ALLOW_YAML_COMMENTS(false),
 ALLOW_UNQUOTED_FIELD_NAMES(false),
 ALLOW_SINGLE_QUOTES(false),
 @Deprecated
 ALLOW_UNQUOTED_CONTROL_CHARS(false),
 @Deprecated
 ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER(false),
 @Deprecated
 ALLOW_NUMERIC_LEADING_ZEROS(false),
 @Deprecated
 ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS(false),
 @Deprecated
 ALLOW_NON_NUMERIC_NUMBERS(false),
 @Deprecated
 ALLOW_MISSING_VALUES(false),
 @Deprecated
 ALLOW_TRAILING_COMMA(false),
 
 STRICT_DUPLICATE_DETECTION(false),
 IGNORE_UNDEFINED(false),
 INCLUDE_SOURCE_IN_LOCATION(true);
}
View Code

比較值得一提的是 ALLOW_COMMENTS、ALLOW_YAML_COMMENTS ,開啟后將允許待解析的JSON數據里帶有注釋,包括 //good    /* good */   # good  三種格式的注釋。

 

4 創建JsonParser、JsonGenerator (jackson-core之JsonFactory

(對應 Jackson系列 文章5) 

JsonFactory是Jackson的(最)主要工廠類,用於 配置和構建 JsonGenerator、JsonParser,可見其雖作為工廠類但職責並不單一。該這個工廠實例是「線程安全」的,因此可以重復使用。 

基本API:

JsonFactory創建JsonParser、JsonGenerator實例的相關API:

編碼自動檢測:

從前面關於JsonParser、JsonGenerator的介紹可知兩者分別用於反序列化、序列化,因此都涉及到編碼問題。對於JsonParser,在解析輸入的文本內容時如何知道內容的編碼方式呢?這得益於jackson的編碼自動檢測機制:JsonFactory在創建JsonParser時會調用 ByteSourceJsonBootstrapper#constructParser -> detectEncoding 方法來檢測輸入內容的編碼。相關源碼:

    public JsonParser constructParser(int parserFeatures, ObjectCodec codec,
            ByteQuadsCanonicalizer rootByteSymbols, CharsToNameCanonicalizer rootCharSymbols,
            int factoryFeatures) throws IOException
    {
        JsonEncoding enc = detectEncoding();

        if (enc == JsonEncoding.UTF8) {
            /* and without canonicalization, byte-based approach is not performant; just use std UTF-8 reader
             * (which is ok for larger input; not so hot for smaller; but this is not a common case)
             */
            if (JsonFactory.Feature.CANONICALIZE_FIELD_NAMES.enabledIn(factoryFeatures)) {
                ByteQuadsCanonicalizer can = rootByteSymbols.makeChild(factoryFeatures);
                return new UTF8StreamJsonParser(_context, parserFeatures, _in, codec, can,
                        _inputBuffer, _inputPtr, _inputEnd, _bufferRecyclable);
            }
        }
        return new ReaderBasedJsonParser(_context, parserFeatures, constructReader(), codec,
                rootCharSymbols.makeChild(factoryFeatures));
    }
constructParser 

JsonFactory的配置項:

 /**
     * Enumeration that defines all on/off features that can only be
     * changed for {@link JsonFactory}.
     */
    public enum Feature {
        
        // // // Symbol handling (interning etc)
        
        /**
         * Feature that determines whether JSON object field names are
         * to be canonicalized using {@link String#intern} or not:
         * if enabled, all field names will be intern()ed (and caller
         * can count on this being true for all such names); if disabled,
         * no intern()ing is done. There may still be basic
         * canonicalization (that is, same String will be used to represent
         * all identical object property names for a single document).
         *<p>
         * Note: this setting only has effect if
         * {@link #CANONICALIZE_FIELD_NAMES} is true -- otherwise no
         * canonicalization of any sort is done.
         *<p>
         * This setting is enabled by default.
         */
        INTERN_FIELD_NAMES(true),

        /**
         * Feature that determines whether JSON object field names are
         * to be canonicalized (details of how canonicalization is done
         * then further specified by
         * {@link #INTERN_FIELD_NAMES}).
         *<p>
         * This setting is enabled by default.
         */
        CANONICALIZE_FIELD_NAMES(true),

        /**
         * Feature that determines what happens if we encounter a case in symbol
         * handling where number of hash collisions exceeds a safety threshold
         * -- which almost certainly means a denial-of-service attack via generated
         * duplicate hash codes.
         * If feature is enabled, an {@link IllegalStateException} is
         * thrown to indicate the suspected denial-of-service attack; if disabled, processing continues but
         * canonicalization (and thereby <code>intern()</code>ing) is disabled) as protective
         * measure.
         *<p>
         * This setting is enabled by default.
         * 
         * @since 2.4
         */
        FAIL_ON_SYMBOL_HASH_OVERFLOW(true),

        /**
         * Feature that determines whether we will use {@link BufferRecycler} with
         * {@link ThreadLocal} and {@link SoftReference}, for efficient reuse of
         * underlying input/output buffers.
         * This usually makes sense on normal J2SE/J2EE server-side processing;
         * but may not make sense on platforms where {@link SoftReference} handling
         * is broken (like Android), or if there are retention issues due to
         * {@link ThreadLocal} (see
         * <a href="https://github.com/FasterXML/jackson-core/issues/189">Issue #189</a>
         * for a possible case)
         *<p>
         * This setting is enabled by default.
         *
         * @since 2.6
         */
        USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING(true)

        ;

        /**
         * Whether feature is enabled or disabled by default.
         */
        private final boolean _defaultState;

        /**
         * Method that calculates bit set (flags) of all features that
         * are enabled by default.
         */
        public static int collectDefaults() {
            int flags = 0;
            for (Feature f : values()) {
                if (f.enabledByDefault()) { flags |= f.getMask(); }
            }
            return flags;
        }
        
        private Feature(boolean defaultState) { _defaultState = defaultState; }
        
        public boolean enabledByDefault() { return _defaultState; }
        public boolean enabledIn(int flags) { return (flags & getMask()) != 0; }
        public int getMask() { return (1 << ordinal()); }
    }
View Code

JsonFactory的實例的創建共有三種方式:

直接new實例,此方式比較常用。

使用JsonFactoryBuilder構建(需要2.10或以上版本),這是推薦的使用方式。

SPI方式創建實例,此方式很少使用。

5 高層API之ObjectMapper

(對應 Jackson系列 文章6) 

前面介紹的 jackson-core 模塊的 JsonParser、JsonGenerator、JsonFactory 都是底層API,雖然很靈活,但對用戶來說使用較為繁瑣。因此Jackson提供了更高層的API,即jackson-databind模塊。

jackson-databind 是Jackson提供的高層API,包含用於Jackson數據處理器的通用 「數據綁定功能」和「樹模型」。它構建在 jackson-core 模塊的API之上,並使用 jackson-annotations 進行配置。它是開發者使用得最多的方式,重要程度可見一斑。

雖然Jackson最初的用例是JSON數據綁定,但現在它也可以用於其它數據格式,只要提供 數據的解析器和生成器 的實現即可。但需要注意的是:類的命名在很多地方仍舊使用了“JSON”這個詞(比如JsonGenerator),盡管它與JSON格式沒有實際的硬依賴關系。

 

基本介紹

ObjectMapper 是jackson-databind模塊最為重要的一個類,它完成了coder對數據綁定的「幾乎所有功能」。主要功能如下:

  • 提供解析和生成JSON的功能(最重要的功能)
    • 普通POJO的序列化/反序列化
    • JSON樹模型的讀/寫
  • 可以被「高度定制」,以使用不同風格的JSON內容
    • 使用Feature進行定制
    • 使用可插拔 com.fasterxml.jackson.databind.Module 模塊來擴展/豐富功能
  • 支持「更高級」的對象概念:比如多態泛型、對象標識
  • 充當更為高級(更強大)的API:ObjectReader和ObjectWriter的「工廠」
    • ObjectReaderObjectWriter底層亦是依賴於jackson-core的API實現讀寫
  • 支持豐富的數據格式,而不是局限於JSON格式。如自 2.10 版本起,提供了JsonMapper、YAMLMapper 子類,分別用於處理json數據、yaml 格式的數據(需額外導包)。

盡管絕大部分的讀/寫API都通過ObjectMapper暴露出去了,但有些功能還是只放在了ObjectReader/ObjectWriter里,比如對於讀/寫 「長序列」 的能力你只能通過ObjectReader#readValues(InputStream) / ObjectWriter#writeValues(OutputStream)去處理。

基本使用

詳情參閱本大節首的參考文章。

生成JSON數據(序列化)

主要API:

 

用的最多的是  writeValueAsString(obj)  方法

代碼示例及執行結果:

// 代碼
    ObjectMapper objectMapper = new ObjectMapper();

    System.out.println("----------寫簡單類型----------");
    System.out.println(objectMapper.writeValueAsString(18));
    System.out.println(objectMapper.writeValueAsString("YourBatman"));

    System.out.println("----------寫集合類型----------");
    System.out.println(objectMapper.writeValueAsString(Arrays.asList(1, 2, 3)));
    System.out.println(objectMapper.writeValueAsString(new HashMap<String, String>() {{
        put("zhName", "A哥");
        put("enName", "YourBatman");
    }}));

    System.out.println("----------寫POJO----------");
    System.out.println(objectMapper.writeValueAsString(new Person("A哥", 18)));




// 執行結果
18
"YourBatman"
----------寫集合類型----------
[1,2,3]
{"zhName":"A哥","enName":"YourBatman"}
----------寫POJO----------
{"name":"A哥","age":18}
View Code

 

解析JSON數據(反序列化)

主要API:

 

用得最多的是  readValue(String content, Class<T> valueType)  方法

代碼示例及執行結果:

 1 // 代碼
 2     ObjectMapper objectMapper = new ObjectMapper();
 3 
 4     System.out.println("----------讀簡單類型----------");
 5     System.out.println(objectMapper.readValue("18", Integer.class));
 6     // 拋錯:JsonParseException  單獨的一個串,解析會拋錯
 7     // System.out.println(objectMapper.readValue("YourBatman", String.class));
 8 
 9     System.out.println("----------讀集合類型----------");
10     System.out.println(objectMapper.readValue("[1,2,3]", List.class));
11     System.out.println(objectMapper.readValue("{\"zhName\":\"A哥\",\"enName\":\"YourBatman\"}", Map.class));
12 
13     System.out.println("----------讀POJO----------");
14     System.out.println(objectMapper.readValue("{\"name\":\"A哥\",\"age\":18}", Person.class));
15 
16 
17 
18     System.out.println("----------讀集合類型 泛型問題----------");
19     List<Long> ids = objectMapper.readValue("[1,2,3]", new TypeReference<List<Long>>() {
20     });
21     Long id = ids.get(0);
22     System.out.println(id);
23 
24 List<Long> list = objectMapper.readValue("[1,2,3]", List.class);
25 //Long id = list.get(0);// 因泛型擦除問題,會報類型轉換錯誤ClassCastException
26 
27 
28 
29 // 執行結果
30 ----------讀簡單類型----------
31 18
32 ----------讀集合類型----------
33 [1, 2, 3]
34 {zhName=A哥, enName=YourBatman}
35 ----------讀POJO----------
36 Person(name=A哥, age=18)
37 ----------讀集合類型 泛型問題----------
38 1
View Code

需要特別注意泛型擦除問題:「若反序列化成為一個集合類型(Collection or Map),泛型會被擦除」,此時你應該使用readValue(String content, TypeReference<T> valueTypeRef)方法代替。詳情可參閱本大節首的參考文章。

 

6 TreeModel

(對應 Jackson系列 文章7) 

雖然ObjectMapper在數據綁定上既可以處理簡單類型(如Integer、List、Map等),也能處理完全類型(如POJO),看似無所不能。但是,若有如下場景它依舊「不太好實現」:

碩大的JSON串中我只想要「某一個」(某幾個)屬性的值而已
臨時使用,我並不想創建一個POJO與之對應,只想直接使用「值」即可(類型轉換什么的我自己來就好)
數據結構高度「動態化」

TreeModel

為了解決這些問題,Jackson提供了強大的「樹模型」 API供以使用。樹模型雖然是jackson-core模塊里定義的,但是是由jackson-databind模塊實現的。

樹模型是JSON數據內存樹的表示形式,這是最靈活的表示,可以動態增減、從任意節點進行遍歷。。Jackson提供了樹模型API來「生成和解析」 JSON串,主要用到如下三個核心類:

JsonNode:表示json節點,類似XML的DOM樹節點。可以往里面塞值,從而最終構造出一顆json樹。

JsonNodeFactory:用來構造各種JsonNode節點的工廠。例如對象節點ObjectNode、數組節點ArrayNode等。

ObjectMapper:實現JsonNode和JSON字符串的互轉。

 

 

代碼示例及執行結果: 

 1 // 代碼
 2 JsonNodeFactory factory = JsonNodeFactory.instance;
 3 
 4     System.out.println("------ValueNode值節點示例------");
 5     // 數字節點
 6     JsonNode node = factory.numberNode(1);
 7     System.out.println(node.isNumber() + ":" + node.intValue());
 8 
 9     // null節點
10     node = factory.nullNode();
11     System.out.println(node.isNull() + ":" + node.asText());
12 
13     // missing節點
14     node = factory.missingNode();
15     System.out.println(node.isMissingNode() + "_" + node.asText());
16 
17     // POJONode節點
18     node = factory.pojoNode(new Person("YourBatman", 18));
19     System.out.println(node.isPojo() + ":" + node.asText());
20 
21     System.out.println("---" + node.isValueNode() + "---");
22 
23 
24 System.out.println("------構建一個JSON結構數據------");
25     ObjectNode rootNode = factory.objectNode();
26 
27     // 添加普通值節點
28     rootNode.put("zhName", "A哥"); // 效果完全同:rootNode.set("zhName", factory.textNode("A哥"))
29     rootNode.put("enName", "YourBatman");
30     rootNode.put("age", 18);
31 
32     // 添加數組容器節點
33     ArrayNode arrayNode = factory.arrayNode();
34     arrayNode.add("java")
35             .add("javascript")
36             .add("python");
37     rootNode.set("languages", arrayNode);
38 
39     // 添加對象節點
40     ObjectNode dogNode = factory.objectNode();
41     dogNode.put("name", "大黃")
42             .put("age", 3);
43     rootNode.set("dog", dogNode);
44 
45     System.out.println(rootNode);
46     System.out.println(rootNode.get("dog").get("name"));
47 
48 
49 
50 // 結果
51 
52 ------ValueNode值節點示例------
53 true:1
54 true:null
55 true_
56 true:Person(name=YourBatman, age=18)
57 ---true---
58 
59 ------構建一個JSON結構數據------
60 {"zhName":"A哥","enName":"YourBatman","age":18,"languages":["java","javascript","python"],"dog":{"name":"大黃","age":3}}
61 "大黃"
View Code

TreeModel數據的序列化與反序列化

ObjectMapper中提供了TreeModel數據的序列化、反序列化的實現。

序列化

相關API:

 

 

示例代碼及執行結果:

 1 // 示例1
 2 public void test1() {
 3     ObjectMapper mapper = new ObjectMapper();
 4 
 5     Person person = new Person();
 6     person.setName("YourBatman");
 7     person.setAge(18);
 8 
 9     person.setDog(new Person.Dog("旺財", 3));
10 
11     JsonNode node = mapper.valueToTree(person);
12 
13     System.out.println(person);
14     // 遍歷打印所有屬性
15     Iterator<JsonNode> it = node.iterator();
16     while (it.hasNext()) {
17         JsonNode nextNode = it.next();
18         if (nextNode.isContainerNode()) {
19             if (nextNode.isObject()) {
20                 System.out.println("狗的屬性:::");
21 
22                 System.out.println(nextNode.get("name"));
23                 System.out.println(nextNode.get("age"));
24             }
25         } else {
26             System.out.println(nextNode.asText());
27         }
28     }
29 
30     // 直接獲取
31     System.out.println("---------------------------------------");
32     System.out.println(node.get("dog").get("name"));
33     System.out.println(node.get("dog").get("age"));
34 }
35 
36 //示例1 結果
37 Person(name=YourBatman, age=18, dog=Person.Dog(name=旺財, age=3))
38 YourBatman
39 18
40 狗的屬性:::
41 "旺財"
42 3
43 ---------------------------------------
44 "旺財"
45 3
46 
47 
48 // 示例2
49 public void test2() throws IOException {
50     ObjectMapper mapper = new ObjectMapper();
51 
52     JsonFactory factory = new JsonFactory();
53     try (JsonGenerator jsonGenerator = factory.createGenerator(System.err, JsonEncoding.UTF8)) {
54 
55         // 1、得到一個jsonNode(為了方便我直接用上面API生成了哈)
56         Person person = new Person();
57         person.setName("YourBatman");
58         person.setAge(18);
59         JsonNode jsonNode = mapper.valueToTree(person);
60 
61         // 使用JsonGenerator寫到輸出流
62         mapper.writeTree(jsonGenerator, jsonNode);
63     }
64 }
65 
66 //示例2結果
67 {"name":"YourBatman","age":18,"dog":null}
View Code

反序列化

相關API:

代碼示例:

public void test4() throws IOException {
    ObjectMapper mapper = new ObjectMapper();

    String jsonStr = "{\"name\":\"YourBatman\",\"age\":18,\"dog\":{\"name\":\"旺財\",\"color\":\"WHITE\"},\"hobbies\":[\"籃球\",\"football\"]}";
    JsonNode node = mapper.readTree(jsonStr);

    System.out.println(node.get("dog").get("color").asText());
}

public void test5() throws JsonProcessingException {
    String jsonStr = "{\"name\":\"YourBatman\",\"age\":18}";

    JsonNode node = new ObjectMapper().readTree(jsonStr);

    System.out.println("-------------向結構里動態添加節點------------");
    // 動態添加一個myDiy節點,並且該節點還是ObjectNode節點
    ((ObjectNode) node).with("myDiy").put("contry", "China");

    System.out.println(node);
}
View Code

可見,在只需要取出一個大json串中的少數幾個字段時用 TreeModel API 比較方便。

 


免責聲明!

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



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