序列化时如果需要修改字段名,比较常见的是使用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组合,既可以给字段统一命名,也可以分别使用不同的名称。 有了以上几种命名方式,给字段命名提供了非常丰富的选择空间。
参考
https://github.com/FasterXML/jackson (opens in a new tab)
https://www.logicbig.com/tutorials/misc/jackson/renaming-properties.html (opens in a new tab)