Jackson 注解示例

1. 概览


在本教程中,我们将深入探讨 Jackson 注解。


我们将看到如何使用现有的注解、如何创建自定义注解,最后如何禁用它们。

2. Jackson 序列化注解


首先,我们来看一下序列化注解。

2.1. @JsonAnyGetter


@JsonAnyGetter 注解允许将 Map 字段用作标准属性,从而提供更大的灵活性。


例如,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"));
}

 我们也可以将 optional 参数设置为 false 来禁用 @JsonAnyGetter()。在这种情况下,Map 将会被转换成 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"
}

它将会像这样包装:

{
    "User": {
        "id": 1,
        "name": "John"
    }
}

那么我们来看一个例子。我们将使用@JsonRootName 注解来指示这个潜在的包装实体的名字:

@JsonRootName(value = "user")
public class UserWithRoot {
    public int id;
    public String name;
}

默认情况下,包装器的名称会是类名——UserWithRoot。通过使用注解,我们可以得到更整洁的 user:

@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)中新增了一个可选参数 namespace。如果我们添加它,将会成为完全限定名的一部分:

@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 表示在序列化实体时使用自定义的序列化器。


让我们来看一个简单的例子。我们将使用@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));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值