jackson 驼峰注解_jackson - jackson annotations注解详解
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 classTestPOJO{
TestPOJO(){}
TestPOJO(String name){this.name =name;
}privateString name;
@OverridepublicString 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 = newObjectMapper();
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY,true);
一些我們比較常用的SerializationFeature配置:
SerializationFeature.WRAP_ROOT_VALUE:是否環繞根元素,默認false,如果為true,則默認以類名作為根元素,你也可以通過@JsonRootName來自定義根元素名稱
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE,true);
舉例:
@JsonRootName("myPojo")public static classTestPOJO{privateString name;publicString getName() {returnname;
}public voidsetName(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);
舉例:
@Testpublic void enumTest() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setName("myName");
testPOJO.setMyEnum(TestEnum.ENUM01);
ObjectMapper objectMapper= newObjectMapper();
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= newObjectMapper();
objectMapper2.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true);
String jsonStr2=objectMapper2.writeValueAsString(testPOJO);
Assert.assertEquals("{\"myEnum\":\"enum_01\",\"name\":\"myName\"}",jsonStr2);
ObjectMapper objectMapper3= newObjectMapper();
objectMapper3.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,true);
String jsonStr3=objectMapper3.writeValueAsString(testPOJO);
Assert.assertEquals("{\"myEnum\":0,\"name\":\"myName\"}",jsonStr3);
}public static classTestPOJO{
TestPOJO(){}privateTestEnum myEnum;privateString name;//getters、setters省略
}public static enumTestEnum{
ENUM01("enum_01"),ENUM02("enum_01"),ENUM03("enum_01");privateString title;
TestEnum(String title) {this.title =title;
}
@OverridepublicString toString() {returntitle;
}
}
SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS:序列化Map時對key進行排序操作,默認false
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true);
舉例:
@Testpublic void singleElemArraysUnwrap() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setName("myName");
List counts = new ArrayList<>();
counts.add(1);
testPOJO.setCounts(counts);
ObjectMapper objectMapper= newObjectMapper();
objectMapper.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED,false);
String jsonStr1=objectMapper.writeValueAsString(testPOJO);
Assert.assertEquals("{\"name\":\"myName\",\"counts\":[1]}",jsonStr1);
ObjectMapper objectMapper2= newObjectMapper();
objectMapper2.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED,true);
String jsonStr2=objectMapper2.writeValueAsString(testPOJO);
Assert.assertEquals("{\"name\":\"myName\",\"counts\":1}",jsonStr2);
}public static classTestPOJO{privateString name;private Listcounts;//getters、setters省略
}
SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS:序列化char[]時以json數組輸出,默認false
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS,true);
舉例:
@Testpublic void orderMapBykey() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setName("myName");
Map 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= newObjectMapper();
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= newObjectMapper();
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 classTestPOJO{privateString name;private Mapcounts;//getters、setters省略
}
SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN:序列化BigDecimal時之間輸出原始數字還是科學計數,默認false,即是否以toPlainString()科學計數方式來輸出
objectMapper.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS,true);
舉例:
@Testpublic void charArraysAsJsonArrays() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setName("myName");char[] counts = new char[]{'a','b','c','d'};
testPOJO.setCounts(counts);
ObjectMapper objectMapper= newObjectMapper();
objectMapper.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS,false);
String jsonStr1=objectMapper.writeValueAsString(testPOJO);
Assert.assertEquals("{\"name\":\"myName\",\"counts\":\"abcd\"}",jsonStr1);
ObjectMapper objectMapper2= newObjectMapper();
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 classTestPOJO{privateString name;private char[] counts;//getters、setters省略
}
更多的序列化配置參見點擊打開鏈接
反序列化的配置這里不再多做解釋,參見點擊打開鏈接
需要注意的是對于第二種通過配置SerializationConfig和DeserializationConfig方式只能啟動/禁止自動檢測,無法修改我們所需的可見級別
有時候對每個實例進行可見級別的注解可能會非常麻煩,這時候我們需要配置一個全局的可見級別,通過objectMapper.setVisibilityChecker()來實現,默認的VisibilityChecker實現類為VisibilityChecker.Std,這樣可以滿足實現復雜場景下的基礎配置。
也有一些實用簡單的可見級別配置,比如:
ObjectMapper objectMapper = newObjectMapper();
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 = newObjectMapper();
objectMapper.setVisibilityChecker(objectMapper.getVisibilityChecker().with(JsonAutoDetect.Visibility.NONE));
jackson的常用注解
看上面自動檢測,不再重復
作用在字段或方法上,用來完全忽略被注解的字段和方法對應的屬性,即便這個字段或方法可以被自動檢測到或者還有其他的注解
舉例
@Testpublic void jsonIgnoreTest() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setId(111);
testPOJO.setName("myName");
testPOJO.setCount(22);
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{private intid;
@JsonIgnoreprivateString name;private intcount;public intgetId() {returnid;
}public void setId(intid) {this.id =id;
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}public intgetCount() {returncount;
}
@JsonIgnorepublic void setCount(intcount) {this.count =count;
}
}
當@JsonIgnore不管注解在getters上還是setters上都會忽略對應的屬性
作用在字段或方法上,用來對屬性的序列化/反序列化,可以用來避免遺漏屬性,同時提供對屬性名稱重命名,比如在很多場景下Java對象的屬性是按照規范的駝峰書寫,但是實際展示的卻是類似C-style或C++/Microsolft style。
它關聯json字段到java屬性。可以標記屬性,也可以用來標記屬性的getter/setter方法。當標記屬性時,可以對屬性字段重命名。當標記方法時,可以把json字段關聯到java屬性的getter或setter方法。
舉例
@Testpublic void jsonPropertyTest() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.wahaha(111);
testPOJO.setFirstName("myName");
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{
@JsonProperty//注意這里必須得有該注解,因為沒有提供對應的getId和setId函數,而是其他的getter和setter,防止遺漏該屬性
private intid;
@JsonProperty("first_name")privateString firstName;public intwahaha() {returnid;
}public void wahaha(intid) {this.id =id;
}publicString getFirstName() {returnfirstName;
}public voidsetFirstName(String firstName) {this.firstName =firstName;
}
}
作用在類上,用來說明有些屬性在序列化/反序列化時需要忽略掉,可以將它看做是@JsonIgnore的批量操作,但它的功能比@JsonIgnore要強,比如一個類是代理類,我們無法將將@JsonIgnore標記在屬性或方法上,此時便可用@JsonIgnoreProperties標注在類聲明上,它還有一個重要的功能是作用在反序列化時解析字段時過濾一些未知的屬性,否則通常情況下解析到我們定義的類不認識的屬性便會拋出異常。
可以注明是想要忽略的屬性列表如@JsonIgnoreProperties({"name","age","title"}),
也可以注明過濾掉未知的屬性如@JsonIgnoreProperties(ignoreUnknown=true)
舉例:
@Test(expected = UnrecognizedPropertyException.class)public void JsonIgnoreProperties() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setId(111);
testPOJO.setName("myName");
testPOJO.setAge(22);
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{private intid;privateString name;private intage;//getters、setters省略
}
如果將上面的
@JsonIgnoreProperties({"name","age","title"})
更換為
@JsonIgnoreProperties(ignoreUnknown=true)
那么測試用例中在反序列化未知的count屬性時便不會拋出異常了
作用在屬性字段或方法上,用來將子JSON對象的屬性添加到封閉的JSON對象,說起來比較難懂,看個例子就很清楚了,不多解釋
舉例
@Testpublic void jsonUnwrapped() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setId(111);
TestName testName= newTestName();
testName.setFirstName("張");
testName.setSecondName("三");
testPOJO.setName(testName);
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{private intid;
@JsonUnwrappedprivateTestName name;//getters、setters省略
} public static classTestName{privateString firstName;privateString 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
2.0+版本新注解,作用于類或屬性上,被用來在序列化/反序列化時為該對象或字段添加一個對象識別碼,通常是用來解決循環嵌套的問題,比如數據庫中的多對多關系,通過配置屬性generator來確定識別碼生成的方式,有簡單的,配置屬性property來確定識別碼的名稱,識別碼名稱沒有限制。
對象識別碼可以是虛擬的,即存在在JSON中,但不是POJO的一部分,這種情況下我們可以如此使用注解
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class,property = "@id")
對象識別碼也可以是真實存在的,即以對象的屬性為識別碼,通常這種情況下我們一般以id屬性為識別碼,可以這么使用注解
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
舉例
@Testpublic void jsonIdentityInfo() throwsException {
Parent parent= newParent();
parent.setName("jack");
Child child= newChild();
child.setName("mike");
Child[] children= newChild[]{child};
parent.setChildren(children);
child.setParent(parent);
ObjectMapper objectMapper= newObjectMapper();
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 classParent{privateString name;privateChild[] children;//getters、setters省略
}public static classChild{privateString name;privateParent parent;//getters、setters省略
}
這里需要提醒一下的是在1.6版本中提供了@JsonManagedReference和@JsonBackReference來解決循環嵌套問題,因為屬于過時注解這里就不解釋了,有興趣的可以自己看
jackson 2.1+版本的注解,作用于類或方法,注意這個注解是在jackson-databind包中而不是在jackson-annotations包里,它可以讓你定制屬性命名策略,作用和前面提到的@JsonProperty的重命名屬性名稱相同。比如
你有一個JSON串{"in_reply_to_user_id":"abc123"},需要反序列化為POJO,POJO一般情況下則需要如此寫
public static classTestPOJO{privateString in_reply_to_user_id;publicString getIn_reply_to_user_id() {returnin_reply_to_user_id;
}public voidsetIn_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 classTestPOJO{
@JsonProperty("in_reply_to_user_id")privateString inReplyToUserId;publicString getInReplyToUserId() {returninReplyToUserId;
}public voidsetInReplyToUserId(String inReplyToUserId) {this.inReplyToUserId =inReplyToUserId;
}
}
這樣就符合規范了,可是如果POJO里有很多屬性,給每個屬性都要加上@JsonProperty是多么繁重的工作,這里就需要用到@JsonNaming了,它不僅能制定統一的命名規則,還能任意按自己想要的方式定制
舉例
@Testpublic void jsonNaming() throwsException{
String jsonStr= "{\"in_reply_to_user_id\":\"abc123\"}";
ObjectMapper objectMapper= newObjectMapper();
TestPOJO testPOJO= objectMapper.readValue(jsonStr,TestPOJO.class);
Assert.assertEquals("abc123",testPOJO.getInReplyToUserId());
TestPOJO testPOJO2= newTestPOJO();
testPOJO2.setInReplyToUserId("abc123");
String jsonStr2=objectMapper.writeValueAsString(testPOJO2);
Assert.assertEquals(jsonStr,jsonStr2);
}
@JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class)public static classTestPOJO{privateString inReplyToUserId;publicString getInReplyToUserId() {returninReplyToUserId;
}public voidsetInReplyToUserId(String inReplyToUserId) {this.inReplyToUserId =inReplyToUserId;
}
}
@JsonNaming使用了jackson已經實現的PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy,它可以將大寫轉換為小寫并添加下劃線。你可以自定義,必須繼承類PropertyNamingStrategy,建議繼承PropertyNamingStrategyBase,我們自己實現一個類似LowerCaseWithUnderscoresStrategy的策略,只是將下劃線改為破折號
舉例
@Testpublic void jsonNaming() throwsException{
String jsonStr= "{\"in-reply-to-user-id\":\"abc123\"}";
ObjectMapper objectMapper= newObjectMapper();
TestPOJO testPOJO= objectMapper.readValue(jsonStr,TestPOJO.class);
Assert.assertEquals("abc123", testPOJO.getInReplyToUserId());
TestPOJO testPOJO2= newTestPOJO();
testPOJO2.setInReplyToUserId("abc123");
String jsonStr2=objectMapper.writeValueAsString(testPOJO2);
Assert.assertEquals(jsonStr, jsonStr2);
}
@JsonNaming(MyPropertyNamingStrategy.class)public static classTestPOJO{privateString inReplyToUserId;publicString getInReplyToUserId() {returninReplyToUserId;
}public voidsetInReplyToUserId(String inReplyToUserId) {this.inReplyToUserId =inReplyToUserId;
}
}public static class MyPropertyNamingStrategy extendsPropertyNamingStrategy.PropertyNamingStrategyBase {
@OverridepublicString 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 = newObjectMapper();
objectMapper.setPropertyNamingStrategy(new MyPropertyNamingStrategy());
多態類型處理
jackson允許配置多態類型處理,當進行反序列話時,JSON數據匹配的對象可能有多個子類型,為了正確的讀取對象的類型,我們需要添加一些類型信息。可以通過下面幾個注解來實現:
作用于類/接口,被用來開啟多態類型處理,對基類/接口和子類/實現類都有效
@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。
作用于類/接口,用來列出給定類的子類,只有當子類類型無法被檢測到時才會使用它
一般是配合@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(value = "sub1")
value屬性作用同上面@JsonSubTypes里的name作用
作用于類,可以自定義多態的類型標識符,這個平時很少用到,主要是現有的一般就已經滿足絕大多數的需求了,如果你需要比較特別的類型標識符,建議使用這2個注解,自己定制基于TypeResolverBuilder和TypeIdResolver的類即可
我們看幾個jackson處理多態的例子
@Testpublic void jsonTypeInfo() throwsException{
Sub1 sub1= newSub1();
sub1.setId(1);
sub1.setName("sub1Name");
Sub2 sub2= newSub2();
sub2.setId(2);
sub2.setAge(33);
ObjectMapper objectMapper= newObjectMapper();
TestPOJO testPOJO= newTestPOJO();
testPOJO.setMyIns(newMyIn[]{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 classMyIn{private intid;//getters、setters省略
}public static class Sub1 extendsMyIn{privateString name;//getters、setters省略
}public static class Sub2 extendsMyIn{private intage;//getters、setters省略
}
這是序列化時最簡單的一種多態處理方式,因為沒有使用任何多態處理注解,即默認使用的識別碼類型為JsonTypeInfo.Id.NONE,而jackson沒有自動搜索功能,所以只能序列化而不能反序列化,上面序列化測試的結果為{"myIns":[{"id":1,"name":"sub1Name"},{"id":2,"age":33}]},我們可以看到JSON串中是沒有對應的多態類型識別碼的。
下面我們在基類MyIn上加上多態處理相關注解,首先我們在基類MyIn上添加@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)即
執行上面的序列化測試代碼結果將會是
{"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 classMyIn{private intid;//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 classMyIn{private intid;//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 classMyIn{private intid;//getters、setters省略
}
測試序列化結果為
{"myIns":[{"typeName":".JacksonUtilsTest$Sub1","id":1,"name":"sub1Name"},{"typeName":".JacksonUtilsTest$Sub2","id":2,"age":33}]}
發現已經沒有同包的package名稱,識別碼的值更加簡短了
測試反序列化
@Testpublic void jsonTypeInfo() throwsException{
ObjectMapper objectMapper= newObjectMapper();
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 classMyIn{private intid;//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 = newObjectMapper();
objectMapper.registerSubtypes(new NamedType(Sub1.class,"sub1"));
objectMapper.registerSubtypes(new NamedType(Sub2.class,"sub2"));
更多多態處理的例子還請大家自己研究
用于序列化和反序列化的注解類
作用于方法和字段上,通過 using(JsonSerializer)和using(JsonDeserializer)來指定序列化和反序列化的實現,通常我們在需要自定義序列化和反序列化時會用到,比如下面的例子中的日期轉換
@Testpublic void jsonSerializeAndDeSerialize() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setName("myName");
testPOJO.setBirthday(newDate());
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{privateString name;
@JsonSerialize(using= MyDateSerializer.class)
@JsonDeserialize(using= MyDateDeserializer.class)privateDate birthday;//getters、setters省略
@OverridepublicString toString() {return "TestPOJO{" +
"name='" + name + '\'' +
", birthday=" + birthday +
'}';
}
}private static class MyDateSerializer extends JsonSerializer{
@Overridepublic void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throwsIOException, 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{
@Overridepublic Date deserialize(JsonParser jp, DeserializationContext ctxt) throwsIOException, JsonProcessingException {
String value=jp.getValueAsString();
DateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");try{returndateFormat.parse(value);
}catch(ParseException e) {
e.printStackTrace();
}return null;
}
}
上面的例子中自定義了日期的序列化和反序列化方式,可以將Date和指定日期格式字符串之間相互轉換。
也可以通過使用as(JsonSerializer)和as(JsonDeserializer)來實現多態類型轉換,上面我們有提到多態類型處理時可以使用@JsonTypeInfo實現,還有一種比較簡便的方式就是使用@JsonSerialize和@JsonDeserialize指定as的子類類型,注意這里必須指定為子類類型才可以實現替換運行時的類型
@Testpublic void jsonSerializeAndDeSerialize() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setName("myName");
Sub1 sub1= newSub1();
sub1.setId(1);
sub1.setName("sub1Name");
Sub2 sub2= newSub2();
sub2.setId(2);
sub2.setAge(22);
testPOJO.setSub1(sub1);
testPOJO.setSub2(sub2);
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{privateString name;
@JsonSerialize(as= Sub1.class)
@JsonDeserialize(as= Sub1.class)privateMyIn sub1;
@JsonSerialize(as= Sub2.class)
@JsonDeserialize(as= Sub2.class)privateMyIn sub2;//getters、setters省略
@OverridepublicString toString() {return "TestPOJO{" +
"name='" + name + '\'' +
", sub1=" + sub1 +
", sub2=" + sub2 +
'}';
}
}public static classMyIn{private intid;//getters、setters省略
}public static class Sub1 extendsMyIn{privateString name;//getters、setters省略
@OverridepublicString toString() {return "Sub1{" +
"id=" + getId() +
"name='" + name + '\'' +
'}';
}
}public static class Sub2 extendsMyIn{private intage;//getters、setters省略
@OverridepublicString toString() {return "Sub1{" +
"id=" + getId() +
"age='" + age +
'}';
}
}
上面例子中通過as來指定了需要替換實際運行時類型的子類,實際上上面例子中序列化時是可以不使用@JsonSerialize(as = Sub1.class)的,因為jackson可以自動將POJO轉換為對應的JSON,而反序列化時由于無法自動檢索匹配類型必須要指定@JsonDeserialize(as = Sub1.class)方可實現
最后@JsonSerialize可以配置include屬性來指定序列化時被注解的屬性被包含的方式,默認總是被包含進來,但是可以過濾掉空的屬性或有默認值的屬性,舉個簡單的過濾空屬性的例子如下
@Testpublic void jsonSerializeAndDeSerialize() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setName("");
ObjectMapper objectMapper= newObjectMapper();
String jsonStr=objectMapper.writeValueAsString(testPOJO);
Assert.assertEquals("{}",jsonStr);
}public static classTestPOJO{
@JsonSerialize(include=JsonSerialize.Inclusion.NON_EMPTY)privateString name;//getters、setters省略
}
作用在類上,被用來指明當序列化時需要對屬性做排序,它有2個屬性
一個是alphabetic:布爾類型,表示是否采用字母拼音順序排序,默認是為false,即不排序
@Testpublic void jsonPropertyOrder() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setA("1");
testPOJO.setB("2");
testPOJO.setC("3");
testPOJO.setD("4");
ObjectMapper objectMapper= newObjectMapper();
String jsonStr=objectMapper.writeValueAsString(testPOJO);
Assert.assertEquals("{\"a\":\"1\",\"c\":\"3\",\"d\":\"4\",\"b\":\"2\"}",jsonStr);
}public static classTestPOJO{privateString a;privateString c;privateString d;privateString b;//getters、setters省略
}
我們先看一個默認的排序方式,序列化單元測試結果依次為{"a":"1","c":"3","d":"4","b":"2"},即是沒有經過排序操作的,在TestPOJO上加上@jsonPropertyOrder(alphabetic = true)再執行測試結果將會為{"a":"1","b":"2","c":"3","d":"4"}
還有一個屬性是value:數組類型,表示將優先其他屬性排序的屬性名稱
@Testpublic void jsonPropertyOrder() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setA("1");
testPOJO.setB("2");
testPOJO.setC("3");
testPOJO.setD("4");
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{privateString a;privateString c;privateString d;privateString b;//getters、setters省略
}
還記得本文上面最開始配置MapperFeature時也有屬性排序么,對,就是
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY,true);
只不過@JsonPropertyOrder顆粒度要更細一點,可以決定哪些屬性優先排序
視圖模板,作用于方法和屬性上,用來指定哪些屬性可以被包含在JSON視圖中,在前面我們知道已經有@JsonIgnore和@JsonIgnoreProperties可以排除過濾掉不需要序列化的屬性,可是如果一個POJO中有上百個屬性,比如訂單類、商品詳情類這種屬性超多,而我們可能只需要概要簡單信息即序列化時只想輸出其中幾個或10幾個屬性,此時使用@JsonIgnore和@JsonIgnoreProperties就顯得非常繁瑣,而使用@JsonView便會非常方便,只許在你想要輸出的屬性(或對應的getter)上添加@JsonView即可,舉例:
@Testpublic void jsonView() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setA("1");
testPOJO.setB("2");
testPOJO.setC("3");
testPOJO.setD("4");
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{
@JsonView(FilterView.OutputA.class)privateString a;
@JsonView(FilterView.OutputA.class)privateString c;
@JsonView(FilterView.OutputB.class)privateString d;
@JsonView(FilterView.OutputB.class)privateString b;//getters、setters忽略
}private static classFilterView {static classOutputA {}static classOutputB {}
}
上面的測試用例中,我們在序列化之前先設置了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可以不需要也能輸出我們想要的結果。
Json屬性過濾器,作用于類,作用同上面的@JsonView,都是過濾掉不想要的屬性,輸出自己想要的屬性。和@FilterView不同的是@JsonFilter可以動態的過濾屬性,比如我不想輸出以system開頭的所有屬性等待,應該說@JsonFilter更高級一點,舉個簡單的例子
@Testpublic void jsonFilter() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setA("1");
testPOJO.setB("2");
testPOJO.setC("3");
testPOJO.setD("4");
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{privateString a;privateString c;privateString d;privateString b;//getters、setters省略
}
上面例子中在我們想要序列化的POJO上加上了@JsonFilter,表示該類將使用名為myFilter的過濾器。在測試中定義了一個名為myFilter的SimpleFilterProvider,這個過濾器將會過濾掉所有除a屬性以外的屬性。這只是最簡單的輸出指定元素的例子,你可以自己實現FilterProvider來滿足你的過濾需求。
有時候我們可能需要根據現有的POJO來過濾屬性,而這種情況下通常不會讓你修改已有的代碼在POJO上加注解,這種情況下我們就可以結合@JsonFilter和MixInAnnotations來實現過濾屬性,如下例所示,不再多做解釋
@Testpublic void jsonFilter() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setA("1");
testPOJO.setB("2");
testPOJO.setC("3");
testPOJO.setD("4");
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{privateString a;privateString c;privateString d;privateString b;//getters、setters省略
}
@JsonFilter("myFilter")private static interfaceMyFilterMixIn{
}
作用于類,表示被注解該類型的屬性將不會被序列化和反序列化,也跟上面幾個一樣屬于過濾屬性功能的注解,舉例:
@Testpublic void jsonFilter() throwsException {
TestPOJO testPOJO= newTestPOJO();
testPOJO.setName("myName");
Sub1 sub1= newSub1();
sub1.setId(1);
sub1.setName("sub1");
Sub2 sub2= newSub2();
sub2.setId(2);
sub2.setAge(22);
testPOJO.setMyIn(sub1);
testPOJO.setSub1(sub1);
testPOJO.setSub2(sub2);
ObjectMapper objectMapper= newObjectMapper();
String jsonStr=objectMapper.writeValueAsString(testPOJO);
System.out.println(jsonStr);
}public static classTestPOJO{privateSub1 sub1;privateSub2 sub2;privateMyIn myIn;privateString name;//getters、setters省略
}public static classMyIn{private intid;//getters、setters省略
}
@JsonIgnoreTypepublic static class Sub1 extendsMyIn{privateString name;//getters、setters省略
}
@JsonIgnoreTypepublic static class Sub2 extendsMyIn{private intage;//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"}
作用于方法,在反序列化時用來處理遇到未知的屬性的時候調用,在本文前面我們知道可以通過注解@JsonIgnoreProperties(ignoreUnknown=true)來過濾未知的屬性,但是如果需要這些未知的屬性該如何是好?那么@JsonAnySetter就可以派上用場了,它通常會和map屬性配合使用用來保存未知的屬性,舉例:
@Testpublic void jsonAnySetter() throwsException {
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{privateString name;private Map other = newHashMap();
@JsonAnySetterpublic voidset(String name,Object value) {
other.put(name,value);
}//getters、setters省略
}
測試用例中我們在set方法上標注了@JsonAnySetter,每當遇到未知的屬性時都會調用該方法
json反序列化為java對象時,該注解用于定義構造函數。當從json創建java時,@JsonCreator注解的構造函數被會調用,如果沒有@JsonCreator注解,則默認調用java類的無參構造函數,此時,如果java類中只有有參構造函數,而無默認的無參構造函數,在反序列化時會拋出這樣的異常:com.fasterxml.jackson.databind.JsonMappingException,所以,當我們不使用@JsonCreator指定反序列化的構造函數,而又在java類中重載了構造函數時,一定要記得編寫類的無參構造函數。
作用于方法,通常用來標注構造方法或靜態工廠方法上,使用該方法來構建實例,默認的是使用無參的構造方法,通常是和@JsonProperty或@JacksonInject配合使用,舉例
@Testpublic void jsonCreator() throwsException {
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{privateString name;private intage;
@JsonCreatorpublic TestPOJO(@JsonProperty("full_name") String name,@JsonProperty("age") intage){this.name =name;this.age =age;
}publicString getName() {returnname;
}public intgetAge() {returnage;
}
}
上面示例中是在構造方法上標注了@JsonCreator,同樣你也可以標注在靜態工廠方法上,比如:
@Testpublic void jsonCreator() throwsException {
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{privateString name;privateDate birthday;privateTestPOJO(String name,Date birthday){this.name =name;this.birthday =birthday;
}
@JsonCreatorpublic static TestPOJO getInstance(@JsonProperty("name") String name,@JsonProperty("birthday") longtimestamp){
Date date= newDate(timestamp);return newTestPOJO(name,date);
}publicString getName() {returnname;
}publicDate getBirthday() {returnbirthday;
}
}
這個實例中,TestPOJO的構造方法是私有的,外面無法new出來該對象,只能通過工廠方法getInstance來構造實例,此時@JsonCreator就標注在工廠方法上。
除了這2種方式外,還有一種構造方式成為授權式構造器,也是我們平常比較常用到的,這個構造器只有一個參數,且不能使用@JsonProperty。舉例:
@Testpublic void jsonCreator() throwsException {
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{privateString name;private intage;
@JsonCreatorpublicTestPOJO(Map map){this.name = (String)map.get("full_name");this.age = (Integer)map.get("age");
}publicString getName() {returnname;
}public intgetAge() {returnage;
}
}
作用于屬性、方法、構造參數上,被用來反序列化時標記已經被注入的屬性,舉例:
@Testpublic void jacksonInject() throwsException {
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{
@JacksonInject("name")privateString name;private intage;//getters、setters省略
}
上面例子中我們在反序列化前通過InjectableValues來進行注入我們想要的屬性
作用于類,用來標注如何定制構建對象,使用的是builder模式來構建,比如Value v = new ValueBuilder().withX(3).withY(4).build();這種就是builder模式來構建對象,通常會喝@JsonDeserialize.builder來配合使用,我們舉個例子:
@Testpublic void jacksonInject() throwsException {
ObjectMapper objectMapper= newObjectMapper();
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 classTestPOJO{privateString name;private intage;public TestPOJO(String name, intage) {this.name =name;this.age =age;
}publicString getName() {returnname;
}public intgetAge() {returnage;
}
}
@JsonPOJOBuilder(buildMethodName= "create",withPrefix = "with")public static classTestPOJOBuilder{privateString name;private intage;publicTestPOJOBuilder withName(String name) {this.name =name;return this;
}public TestPOJOBuilder withAge(intage) {this.age =age;return this;
}publicTestPOJO create() {return newTestPOJO(name,age);
}
}
在TestPOJOBuilder上有@JsonPOJOBuilder注解,表示所有的參數傳遞方法都是以with開頭,最終構建好的對象是通過create方法來獲得,而在TestPOJO上使用了@JsonDeserializer,告訴我們在反序列化的時候我們使用的是TestPOJOBuilder來構建此對象的
還有一些過期不推薦使用的注解,我們一筆帶過,主要知道他們是跟哪些其他注解功能一樣即可
作用于方法,1.0版本開始的注解,已經過期,不推薦使用,改用@JsonProperty
@JsonUseSerializer
作用于類和方法,1.5版本開始被移除了,改用@JsonSerialize
@JsonSetter
作用于方法,1.0版本開始的注解,已過期,不推薦使用,改用@JsonProperty
作用于方法和類,1.9版本開始被移除了,改為@JsonDeserialize.as
作用于方法,1.9版本開始被移除了,改為@JsonDeserialize.contentAs
作用于方法和類,1.9版本開始被移除了,改為@JsonDeserialize.keyAs
作用于方法和類,1.5版本開始被移除了,改為@JsonDeserialize
轉:https://blog.csdn.net/sdyy321/article/details/40298081
總結
以上是生活随笔為你收集整理的jackson 驼峰注解_jackson - jackson annotations注解详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: unet 层_UNet解释及Python
- 下一篇: jupyter代码字体大小_Jupyte