java:jackson 一:Jackson Annotation
1 前言
参考文档地址:
https://www.baeldung.com/jackson
https://www.baeldung.com/jackson-annotations
2 使用
2.1 Jackson Serialization Annotations
jackson 序列化注解
2.1.1 @JsonAnyGetter
The @JsonAnyGetter annotation allows for the flexibility of using a Map field as standard properties.
package com.xiaoxu.test.jackson;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.text.StringEscapeUtils;
import java.util.HashMap;
import java.util.Map;
/**
* @author xiaoxu
* @date 2022-12-21
* spring_boot:com.xiaoxu.test.jackson.TestJaskSon
*/
public class TestJaskSon {
public static void main(String[] args) throws Exception{
ExtendableBean bean = new ExtendableBean("My bean");
bean.add("attr1", "val1");
bean.add("attr2", "val2");
System.out.println(bean);
String result = new ObjectMapper().writeValueAsString(bean);
System.out.println(result);
String a = "{\\\"name\\\":\\\"xiaoxu\\\",\\\"age\\\":\\\"27\\\"}";
String s = StringEscapeUtils.unescapeJava(a);
System.out.println(s);
UseRR useRR = JSON.parseObject(s, UseRR.class);
System.out.println(useRR);
}
}
class UseRR{
String name;
String age;
public void setName(String name) {
this.name = name;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "UseRR{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
class ExtendableBean {
public String name;
private Map<String, String> properties;
ExtendableBean(String name){
this.name = name;
this.properties = new HashMap<>();
}
public void add(String key,String value){
this.properties.put(key,value);
}
@JsonAnyGetter
public Map<String, String> getProperties() {
return properties;
}
@Override
public String toString() {
return "ExtendableBean{" +
"name='" + name + '\'' +
", properties=" + properties +
'}';
}
}
ExtendableBean{name='My bean', properties={attr2=val2, attr1=val1}}
{"name":"My bean","attr2":"val2","attr1":"val1"}
{"name":"xiaoxu","age":"27"}
UseRR{name='xiaoxu', age='27'}
可见,@JsonAnyGetter加在Map属性的get方法上时,打印的json字符串为将Map属性的key、value也直接展示在json结果中了。
2.1.2 @JsonGetter
The @JsonGetter annotation is an alternative to the @JsonProperty annotation, which marks a method as a getter method.
先观察@JsonProperty的使用:
如下DTO的name属性的set和get方法名称,不是传统的setter、getter方法名称:
package test.jackson;
import lombok.AllArgsConstructor;
/**
* @author xiaoxu
* @date 2022-12-27
* java_demo:test.jackson.JacksonDTO
*/
@AllArgsConstructor
public class JacksonDTO {
int id;
String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMyName() {
return name;
}
public void setMyName(String name) {
this.name = name;
}
}
package test.jackson;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
/**
* @author xiaoxu
* @date 2022-12-27
* java_demo:test.jackson.JacksonAnnotationTest
*/
public class JacksonAnnotationTest {
private static final ObjectMapper objectMapper;
static {
objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
}
public static void demo1() throws Exception{
JacksonDTO jacksonDTO = new JacksonDTO(1,"xiaoxu");
System.out.println(objectMapper.writeValueAsString(jacksonDTO));
}
public static void main(String[] args) throws Exception{
demo1();
}
}
上述执行结果如下,可见序列化后,不为name,是myName:
{
"id" : 1,
"myName" : "xiaoxu"
}
使用@JsonProperty:
package test.jackson;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* @author xiaoxu
* @date 2022-12-27
* java_demo:test.jackson.JacksonDTO
*/
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class JacksonDTO {
@JsonProperty(value = "mid")
int id;
String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@JsonProperty(value = "xName")
public String getMyName() {
return name;
}
// @JsonProperty(value = "xName")
public void setMyName(String name) {
this.name = name;
}
}
package test.jackson;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
/**
* @author xiaoxu
* @date 2022-12-27
* java_demo:test.jackson.JacksonAnnotationTest
*/
public class JacksonAnnotationTest {
private static final ObjectMapper objectMapper;
static {
objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
}
public static void demo1() throws Exception{
JacksonDTO jacksonDTO = new JacksonDTO(1,"xiaoxu");
System.out.println(objectMapper.writeValueAsString(jacksonDTO));
/* 反序列化的前提:需要有无参构造方法,否则报错:
*
* (no Creators, like default constructor, exist):
* cannot deserialize from Object value (no delegate- or property-based Creator)
* */
JacksonDTO jacksonDTO1 = objectMapper.readerFor(JacksonDTO.class)
.readValue(objectMapper.writeValueAsString(jacksonDTO));
System.out.println(jacksonDTO1);
}
public static void main(String[] args) throws Exception{
demo1();
}
}
序列化结果:
{
"mid" : 1,
"xName" : "xiaoxu"
}
JacksonDTO(id=1, name=xiaoxu)
@JsonGetter可替代如上@JsonProperty注解使用:
再次执行,序列化的效果一致:
2.1.3 @JsonPropertyOrder
We can use the @JsonPropertyOrder annotation to specify the order of properties on serialization.
@JsonPropertyOrder主要是更新序列化后的结果的字段顺序,如果同时存在使用了@JsonProperty注解,必须按照@JsonProperty注解的value设置值,才能更新顺序成功(无法匹配则没有效果)。
@ToString
@AllArgsConstructor
@NoArgsConstructor
@JsonPropertyOrder(value = {"xxName","mid"})
public class JacksonDTO {
@JsonProperty(value = "mid")
int id;
String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@JsonGetter(value = "xxName")
public String getMyName() {
return name;
}
// @JsonProperty(value = "xName")
public void setMyName(String name) {
this.name = name;
}
}
再次执行,DTO的字段顺序改变:
2.1.4 @JsonRawValue
The @JsonRawValue annotation can instruct Jackson to serialize a property exactly as is.
@ToString
@AllArgsConstructor
@NoArgsConstructor
/* 序列化时,有getter方法即可 */
@Getter
public class JacksonDTO1 {
int id;
String name;
@JsonRawValue
String jsonData;
}
JacksonDTO1 jacksonDTO1 = new JacksonDTO1(1,"xiaoxu","{\"myName\":\"xiaoxu\",\"age\":\"55\"}");
System.out.println(objectMapper.writeValueAsString(jacksonDTO1));
执行结果:
{
"id" : 1,
"name" : "xiaoxu",
"jsonData" : {"myName":"xiaoxu","age":"55"}
}
2.1.5 @JsonValue
@JsonValue indicates a single method that the library will use to serialize the entire instance.
For example, in an enum, we annotate the getName with @JsonValue so that any such entity is serialized via its name.
enum JackEnum{
Study("study",1234);
private String code;
private long value;
JackEnum(String code, long value){
this.code = code;
this.value = value;
}
@JsonValue
public String getCode() {
return code;
}
public long getValue() {
return value;
}
}
System.out.println(objectMapper.writeValueAsString(JackEnum.Study));
执行结果:
"study"
2.1.6 @JsonRootName
The @JsonRootName annotation is used, if wrapping is enabled, to specify the name of the root wrapper to be used.
Wrapping means that instead of serializing a User to something like:
@ToString
@AllArgsConstructor
@NoArgsConstructor
/* 序列化时,有getter方法即可 */
@Getter
@JsonRootName(value = "specialPerson")
class JacksonDTO2 {
int id;
String name;
}
/* 不增加 objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
* @JsonRootName(value = "specialPerson") 将不会生效
* */
objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
JacksonDTO2 jacksonDTO2 = new JacksonDTO2(1,"xiaoxu");
System.out.println(objectMapper.writeValueAsString(jacksonDTO2));
执行结果:
{
"specialPerson" : {
"id" : 1,
"name" : "xiaoxu"
}
}
2.1.7 @JsonSerialize
We’re going to use @JsonSerialize to serialize the eventDate property with a CustomDateSerializer:
该注解常用于和自定义序列化(或类似@JsonDeserialize,与自定义反序列化)器一同使用
使用参考如下:
https://blog.csdn.net/a232884c/article/details/128418713
2.2 Jackson Deserialization Annotations
jackson 反序列化注解
2.2.1 @JsonCreator
We can use the @JsonCreator annotation to tune the constructor/factory used in deserialization.
It’s very useful when we need to deserialize some JSON that doesn’t exactly match the target entity we need to get.
去掉@JsonCreator,只使用@JsonProperty,效果是一样的:
@ToString
class JacksonDTO3 {
int id;
String name;
/* 构造方法为反序列化时的myName,映射为name */
@JsonCreator
public JacksonDTO3(@JsonProperty("id") int id,
@JsonProperty("myName") String name){
this.id = id;
this.name = name;
}
}
String value = "{\"id\":\"123\",\"myName\":\"xiaoxu\"}";
JacksonDTO3 dto3 = objectMapper.readerFor(JacksonDTO3.class)
.readValue(value);
System.out.println(dto3);
执行结果:
JacksonDTO3(id=123, name=xiaoxu)
2.2.2 @JacksonInject
@JacksonInject indicates that a property will get its value from the injection and not from the JSON data.
In the following example, we use @JacksonInject to inject the property id:
@ToString
class JacksonDTO4 {
@JacksonInject
int id;
String name;
/* id 是注入的, 但是name反序列化时,取的jsonData中的,
* 必须加上getter方法,否则将会抛出异常
* */
public String getName() {
return name;
}
}
String value = "{\"name\":\"xiaoxu\"}";
InjectableValues inject = new InjectableValues.Std().addValue(int.class, 666);
JacksonDTO4 dto4 = objectMapper.reader(inject)
.forType(JacksonDTO4.class)
.readValue(value);
System.out.println(dto4);
执行结果:
JacksonDTO4(id=666, name=xiaoxu)
2.2.3 @JsonAnySetter
@JsonAnySetter allows us the flexibility of using a Map as standard properties. On deserialization, the properties from JSON will simply be added to the map.
@ToString
class ExtendableBean {
public String name;
private final Map<String, String> properties = new HashMap<>();
@JsonAnySetter
public void add(String key, String value) {
properties.put(key, value);
}
}
String json
= "{\"name\":\"xiaoxu\",\"attr2\":\"val2\",\"attr1\":\"val1\"}";
ExtendableBean bean = objectMapper
.readerFor(ExtendableBean.class)
.readValue(json);
System.out.println(bean);
执行结果:
ExtendableBean(name=xiaoxu, properties={attr2=val2, attr1=val1})
2.2.4 @JsonSetter
@JsonSetter is an alternative to @JsonProperty that marks the method as a setter method.
This is incredibly useful when we need to read some JSON data, but the target entity class doesn’t exactly match that data, and so we need to tune the process to make it fit.
此注解和@JsonGetter效果类似,只是用于的是反序列化
@ToString
class JacksonDTO5 {
int id;
String name;
/* 反序列化时,id 有setter或者getter方法均可 */
public void setId(int id) {
this.id = id;
}
@JsonSetter("name")
public void setMyName(String name) {
this.name = name;
}
}
String value = "{\"id\":\"123999\",\"name\":\"xiaoxu\"}";
JacksonDTO5 dto5 = objectMapper.readerFor(JacksonDTO5.class)
.readValue(value);
System.out.println(dto5);
执行结果:
JacksonDTO5(id=123999, name=xiaoxu)
2.2.5 @JsonDeserialize
@JsonDeserialize indicates the use of a custom deserializer.
该注解@JsonDeserialize用于和自定义反序列化器一同使用
使用参考如下:
https://blog.csdn.net/a232884c/article/details/128407205
2.2.6 @JsonAlias
The @JsonAlias defines one or more alternative names for a property during deserialization.
@ToString
class JacksonDTO6 {
int id;
@JsonAlias(value = {"f_name","frName"})
String fruitName;
/* 反序列化时,id 有setter或者getter方法均可 */
public void setId(int id) {
this.id = id;
}
/* 反序列化时,fruitName 有setter或者getter方法均可 */
public String getFruitName() {
return fruitName;
}
}
String value = "{\"id\":\"123888\",\"frName\":\"xiaoxu\"}";
JacksonDTO6 dto6 = objectMapper.readerFor(JacksonDTO6.class)
.readValue(value);
System.out.println(dto6);
执行结果:
JacksonDTO6(id=123888, fruitName=xiaoxu)