1. Jackson 注解使用指南
introduction
Jackson, formerly known as hte standard JSON library for Java, or, as the "best JSON parser for Java", or simply as "JSON for Java.", more than that Jackson is a suite of data-processing tools for Java, including the flagship streaming[JOSON], etc...
以下内容翻译自baeldung
概括
这篇文章将带你深入Jackson Annotations并学习如何使用这些Annotations、 如何创建自定义的注解, 并且如何禁用它们。
Jaskson Serialization Annotations( Jackson 序列化注解 )
@JsonAnyGetter
这个注解允许使用Map灵活输出属性,下面是代码片段——ExtendableBean 类有一个 name 属性 和一个可拓展的 key/value 格式的属性。
public class ExtendableBean {
public String name;
public Map<String, String> properties;
@JsonAnyGetter
public Map<String, String> getProperties() {
return properties
}
}
当我们序列化这个实体的实例的时候,我们将得到所有Map中 key-values ,并以标准的形式输出:
{
"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"));
}
同样的, 我们可以使用可选参数 enabled
,传入false
禁用 @JsonAnyGetter, 本例中,序列化后的 Map 将会转化为Json格式的 properties 变量。
@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"));
}
@JsonPropertyOrder
用以指定Json序列化顺序, 自定义属性顺序代码:
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
public int id;
public String name;
}
@JsonRawValue
用以命令 Jackson 原原本本地序列化一个属性。
public class RawBean {
public String name;
@JsonRawValue
public String json;
}
以上代码将会输出以下格式
{
"name":"My bean",
"json":{
"attr":false
}
}
@JsonValue
被 @JsonValue
标识地方法会被Jackson库用于序列化整个对象实例,
TYPE1(1, "Type A"), TYPE2(2, "Type 2");
private Integer id;
private String name;
// standard constructors
@JsonValue
public String getName() {
return name;
}
}
例如,在枚举类型中,我们使用 @JsonValue 注解 getName 方法, 整个实体将会被序列化为它的 name 属性
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;
}
}
@JsonRootName
当启用Wrapping的时候, @JsonRootName 注解用于指定根 Wrapper 的名字。
Wrapping 指的是, 例如一个 User 实例原本序列化为以下格式:
{
"id": 1,
"name": "John"
}
启用被 Wrapped 后将变成以下格式:
{
"User": {
"id": 1,
"name": "John"
}
}
案例: 使用 @JsonRootName 指定一个隐式的Wrapper 实体的名字 :
@JsonRootName(value = "user")
public class UserWithRoot {
public int id;
public String name;
}
一般情况下, Wrapper的名字是类的名字 - UserWithRoot, 使用这个注解后,我们会得到更简洁的类名字。
@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"
}
}
tip: Jackson 2.4以后, 一个新的可选参数namespace
可用, 该选项用于像是XML的数据格式。 如果我们加上这个参数,那么其指定的值将成为一个完全合法的名字。
@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>
@JsonSerialize
@JsonSerialize 指定一个自定义序列化器, 用于序列化一个实体。
快速示例——使用@JsonSerialize 指定CustomDateSerilizer 类序列化eventDate属性。
public class EventWithSerializer {
public String name;
@JsonSerialize(using = CustomDateSerializer.class)
public Date eventDate;
}
CustomDateSerilizer 序列化器参考实现:
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));
}
}
反序列注解
@JsonCreator
用于调整用于反序列的构造函数/工厂。
当我们需要序列化一些并不需要完全匹配目标实体的JSON的时候,可以用 @JsonCreator 注解
假设我们需要反序列下面这个JSON:
{
"id":1,
"theName":"My bean"
}
然而目标实体只有name而并没有theName字段。 在不改变实体的前提下,我们需要对反序列过程更大程度的控制——用@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;
}
}
@JacksonInject
@JacksonInject 标识一个属性将被注入其值,而非从JSON数据。
对id 属性进行注入:
public class BeanWithInject {
@JacksonInject
public int id;
public String name;
}
@JsonAnySetter
@JsonAnySetter 允许使用 Map 灵活加入属性。 在反序列化过程中, JSON中的属性会轻松地加入到map中。
使用@JsonAnySetter 反序列化实体类 EntendableBean:
public class ExtendableBean {
public String name;
private Map<String, String> properties;
@JsonAnySetter
public void add(String key, String value) {
properties.put(key, value);
}
}
输出:
{
"name":"My bean",
"attr2":"val2",
"attr1":"val1"
}
译者:结合 @JsonAnyGetter 加深印象
@JsonSetter
@JsonSetter 作为@JsonProperty地替代——将一个方法标记为setter。
当我们需要读取JSON数据但是目标实体类并不能完全匹配对应字段的时候, 这个注解将非常有用。
下面这个示例指定MyBean 实体类中的 setTheName()
作为 name 属性的 setter 。
public class MyBean {
public int id;
private String name;
@JsonSetter("name")
public void setTheName(String name) {
this.name = name;
}
}
@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);
}
}
}
@JsonAlias
@JsonAlias 在反序列过程中为属性定义一个或多个别名
示例:
public class AliasBean {
@JsonAlias({ "fName", "f_name" })
private String firstName;
private String lastName;
}
在以上的POJO, Jackson库将JSON中带有诸如 fName, f_name, firstName 的字段反序列化到firstName 变量中。
Jackson Property Inclusion Annotations(Jackson 包含注解)
@JsonIgnoreProperties
@JsonIgnoreProperties 是一个类级别的注解, 它标记一个属性或者一个属性列表,被标记的属性或属性列表将会被忽略输出
示例, 从序列化中忽略id属性
@JsonIgnoreProperties({ "id" })
public class BeanWithIgnore {
public int id;
public String name;
}
@JsonIgnore
@JsonIgnore 注解用于标记一个字段级别的属性。
示例, 在序列化中忽略id属性
public class BeanWithIgnore {
@JsonIgnore
public int id;
public String name;
}
@JsonIgnoreType
@JsonIgnoreType 将忽略所有被注解的属性类型
示例, 忽略所有类型为Name的属性
public class User {
public int id;
public Name name;
@JsonIgnoreType
public static class Name {
public String firstName;
public String lastName;
}
}
@JsonInclude
使用 @JsonInclude
排除empty/null/default的值
示例, 序列化中排除所有null 值
@JsonInclude(Include.NON_NULL)
public class MyBean {
public int id;
public String name;
}
@JsonAutoDetect
使用@JsonAutoDtect覆盖默认语义下的属性可见性。
示例,启用序列化私有属性
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class PrivateBean {
private int id;
private String name;
}
Jackson Polymorphic Type Handling Annotations(Jackson 多态类型处理注解)
*@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"));
}
输出:
{
"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());
}