1. 概述
在本教程中,我們將介紹如何使用 Jackson JSON Views 來序列化/反序列化對象、自定義視圖,以及最後 – 如何與 Spring 集成。
2. 使用 JSON Views 進行序列化
首先,我們通過一個簡單的例子——使用 @JsonView序列化一個對象。
這是我們的視圖:
public class Views {
public static class Public {
}
}
以及“User”實體:
public class User {
public int id;
@JsonView(Views.Public.class)
public String name;
}
現在,我們使用我們的視圖序列化一個“User”實例:
@Test
public void whenUseJsonViewToSerialize_thenCorrect()
throws JsonProcessingException {
User user = new User(1, "John");
ObjectMapper mapper = new ObjectMapper();
mapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION);
String result = mapper
.writerWithView(Views.Public.class)
.writeValueAsString(user);
assertThat(result, containsString("John"));
assertThat(result, not(containsString("1")));
}
請注意,因為我們使用特定視圖進行序列化,所以我們只看到正確的字段被序列化。
此外,默認情況下,未明確標記為屬於視圖的屬性都會被序列化。我們使用方便的 DEFAULT_VIEW_INCLUSION功能來禁用此行為。
3. 使用多個JSON視圖
接下來,讓我們看看如何使用多個JSON視圖——每個視圖都有不同的字段,如以下示例所示:
我們有兩個視圖,Internal擴展Public,內部視圖擴展了公共視圖:
public class Views {
public static class Public {
}
public static class Internal extends Public {
}
}
下面是我們的實體“Item”,其中僅包含id和name字段在Public視圖中:
public class Item {
@JsonView(Views.Public.class)
public int id;
@JsonView(Views.Public.class)
public String itemName;
@JsonView(Views.Internal.class)
public String ownerName;
}
如果我們使用Public視圖進行序列化,則僅序列化id和name字段到JSON中:
@Test
public void whenUsePublicView_thenOnlyPublicSerialized()
throws JsonProcessingException {
Item item = new Item(2, "book", "John");
ObjectMapper mapper = new ObjectMapper();
String result = mapper
.writerWithView(Views.Public.class)
.writeValueAsString(item);
assertThat(result, containsString("book"));
assertThat(result, containsString("2"));
assertThat(result, not(containsString("John")));
}
但是,如果我們使用Internal視圖進行序列化,則所有字段都將包含在JSON輸出中:
@Test
public void whenUseInternalView_thenAllSerialized()
throws JsonProcessingException {
Item item = new Item(2, "book", "John");
ObjectMapper mapper = new ObjectMapper();
String result = mapper
.writerWithView(Views.Internal.class)
.writeValueAsString(item);
assertThat(result, containsString("book"));
assertThat(result, containsString("2"));
assertThat(result, containsString("John"));
}
4. 使用 JSON 視圖進行反序列化
現在,讓我們看看如何使用 JSON 視圖來反序列化對象——特別是,一個 User 實例:
@Test
public void whenUseJsonViewToDeserialize_thenCorrect()
throws IOException {
String json = "{\"id\":1,\"name\":\"John\"}";
ObjectMapper mapper = new ObjectMapper();
User user = mapper
.readerWithView(Views.Public.class)
.forType(User.class)
.readValue(json);
assertEquals(1, user.getId());
assertEquals("John", user.getName());
}
請注意,我們正在使用 readerWithView() API 創建一個 ObjectReader,使用提供的視圖。
5. 定製 JSON 視圖
接下來,讓我們看看如何定製 JSON 視圖。 在下一個示例中,我們希望在序列化結果中將 User 的 “name” 轉換為大寫。
我們將使用 BeanPropertyWriter 和 BeanSerializerModifier 來定製我們的 JSON 視圖。 首先,這是 BeanPropertyWriter 的 UpperCasingWriter,用於將 User 的 name 轉換為大寫:
public class UpperCasingWriter extends BeanPropertyWriter {
BeanPropertyWriter _writer;
public UpperCasingWriter(BeanPropertyWriter w) {
super(w);
_writer = w;
}
@Override
public void serializeAsField(Object bean, JsonGenerator gen,
SerializerProvider prov) throws Exception {
String value = ((User) bean).name;
value = (value == null) ? "" : value.toUpperCase();
gen.writeStringField("name", value);
}
}
這裏是 BeanSerializerModifier,用於將 User 的 name 與我們的自定義 UpperCasingWriter 相關聯:
public class MyBeanSerializerModifier extends BeanSerializerModifier{
@Override
public List<BeanPropertyWriter> changeProperties(
SerializationConfig config, BeanDescription beanDesc,
List<BeanPropertyWriter> beanProperties) {
for (int i = 0; i < beanProperties.size(); i++) {
BeanPropertyWriter writer = beanProperties.get(i);
if (writer.getName() == "name") {
beanProperties.set(i, new UpperCasingWriter(writer));
}
}
return beanProperties;
}
}
現在,讓我們使用修改後的序列化器序列化一個 User 實例:
@Test
public void whenUseCustomJsonViewToSerialize_thenCorrect()
throws JsonProcessingException {
User user = new User(1, "John");
SerializerFactory serializerFactory = BeanSerializerFactory.instance
.withSerializerModifier(new MyBeanSerializerModifier());
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializerFactory(serializerFactory);
String result = mapper
.writerWithView(Views.Public.class)
.writeValueAsString(user);
assertThat(result, containsString("JOHN"));
assertThat(result, containsString("1"));
}
6. 使用 JSON 視圖與 Spring
最後,讓我們快速瞭解一下如何使用 JSON 視圖與 Spring Framework。我們可以利用 @JsonView 註解來自定義 API 級別的 JSON 響應。
在下面的示例中,我們使用了 Public 視圖來響應:
@JsonView(Views.Public.class)
@RequestMapping("/items/{id}")
public Item getItemPublic(@PathVariable int id) {
return ItemManager.getById(id);
}
響應是:
{"id":2,"itemName":"book"}
當使用 Internal 視圖時,如下所示:
@JsonView(Views.Internal.class)
@RequestMapping("/items/internal/{id}")
public Item getItemInternal(@PathVariable int id) {
return ItemManager.getById(id);
}
響應是:
{"id":2,"itemName":"book","ownerName":"John"}
如果您想更深入地瞭解使用視圖與 Spring 4.1 的用法,請查看 Spring 4.1 中 Jackson 改進。
7. 結論
在本快速教程中,我們探討了 Jackson JSON 視圖以及 @JsonView 註解。我們演示瞭如何使用 JSON 視圖對我們的序列化/反序列化過程進行精細控制——使用單個或多個視圖。