Java序列化組件之Jackson ObejectMapper

 

目錄

 

1. Bean序列化爲json,要求屬性排序:

2. ObjectMapper序列化時的屬性

3.  ObjectMapper 反序列化的屬性


1. Bean序列化爲json,要求屬性排序:

1.1. 在bean上加JsonPropertyOrder註解

 //確保在其他屬性之前輸出id”和name”
 @JsonPropertyOrder({id”,name”})
 
 //使用字母順序訂購任何沒有顯式設置的屬性
 @JsonPropertyOrder(alphabetic = true)

1.2. 序列化時配置mapper

// 加上按屬性命名字母排序
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY,true);
// json 裏有map的時候,key也是按順序.       
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS,true);

 

2. ObjectMapper序列化時的屬性


//這個特性,決定了解析器是否將自動關閉那些不屬於parser自己的輸入源。
// 如果禁止,則調用應用不得不分別去關閉那些被用來創建parser的基礎輸入流InputStream和reader;
//默認是true

objectMapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);

//是否允許解析使用Java/C++ 樣式的註釋(包括'/'+'*' 和'//' 變量)
objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);

//設置爲true時,屬性名稱不帶雙引號
objectMapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);

//反序列化是是否允許屬性名稱不帶雙引號
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

//是否允許單引號來包住屬性名稱和字符串值
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, tru

//是否允許JSON字符串包含非引號控制字符(值小於32的ASCI
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);

//是否允許JSON整數以多個0開始
objectMapper.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);

//null的屬性不序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

//按字母順序排序屬性,默認false
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);

//是否以類名作爲根元素,可以通過@JsonRootName來自定義根元素名稱,默認false
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);

//是否縮放排列輸出,默認false
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, false);

//序列化Date日期時以timestamps輸出,默認true
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);

//序列化枚舉是否以toString()來輸出,默認false,即默認以name()來輸出
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);

//序列化枚舉是否以ordinal()來輸出,默認false
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX, false);

//序列化單元素數組時不以數組來輸出,默認false
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);

//序列化Map時對key進行排序操作,默認false
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);

//序列化char[]時以json數組輸出,默認false
objectMapper.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS, true);

//序列化BigDecimal時是輸出原始數字還是科學計數,默認false,即以toPlainString()科學計數方式來輸出
objectMapper.configure(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN, true);

3.  ObjectMapper 反序列化的屬性

//當遇到未知屬性(沒有映射到屬性,沒有任何setter或者任何可以處理它的handler,是否應該拋出JsonMappingException異常
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

//該特性決定對於json浮點數,是否使用BigDecimal來序列化。如果不允許,則使用Double序列化。 默認爲false
objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, false);

//該特性決定對於json整形(非浮點),是否使用BigInteger來序列化。如果不允許,則根據數值大小來確定 是使用Integer或者Long
objectMapper.configure(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS, false);

//該特性決定JSON ARRAY是映射爲Object[]還是List<Object>。如果開啓,都爲Object[],false時,則使用List  默認爲false
objectMapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, false);

//是否使用Enum.toString()的值對json string進行反序列化。這個的設置和WRITE_ENUMS_USING_TO_STRING需要一致。
objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);

原文鏈接:

https://blog.csdn.net/sdyy321/article/details/40298081

https://www.cnblogs.com/jian-xiao/p/6009435.html

備份:

官方WIKI:https://github.com/FasterXML/jackson-databind/wiki

jackson 1.x和2.x版本的註解是放置在不同的包下的

1.x是在jackson core jar包org.codehaus.jackson.annotate下

2.x是在jackson-databind包com.fasterxml.jackson.annotation下

jackson的自動檢測機制
jackson允許使用任意的構造方法或工廠方法來構造實例

使用@JsonAutoDetect(作用在類上)來開啓/禁止自動檢測
fieldVisibility:字段的可見級別

ANY:任何級別的字段都可以自動識別

NONE:所有字段都不可以自動識別

NON_PRIVATE:非private修飾的字段可以自動識別

PROTECTED_AND_PUBLIC:被protected和public修飾的字段可以被自動識別

PUBLIC_ONLY:只有被public修飾的字段纔可以被自動識別

DEFAULT:同PUBLIC_ONLY

jackson默認的字段屬性發現規則如下:

所有被public修飾的字段->所有被public修飾的getter->所有被public修飾的setter

舉例:

  

  public static class TestPOJO{
        TestPOJO(){}
        
        TestPOJO(String name){
            this.name = name;
        }
        private String name;
 
        @Override
        public String toString() {
            return "TestPOJO{" +
                            "name='" + name + '\'' +
                            '}';
        }
    }


這個類我們只有一個private的name屬性,並且沒有提供對應的get,set方法,如果按照默認的屬性發現規則我們將無法序列化和反序列化name字段(如果沒有get,set方法,只有被public修飾的屬性纔會被發現),你可以通過修改@JsonAutoDetect的fieldVisibility來調整自動發現級別,爲了使name被自動發現,我們需要將級別調整爲ANY
    @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
同理,除了fieldVisibility可以設置外,還可以設置getterVisibility、setterVisibility、isGetterVisibility、creatorVisibility級別,不再多講


除了上面的方式,你還可以有一些其他方式可以配置methods,fields和creators(構造器和靜態方法)的自動檢測,例如:

你可以配置MapperFeature來啓動/禁止一些特別類型(getters,setters,fields,creators)的自動檢測

比如下面的MapperFeature配置:

SORT_PROPERTIES_ALPHABETICALLY:按字母順序排序屬性

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY,true);

配置SerializationFeature
一些我們比較常用的SerializationFeature配置:

SerializationFeature.WRAP_ROOT_VALUE:是否環繞根元素,默認false,如果爲true,則默認以類名作爲根元素,你也可以通過@JsonRootName來自定義根元素名稱
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE,true);
舉例:

    

@JsonRootName("myPojo")
    public static class TestPOJO{
        private String name;
 
        public String getName() {
            return name;
        }
 
        public void setName(String name) {
            this.name = name;
        }
    }


該類在序列化成json後類似如下:{"myPojo":{"name":"aaaa"}}
SerializationFeature.INDENT_OUTPUT:是否縮放排列輸出,默認false,有些場合爲了便於排版閱讀則需要對輸出做縮放排列
objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
舉例:

如果一個類中有a、b、c、d四個可檢測到的屬性,那麼序列化後的json輸出類似下面:

{
  "a" : "aaa",
  "b" : "bbb",
  "c" : "ccc",
  "d" : "ddd"
}

