概述
在这个教程中,我们将讲解如何使用Jackson JSON视图来序列化/反序列化对象,自定义视图,并最终集成到Spring框架。
2. 使用JSON视图进行序列化
首先,我们来看一个简单的例子:使用@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”实体中,“Public”视图只包括id和name字段:
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视图。首先,这是将User的name转换为大写的BeanPropertyWriter
,名为UpperCasingWriter
:
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);
}
}
然后,这是设置User名称BeanPropertyWriter
为自定义UpperCasingWriter
的BeanSerializerModifier
:
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. 在Spring中使用JSON视图
最后,让我们快速了解一下如何在Spring框架中使用JSON视图。我们可以利用@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视图精细控制序列化/反序列化过程,无论是使用单个视图还是多个视图。本教程的完整代码可以在GitHub上找到。