1. 概述
在本文中,我們將深入研究Jackson注解。
我們將看到如何使用現有的注釋,如何創建自定義的注釋,最后—如何禁用它們。
2. Jackson序列化注解
首先,我們將查看序列化注釋。
2.1. @JsonAnyGetter
@JsonAnyGetter注釋允許靈活地使用映射字段作為標準屬性。
下面是一個快速的例子——ExtendableBean實體擁有name屬性和一組可擴展屬性,它們以鍵/值對的形式存在:
public class ExtendableBean {
public String name;
private Map<String, String> properties;
@JsonAnyGetter
public Map<String, String> getProperties() {
return properties;
}
}
當我們序列化這個實體的一個實例時,我們會得到Map中所有的鍵值作為標準的普通屬性:
{
"name":"My bean",
"attr2":"val2",
"attr1":"val1"
}
這里是如何序列化這個實體看起來像在實踐:
@Test
public void whenSerializingUsingJsonAnyGetter_thenCorrect()
throws JsonProcessingException {
ExtendableBean bean = new ExtendableBean("My bean");
bean.add("attr1", "val1");
bean.add("attr2", "val2");
String result = new ObjectMApper().writeValueAsString(bean);
assertThat(result, containsString("attr1"));
assertThat(result, containsString("val1"));
}
我們還可以使用可選參數enabled為false來禁用@JsonAnyGetter()。在本例中,映射將被轉換為JSON,并在序列化之后出現在properties變量下。
2.2. @JsonGetter
@JsonGetter注釋是@JsonProperty注釋的替代品,它將方法標記為getter方法。
在下面的例子中-我們指定getTheName()方法作為MyBean實體的name屬性的getter方法:
public class MyBean {
public int id;
private String name;
@JsonGetter("name")
public String getTheName() {
return name;
}
}
這是如何在實踐中運作的:
@Test
public void whenSerializingUsingJsonGetter_thenCorrect()
throws JsonProcessingException {
MyBean bean = new MyBean(1, "My bean");
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, containsString("1"));
}
2.3. @JsonPropertyOrder
我們可以使用@JsonPropertyOrder注釋來指定序列化時屬性的順序。
讓我們為MyBean實體的屬性設置一個自定義順序:
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
public int id;
public String name;
}
這是序列化的輸出:
{
"name":"My bean",
"id":1
}
還有一個簡單的測試:
@Test
public void whenSerializingUsingJsonPropertyOrder_thenCorrect()
throws JsonProcessingException {
MyBean bean = new MyBean(1, "My bean");
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, containsString("1"));
}
我們還可以使用@JsonPropertyOrder(alphabetic=true)按字母順序排列屬性。在這種情況下,序列化的輸出將是:
{
"id":1,
"name":"My bean"
}
2.4. @JsonRawValue
@JsonRawValue注釋可以指示Jackson按原樣序列化屬性。
在下面的例子中,我們使用@JsonRawValue嵌入一些定制的JSON作為一個實體的值:
public class RawBean {
public String name;
@JsonRawValue
public String json;
}
序列化實體的輸出為:
{
"name":"My bean",
"json":{
"attr":false
}
}
還有一個簡單的測試:
@Test
public void whenSerializingUsingJsonRawValue_thenCorrect()
throws JsonProcessingException {
RawBean bean = new RawBean("My bean", "{"attr":false}");
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, containsString("{"attr":false}"));
}
我們還可以使用可選的布爾參數值來定義這個注釋是否是活動的。
2.5. @JsonValue
@JsonValue表示庫將使用一個方法來序列化整個實例。
例如,在枚舉中,我們用@JsonValue注釋getName,這樣任何這樣的實體都可以通過其名稱序列化:
public enum TypeEnumWithValue {
TYPE1(1, "Type A"), TYPE2(2, "Type 2");
private Integer id;
private String name;
// standard constructors
@JsonValue
public String getName() {
return name;
}
}
我們的測試:
@Test
public void whenSerializingUsingJsonValue_thenCorrect()
throws JsonParseException, IOException {
String enumAsString = new ObjectMapper()
.writeValueAsString(TypeEnumWithValue.TYPE1);
assertThat(enumAsString, is(""Type A""));
}
2.6. @JsonRootName
如果啟用了包裝,則使用@JsonRootName注釋來指定要使用的根包裝器的名稱。
包裝意味著不將用戶序列化為以下內容:
它會像這樣包裝:
{
"User": {
"id": 1,
"name": "John"
}
}
那么,讓我們來看一個例子——我們將使用@JsonRootName注釋來表示這個潛在的包裝實體的名稱:
@JsonRootName(value = "user")
public class UserWithRoot {
public int id;
public String name;
}
默認情況下,包裝器的名稱將是類的名稱- UserWithRoot。通過使用注釋,我們得到了看起來更干凈的用戶:
@Test
public void whenSerializingUsingJsonRootName_thenCorrect()
throws JsonProcessingException {
UserWithRoot user = new User(1, "John");
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
String result = mapper.writeValueAsString(user);
assertThat(result, containsString("John"));
assertThat(result, containsString("user"));
}
這是序列化的輸出:
{
"user":{
"id":1,
"name":"John"
}
}
自Jackson 2.4以來,一個新的可選參數名稱空間可用于XML等數據格式。如果我們添加它,它將成為完全限定名的一部分:
@JsonRootName(value = "user", namespace="users")
public class UserWithRootNamespace {
public int id;
public String name;
// ...
}
如果我們用XmlMapper序列化它,輸出將是:
<user xmlns="users">
<id xmlns="">1</id>
<name xmlns="">John</name>
<items xmlns=""/>
</user>
2.7. @JsonSerialize
讓我們看一個簡單的例子。我們將使用@JsonSerialize用CustomDateSerializer來序列化eventDate屬性:
public class EventWithSerializer {
public String name;
@JsonSerialize(using = CustomDateSerializer.class)
public Date eventDate;
}
下面是簡單的自定義Jackson序列化器:
public class CustomDateSerializer extends StdSerializer<Date> {
private static SimpleDateFormat formatter
= new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
public CustomDateSerializer() {
this(null);
}
public CustomDateSerializer(Class<Date> t) {
super(t);
}
@Override
public void serialize(
Date value, JsonGenerator gen, SerializerProvider arg2)
throws IOException, JsonProcessingException {
gen.writeString(formatter.format(value));
}
}
讓我們在測試中使用這些:
@Test
public void whenSerializingUsingJsonSerialize_thenCorrect()
throws JsonProcessingException, ParseException {
SimpleDateFormat df
= new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
String toParse = "20-12-2014 02:30:00";
Date date = df.parse(toParse);
EventWithSerializer event = new EventWithSerializer("party", date);
String result = new ObjectMapper().writeValueAsString(event);
assertThat(result, containsString(toParse));
}
Jackson反序列化注解
接下來——讓我們研究Jackson反序列化注解。
3.1. @JsonCreator
我們可以使用@JsonCreator注釋來調優反序列化中使用的構造器/工廠。
當我們需要反序列化一些與我們需要獲取的目標實體不完全匹配的JSON時,它非常有用。
我們來看一個例子;說我們需要反序列化以下JSON:
{
"id":1,
"theName":"My bean"
}
但是,在我們的目標實體中沒有theName字段—只有name字段。現在,我們不想改變實體本身—我們只需要對數據編出過程進行更多的控制—通過使用@JsonCreator和@JsonProperty注釋來注釋構造函數:
public class BeanWithCreator {
public int id;
public String name;
@JsonCreator
public BeanWithCreator(
@JsonProperty("id") int id,
@JsonProperty("theName") String name) {
this.id = id;
this.name = name;
}
}
讓我們來看看這是怎么回事:
@Test
public void whenDeserializingUsingJsonCreator_thenCorrect()
throws IOException {
String json = "{"id":1,"theName":"My bean"}";
BeanWithCreator bean = new ObjectMapper()
.readerFor(BeanWithCreator.class)
.readValue(json);
assertEquals("My bean", bean.name);
}
3.2. @JacksonInject
@JacksonInject表示屬性將從注入中獲得其值,而不是從JSON數據中。
在下面的例子中,我們使用@JacksonInject注入屬性id:
public class BeanWithInject {
@JacksonInject
public int id;
public String name;
}
它是這樣工作的:
@Test
public void whenDeserializingUsingJsonInject_thenCorrect()
throws IOException {
String json = "{"name":"My bean"}";
InjectableValues inject = new InjectableValues.Std()
.addValue(int.class, 1);
BeanWithInject bean = new ObjectMapper().reader(inject)
.forType(BeanWithInject.class)
.readValue(json);
assertEquals("My bean", bean.name);
assertEquals(1, bean.id);
}
3.3. @JsonAnySetter
@JsonAnySetter允許我們靈活地使用映射作為標準屬性。在反序列化時,JSON的屬性將被添加到映射中。
讓我們看看這是如何工作的-我們將使用@JsonAnySetter來反序列化實體ExtendableBean:
public class ExtendableBean {
public String name;
private Map<String, String> properties;
@JsonAnySetter
public void add(String key, String value) {
properties.put(key, value);
}
}
這是我們需要反序列化的JSON:
{
"name":"My bean",
"attr2":"val2",
"attr1":"val1"
}
而這一切是如何聯系在一起的:
@Test
public void whenDeserializingUsingJsonAnySetter_thenCorrect()
throws IOException {
String json
= "{"name":"My bean","attr2":"val2","attr1":"val1"}";
ExtendableBean bean = new ObjectMapper()
.readerFor(ExtendableBean.class)
.readValue(json);
assertEquals("My bean", bean.name);
assertEquals("val2", bean.getProperties().get("attr2"));
}
3.4. @JsonSetter
@JsonSetter是@JsonProperty的替代方法—它將方法標記為setter方法。
當我們需要讀取一些JSON數據,但目標實體類與該數據不完全匹配時,這非常有用,因此我們需要調優流程以使其適合該數據。
在下面的例子中,我們將指定方法setTheName()作為MyBean實體中name屬性的setter:
public class MyBean {
public int id;
private String name;
@JsonSetter("name")
public void setTheName(String name) {
this.name = name;
}
}
現在,當我們需要unmarshall一些JSON數據-這是完美的工作:
@Test
public void whenDeserializingUsingJsonSetter_thenCorrect()
throws IOException {
String json = "{"id":1,"name":"My bean"}";
MyBean bean = new ObjectMapper()
.readerFor(MyBean.class)
.readValue(json);
assertEquals("My bean", bean.getTheName());
}
3.5. @JsonDeserialize
@JsonDeserialize表示使用自定義反序列化器。
讓我們看看這是如何實現的-我們將使用@JsonDeserialize來反序列化eventDate屬性與CustomDateDeserializer:
public class EventWithSerializer {
public String name;
@JsonDeserialize(using = CustomDateDeserializer.class)
public Date eventDate;
}
這是自定義反序列化器:
public class CustomDateDeserializer
extends StdDeserializer<Date> {
private static SimpleDateFormat formatter
= new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
public CustomDateDeserializer() {
this(null);
}
public CustomDateDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Date deserialize(
JsonParser jsonparser, DeserializationContext context)
throws IOException {
String date = jsonparser.getText();
try {
return formatter.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
這是背靠背的測試:
@Test
public void whenDeserializingUsingJsonDeserialize_thenCorrect()
throws IOException {
String json
= "{"name":"party","eventDate":"20-12-2014 02:30:00"}";
SimpleDateFormat df
= new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
EventWithSerializer event = new ObjectMapper()
.readerFor(EventWithSerializer.class)
.readValue(json);
assertEquals(
"20-12-2014 02:30:00", df.format(event.eventDate));
}
3.6 @JsonAlias
@JsonAlias在反序列化期間為屬性定義一個或多個替代名稱。
讓我們通過一個簡單的例子來看看這個注釋是如何工作的:
public class AliasBean {
@JsonAlias({ "fName", "f_name" })
private String firstName;
private String lastName;
}
在這里,我們有一個POJO,我們想用fName、f_name和firstName等值反序列化JSON到POJO的firstName變量中。
這里有一個測試,確保這個注釋像expecte一樣工作:
@Test
public void whenDeserializingUsingJsonAlias_thenCorrect() throws IOException {
String json = "{"fName": "John", "lastName": "Green"}";
AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json);
assertEquals("John", aliasBean.getFirstName());
}
4. Jackson屬性包含注釋
4.1. @JsonIgnoreProperties
@JsonIgnoreProperties是一個類級注釋,它標記Jackson將忽略的一個屬性或一列屬性。
讓我們來看一個忽略屬性id的例子:
@JsonIgnoreProperties({ "id" })
public class BeanWithIgnore {
public int id;
public String name;
}
下面是確保忽略發生的測試:
@Test
public void whenSerializingUsingJsonIgnoreProperties_thenCorrect()
throws JsonProcessingException {
BeanWithIgnore bean = new BeanWithIgnore(1, "My bean");
String result = new ObjectMapper()
.writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, not(containsString("id")));
}
為了毫無例外地忽略JSON輸入中的任何未知屬性,我們可以對@JsonIgnoreProperties注釋設置ignoreUnknown=true。
4.2. @JsonIgnore
@JsonIgnore注釋用于在字段級別標記要忽略的屬性。
讓我們使用@JsonIgnore來忽略序列化中的屬性id:
public class BeanWithIgnore {
@JsonIgnore
public int id;
public String name;
}
確保id被成功忽略的測試:
@Test
public void whenSerializingUsingJsonIgnore_thenCorrect()
throws JsonProcessingException {
BeanWithIgnore bean = new BeanWithIgnore(1, "My bean");
String result = new ObjectMapper()
.writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, not(containsString("id")));
}
4.3. @JsonIgnoreType
@JsonIgnoreType將注釋類型的所有屬性標記為忽略。
讓我們使用注釋來標記所有類型名稱的屬性被忽略:
public class User {
public int id;
public Name name;
@JsonIgnoreType
public static class Name {
public String firstName;
public String lastName;
}
}
這里有一個簡單的測試,確保忽略工作正確:
@Test
public void whenSerializingUsingJsonIgnoreType_thenCorrect()
throws JsonProcessingException, ParseException {
User.Name name = new User.Name("John", "Doe");
User user = new User(1, name);
String result = new ObjectMapper()
.writeValueAsString(user);
assertThat(result, containsString("1"));
assertThat(result, not(containsString("name")));
assertThat(result, not(containsString("John")));
}
4.4. @JsonInclude
我們可以使用@JsonInclude來排除具有空/空/默認值的屬性。
讓我們看一個例子-排除null從序列化:
@JsonInclude(Include.NON_NULL)
public class MyBean {
public int id;
public String name;
}
下面是完整的測試:
public void whenSerializingUsingJsonInclude_thenCorrect()
throws JsonProcessingException {
MyBean bean = new MyBean(1, null);
String result = new ObjectMapper()
.writeValueAsString(bean);
assertThat(result, containsString("1"));
assertThat(result, not(containsString("name")));
}
4.5. @JsonAutoDetect
@JsonAutoDetect可以覆蓋哪些屬性可見,哪些不可見的默認語義。
讓我們通過一個簡單的例子來看看這個注釋是如何非常有用的——讓我們啟用序列化私有屬性:
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class PrivateBean {
private int id;
private String name;
}
測試:
@Test
public void whenSerializingUsingJsonAutoDetect_thenCorrect()
throws JsonProcessingException {
PrivateBean bean = new PrivateBean(1, "My bean");
String result = new ObjectMapper()
.writeValueAsString(bean);
assertThat(result, containsString("1"));
assertThat(result, containsString("My bean"));
}
5. Jackson多態類型處理注釋
接下來,讓我們看看Jackson多態類型處理注釋:
- @JsonTypeInfo——指示要在序列化中包含什么類型信息的詳細信息
- @JsonSubTypes——指示注釋類型的子類型
- @JsonTypeName—定義了一個用于注釋類的邏輯類型名
讓我們看一個更復雜的例子,使用所有這三個——@JsonTypeInfo, @JsonSubTypes,和@JsonTypeName——來序列化/反序列化實體Zoo:
public class Zoo {
public Animal animal;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public static class Animal {
public String name;
}
@JsonTypeName("dog")
public static class Dog extends Animal {
public double barkVolume;
}
@JsonTypeName("cat")
public static class Cat extends Animal {
boolean likesCream;
public int lives;
}
}
當我們進行序列化時:
@Test
public void whenSerializingPolymorphic_thenCorrect()
throws JsonProcessingException {
Zoo.Dog dog = new Zoo.Dog("lacy");
Zoo zoo = new Zoo(dog);
String result = new ObjectMapper()
.writeValueAsString(zoo);
assertThat(result, containsString("type"));
assertThat(result, containsString("dog"));
}
下面是將動物園實例與狗序列化將得到的結果:
{
"animal": {
"type": "dog",
"name": "lacy",
"barkVolume": 0
}
}
現在反序列化-讓我們從以下JSON輸入開始:
{
"animal":{
"name":"lacy",
"type":"cat"
}
}
讓我們看看它是如何被分解到一個動物園實例的:
@Test
public void whenDeserializingPolymorphic_thenCorrect()
throws IOException {
String json = "{"animal":{"name":"lacy","type":"cat"}}";
Zoo zoo = new ObjectMapper()
.readerFor(Zoo.class)
.readValue(json);
assertEquals("lacy", zoo.animal.name);
assertEquals(Zoo.Cat.class, zoo.animal.getClass());
}
6. Jackson通用注解
接下來——讓我們討論Jackson的一些更通用的注釋。
6.1. @JsonProperty
我們可以添加@JsonProperty注釋來表示JSON中的屬性名。
當我們處理非標準的getter和setter時,讓我們使用@JsonProperty來序列化/反序列化屬性名:
public class MyBean {
public int id;
private String name;
@JsonProperty("name")
public void setTheName(String name) {
this.name = name;
}
@JsonProperty("name")
public String getTheName() {
return name;
}
}
我們的測試:
@Test
public void whenUsingJsonProperty_thenCorrect()
throws IOException {
MyBean bean = new MyBean(1, "My bean");
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, containsString("1"));
MyBean resultBean = new ObjectMapper()
.readerFor(MyBean.class)
.readValue(result);
assertEquals("My bean", resultBean.getTheName());
}
6.2. @JsonFormat
@JsonFormat注釋在序列化日期/時間值時指定一種格式。
在下面的例子中,我們使用@JsonFormat來控制屬性eventDate的格式:
public class EventWithFormat {
public String name;
@JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "dd-MM-yyyy hh:mm:ss")
public Date eventDate;
}
下面是測試:
@Test
public void whenSerializingUsingJsonFormat_thenCorrect()
throws JsonProcessingException, ParseException {
SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
String toParse = "20-12-2014 02:30:00";
Date date = df.parse(toParse);
EventWithFormat event = new EventWithFormat("party", date);
String result = new ObjectMapper().writeValueAsString(event);
assertThat(result, containsString(toParse));
}
6.3. @JsonUnwrapped
@JsonUnwrapped定義了在序列化/反序列化時應該被解包裝/扁平化的值。
我們來看看它是如何工作的;我們將使用注釋來展開屬性名:
public class UnwrappedUser {
public int id;
@JsonUnwrapped
public Name name;
public static class Name {
public String firstName;
public String lastName;
}
}
現在讓我們序列化這個類的一個實例:
@Test
public void whenSerializingUsingJsonUnwrapped_thenCorrect()
throws JsonProcessingException, ParseException {
UnwrappedUser.Name name = new UnwrappedUser.Name("John", "Doe");
UnwrappedUser user = new UnwrappedUser(1, name);
String result = new ObjectMapper().writeValueAsString(user);
assertThat(result, containsString("John"));
assertThat(result, not(containsString("name")));
}
下面是輸出的樣子-靜態嵌套類的字段與其他字段一起展開:
{
"id":1,
"firstName":"John",
"lastName":"Doe"
}
6.4. @JsonView
@JsonView表示將包含該屬性進行序列化/反序列化的視圖。
我們將使用@JsonView來序列化項目實體的實例。
讓我們從視圖開始:
public class Views {
public static class Public {}
public static class Internal extends Public {}
}
現在這是Item實體,使用視圖:
public class Item {
@JsonView(Views.Public.class)
public int id;
@JsonView(Views.Public.class)
public String itemName;
@JsonView(Views.Internal.class)
public String ownerName;
}
最后-完整測試:
@Test
public void whenSerializingUsingJsonView_thenCorrect()
throws JsonProcessingException {
Item item = new Item(2, "book", "John");
String result = new ObjectMapper()
.writerWithView(Views.Public.class)
.writeValueAsString(item);
assertThat(result, containsString("book"));
assertThat(result, containsString("2"));
assertThat(result, not(containsString("John")));
}
6.5. @JsonManagedReference, @JsonBackReference
@JsonManagedReference和@JsonBackReference注釋可以處理父/子關系并在循環中工作。
在下面的例子中-我們使用@JsonManagedReference和@JsonBackReference來序列化我們的ItemWithRef實體:
public class ItemWithRef {
public int id;
public String itemName;
@JsonManagedReference
public UserWithRef owner;
}
我們的UserWithRef實體:
public class UserWithRef {
public int id;
public String name;
@JsonBackReference
public List<ItemWithRef> userItems;
}
測試:
@Test
public void whenSerializingUsingJacksonReferenceAnnotation_thenCorrect()
throws JsonProcessingException {
UserWithRef user = new UserWithRef(1, "John");
ItemWithRef item = new ItemWithRef(2, "book", user);
user.addItem(item);
String result = new ObjectMapper().writeValueAsString(item);
assertThat(result, containsString("book"));
assertThat(result, containsString("John"));
assertThat(result, not(containsString("userItems")));
}
6.6. @JsonIdentityInfo
@JsonIdentityInfo表示在序列化/反序列化值時應該使用對象標識—例如,用于處理無限遞歸類型的問題。
在下面的例子中-我們有一個ItemWithIdentity實體,它與UserWithIdentity實體具有雙向關系:
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class ItemWithIdentity {
public int id;
public String itemName;
public UserWithIdentity owner;
}
和UserWithIdentity實體:
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class UserWithIdentity {
public int id;
public String name;
public List<ItemWithIdentity> userItems;
}
現在,讓我們看看無限遞歸問題是如何處理的:
@Test
public void whenSerializingUsingJsonIdentityInfo_thenCorrect()
throws JsonProcessingException {
UserWithIdentity user = new UserWithIdentity(1, "John");
ItemWithIdentity item = new ItemWithIdentity(2, "book", user);
user.addItem(item);
String result = new ObjectMapper().writeValueAsString(item);
assertThat(result, containsString("book"));
assertThat(result, containsString("John"));
assertThat(result, containsString("userItems"));
}
下面是序列化的項目和用戶的完整輸出:
{
"id": 2,
"itemName": "book",
"owner": {
"id": 1,
"name": "John",
"userItems": [
2
]
}
}
6.7. @JsonFilter
@JsonFilter注釋指定要在序列化期間使用的過濾器。
讓我們看一個例子;首先,我們定義實體,并指向過濾器:
@JsonFilter("myFilter")
public class BeanWithFilter {
public int id;
public String name;
}
現在,在完整的測試中,我們定義了過濾器——它排除了序列化中除了name之外的所有其他屬性:
@Test
public void whenSerializingUsingJsonFilter_thenCorrect()
throws JsonProcessingException {
BeanWithFilter bean = new BeanWithFilter(1, "My bean");
FilterProvider filters
= new SimpleFilterProvider().addFilter(
"myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("name"));
String result = new ObjectMapper()
.writer(filters)
.writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, not(containsString("id")));
}
7. Jackson自定義注釋
接下來,讓我們看看如何創建自定義Jackson注釋。我們可以使用@JacksonAnnotationsInside注釋:
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({ "name", "id", "dateCreated" })
public @interface CustomAnnotation {}
現在,如果我們對一個實體使用新的注釋:
@CustomAnnotation
public class BeanWithCustomAnnotation {
public int id;
public String name;
public Date dateCreated;
}
我們可以看到它是如何將現有的注解組合成一個更簡單的、自定義的注解,我們可以使用它作為速記:
@Test
public void whenSerializingUsingCustomAnnotation_thenCorrect()
throws JsonProcessingException {
BeanWithCustomAnnotation bean
= new BeanWithCustomAnnotation(1, "My bean", null);
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, containsString("1"));
assertThat(result, not(containsString("dateCreated")));
}
序列化過程的輸出:
{
"name":"My bean",
"id":1
}
8. Jackson MixIn 注解
接下來——讓我們看看如何使用Jackson MixIn注釋。
讓我們使用MixIn注釋——例如——忽略類型User的屬性:
public class Item {
public int id;
public String itemName;
public User owner;
}
@JsonIgnoreType
public class MyMixInForIgnoreType {}
讓我們來看看這是怎么回事:
@Test
public void whenSerializingUsingMixInAnnotation_thenCorrect()
throws JsonProcessingException {
Item item = new Item(1, "book", null);
String result = new ObjectMapper().writeValueAsString(item);
assertThat(result, containsString("owner"));
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(User.class, MyMixInForIgnoreType.class);
result = mapper.writeValueAsString(item);
assertThat(result, not(containsString("owner")));
}
9. 禁用Jackson注解
最后,讓我們看看如何禁用所有Jackson注釋。我們可以通過禁用MapperFeature來做到這一點。如下例所示:
@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
public int id;
public String name;
}
現在,禁用注釋后,這些應該沒有效果,庫的默認值應該適用:
@Test
public void whenDisablingAllAnnotations_thenAllDisabled()
throws IOException {
MyBean bean = new MyBean(1, null);
ObjectMapper mapper = new ObjectMapper();
mapper.disable(MapperFeature.USE_ANNOTATIONS);
String result = mapper.writeValueAsString(bean);
assertThat(result, containsString("1"));
assertThat(result, containsString("name"));
禁用注釋之前序列化的結果:
{"id":1}
禁用注釋后序列化的結果:
{
"id":1,
"name":null
}
{
"id":1,
"name":null
}
10. 結論
本教程對Jackson注釋進行了深入的研究,只觸及了正確使用它們所能獲得的靈活性的表面。