SerializationFeature.WRITE_DATES_AS_TIMESTAMPS:序列化日期時以timestamps輸出,默認true
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,true);
比如如果一個類中有private Date date;這種日期屬性,序列化後爲:{"date" : 1413800730456},若不爲true,則爲{"date" : "2014-10-20T10:26:06.604+0000"}
SerializationFeature.WRITE_ENUMS_USING_TO_STRING:序列化枚舉是以toString()來輸出,默認false,即默認以name()來輸出
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true);
SerializationFeature.WRITE_ENUMS_USING_INDEX:序列化枚舉是以ordinal()來輸出,默認false
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,true);
舉例:
  

 @Test
    public void enumTest() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setName("myName");
        testPOJO.setMyEnum(TestEnum.ENUM01);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,false);
        objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,false);
        String jsonStr1 = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"myEnum\":\"ENUM01\",\"name\":\"myName\"}",jsonStr1);
 
        ObjectMapper objectMapper2 = new ObjectMapper();
        objectMapper2.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true);
        String jsonStr2 = objectMapper2.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"myEnum\":\"enum_01\",\"name\":\"myName\"}",jsonStr2);
 
        ObjectMapper objectMapper3 = new ObjectMapper();
        objectMapper3.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,true);
        String jsonStr3 = objectMapper3.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"myEnum\":0,\"name\":\"myName\"}",jsonStr3);
    }
    public static class TestPOJO{
        TestPOJO(){}
        private TestEnum myEnum;
        private String name;
 
        //getters、setters省略
    }
 
    public static enum TestEnum{
        ENUM01("enum_01"),ENUM02("enum_01"),ENUM03("enum_01");
 
        private String title;
 
        TestEnum(String title) {
            this.title = title;
        }
 
        @Override
        public String toString() {
            return title;
        }
    }

SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED:序列化單元素數組時不以數組來輸出,默認false
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true);
舉例:
  

 @Test
    public void singleElemArraysUnwrap() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setName("myName");
        List<Integer> counts = new ArrayList<>();
        counts.add(1);
        testPOJO.setCounts(counts);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED,false);
        String jsonStr1 = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"name\":\"myName\",\"counts\":[1]}",jsonStr1);
 
        ObjectMapper objectMapper2 = new ObjectMapper();
        objectMapper2.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED,true);
        String jsonStr2 = objectMapper2.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"name\":\"myName\",\"counts\":1}",jsonStr2);
    }
 
    public static class TestPOJO{
        private String name;
        private List<Integer> counts;
 
        //getters、setters省略
    }

SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS:序列化Map時對key進行排序操作,默認false
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS,true);
舉例:
  

 @Test
    public void orderMapBykey() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setName("myName");
        Map<String,Integer> counts = new HashMap<>();
        counts.put("a",1);
        counts.put("d",4);
        counts.put("c",3);
        counts.put("b",2);
        counts.put("e",5);
        testPOJO.setCounts(counts);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS,false);
        String jsonStr1 = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"name\":\"myName\",\"counts\":{\"d\":4,\"e\":5,\"b\":2,\"c\":3,\"a\":1}}",jsonStr1);
 
        ObjectMapper objectMapper2 = new ObjectMapper();
        objectMapper2.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS,true);
        String jsonStr2 = objectMapper2.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"name\":\"myName\",\"counts\":{\"a\":1,\"b\":2,\"c\":3,\"d\":4,\"e\":5}}",jsonStr2);
    }
 
    public static class TestPOJO{
        private String name;
        private Map<String,Integer> counts;
 
        //getters、setters省略
    }

SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS:序列化char[]時以json數組輸出,默認false
objectMapper.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS,true);
舉例:
  

 @Test
    public void charArraysAsJsonArrays() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setName("myName");
        char[] counts = new char[]{'a','b','c','d'};
        testPOJO.setCounts(counts);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS,false);
        String jsonStr1 = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"name\":\"myName\",\"counts\":\"abcd\"}",jsonStr1);
 
        ObjectMapper objectMapper2 = new ObjectMapper();
        objectMapper2.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS,true);
        String jsonStr2 = objectMapper2.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"name\":\"myName\",\"counts\":[\"a\",\"b\",\"c\",\"d\"]}",jsonStr2);
    }
 
    public static class TestPOJO{
        private String name;
        private char[] counts;
 
        //getters、setters省略
    }

SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN:序列化BigDecimal時之間輸出原始數字還是科學計數,默認false,即是否以toPlainString()科學計數方式來輸出
objectMapper.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS,true);
舉例:
  

 @Test
    public void bigDecimalAsPlain() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setName("myName");
        testPOJO.setCount(new BigDecimal("1e20"));
 
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN,false);
        String jsonStr1 = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"name\":\"myName\",\"count\":1E+20}",jsonStr1);
 
        ObjectMapper objectMapper2 = new ObjectMapper();
        objectMapper2.configure(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN,true);
        String jsonStr2 = objectMapper2.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"name\":\"myName\",\"count\":100000000000000000000}",jsonStr2);
    }


更多的序列化配置參見點擊打開鏈接
配置DeserializationFeature

反序列化的配置這裏不再多做解釋,參見點擊打開鏈接

需要注意的是對於第二種通過配置SerializationConfig和DeserializationConfig方式只能啓動/禁止自動檢測,無法修改我們所需的可見級別
有時候對每個實例進行可見級別的註解可能會非常麻煩,這時候我們需要配置一個全局的可見級別,通過objectMapper.setVisibilityChecker()來實現,默認的VisibilityChecker實現類爲VisibilityChecker.Std,這樣可以滿足實現複雜場景下的基礎配置。

也有一些實用簡單的可見級別配置,比如:

      

 ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) // auto-detect all member fields
                        .setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE) // but only public getters
                        .setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE) // and none of "is-setters";


你也可以通過下面方式來禁止所有的自動檢測功能
      

  ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibilityChecker(objectMapper.getVisibilityChecker().with(JsonAutoDetect.Visibility.NONE));

jackson的常用註解
1、@JsonAutoDetect
看上面自動檢測,不再重複

2、@JsonIgnore
作用在字段或方法上,用來完全忽略被註解的字段和方法對應的屬性,即便這個字段或方法可以被自動檢測到或者還有其他的註解

舉例

     

  @Test
    public void jsonIgnoreTest() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setId(111);
        testPOJO.setName("myName");
        testPOJO.setCount(22);
 
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"id\":111}",jsonStr);
 
        String jsonStr2 = "{\"id\":111,\"name\":\"myName\",\"count\":22}";
        TestPOJO testPOJO2 = objectMapper.readValue(jsonStr2, TestPOJO.class);
        Assert.assertEquals(111,testPOJO2.getId());
        Assert.assertNull(testPOJO2.getName());
        Assert.assertEquals(0,testPOJO2.getCount());
    }
 
    public static class TestPOJO{
        private int id;
        @JsonIgnore
        private String name;
        private int count;
 
        public int getId() {
            return id;
        }
 
        public void setId(int id) {
            this.id = id;
        }
 
        public String getName() {
            return name;
        }
 
        public void setName(String name) {
            this.name = name;
        }
 
        public int getCount() {
            return count;
        }
        @JsonIgnore
        public void setCount(int count) {
            this.count = count;
        }
    }


當@JsonIgnore不管註解在getters上還是setters上都會忽略對應的屬性
3、@JsonProperty
作用在字段或方法上,用來對屬性的序列化/反序列化,可以用來避免遺漏屬性,同時提供對屬性名稱重命名,比如在很多場景下Java對象的屬性是按照規範的駝峯書寫,但是實際展示的卻是類似C-style或C++/Microsolft style

