Jackson字段命名之JsonAlias、JsonGetter和JsonSetter

序列化时如果需要修改字段名,比较常见的是使用JsonProperty注解来实现。

有时候,序列化和反序列化需要使用不同的字段名称。在《Jackson修改字段名和自定义命名策略》一文中讲到,使用自定义的命名策略,可以分别指定getter和setter的方法名称,从而实现序列化和反序列化同一字段时采用不同的JSON属性名称。

除此之外,Jackson还提供了几个注解,可以实现类似的功能。这几个注解,分别是JsonAlias、JsonGetter和JsonSetter。

本篇内容基于Jackson 2.11.2版本,马上开始学习吧。

JsonAlias指定反序列化别名

JsonAlias注解,支持指定多个别名。该注解可用于字段、getter和setter方法,效果是一样的。

JsonAlias反序列化

public class Article {

    private String title;
    @JsonAlias({"cont", "detail"})
    private String content;

    // 省略getter、setter方法
}
/**
 * 反序列化时,既支持使用原来的字段名,也支持使用指定的任一别名
 * 
 * @throws JsonMappingException
 * @throws JsonProcessingException
 */
@Test
public void deserializeWithJsonAlias() throws JsonMappingException, JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    // 使用原字段名
    String jsonString = "{\"title\":\"spring\",\"content\":\"flowers\"}";
    Article article = mapper.readValue(jsonString, Article.class);
    System.out.println(mapper.writeValueAsString(article));

    // 使用别名cont
    jsonString = "{\"title\":\"spring\",\"cont\":\"flowers\"}";
    article = mapper.readValue(jsonString, Article.class);
    System.out.println(mapper.writeValueAsString(article));

    // 使用别名detail
    jsonString = "{\"title\":\"spring\",\"detail\":\"flowers\"}";
    article = mapper.readValue(jsonString, Article.class);
    System.out.println(mapper.writeValueAsString(article));
}

执行结果:

{"title":"spring","content":"flowers"}
{"title":"spring","content":"flowers"}
{"title":"spring","content":"flowers"}

使用JsonAlias进行反序列化时,除了支持指定的别名,还支持使用原来的字段名(这一点在Jackson中比较少见)。

JsonAlias别名不支持序列化

JsonAlias别名只用于反序列化,并不支持序列化。

/**
 * 序列化时,使用原来的字段名,不会替换为别名
 * 
 * @throws JsonProcessingException
 */
@Test
public void serializeNoEffect() throws JsonProcessingException {
    Article article = new Article();
    article.setTitle("spring");
    article.setContent("flowers");

    ObjectMapper mapper = new ObjectMapper();
    System.out.println(mapper.writeValueAsString(article));
}

执行结果:

{"title":"spring","content":"flowers"}

JsonGetter和JsonSetter

使用JsonGetter和JsonSetter注解,可以实现类似于JsonProperty和JsonAlias修改字段名的功能。同时,可以实现setter和getter使用不同的名称。

序列化和反序列化使用相同的别名

public class Article1 {

    private String title;
    private String content;

    @JsonGetter("t")
    public String getTitle() {
        return title;
    }

    @JsonSetter("t")
    public void setTitle(String title) {
        this.title = title;
    }

    @JsonGetter("c")
    public String getContent() {
        return content;
    }

    @JsonSetter("c")
    public void setContent(String content) {
        this.content = content;
    }

}

1)使用注解的别名进行序列化

/**
 * 使用注解的别名进行序列化
 * 
 * @throws JsonProcessingException
 */
@Test
public void serialize1() throws JsonProcessingException {
    Article1 article = new Article1();
    article.setTitle("spring");
    article.setContent("flowers");

    ObjectMapper mapper = new ObjectMapper();
    System.out.println(mapper.writeValueAsString(article));
}

执行结果:

{"t":"spring","c":"flowers"}

2)反序列化时,只支持使用字段别名,不支持使用原字段名

/**
 * 反序列化时,只支持使用字段别名
 * 
 * @throws JsonMappingException
 * @throws JsonProcessingException
 */
@Test
public void deserialize1() throws JsonMappingException, JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    // 不支持使用原字段名
//  String jsonString = "{\"title\":\"spring\",\"content\":\"flowers\"}";
    // 正确. 使用别名
    String jsonString = "{\"t\":\"spring\",\"c\":\"flowers\"}";
    Article1 article = mapper.readValue(jsonString, Article1.class);
    System.out.println(mapper.writeValueAsString(article));
}

