使用jackson annotations简化和增强的json解析与生成。
Jackson-2.x通用annotations列表:链接
Jackson-1.x通用annotations列表:链接
Jackson - Annotations
想要了解更多内容,请查看annotations列表。下面只列出一些常用的Json注解。
- @JsonProperty
它关联json字符串中的字段到java属性的映射。可以标记属性,也可以用来标记属性的getter/setter方法。当标记属性时,可以对属性字段重命名。当标记方法时,可以把json字段关联到java属性的getter或setter方法。
- @JsonCreator
json反序列化为java对象时,该注解用于定义构造函数。当从json创建java时,@JsonCreator注解的构造函数被会调用,如果没有@JsonCreator注解,则默认调用java类的无参构造函数,此时,如果java类中只有有参构造函数,而无默认的无参构造函数,在反序列化时会抛出这样的异常:com.fasterxml.jackson.databind.JsonMappingException,所以,当我们不使用@JsonCreator指定反序列化的构造函数,而又在java类中重载了构造函数时,一定要记得编写类的无参构造函数。
- @JsonAnyGetter和@JsonAnySetter
用于标记类方法,设置和读取json字段作为键值对存储到map中,这两个注解标记的方法不会处理任何java类中已经定义过的属性变量,只对java中未定义的json字段作处理。
- @JsonIgnoreProperties和@JsonIgnore
用于标记属性,在json与java之间相互转化时,将忽略被此注解标记的属性。@JsonIgnoreProperties是类级别注解,可以忽略多个属性,@JsonIgnore用来标注单个属性。
- @JsonTypeInfo和@JsonSubTypes
于维持java类的子类信息,将子类对象类型信息嵌入到json中,以便反序列化创建具体的对象。
@JsonProperty
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonProperty {
String USE_DEFAULT_NAME = "";
int INDEX_UNKNOWN = -1;
String value() default ""; //更改json对应pojo的属性的别名
boolean required() default false; //是否是必须的属性
int index() default -1; //序列化的顺序
String defaultValue() default ""; //json字符串中没有对应的属性时的默认值
JsonProperty.Access access() default JsonProperty.Access.AUTO;
public static enum Access {
AUTO,
READ_ONLY,
WRITE_ONLY,
READ_WRITE;
private Access() {
}
}
}
User:
public class User {
private String name;
private int age;
private String address;
private Date birthday;
//省略set、get、无参构造函数
}
没使用注解之前:
String json = "{\"name\":\"gakki\",\"age\":18,\"address\":\"东京\"}";
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(json, User.class);
System.out.println(user);
String userStr = mapper.writeValueAsString(user);
System.out.println(userStr);
输出:
User{name='gakki', age=18, address='东京', birthday=null}
{"name":"gakki","age":18,"address":"东京","birthday":null}
使用注解JsonProperty:value
public class User {
@JsonProperty("MyName")
private String name;
private int age;
private String address;
private Date birthday;
String json = "{\"MyName\":\"gakki\",\"address\":\"东京\",\"birthday\":\"2020-01-01\"}";
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
mapper.setDateFormat(dateFormat);
User user = mapper.readValue(json, User.class);
System.out.println(user);
String userStr = mapper.writeValueAsString(user);
System.out.println(userStr);
输出:
User{name='gakki', age=0, address='东京', birthday=Wed Jan 01 00:00:00 CST 2020}
{"age":0,"address":"东京","birthday":"2020-01-01","MyName":"gakki"}
注意:这里配置忽略不存在的属性:DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,否则会出错,
而且name改成了MyName。
一般,我只使用value来修改json字符串与pojo属性的名字的对应关系,该注解的其它属性使用的少,大家可以去尝试。
@JsonAlias
别名。
public class AliasBean {
@JsonAlias({ "fName", "f_name" })
private String firstName;
private String lastName;
}
String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}";
AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json);
assertEquals("John", aliasBean.getFirstName());
@JsonGetter
该注解主要用来单独改变序列化的属性名称
作用在get方法上面
User:
public class User {
@JsonProperty(value = "MyName")
private String name;
private int age;
private String address;
private Date birthday;
// 省略get、set、toString方法
}
String json = "{\"MyName\":\"gakki\",\"xxxx\":\"yyyy\",\"birthday\":\"2020-01-01\"}";
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
mapper.setDateFormat(dateFormat);
User user = mapper.readValue(json, User.class);
System.out.println(user);
String userStr = mapper.writeValueAsString(user);
System.out.println(userStr);
User{name='gakki', age=0, address='null', birthday=Wed Jan 01 00:00:00 CST 2020}
{"age":0,"address":null,"birthday":"2020-01-01","MyName":"gakki"}
此时,序列化的属性名称,除了name改变了,其它的都没有改变,使用@JsonProperty是将反序列和序列化都改变了。
现在给address的get方法添加该注解:
@JsonGetter(value = "myAddress")
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
String json = "{\"MyName\":\"gakki\",\"xxxx\":\"yyyy\",\"address\":\"冲绳\",\"birthday\":\"2020-01-01\"}";
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
mapper.setDateFormat(dateFormat);
User user = mapper.readValue(json, User.class);
System.out.println(user);
String userStr = mapper.writeValueAsString(user);
System.out.println(userStr);
User{name='gakki', age=0, address='null', birthday=Wed Jan 01 00:00:00 CST 2020}
{"age":0,"birthday":"2020-01-01","MyName":"gakki","myAddress":null}
此时,address确实名称改成了myAddress了,但是反序列化的值没了???
需要添加:@JsonSetter注解了。
@JsonGetter(value = "myAddress")
public String getAddress() {
return address;
}
@JsonSetter(value = "address")
public void setAddress(String address) {
this.address = address;
}
User{name='gakki', age=0, address='冲绳', birthday=Wed Jan 01 00:00:00 CST 2020}
{"age":0,"birthday":"2020-01-01","MyName":"gakki","myAddress":"冲绳"}
@JsonSetter
该注解用于反序列化时给属性命名
作用与:set方法上面。
上面已经给出了案例,就不演示了。
@JsonPropertyOrder
定制序列化的顺序:
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonPropertyOrder {
String[] value() default {};
boolean alphabetic() default false;
}
@JsonPropertyOrder(value = {"birthday","myAddress","age","MyName"})
public class User {
···
}
User{name='gakki', age=0, address='冲绳', birthday=Wed Jan 01 00:00:00 CST 2020}
{"birthday":"2020-01-01","myAddress":"冲绳","age":0,"MyName":"gakki"}
看到,序列化的顺序,全部都是按照注解中的顺序来的。
注意:书写注解中的顺序时,如果属性名字改了,请换成改后的名称,例如这里的name,改成了MyName。
@JsonRawValue
该注解用于序列化时,原样输出。
public class User {
@JsonProperty(value = "MyName")
private String name;
private int age;
private String address;
private Date birthday;
@JsonRawValue
public String json;
public User(String name, String json) {
this.name = name;
this.json = json;
}
}
ObjectMapper mapper = new ObjectMapper();
User user = new User("gakki","{\"name\":\"jacklove\"}");
System.out.println(user);
String userStr = mapper.writeValueAsString(user);
System.out.println(userStr);
User{name='gakki', age=0, address='null', birthday=null, json='{"name":"jacklove"}'}
{"birthday":null,"myAddress":null,"age":0,"MyName":"gakki","json":{"name":"jacklove"}}
这里的json本身也是一个json对象字符串。
@JsonRootName
给序列化后的字符串添加一个根名字:
@JsonRootName(value = "user")
public class User {
@JsonProperty(value = "MyName")
private String name;
private int age;
private String address;
private Date birthday;
}
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT); //序列化成漂亮的格式
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE); //允许添加根名称
User user = new User();
user.setName("gakkij");
user.setAge(18);
user.setAddress("冲绳");
System.out.println(user);
String userStr = mapper.writeValueAsString(user);
System.out.println(userStr);
User{name='gakkij', age=18, address='冲绳', birthday=null}
{
"user" : {
"age" : 18,
"birthday" : null,
"MyName" : "gakkij",
"myAddress" : "冲绳"
}
}
@JsonIgnore
该注解用于忽略属性是否该序列化和反序列化。
可以修饰属性,也可以修饰set和get方法。
User:
public class User {
@JsonProperty(value = "MyName", index = 4)
private String name;
private int age;
@JsonIgnore
private String address;
private Date birthday;
}
输出:
User{name='gakki', age=0, address='null', birthday=Wed Jan 01 00:00:00 CST 2020}
{"age":0,"birthday":"2020-01-01","MyName":"gakki"}
可以看出,address属性没有被反序列,而且也没有序列化。
修改:get方法
@JsonIgnore
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
输出:
User{name='gakki', age=0, address='null', birthday=Wed Jan 01 00:00:00 CST 2020}
{"age":0,"birthday":"2020-01-01","MyName":"gakki"}
反序列化和序列化都忽略了。
修饰:set方法
//@JsonIgnore
public String getAddress() {
return address;
}
@JsonIgnore
public void setAddress(String address) {
this.address = address;
}
输出:
User{name='gakki', age=0, address='null', birthday=Wed Jan 01 00:00:00 CST 2020}
{"age":0,"birthday":"2020-01-01","MyName":"gakki"}
效果一样!!!
@JsonIgnoreProperties
该注解与@JsonIgnore类似,但是它是作用于类的。
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonIgnoreProperties {
String[] value() default {};
boolean ignoreUnknown() default false;
boolean allowGetters() default false;
boolean allowSetters() default false;
User:
@JsonIgnoreProperties(value = {"MyName","birthday"})
public class User {
@JsonProperty(value = "MyName", index = 4)
private String name;
private int age;
private String address;
private Date birthday;
输出:
User{name='null', age=0, address='东京', birthday=null}
{"age":0,"address":"东京"}
我们知道,当json串中有pojo没有匹配的属性时,就会报错!需要我们配置:
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);//忽略不匹配的属性
这样比较麻烦,我们可以使用:@JsonIgnoreProperties的ignoreUnknown
为true来到达相同的效果:
@JsonIgnoreProperties(value = {"MyName", "birthday"}, ignoreUnknown = true)
public class User {
@JsonProperty(value = "MyName", index = 4)
private String name;
private int age;
private String address;
private Date birthday;
String json = "{\"MyName\":\"gakki\",\"unknow\":\"unknow\",\"address\":\"东京\",\"birthday\":\"2020-01-01\"}";
ObjectMapper mapper = new ObjectMapper();
//mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
mapper.setDateFormat(dateFormat);
User user = mapper.readValue(json, User.class);
System.out.println(user);
String userStr = mapper.writeValueAsString(user);
System.out.println(userStr);
User{name='null', age=0, address='东京', birthday=null}
{"age":0,"address":"东京"}
现在添加了,unknown属性,依然没有报错!!!
使用:allowGetters 和 allowSetters。
@JsonIgnoreProperties(ignoreUnknown = true, allowGetters = true)
public class User {
····
@JsonIgnore
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
输出:
User{name='gakki', age=0, address='null', birthday=Wed Jan 01 00:00:00 CST 2020}
{"age":0,"birthday":"2020-01-01","MyName":"gakki"}
@JsonIgnoreProperties(ignoreUnknown = true, allowSetters = true)
public class User {
···
//@JsonIgnore
public String getAddress() {
return address;
}
@JsonIgnore
public void setAddress(String address) {
this.address = address;
}
}
User{name='gakki', age=0, address='null', birthday=Wed Jan 01 00:00:00 CST 2020}
{"age":0,"birthday":"2020-01-01","MyName":"gakki"}
一样的效果···
@JsonCreator
User:
public class User {
@JsonProperty(value = "MyName", index = 4)
private String name;
private int age;
private String address;
private Date birthday;
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
去掉了无参的构造函数
运行:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.liuzhuo.jackson.domain.User` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"MyName":"gakki","unknow":"unknow","address":"东京","birthday":"2020-01-01"}"; line: 1, column: 2]
报:没有无参的构造函数问题!
修改:User
@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
private String name;
private int age;
private String address;
private Date birthday;
@JsonCreator
public User(@JsonProperty("MyName") String name) {
this.name = name;
}
}
String json = "{\"MyName\":\"gakki\",\"unknow\":\"unknow\",\"address\":\"东京\",\"birthday\":\"2020-01-01\"}";
ObjectMapper mapper = new ObjectMapper();
//mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
mapper.setDateFormat(dateFormat);
User user = mapper.readValue(json, User.class);
System.out.println(user);
String userStr = mapper.writeValueAsString(user);
System.out.println(userStr);
输出:
User{name='gakki', age=0, address='东京', birthday=Wed Jan 01 00:00:00 CST 2020}
{"name":"gakki","age":0,"address":"东京","birthday":"2020-01-01"}
@JsonAnySetter
User:
public class User {
@JsonProperty(value = "MyName")
private String name;
private int age;
private String address;
private Date birthday;
@JsonAnySetter
private Map<String,Object> unknow = new HashMap<>();
String json = "{\"MyName\":\"gakki\",\"xxxx\":\"yyyy\",\"address\":\"东京\",\"birthday\":\"2020-01-01\"}";
ObjectMapper mapper = new ObjectMapper();
//mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
mapper.setDateFormat(dateFormat);
User user = mapper.readValue(json, User.class);
System.out.println(user);
String userStr = mapper.writeValueAsString(user);
System.out.println(userStr);
输出:
User{name='gakki', age=0, address='东京', birthday=Wed Jan 01 00:00:00 CST 2020, unknow={xxxx=yyyy}}
{"age":0,"address":"东京","birthday":"2020-01-01","MyName":"gakki"}
可以看到,即使我们没有配置:
- mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
- @JsonIgnoreProperties( ignoreUnknown = true)
也不会报错了,会把不匹配的属性放到使用@JsonAnySetter注解的map中。
注意:这里的map请直接初始化,不需要添加get和set方法,否则会序列化出去的。@JsonInclude
例如:@JsonInclude(JsonInclude.Include.NON_NULL)
这个注解表示,如果值为null,则不返回,还可以在类上添加这个注释,当实体类与json互相转换的时候,属性值为null的不参与序列化。
String json = "{\"MyName\":\"gakki\",\"xxxx\":\"yyyy\",\"birthday\":\"2020-01-01\"}";
ObjectMapper mapper = new ObjectMapper();
//mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
mapper.setDateFormat(dateFormat);
User user = mapper.readValue(json, User.class);
System.out.println(user);
String userStr = mapper.writeValueAsString(user);
System.out.println(userStr);
输出:
User{name='gakki', age=0, address='null', birthday=Wed Jan 01 00:00:00 CST 2020, unknow={xxxx=yyyy}}
{"age":0,"address":null,"birthday":"2020-01-01","MyName":"gakki"}
此时,address为null也序列化出来了。
给address添加该注解后:
@JsonInclude(JsonInclude.Include.NON_NULL)
private String address;
User{name='gakki', age=0, address='null', birthday=Wed Jan 01 00:00:00 CST 2020, unknow={xxxx=yyyy}}
{"age":0,"birthday":"2020-01-01","MyName":"gakki"}
此时,address也为null,但是不再序列化出来了。
给age添加该注解后:
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
private int age;
User{name='gakki', age=0, address='null', birthday=Wed Jan 01 00:00:00 CST 2020, unknow={xxxx=yyyy}}
{"birthday":"2020-01-01","MyName":"gakki"}
此时,age=0也不被序列化出来了。
Include是一个枚举类型:
public static enum Include {
ALWAYS,
NON_NULL, // 不序列化null值
NON_ABSENT,
NON_EMPTY, // null 和 "" 都不序列化
NON_DEFAULT, // 不序列化默认值
CUSTOM,
USE_DEFAULTS;
private Include() {
}
}