舉例

    @Test
    public void jsonPropertyTest() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.wahaha(111);
        testPOJO.setFirstName("myName");
 
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"id\":111,\"first_name\":\"myName\"}",jsonStr);
 
        String jsonStr2 = "{\"id\":111,\"first_name\":\"myName\"}";
        TestPOJO testPOJO2 = objectMapper.readValue(jsonStr2, TestPOJO.class);
        Assert.assertEquals(111, testPOJO2.wahaha());
        Assert.assertEquals("myName", testPOJO2.getFirstName());
    }
 
    public static class TestPOJO{
        @JsonProperty//注意這裏必須得有該註解,因爲沒有提供對應的getId和setId函數,而是其他的getter和setter,防止遺漏該屬性
        private int id;
        @JsonProperty("first_name")
        private String firstName;
 
        public int wahaha() {
            return id;
        }
 
        public void wahaha(int id) {
            this.id = id;
        }
 
        public String getFirstName() {
            return firstName;
        }
 
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
    }
4、@JsonIgnoreProperties
作用在類上,用來說明有些屬性在序列化/反序列化時需要忽略掉,可以將它看做是@JsonIgnore的批量操作,但它的功能比@JsonIgnore要強,比如一個類是代理類,我們無法將將@JsonIgnore標記在屬性或方法上,此時便可用@JsonIgnoreProperties標註在類聲明上,它還有一個重要的功能是作用在反序列化時解析字段時過濾一些未知的屬性,否則通常情況下解析到我們定義的類不認識的屬性便會拋出異常。

可以註明是想要忽略的屬性列表如@JsonIgnoreProperties({"name","age","title"}),

也可以註明過濾掉未知的屬性如@JsonIgnoreProperties(ignoreUnknown=true)

舉例:

    @Test(expected = UnrecognizedPropertyException.class)
    public void JsonIgnoreProperties() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setId(111);
        testPOJO.setName("myName");
        testPOJO.setAge(22);
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"id\":111}",jsonStr);//name和age被忽略掉了
 
        String jsonStr2 = "{\"id\":111,\"name\":\"myName\",\"age\":22,\"title\":\"myTitle\"}";
        TestPOJO testPOJO2 = objectMapper.readValue(jsonStr2, TestPOJO.class);
        Assert.assertEquals(111, testPOJO2.getId());
        Assert.assertNull(testPOJO2.getName());
        Assert.assertEquals(0,testPOJO2.getAge());
        String jsonStr3 = "{\"id\":111,\"name\":\"myName\",\"count\":33}";//這裏有個未知的count屬性,反序列化會報錯
        objectMapper.readValue(jsonStr3, TestPOJO.class);
    }
 
    @JsonIgnoreProperties({"name","age","title"})
    public static class TestPOJO{
        private int id;
        private String name;
        private int age;
 
        //getters、setters省略
    }
如果將上面的
@JsonIgnoreProperties({"name","age","title"})
更換爲

@JsonIgnoreProperties(ignoreUnknown=true)
那麼測試用例中在反序列化未知的count屬性時便不會拋出異常了

5、@JsonUnwrapped
作用在屬性字段或方法上,用來將子JSON對象的屬性添加到封閉的JSON對象,說起來比較難懂,看個例子就很清楚了,不多解釋

舉例

    @Test
    public void jsonUnwrapped() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setId(111);
        TestName testName = new TestName();
        testName.setFirstName("張");
        testName.setSecondName("三");
        testPOJO.setName(testName);
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        //如果沒有@JsonUnwrapped,序列化後將爲{"id":111,"name":{"firstName":"張","secondName":"三"}}
        //因爲在name屬性上加了@JsonUnwrapped,所以name的子屬性firstName和secondName將不會包含在name中。
        Assert.assertEquals("{\"id\":111,\"firstName\":\"張\",\"secondName\":\"三\"}",jsonStr);
        String jsonStr2 = "{\"id\":111,\"firstName\":\"張\",\"secondName\":\"三\"}";
        TestPOJO testPOJO2 = objectMapper.readValue(jsonStr2,TestPOJO.class);
        Assert.assertEquals(111,testPOJO2.getId());
        Assert.assertEquals("張",testPOJO2.getName().getFirstName());
        Assert.assertEquals("三",testPOJO2.getName().getSecondName());
    }
 
    public static class TestPOJO{
        private int id;
        @JsonUnwrapped
        private TestName name;
 
        //getters、setters省略
    }                                                                                                                              public static class TestName{
        private String firstName;
        private String secondName;
 
        //getters、setters省略
    }
在2.0+版本中@JsonUnwrapped添加了prefix和suffix屬性,用來對字段添加前後綴,這在有關屬性分組上比較有用,在上面的測試用例中,如果我們將TestPOJO的name屬性上的@JsonUnwrapped添加前後綴配置,即
    @JsonUnwrapped(prefix = "name_",suffix = "_test")
那麼TestPOJO序列化後將爲{"id":111,"name_firstName_test":"張","name_secondName_test":"三"},反序列化時也要加上前後綴纔會被解析爲POJO
6、@JsonIdentityInfo
2.0+版本新註解,作用於類或屬性上,被用來在序列化/反序列化時爲該對象或字段添加一個對象識別碼,通常是用來解決循環嵌套的問題,比如數據庫中的多對多關係,通過配置屬性generator來確定識別碼生成的方式,有簡單的,配置屬性property來確定識別碼的名稱,識別碼名稱沒有限制。
對象識別碼可以是虛擬的,即存在在JSON中,但不是POJO的一部分,這種情況下我們可以如此使用註解

@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class,property = "@id")

對象識別碼也可以是真實存在的,即以對象的屬性爲識別碼,通常這種情況下我們一般以id屬性爲識別碼,可以這麼使用註解
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
舉例
    @Test
    public void jsonIdentityInfo() throws Exception {
        Parent parent = new Parent();
        parent.setName("jack");
        Child child = new Child();
        child.setName("mike");
        Child[] children = new Child[]{child};
        parent.setChildren(children);
        child.setParent(parent);
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(parent);
        Assert.assertEquals("{\"@id\":1,\"name\":\"jack\",\"children\":[{\"name\":\"mike\",\"parent\":1}]}",jsonStr);
    }
 
    @JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class,property = "@id")
    public static class Parent{
        private String name;
        private Child[] children;
 
        //getters、setters省略
    }
 
    public static class Child{
        private String name;
        private Parent parent;
 
        //getters、setters省略
    }
這裏需要提醒一下的是在1.6版本中提供了@JsonManagedReference和@JsonBackReference來解決循環嵌套問題,因爲屬於過時註解這裏就不解釋了,有興趣的可以自己看

