1. 概述
在本教程中,我們將介紹如何使用 Jackson JSON Views 對對象進行序列化/反序列化,自定義視圖,以及最終如何將其集成到 Spring 中。
2. 使用 JSON 視圖進行序列化
首先,我們通過一個簡單的例子來演示 – 使用 @JsonView 序列化一個對象。
以下是我們的視圖:
public class Views {
public static class Public {
}
}以及“”實體:
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")));
}如果使用 內部視圖進行序列化,則所有字段都將包含在 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 名稱設置為 BeanPropertyWriter,並使用自定義的 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"}當我們使用內部視圖如下所示:
@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 視圖對我們的序列化/反序列化過程進行精細控制——通過單個或多個視圖。