概述
在本教程中,我们将深入探讨 Jackson Annotations。
学到什么
- 如何使用现有注解
- 如何创建自定义注解并且使用自定义注解
Jackson 序列化注解
@JsonAnyGetter
定义
允许灵活地将 Map 字段用作标准属性
例子
- ExtendableBean 实体具有名称属性和一组键/值对形式的可扩展属性:
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"
}
- 我们还可以使用可选参数 enabled=false 来禁用 @JsonAnyGetter().
@JsonGetter
定义
@JsonGetter 注解是@JsonProperty 注解的替代方法,标记在get方法上
例子
- 在下面的示例中,我们将方法 getTheName() 指定为 MyBean 实体的名称属性的 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"));
}
- 这个没啥好讲的
@JsonPropertyOrder
定义
我们可以使用 @JsonPropertyOrder 注解来控制属性在序列化时的顺序。
例子
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
public int id;
public String name;
}
输出
{
"name":"My bean",
"id":1
}
@JsonSerialize
定义
@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反序列化注解
@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);
}
@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);
}
@JsonAnySetter
定义
允许我们灵活地使用 Map 作为标准属性。在反序列化时,JSON 中的属性将简单地添加到map中。
例子
- 我们将使用 @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);
}
}
- 这是我们不加JsonAnySetter注解的反序列化的 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"));
}
@JsonDeserialize
定义
@JsonDeserialize 表示使用自定义反序列化器。
例子
- 我们将使用 @JsonDeserialize 通过 CustomDateDeserializer 反序列化 eventDate 属性:
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));
}
Jackson 属性包含注解
@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")));
}
@JsonIgnore
定义
用于标记要在字段级别忽略的属性。
例子
- 使用 @JsonIgnore 来忽略序列化中的属性 id
public class BeanWithIgnore {
@JsonIgnore
public int id;
public String name;
}
- 测试用例
@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")));
}
@JsonIgnoreType
定义
忽略的注解类型的所有属性。
例子
- 使用注解来标记要忽略的所有 Name 类型的属性
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")));
}
@JsonInclude
定义
可以使用 @JsonInclude 来排除具有空/空/默认值的属性
例子
- 从序列化中排除空值的例子:
@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")));
}
@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"));
}
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"));
}
- 使用 Dog 序列化 Zoo 实例的结果:
{
"animal": {
"type": "dog",
"name": "lacy",
"barkVolume": 0
}
}
- 现在进行反序列化。让我们从以下 JSON 输入开始:
{
"animal":{
"name":"lacy",
"type":"cat"
}
}
- 然后让我们看看如何将其解组到 Zoo 实例:
@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());
}
Jackson 通用注解
@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"
}
自定义注解
定义
- 如何创建自定义 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
}
禁用注解
定义
如何禁用所有 Jackson 注解
例子
- 通过禁用 MapperFeature.USE_ANNOTATIONS 来做到这一点
@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
}
结论
在本文中,我们研究了 Jackson 注解,仅仅是挖掘了正确使用它们所能带来的灵活性表面。