7、@JsonNaming
jackson 2.1+版本的註解,作用於類或方法,注意這個註解是在jackson-databind包中而不是在jackson-annotations包裏,它可以讓你定製屬性命名策略,作用和前面提到的@JsonProperty的重命名屬性名稱相同。比如
你有一個JSON串{"in_reply_to_user_id":"abc123"},需要反序列化爲POJO,POJO一般情況下則需要如此寫

    public static class TestPOJO{
 
        private String in_reply_to_user_id;
 
        public String getIn_reply_to_user_id() {
            return in_reply_to_user_id;
        }
 
        public void setIn_reply_to_user_id(String in_reply_to_user_id) {
            this.in_reply_to_user_id = in_reply_to_user_id;
        }
    }
但這顯然不符合JAVA的編碼規範,你可以用@JsonProperty,比如:
    public static class TestPOJO{
 
        @JsonProperty("in_reply_to_user_id")
        private String inReplyToUserId;
 
        public String getInReplyToUserId() {
            return inReplyToUserId;
        }
 
        public void setInReplyToUserId(String inReplyToUserId) {
            this.inReplyToUserId = inReplyToUserId;
        }
    }
這樣就符合規範了,可是如果POJO裏有很多屬性,給每個屬性都要加上@JsonProperty是多麼繁重的工作,這裏就需要用到@JsonNaming了,它不僅能制定統一的命名規則,還能任意按自己想要的方式定製
舉例

    @Test
    public void jsonNaming() throws Exception{
        String jsonStr = "{\"in_reply_to_user_id\":\"abc123\"}";
        ObjectMapper objectMapper = new ObjectMapper();
        TestPOJO testPOJO = objectMapper.readValue(jsonStr,TestPOJO.class);
        Assert.assertEquals("abc123",testPOJO.getInReplyToUserId());
 
        TestPOJO testPOJO2 = new TestPOJO();
        testPOJO2.setInReplyToUserId("abc123");
        String jsonStr2 = objectMapper.writeValueAsString(testPOJO2);
        Assert.assertEquals(jsonStr,jsonStr2);
    }
 
    @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class)
    public static class TestPOJO{
 
        private String inReplyToUserId;
 
        public String getInReplyToUserId() {
            return inReplyToUserId;
        }
 
        public void setInReplyToUserId(String inReplyToUserId) {
            this.inReplyToUserId = inReplyToUserId;
        }
    }
@JsonNaming使用了jackson已經實現的PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy,它可以將大寫轉換爲小寫並添加下劃線。你可以自定義,必須繼承類PropertyNamingStrategy,建議繼承PropertyNamingStrategyBase,我們自己實現一個類似LowerCaseWithUnderscoresStrategy的策略,只是將下劃線改爲破折號
舉例

    @Test
    public void jsonNaming() throws Exception{
        String jsonStr = "{\"in-reply-to-user-id\":\"abc123\"}";
        ObjectMapper objectMapper = new ObjectMapper();
        TestPOJO testPOJO = objectMapper.readValue(jsonStr,TestPOJO.class);
        Assert.assertEquals("abc123", testPOJO.getInReplyToUserId());
 
        TestPOJO testPOJO2 = new TestPOJO();
        testPOJO2.setInReplyToUserId("abc123");
        String jsonStr2 = objectMapper.writeValueAsString(testPOJO2);
        Assert.assertEquals(jsonStr, jsonStr2);
    }
 
    @JsonNaming(MyPropertyNamingStrategy.class)
    public static class TestPOJO{
 
        private String inReplyToUserId;
 
        public String getInReplyToUserId() {
            return inReplyToUserId;
        }
 
        public void setInReplyToUserId(String inReplyToUserId) {
            this.inReplyToUserId = inReplyToUserId;
        }
    }
 
    public static class MyPropertyNamingStrategy extends PropertyNamingStrategy.PropertyNamingStrategyBase {
        @Override
        public String translate(String input) {
            if (input == null) return input; // garbage in, garbage out
            int length = input.length();
            StringBuilder result = new StringBuilder(length * 2);
            int resultLength = 0;
            boolean wasPrevTranslated = false;
            for (int i = 0; i < length; i++)
            {
                char c = input.charAt(i);
                if (i > 0 || c != '-') // skip first starting underscore
                {
                    if (Character.isUpperCase(c))
                    {
                        if (!wasPrevTranslated && resultLength > 0 && result.charAt(resultLength - 1) != '-')
                        {
                            result.append('-');
                            resultLength++;
                        }
                        c = Character.toLowerCase(c);
                        wasPrevTranslated = true;
                    }
                    else
                    {
                        wasPrevTranslated = false;
                    }
                    result.append(c);
                    resultLength++;
                }
            }
            return resultLength > 0 ? result.toString() : input;
        }
    }
如果你想讓自己定製的策略對所有解析都實現,除了對每個具體的實體類對應的位置加上@JsonNaming外你還可以如下做全局配置
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setPropertyNamingStrategy(new MyPropertyNamingStrategy());

多態類型處理
jackson允許配置多態類型處理,當進行反序列話時,JSON數據匹配的對象可能有多個子類型,爲了正確的讀取對象的類型,我們需要添加一些類型信息。可以通過下面幾個註解來實現:

@JsonTypeInfo
作用於類/接口,被用來開啓多態類型處理,對基類/接口和子類/實現類都有效

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property = "name")
這個註解有一些屬性,
use:定義使用哪一種類型識別碼,它有下面幾個可選值:

1、JsonTypeInfo.Id.CLASS:使用完全限定類名做識別

2、JsonTypeInfo.Id.MINIMAL_CLASS:若基類和子類在同一包類,使用類名(忽略包名)作爲識別碼

3、JsonTypeInfo.Id.NAME:一個合乎邏輯的指定名稱

4、JsonTypeInfo.Id.CUSTOM:自定義識別碼,由@JsonTypeIdResolver對應,稍後解釋

5、JsonTypeInfo.Id.NONE:不使用識別碼

include(可選):指定識別碼是如何被包含進去的,它有下面幾個可選值:

1、JsonTypeInfo.As.PROPERTY:作爲數據的兄弟屬性

2、JsonTypeInfo.As.EXISTING_PROPERTY:作爲POJO中已經存在的屬性

3、JsonTypeInfo.As.EXTERNAL_PROPERTY:作爲擴展屬性

4、JsonTypeInfo.As.WRAPPER_OBJECT:作爲一個包裝的對象

5、JsonTypeInfo.As.WRAPPER_ARRAY:作爲一個包裝的數組

property(可選):制定識別碼的屬性名稱

此屬性只有當use爲JsonTypeInfo.Id.CLASS(若不指定property則默認爲@class)、JsonTypeInfo.Id.MINIMAL_CLASS(若不指定property則默認爲@c)、JsonTypeInfo.Id.NAME(若不指定property默認爲@type),include爲JsonTypeInfo.As.PROPERTY、JsonTypeInfo.As.EXISTING_PROPERTY、JsonTypeInfo.As.EXTERNAL_PROPERTY時纔有效

defaultImpl(可選):如果類型識別碼不存在或者無效,可以使用該屬性來制定反序列化時使用的默認類型

visible(可選,默認爲false):是否可見