执行结果:

{"t":"spring","c":"flowers"}

3)同一字段只使用JsonGetter和JsonSetter任一个注解

如果只给字段添加JsonGetter注解,或者只添加JsonSetter注解。在序列化和反序列化时,都需要统一用注解的名称。

public class Article2 {

    private String title;
    private String content;

    @JsonGetter("t")
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    @JsonSetter("c")
    public void setContent(String content) {
        this.content = content;
    }

}

getContent()方法没注解,序列化时别名和JsonSetter注解相同,名称为c。

/**
 * 使用注解的别名进行序列化
 * 
 * @throws JsonProcessingException
 */
@Test
public void serialize2() throws JsonProcessingException {
    Article2 article = new Article2();
    article.setTitle("spring");
    article.setContent("flowers");

    ObjectMapper mapper = new ObjectMapper();
    System.out.println(mapper.writeValueAsString(article));
}

执行结果:

{"t":"spring","c":"flowers"}

setTitle()方法没注解,反序列化时别名和JsonGetter注解相同,名称为t。

/**
 * 反序列化时,只支持使用字段别名
 * 
 * @throws JsonMappingException
 * @throws JsonProcessingException
 */
@Test
public void deserialize2() throws JsonMappingException, JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    // 不支持使用原字段名
//  String jsonString = "{\"title\":\"spring\",\"content\":\"flowers\"}";
    // 不支持. 即使setTitle()方法没有注解,也需要使用JsonGetter注解的别名.
//  String jsonString = "{\"title\":\"spring\",\"c\":\"flowers\"}";
    // 正确. 都使用别名
    String jsonString = "{\"t\":\"spring\",\"c\":\"flowers\"}";
    Article2 article = mapper.readValue(jsonString, Article2.class);
    System.out.println(mapper.writeValueAsString(article));
}

执行结果:

{"t":"spring","c":"flowers"}

虽然只给getTitle()方法添加了JsonGetter注解,但即使setTitle()方法没有注解,也需要使用JsonGetter注解的别名进行反序列化。

序列化和反序列化使用不同的名称

public class Article3 {

    private String title;
    private String content;

    @JsonGetter("tr")
    public String getTitle() {
        return title;
    }

    @JsonSetter("tw")
    public void setTitle(String title) {
        this.title = title;
    }

    @JsonGetter("cr")
    public String getContent() {
        return content;
    }

    @JsonSetter("cw")
    public void setContent(String content) {
        this.content = content;
    }

}

1)使用JsonGetter注解的别名进行序列化

/**
 * 使用JsonGetter注解的别名进行序列化
 * 
 * @throws JsonProcessingException
 */
@Test
public void serialize3() throws JsonProcessingException {
    Article3 article = new Article3();
    article.setTitle("spring");
    article.setContent("flowers");

    ObjectMapper mapper = new ObjectMapper();
    System.out.println(mapper.writeValueAsString(article));
}

执行结果:

{"tr":"spring","cr":"flowers"}

2)使用JsonSetter注解的别名进行反序列化

/**
 * 使用JsonSetter注解的别名进行反序列化
 * 
 * @throws JsonMappingException
 * @throws JsonProcessingException
 */
@Test
public void deserialize3() throws JsonMappingException, JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    String jsonString = "{\"tw\":\"spring\",\"cw\":\"flowers\"}";
    Article3 article = mapper.readValue(jsonString, Article3.class);
    System.out.println(mapper.writeValueAsString(article));
}

执行结果:

{"tr":"spring","cr":"flowers"}

小结

Jackson为字段命名提供了多种实现方式,用来灵活的支持各种应用场景。

使用JsonProperty注解是比较常用的统一字段命名方式,使用简单。

使用命名策略可以实现比较复杂的命名规则,可以通过扩展PropertyNamingStrategy来自定义命名规则。

JsonAlias支持指定多个别名,但只能应用于反序列化操作。

在序列化和反序列化时,使用JsonGetter和JsonSetter组合,既可以给字段统一命名,也可以分别使用不同的名称。

有了以上几种命名方式,给字段命名提供了非常丰富的选择空间。

参考

《轻松学习Jackson》

https://github.com/FasterXML/jackson

https://www.logicbig.com/tutorials/misc/jackson/renaming-properties.html


---转载本站文章请注明作者和出处 996极客教程(996geek.com),请勿用于任何商业用途---

留下评论