jackson annotations註解詳解

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

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

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

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

 

jackson的自動檢測機制

jackson容許使用任意的構造方法或工廠方法來構造實例github

使用@JsonAutoDetect(做用在類上)來開啓/禁止自動檢測

fieldVisibility:字段的可見級別sql

ANY:任何級別的字段均可以自動識別數據庫

NONE:全部字段都不能夠自動識別json

NON_PRIVATE:非private修飾的字段能夠自動識別數組

PROTECTED_AND_PUBLIC:被protected和public修飾的字段能夠被自動識別app

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的經常使用註解

 

一、@JsonAutoDetect

看上面自動檢測,再也不重複

二、@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上都會忽略對應的屬性

三、@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;  
    }  
}

四、@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屬性時便不會拋出異常了

五、@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

 

六、@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來解決循環嵌套問題,由於屬於過期註解這裏就不解釋了,有興趣的能夠本身看

七、@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:定義使用哪種類型識別碼,它有下面幾個可選值:

一、JsonTypeInfo.Id.CLASS:使用徹底限定類名作識別

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

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

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

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

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

一、JsonTypeInfo.As.PROPERTY:做爲數據的兄弟屬性

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

三、JsonTypeInfo.As.EXTERNAL_PROPERTY:做爲擴展屬性

四、JsonTypeInfo.As.WRAPPER_OBJECT:做爲一個包裝的對象

五、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":[{"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"));

更多多態處理的例子還請你們本身研究

 

 

用於序列化和反序列化的註解類

一、@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省略  
}

二、@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顆粒度要更細一點,能夠決定哪些屬性優先排序

 

 

三、@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能夠不須要也能輸出咱們想要的結果。

 

四、@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{  
}

五、@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、Sub一、Sub2。輸出結果爲{"name":"myName"}

 

六、@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,每當遇到未知的屬性時都會調用該方法

七、@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;  
    }  
}

八、@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來進行注入咱們想要的屬性

九、@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

相關文章
相關標籤/搜索