屬性定義了類型標識符的值是否會通過JSON流成爲反序列化器的一部分,默認爲fale,也就是說,jackson會從JSON內容中處理和刪除類型標識符再傳遞給JsonDeserializer。

@JsonSubTypes
作用於類/接口,用來列出給定類的子類,只有當子類類型無法被檢測到時纔會使用它
一般是配合@JsonTypeInfo在基類上使用,比如:

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property = "typeName")
    @JsonSubTypes({@JsonSubTypes.Type(value=Sub1.class,name = "sub1"),@JsonSubTypes.Type(value=Sub2.class,name = "sub2")})
@JsonSubTypes的值是一個@JsonSubTypes.Type[]數組,裏面枚舉了多態類型(value對應類)和類型的標識符值(name對應@JsonTypeInfo中的property標識名稱的值,此爲可選值,若不制定需由@JsonTypeName在子類上制定)
@JsonTypeName
作用於子類,用來爲多態子類指定類型標識符的值

比如:

@JsonTypeName(value = "sub1")
value屬性作用同上面@JsonSubTypes裏的name作用
@JsonTypeResolver和@JsonTypeIdResoler
作用於類,可以自定義多態的類型標識符,這個平時很少用到,主要是現有的一般就已經滿足絕大多數的需求了,如果你需要比較特別的類型標識符,建議使用這2個註解,自己定製基於TypeResolverBuilder和TypeIdResolver的類即可

我們看幾個jackson處理多態的例子

    @Test
    public void jsonTypeInfo() throws Exception{
        Sub1 sub1 = new Sub1();
        sub1.setId(1);
        sub1.setName("sub1Name");
        Sub2 sub2 = new Sub2();
        sub2.setId(2);
        sub2.setAge(33);
        ObjectMapper objectMapper = new ObjectMapper();
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setMyIns(new MyIn[]{sub1, sub2});
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"myIns\":[{\"id\":1,\"name\":\"sub1Name\"},{\"id\":2,\"age\":33}]}", jsonStr);
        System.out.println(jsonStr);
    }
 
    public static abstract class MyIn{
        private int id;
 
        //getters、setters省略
    }
 
    public static class Sub1 extends MyIn{
        private String name;
 
        //getters、setters省略
    }
 
    public static class Sub2 extends MyIn{
        private int age;
 
        //getters、setters省略
    }
這是序列化時最簡單的一種多態處理方式,因爲沒有使用任何多態處理註解,即默認使用的識別碼類型爲JsonTypeInfo.Id.NONE,而jackson沒有自動搜索功能,所以只能序列化而不能反序列化,上面序列化測試的結果爲{"myIns":[{"id":1,"name":"sub1Name"},{"id":2,"age":33}]},我們可以看到JSON串中是沒有對應的多態類型識別碼的。
下面我們在基類MyIn上加上多態處理相關注解,首先我們在基類MyIn上添加@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)即

    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
    public static abstract class MyIn{
        private int id;
 
        //getters、setters省略
    }
執行上面的序列化測試代碼結果將會是
{"myIns":[{"@class":"cn.yangyong.fodder.util.JacksonUtilsTest$Sub1","id":1,"name":"sub1Name"},{"@class":"cn.yangyong.fodder.util.JacksonUtilsTest$Sub2","id":2,"age":33}]}

我們可以看到多了相應的多態類型識別碼,識別碼名稱爲默認的@class(因爲沒有指定名稱),識別碼的值爲JsonTypeInfo.Id.CLASS即子類完全限定名

我們再添加上property屬性@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,property = "typeName")即

    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,property = "typeName")
    public static abstract class MyIn{
        private int id;
 
        //getters、setters省略
    }
再次執行上面的序列化測試代碼結果將會是
{"myIns":[{"typeName":"cn.yangyong.fodder.util.JacksonUtilsTest$Sub1","id":1,"name":"sub1Name"},{"typeName":"cn.yangyong.fodder.util.JacksonUtilsTest$Sub2","id":2,"age":33}]}

這次多態類型識別碼的名稱已經變成了我們指定的typeName而不是默認的@class了

上面的例子都是默認選擇的include爲JsonTypeInfo.As.PROPERTY,下面我們更改include方式,看看有什麼變化,將include設置爲JsonTypeInfo.As.WRAPPER_OBJECT即

    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,include = JsonTypeInfo.As.WRAPPER_OBJECT,property = "typeName")
    public static abstract class MyIn{
        private int id;
 
        //getters、setters省略
    }
再次執行序列化測試,結果爲
{"myIns":[{"cn.yangyong.fodder.util.JacksonUtilsTest$Sub1":{"id":1,"name":"sub1Name"}},{"cn.yangyong.fodder.util.JacksonUtilsTest$Sub2":{"id":2,"age":33}}]}

我們看到類型識別碼不再成爲兄弟屬性包含進去了而是爲父屬性將其他屬性包含進去,此時我們指定的property=“typeName”已經無用了

再次修改use屬性指定爲JsonTypeInfo.Id.MINIMAL_CLASS,即@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS,include = JsonTypeInfo.As.PROPERTY,property = "typeName")

    @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS,include = JsonTypeInfo.As.PROPERTY,property = "typeName")
    public static abstract class MyIn{
        private int id;
 
        //getters、setters省略
    }
測試序列化結果爲
{"myIns":[{"typeName":".JacksonUtilsTest$Sub1","id":1,"name":"sub1Name"},{"typeName":".JacksonUtilsTest$Sub2","id":2,"age":33}]}

發現已經沒有同包的package名稱,識別碼的值更加簡短了

測試反序列化

    @Test
    public void jsonTypeInfo() throws Exception{
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr2 = "{\"myIns\":[{\"typeName\":\".JacksonUtilsTest$Sub1\",\"id\":1,\"name\":\"sub1Name\"},{\"typeName\":\".JacksonUtilsTest$Sub2\",\"id\":2,\"age\":33}]}";
        TestPOJO testPOJO2 = objectMapper.readValue(jsonStr2,TestPOJO.class);
        MyIn[] myIns = testPOJO2.getMyIns();
        for (MyIn myIn : myIns) {
            System.out.println(myIn.getClass().getSimpleName());
        }
    }
結果將會顯示爲Sub1和Sub2說明是可以實現多態的反序列化的
可能我們在反序列化時覺得如此傳遞識別碼很不友好,最好可以自定義識別碼的值,可以選擇use = JsonTypeInfo.Id.NAME和@JsonSubTypes配合即

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property = "typeName")
    @JsonSubTypes({@JsonSubTypes.Type(value=Sub1.class,name="sub1"),@JsonSubTypes.Type(value=Sub2.class,name="sub2")})
    public static abstract class MyIn{
        private int id;
        //getters、setters省略
    }
執行序列化結果爲
{"myIns":[{"typeName":"sub1","id":1,"name":"sub1Name"},{"typeName":"sub2","id":2,"age":33}]}

使用這個結果反序列化也可以得到我們想要的結果,或者在子類上添加@JsonTypeName(value = "sub1")和@JsonTypeName(value = "sub2")以便取代@JsonSubTypes裏的name

如果想不使用@JsonSubTypes來實現反序列化,我們可以在ObjectMapper上註冊子類實現,即

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerSubtypes(new NamedType(Sub1.class,"sub1"));
objectMapper.registerSubtypes(new NamedType(Sub2.class,"sub2"));
更多多態處理的例子還請大家自己研究


用於序列化和反序列化的註解類
1、@JsonSerialize和@JsonDeserialize
作用於方法和字段上,通過 using(JsonSerializer)和using(JsonDeserializer)來指定序列化和反序列化的實現,通常我們在需要自定義序列化和反序列化時會用到,比如下面的例子中的日期轉換

    @Test
    public void jsonSerializeAndDeSerialize() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setName("myName");
        testPOJO.setBirthday(new Date());
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        System.out.println(jsonStr);
 
        String jsonStr2 = "{\"name\":\"myName\",\"birthday\":\"2014-11-11 19:01:58\"}";
        TestPOJO testPOJO2 = objectMapper.readValue(jsonStr2,TestPOJO.class);
        System.out.println(testPOJO2.toString());
    }
 
    public static class TestPOJO{
        private String name;
        @JsonSerialize(using = MyDateSerializer.class)
        @JsonDeserialize(using = MyDateDeserializer.class)
        private Date birthday;
 
        //getters、setters省略
 
        @Override
        public String toString() {
            return "TestPOJO{" +
                "name='" + name + '\'' +
                ", birthday=" + birthday +
                '}';
        }
    }
 
    private static class MyDateSerializer extends JsonSerializer<Date>{
        @Override
        public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String dateStr = dateFormat.format(value);
            jgen.writeString(dateStr);
        }
    }
 
    private static class MyDateDeserializer extends JsonDeserializer<Date>{
        @Override
        public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            String value = jp.getValueAsString();
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                return dateFormat.parse(value);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
上面的例子中自定義了日期的序列化和反序列化方式,可以將Date和指定日期格式字符串之間相互轉換。

也可以通過使用as(JsonSerializer)和as(JsonDeserializer)來實現多態類型轉換,上面我們有提到多態類型處理時可以使用@JsonTypeInfo實現,還有一種比較簡便的方式就是使用@JsonSerialize和@JsonDeserialize指定as的子類類型,注意這裏必須指定爲子類類型纔可以實現替換運行時的類型
    @Test
    public void jsonSerializeAndDeSerialize() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setName("myName");
        Sub1 sub1 = new Sub1();
        sub1.setId(1);
        sub1.setName("sub1Name");
        Sub2 sub2 = new Sub2();
        sub2.setId(2);
        sub2.setAge(22);
        testPOJO.setSub1(sub1);
        testPOJO.setSub2(sub2);
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        System.out.println(jsonStr);
 
        String jsonStr2 = "{\"name\":\"myName\",\"sub1\":{\"id\":1,\"name\":\"sub1Name\"},\"sub2\":{\"id\":2,\"age\":22}}";
        TestPOJO testPOJO2 = objectMapper.readValue(jsonStr2,TestPOJO.class);
        System.out.println(testPOJO2.toString());
    }
 
    public static class TestPOJO{
        private String name;
        @JsonSerialize(as = Sub1.class)
        @JsonDeserialize(as = Sub1.class)
        private MyIn sub1;
        @JsonSerialize(as = Sub2.class)
        @JsonDeserialize(as = Sub2.class)
        private MyIn sub2;
 
        //getters、setters省略
 
        @Override
        public String toString() {
            return "TestPOJO{" +
                "name='" + name + '\'' +
                ", sub1=" + sub1 +
                ", sub2=" + sub2 +
                '}';
        }
    }
 
    public static class MyIn{
        private int id;
 
        //getters、setters省略
    }
 
    public static class Sub1 extends MyIn{
        private String name;
 
        //getters、setters省略
 
        @Override
        public String toString() {
            return "Sub1{" +
                "id=" + getId()  +
                "name='" + name + '\'' +
                '}';
        }
    }
    public static class Sub2 extends MyIn{
        private int age;
        //getters、setters省略
 
        @Override
        public String toString() {
            return "Sub1{" +
                "id=" + getId() +
                "age='" + age +
                '}';
        }
    }
上面例子中通過as來指定了需要替換實際運行時類型的子類,實際上上面例子中序列化時是可以不使用@JsonSerialize(as = Sub1.class)的,因爲jackson可以自動將POJO轉換爲對應的JSON,而反序列化時由於無法自動檢索匹配類型必須要指定@JsonDeserialize(as = Sub1.class)方可實現
最後@JsonSerialize可以配置include屬性來指定序列化時被註解的屬性被包含的方式,默認總是被包含進來,但是可以過濾掉空的屬性或有默認值的屬性,舉個簡單的過濾空屬性的例子如下

    @Test
    public void jsonSerializeAndDeSerialize() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setName("");
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{}",jsonStr);
    }
 
    public static class TestPOJO{
        @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
        private String name;
 
        //getters、setters省略
    }
2、@JsonPropertyOrder
作用在類上,被用來指明當序列化時需要對屬性做排序,它有2個屬性
一個是alphabetic:布爾類型,表示是否採用字母拼音順序排序,默認是爲false,即不排序

    @Test
    public void jsonPropertyOrder() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setA("1");
        testPOJO.setB("2");
        testPOJO.setC("3");
        testPOJO.setD("4");
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"a\":\"1\",\"c\":\"3\",\"d\":\"4\",\"b\":\"2\"}",jsonStr);
    }
 
    public static class TestPOJO{
        private String a;
        private String c;
        private String d;
        private String b;
 
        //getters、setters省略
    }
我們先看一個默認的排序方式,序列化單元測試結果依次爲{"a":"1","c":"3","d":"4","b":"2"},即是沒有經過排序操作的,在TestPOJO上加上@jsonPropertyOrder(alphabetic = true)再執行測試結果將會爲{"a":"1","b":"2","c":"3","d":"4"}
還有一個屬性是value:數組類型,表示將優先其他屬性排序的屬性名稱
    @Test
    public void jsonPropertyOrder() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setA("1");
        testPOJO.setB("2");
        testPOJO.setC("3");
        testPOJO.setD("4");
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        System.out.println(jsonStr);
        Assert.assertEquals("{\"c\":\"3\",\"b\":\"2\",\"a\":\"1\",\"d\":\"4\"}",jsonStr);
    }
 
    @JsonPropertyOrder(alphabetic = true,value = {"c","b"})
    public static class TestPOJO{
        private String a;
        private String c;
        private String d;
        private String b;
 
        //getters、setters省略
    }
上面例子可以看到value指定了c和b屬性優先排序,所以序列化後爲{"c":"3","b":"2","a":"1","d":"4"}
還記得本文上面最開始配置MapperFeature時也有屬性排序麼,對,就是

objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY,true);
只不過@JsonPropertyOrder顆粒度要更細一點,可以決定哪些屬性優先排序
3、@JsonView
視圖模板,作用於方法和屬性上,用來指定哪些屬性可以被包含在JSON視圖中,在前面我們知道已經有@JsonIgnore和@JsonIgnoreProperties可以排除過濾掉不需要序列化的屬性,可是如果一個POJO中有上百個屬性,比如訂單類、商品詳情類這種屬性超多,而我們可能只需要概要簡單信息即序列化時只想輸出其中幾個或10幾個屬性,此時使用@JsonIgnore和@JsonIgnoreProperties就顯得非常繁瑣,而使用@JsonView便會非常方便,只許在你想要輸出的屬性(或對應的getter)上添加@JsonView即可,舉例:
    @Test
    public void jsonView() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setA("1");
        testPOJO.setB("2");
        testPOJO.setC("3");
        testPOJO.setD("4");
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
        String jsonStr = objectMapper.writerWithView(FilterView.OutputA.class).writeValueAsString(testPOJO);
        Assert.assertEquals("{\"a\":\"1\",\"c\":\"3\"}",jsonStr);
        String jsonStr2 = objectMapper.writerWithView(FilterView.OutputB.class).writeValueAsString(testPOJO);
        Assert.assertEquals("{\"d\":\"4\",\"b\":\"2\"}",jsonStr2);
    }
 
    public static class TestPOJO{
        @JsonView(FilterView.OutputA.class)
        private String a;
        @JsonView(FilterView.OutputA.class)
        private String c;
        @JsonView(FilterView.OutputB.class)
        private String d;
        @JsonView(FilterView.OutputB.class)
        private String b;
        //getters、setters忽略
    }
 
 
    private static class FilterView {
        static class OutputA {}
        static class OutputB {}
    }
上面的測試用例中,我們在序列化之前先設置了objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false),看javadoc說這是一個雙向開關,開啓將輸出沒有JsonView註解的屬性,false關閉將輸出有JsonView註解的屬性,可惜我在測試中開啓開關後有JsonView註解的屬性任然輸出了,大家可以研究下。序列化時使用了objectMapper.writerWithView(FilterView.OutputA.class).writeValueAsString(testPOJO),即使用哪個視圖來輸出。在上面的例子中又2種視圖,我們在序列化的時候可以選擇想要的視圖來輸出,這在一些地方比較好用,比如安卓、蘋果、桌面等不同的客戶端可能會輸出不同的屬性。在1.6版本中這個@JsonView註解同時也會強制性自動發現,也就是說不管屬性的可見性以及是否設置了自動發現這些屬性都將會自動被發現,在上例中TestPOJO中的getters、setters可以不需要也能輸出我們想要的結果。
4、@JsonFilter
Json屬性過濾器,作用於類,作用同上面的@JsonView,都是過濾掉不想要的屬性,輸出自己想要的屬性。和@FilterView不同的是@JsonFilter可以動態的過濾屬性,比如我不想輸出以system開頭的所有屬性等待,應該說@JsonFilter更高級一點,舉個簡單的例子

    @Test
    public void jsonFilter() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setA("1");
        testPOJO.setB("2");
        testPOJO.setC("3");
        testPOJO.setD("4");
        ObjectMapper objectMapper = new ObjectMapper();
        FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter",SimpleBeanPropertyFilter.filterOutAllExcept("a"));
        objectMapper.setFilters(filters);
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"a\":\"1\"}",jsonStr);
    }
 
    @JsonFilter("myFilter")
    public static class TestPOJO{
        private String a;
        private String c;
        private String d;
        private String b;
 
        //getters、setters省略
    }
上面例子中在我們想要序列化的POJO上加上了@JsonFilter,表示該類將使用名爲myFilter的過濾器。在測試中定義了一個名爲myFilter的SimpleFilterProvider,這個過濾器將會過濾掉所有除a屬性以外的屬性。這只是最簡單的輸出指定元素的例子,你可以自己實現FilterProvider來滿足你的過濾需求。
有時候我們可能需要根據現有的POJO來過濾屬性,而這種情況下通常不會讓你修改已有的代碼在POJO上加註解,這種情況下我們就可以結合@JsonFilter和MixInAnnotations來實現過濾屬性,如下例所示,不再多做解釋

    @Test
    public void jsonFilter() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setA("1");
        testPOJO.setB("2");
        testPOJO.setC("3");
        testPOJO.setD("4");
        ObjectMapper objectMapper = new ObjectMapper();
        FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter",SimpleBeanPropertyFilter.filterOutAllExcept("a"));
        objectMapper.setFilters(filters);
        objectMapper.addMixInAnnotations(TestPOJO.class,MyFilterMixIn.class);
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        Assert.assertEquals("{\"a\":\"1\"}",jsonStr);
    }
 
    public static class TestPOJO{
        private String a;
        private String c;
        private String d;
        private String b;
        //getters、setters省略
    }
 
    @JsonFilter("myFilter")
    private static interface MyFilterMixIn{
    }
5、@JsonIgnoreType
作用於類,表示被註解該類型的屬性將不會被序列化和反序列化,也跟上面幾個一樣屬於過濾屬性功能的註解,舉例:
    @Test
    public void jsonFilter() throws Exception {
        TestPOJO testPOJO = new TestPOJO();
        testPOJO.setName("myName");
        Sub1 sub1 = new Sub1();
        sub1.setId(1);
        sub1.setName("sub1");
        Sub2 sub2 = new Sub2();
        sub2.setId(2);
        sub2.setAge(22);
        testPOJO.setMyIn(sub1);
        testPOJO.setSub1(sub1);
        testPOJO.setSub2(sub2);
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(testPOJO);
        System.out.println(jsonStr);
    }
 
    public static class TestPOJO{
        private Sub1 sub1;
        private Sub2 sub2;
        private MyIn myIn;
        private String name;
        //getters、setters省略
    }
 
    public static class MyIn{
        private int id;
        //getters、setters省略
    }
 
    @JsonIgnoreType
    public static class Sub1 extends MyIn{
        private String name;
        //getters、setters省略
    }
 
    @JsonIgnoreType
    public static class Sub2 extends MyIn{
        private int age;
        //getters、setters省略
    }
上面例子中我們在類Sub1和Sub2上都加上了@JsonIgnoreType,那麼需要序列化和反序列時POJO中所有Sub1和Sub2類型的屬性都將會被忽略,上面測試結果爲{"myIn":{"id":1,"name":"sub1"},"name":"myName"},只輸出了name和myIn屬性。需要注意的是@JsonIgnoreType是可以繼承的,即如果在基類上添加了該註解,那麼子類也相當於加了該註解。在上例中,如果只在基類MyIn上添加@JsonIgnoreType那麼序列化TestPOJO時將會過濾掉MyIn、Sub1、Sub2。輸出結果爲{"name":"myName"}
6、@JsonAnySetter
作用於方法,在反序列化時用來處理遇到未知的屬性的時候調用,在本文前面我們知道可以通過註解@JsonIgnoreProperties(ignoreUnknown=true)來過濾未知的屬性,但是如果需要這些未知的屬性該如何是好?那麼@JsonAnySetter就可以派上用場了,它通常會和map屬性配合使用用來保存未知的屬性,舉例:
    @Test
    public void jsonAnySetter() throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = "{\"name\":\"myName\",\"code\":\"12345\",\"age\":12}";
        TestPOJO testPOJO = objectMapper.readValue(jsonStr,TestPOJO.class);
        Assert.assertEquals("myName",testPOJO.getName());
        Assert.assertEquals("12345",testPOJO.getOther().get("code"));
        Assert.assertEquals(12,testPOJO.getOther().get("age"));
    }
 
    public static class TestPOJO{
        private String name;
 
        private Map other = new HashMap();
 
        @JsonAnySetter
        public void set(String name,Object value) {
            other.put(name,value);
        }
 
        //getters、setters省略
    }
測試用例中我們在set方法上標註了@JsonAnySetter,每當遇到未知的屬性時都會調用該方法
7、@JsonCreator
作用於方法,通常用來標註構造方法或靜態工廠方法上,使用該方法來構建實例,默認的是使用無參的構造方法,通常是和@JsonProperty或@JacksonInject配合使用,舉例

    @Test
    public void jsonCreator() throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = "{\"full_name\":\"myName\",\"age\":12}";
        TestPOJO testPOJO = objectMapper.readValue(jsonStr,TestPOJO.class);
        Assert.assertEquals("myName",testPOJO.getName());
        Assert.assertEquals(12, testPOJO.getAge());
    }
 
    public static class TestPOJO{
        private String name;
        private int age;
 
        @JsonCreator
        public TestPOJO(@JsonProperty("full_name") String name,@JsonProperty("age") int age){
            this.name = name;
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public int getAge() {
            return age;
        }
    }
上面示例中是在構造方法上標註了@JsonCreator,同樣你也可以標註在靜態工廠方法上,比如:
    @Test
    public void jsonCreator() throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = "{\"name\":\"myName\",\"birthday\":1416299461556}";
        TestPOJO testPOJO = objectMapper.readValue(jsonStr,TestPOJO.class);
        Assert.assertEquals("myName",testPOJO.getName());
        System.out.println(testPOJO.getBirthday());
    }
 
    public static class TestPOJO{
        private String name;
        private Date birthday;
 
        private TestPOJO(String name,Date birthday){
            this.name = name;
            this.birthday = birthday;
        }
 
        @JsonCreator
        public static TestPOJO getInstance(@JsonProperty("name") String name,@JsonProperty("birthday") long timestamp){
            Date date = new Date(timestamp);
            return new TestPOJO(name,date);
        }
 
        public String getName() {
            return name;
        }
 
        public Date getBirthday() {
            return birthday;
        }
    }
這個實例中,TestPOJO的構造方法是私有的,外面無法new出來該對象,只能通過工廠方法getInstance來構造實例,此時@JsonCreator就標註在工廠方法上。
除了這2種方式外,還有一種構造方式成爲授權式構造器,也是我們平常比較常用到的,這個構造器只有一個參數,且不能使用@JsonProperty。舉例:

    @Test
    public void jsonCreator() throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = "{\"full_name\":\"myName\",\"age\":12}";
        TestPOJO testPOJO = objectMapper.readValue(jsonStr,TestPOJO.class);
        Assert.assertEquals("myName",testPOJO.getName());
        Assert.assertEquals(12,testPOJO.getAge());
    }
 
    public static class TestPOJO{
        private String name;
        private int age;
        @JsonCreator
        public TestPOJO(Map map){
            this.name = (String)map.get("full_name");
            this.age = (Integer)map.get("age");
        }
 
        public String getName() {
            return name;
        }
 
        public int getAge() {
            return age;
        }
    }
8、@JacksonInject
作用於屬性、方法、構造參數上,被用來反序列化時標記已經被注入的屬性,舉例:
    @Test
    public void jacksonInject() throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = "{\"age\":12}";
        InjectableValues inject = new InjectableValues.Std().addValue("name","myName");
        TestPOJO testPOJO = objectMapper.reader(TestPOJO.class).with(inject).readValue(jsonStr);
        Assert.assertEquals("myName", testPOJO.getName());
        Assert.assertEquals(12,testPOJO.getAge());
    }
 
    public static class TestPOJO{
        @JacksonInject("name")
        private String name;
        private int age;
 
        //getters、setters省略
    }
上面例子中我們在反序列化前通過InjectableValues來進行注入我們想要的屬性
9、@JsonPOJOBuilder
作用於類,用來標註如何定製構建對象,使用的是builder模式來構建,比如Value v = new ValueBuilder().withX(3).withY(4).build();這種就是builder模式來構建對象,通常會喝@JsonDeserialize.builder來配合使用,我們舉個例子:

    @Test
    public void jacksonInject() throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = "{\"name\":\"myName\",\"age\":12}";
        TestPOJO testPOJO = objectMapper.readValue(jsonStr,TestPOJO.class);
        Assert.assertEquals("myName", testPOJO.getName());
        Assert.assertEquals(12,testPOJO.getAge());
    }
 
    @JsonDeserialize(builder=TestPOJOBuilder.class)
    public static class TestPOJO{
        private String name;
        private int age;
 
        public TestPOJO(String name, int age) {
            this.name = name;
            this.age = age;
        }
 
        public String getName() {
            return name;
        }
 
        public int getAge() {
            return age;
        }
    }
 
    @JsonPOJOBuilder(buildMethodName = "create",withPrefix = "with")
    public static class TestPOJOBuilder{
        private String name;
        private int age;
 
        public TestPOJOBuilder withName(String name) {
            this.name = name;
            return this;
        }
 
        public TestPOJOBuilder withAge(int age) {
            this.age = age;
            return this;
        }
 
        public TestPOJO create() {
            return new TestPOJO(name,age);
        }
    }
在TestPOJOBuilder上有@JsonPOJOBuilder註解,表示所有的參數傳遞方法都是以with開頭,最終構建好的對象是通過create方法來獲得,而在TestPOJO上使用了@JsonDeserializer,告訴我們在反序列化的時候我們使用的是TestPOJOBuilder來構建此對象的

還有一些過期不推薦使用的註解,我們一筆帶過,主要知道他們是跟哪些其他註解功能一樣即可

@JsonGetter

作用於方法,1.0版本開始的註解,已經過期,不推薦使用,改用@JsonProperty
@JsonUseSerializer

作用於類和方法,1.5版本開始被移除了,改用@JsonSerialize

@JsonSetter
作用於方法,1.0版本開始的註解,已過期,不推薦使用,改用@JsonProperty

@JsonClass

作用於方法和類,1.9版本開始被移除了,改爲@JsonDeserialize.as

@JsonContentClass

作用於方法,1.9版本開始被移除了,改爲@JsonDeserialize.contentAs

@JsonKeyClass

作用於方法和類,1.9版本開始被移除了,改爲@JsonDeserialize.keyAs

@JsonUseDeserializer

作用於方法和類,1.5版本開始被移除了,改爲@JsonDeserialize

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章