提起 jackson,在日常使用中,由於涉及到各種序列化和反序列化的處理,就不能不提 註解,瞭解註解的常用方式可以極大地方便我們處理序列化,今天分享一些在使用 jackson 中涉及到的註解。 目錄1.@JsonProperty - 欄位命名2.@JsonPropertyOrder - 欄位序列化順 ...
提起 jackson
,在日常使用中,由於涉及到各種序列化和反序列化的處理,就不能不提 註解
,瞭解註解的常用方式可以極大地方便我們處理序列化,今天分享一些在使用 jackson 中涉及到的註解。
1.@JsonProperty
- 欄位命名2.@JsonPropertyOrder
- 欄位序列化順序3.@JsonAlias
- 欄位別名,反序列化4.@JsonIgnore
-序列化時忽略欄位5.@JsonIgnoreProperties
- 序列化時忽略某些欄位6.@JsonInclude
- 序列化時作用於滿足條件的7.@JsonFormat
- 設置格式,如日期時間等8.@JacksonInject
- 反序列化時註入到 java 對象9.@JsonCreator && @ConstructorProperties
- 反序列化時採用的構造方法10.@JsonSerialize && @JsonDeserialize
- 自定義序列化方法11.@JsonAnyGetter && @JsonANySetter
- 序列化對map欄位的處理12.@JsonNaming
- 序列化時輸出格式13.staic 和 transient 欄位
1.@JsonProperty
- 欄位命名
@JsonProperty
註解用於在序列化時按照給定的欄位名命名,在反序列化時,在 json 串中的註解欄位給該欄位設置屬性值。
下麵是註解的簡單示例:
package org.example;
import com.fasterxml.jackson.annotation.JsonProperty;
public class PersonProperty {
@JsonProperty("first_name")
private String firstName;
public PersonProperty() {
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
---
public static void jsonPropertyDemo() {
ObjectMapper objectMapper = new ObjectMapper();
PersonProperty pp = new PersonProperty();
pp.setFirstName("Alice");
String jsonString = null;
try {
jsonString = objectMapper.writeValueAsString(pp);
System.out.println("json property: " + jsonString);
} catch (Exception e) {
e.printStackTrace();
}
try {
PersonProperty pp1 = objectMapper.readValue(jsonString, PersonProperty.class);
System.out.println(pp1.getFirstName());
} catch (Exception e) {
e.printStackTrace();
}
}
---
2.@JsonPropertyOrder
- 欄位序列化順序
@JsonPropertyOrder
加在類上,用以規定數據序列化時欄位出現的順序。
package org.example;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
// {"name":"Bob","id":"111","age":25,"phone":"12345678910"}
@JsonPropertyOrder({"name", "id", "age", "phone"})
// 沒有定義順序,就按照字典序排列,{"age":25,"id":"111","name":"Bob","phone":"12345678910"}
// @JsonPropertyOrder(alphabetic = true)
public class PersonPropertyOrder {
private String id;
private String name;
private int age;
private String phone;
public PersonPropertyOrder() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
---
public static void jsonPropertyOrder() {
ObjectMapper objectMapper = new ObjectMapper();
PersonPropertyOrder ppo = new PersonPropertyOrder();
ppo.setAge(25);
ppo.setId("111");
ppo.setName("Bob");
ppo.setPhone("12345678910");
String jsonString = null;
try {
jsonString = objectMapper.writeValueAsString(ppo);
System.out.println("json property: " + jsonString);
} catch (Exception e) {
e.printStackTrace();
}
}
---
3.@JsonAlias
- 欄位別名,反序列化
在數據反序列化時,通過 @JsonAlias
註解來設置欄位的值,只要是 alias中的和欄位本身都可以正常反序列化。
package org.example;
import com.fasterxml.jackson.annotation.JsonAlias;
public class PersonAlias {
@JsonAlias({"firstName", "personName"})
private String name;
public PersonAlias() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
---
public static void jsonAlias() {
String jsonString1 = "{"name":"Bob"}";
String jsonString2 = "{"firstName":"Bob"}";
String jsonString3 = "{"personName":"Bob"}";
ObjectMapper objectMapper = new ObjectMapper();
try {
PersonAlias p1 = objectMapper.readValue(jsonString1, PersonAlias.class);
PersonAlias p2 = objectMapper.readValue(jsonString2, PersonAlias.class);
PersonAlias p3 = objectMapper.readValue(jsonString3, PersonAlias.class);
System.out.printf("p1: %s, p2: %s, p3: %s", p1.getName(),p2.getName(), p3.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
---
4.@JsonIgnore
-序列化時忽略欄位
@JsonIgnore
加在欄位上,用以在序列化時,忽略其,在反序列化時,僅賦值null。
package org.example;
import com.fasterxml.jackson.annotation.JsonIgnore;
public class PersonIgnore {
private String name;
@JsonIgnore // 不將其序列化,忽略該欄位
private String[] hobbies;
public PersonIgnore() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String[] getHobbies() {
return hobbies;
}
public void setHobbies(String[] hobbies) {
this.hobbies = hobbies;
}
}
---
public static void jsonIgnore() {
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = null;
try {
PersonIgnore pi = new PersonIgnore();
pi.setName("Cathy");
pi.setHobbies(null);
jsonString = objectMapper.writeValueAsString(pi);
System.out.println(jsonString);
} catch (Exception e) {
e.printStackTrace();
}
}
---
5.@JsonIgnoreProperties
- 序列化時忽略某些欄位
@JsonIgnoreProperties
加在類上,用於在序列化時,忽略給定的某些欄位。
package org.example;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties({"age"})
public class PersonIgnoreProperties {
private String name = "Alice";
private int age;
public PersonIgnoreProperties() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
---
public static void jsonIgnoreProperties() {
ObjectMapper objectMapper = new ObjectMapper();
PersonIgnoreProperties pip = new PersonIgnoreProperties();
pip.setName("Bob");
pip.setAge(18);
try {
String jsonString = objectMapper.writeValueAsString(pip);
System.out.println(jsonString);
} catch (Exception e) {
e.printStackTrace();
}
}
---
6.@JsonInclude
- 序列化時作用於滿足條件的
@JsonInclude
可以加在類上,也可以加在欄位上。該註解表示滿足某些條件(
NON_NULL,
NON_ABSENT,
NON_EMPTY,
NON_DEFAULT,
等)的才能序列化,e.g.如果加在類上,表示只要對象有null 就忽略該對象,加在欄位上,如果欄位是null,則忽略該欄位。
package org.example;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class PersonInclude {
private int id;
private String name;
@JsonInclude(JsonInclude.Include.NON_NULL)
private String[] hobbies;
public PersonInclude() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String[] getHobbies() {
return hobbies;
}
public void setHobbies(String[] hobbies) {
this.hobbies = hobbies;
}
}
---
public static void jsonInclude() {
ObjectMapper objectMapper = new ObjectMapper();
PersonInclude pi = new PersonInclude();
pi.setName("Cathy");
pi.setId(1111);
try {
String jsonString = objectMapper.writeValueAsString(pi);
System.out.println(jsonString);
} catch (Exception e) {
e.printStackTrace();
}
}
---
7.@JsonFormat
- 設置格式,如日期時間等
用於設置時間格式,或者是數字,或者是日期格式。
package org.example;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDate;
import java.util.Date;
public class PersonFormat {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss", timezone = "GMT+8")
private Date birthDate;
public PersonFormat() {
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
}
---
public static void jsonFormat() {
ObjectMapper objectMapper = new ObjectMapper();
PersonFormat pf = new PersonFormat();
pf.setBirthDate(new Date());
try {
String jsonString = objectMapper.writeValueAsString(pf);
System.out.println(jsonString);
} catch (Exception e) {
e.printStackTrace();
}
}
---
8.@JacksonInject
- 反序列化時註入到 java 對象
該註解用於在數據反序列化時將其他欄位註入進 Java對象。
package org.example;
import com.fasterxml.jackson.annotation.JacksonInject;
import java.time.LocalDate;
import java.time.LocalDateTime;
public class PersonInject {
private String name;
private int age;
@JacksonInject("responseTime")
private LocalDateTime responseTime;
public PersonInject() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public LocalDateTime getResponseTime() {
return responseTime;
}
public void setResponseTime(LocalDateTime responseTime) {
this.responseTime = responseTime;
}
}
---
public static void jsonInject() {
InjectableValues.Std iv = new InjectableValues.Std();
ObjectMapper objectMapper = new ObjectMapper();
iv.addValue("responseTime", LocalDateTime.now());
//將JSON字元串反序列化為java對象
String jsonString = "{"name":"Alice","age":23}";
objectMapper.setInjectableValues(iv);
try {
PersonInject pi = objectMapper.readValue(jsonString, PersonInject.class);
System.out.println(pi.getResponseTime());
} catch (Exception e) {
e.printStackTrace();
}
}
---
9.@JsonCreator && @ConstructorProperties
- 反序列化時採用的構造方法
@JsonCreator
用於在json數據反序列化到實例對象時採用哪個構造方法,同時搭配 @JsonProperty
註解用於相關屬性的。
package org.example;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
public class PersonCreator {
private String name;
private int age;
// 構造方法1
public PersonCreator(String name) {
this.name = name;
}
// 構造方法2
@JsonCreator // 用於反序列化時的處理
public PersonCreator(@JsonProperty("username") String name,
@JsonProperty("age") int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Test{" +
"name='" + name + ''' +
", age='" + age + ''' +
'}';
}
public static void main(String[] args) throws Exception {
String jsonString = "{"username": "Alice", "age": 18}"; // username -> name
ObjectMapper objectMapper = new ObjectMapper();
try {
PersonCreator pc = objectMapper.readValue(jsonString, PersonCreator.class);
System.out.println(pc);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@ConstructorProperties
也用於構造方法,但相比 @JsonCreator
的使用要簡單,可以認為 @ConstructorProperties = @JsonCreator + @JsonProperty
。
package org.example;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.beans.ConstructorProperties;
public class PersonConstructorProperties {
private String username;
private int age;
public PersonConstructorProperties(String username) {
this.username = username;
}
@ConstructorProperties({"name", "age"})
public PersonConstructorProperties(String username, int age) {
System.out.println("全參構造函數...");
this.username = username;
this.age = age;
}
@Override
public String toString() {
return "Test{" +
"username='" + username + ''' +
", age='" + age + ''' +
'}';
}
public static void main(String[] args) {
String jsonString = "{"name": "Bob", "age": 29}";
ObjectMapper objectMapper = new ObjectMapper();
try {
PersonConstructorProperties pcp = objectMapper.readValue(jsonString, PersonConstructorProperties.class);
System.out.println(pcp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
10.@JsonSerialize && @JsonDeserialize
- 自定義序列化方法
這兩個註解用於實現自定義的序列化和反序列化的處理,比如我們有個需求,需要將小數的某個欄位規定精確位數,為空時輸出空字元串。
@JsonSerialize
package org.example;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.IOException;
import java.math.RoundingMode;
import java.text.DecimalFormat;
public class PersonSerialize {
@JsonSerialize(using = CustomDoubleSerialize.class, nullsUsing = NullNumberSerialize.class)
private Double model;
@JsonSerialize(nullsUsing = NullNumberSerialize.class)
private Double business;
private String name;
public PersonSerialize() {
}
public Double getModel() {
return model;
}
public void setModel(Double model) {
this.model = model;
}
public Double getBusiness() {
return business;
}
public void setBusiness(Double business) {
this.business = business;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* Double保留4位小數,輸出string
*/
class CustomDoubleSerialize extends JsonSerializer<Double> {
private static final DecimalFormat df = new DecimalFormat("#.####");
@Override
public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
df.setRoundingMode(RoundingMode.HALF_UP); // 4
gen.writeString(df.format(value));
}
}
/**
* 任意類型null值,改為空字元串輸出
*/
class NullNumberSerialize extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString("");
}
}
---
public static void jsonSerialize() {
ObjectMapper objectMapper = new ObjectMapper();
PersonSerialize ps = new PersonSerialize();
ps.setName("Alice");
ps.setModel(1.2345678);
try {
String jsonString = objectMapper.writeValueAsString(ps);
System.out.println(jsonString); // {"model":"1.2346","business":"","name":"Alice"}
} catch (Exception e) {
e.printStackTrace();
}
}
---
@JsonDeserialize
package org.example;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
public class PersonDeserialize {
@JsonSerialize(using = LocalDatetimeSerialize.class)
@JsonDeserialize(using = LocalDatetimeDeserialize.class)
private LocalDateTime birthDate;
private String name;
public PersonDeserialize() {
}
public LocalDateTime getBirthDate() {
return birthDate;
}
public void setBirthDate(LocalDateTime birthDate) {
this.birthDate = birthDate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class LocalDatetimeSerialize extends JsonSerializer<LocalDateTime> {
static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException {
String str = value.format(DATE_FORMATTER);
gen.writeString(str);
}
}
class LocalDatetimeDeserialize extends JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
String str = p.getText();
return LocalDateTime.parse(str, LocalDatetimeSerialize.DATE_FORMATTER);
}
}
---
public static void jsonDeserialize() {
ObjectMapper objectMapper = new ObjectMapper();
PersonDeserialize pd = new PersonDeserialize();
pd.setName("Dav");
pd.setBirthDate(LocalDateTime.of(2000, 12, 5, 0, 0));
String jsonString = null;
// serialize
try {
jsonString = objectMapper.writeValueAsString(pd);
System.out.println(jsonString); // {"birthDate":"2000年12月5日 00:00:00","name":"Dav"}
} catch (Exception e) {
e.printStackTrace();
}
// deserialize
try {
PersonDeserialize pd1 = objectMapper.readValue(jsonString, PersonDeserialize.class);
// person -> name: Dav, birthdate: 2000-12-05T00:00
System.out.printf("person -> name: %s, birthdate: %s\n", pd1.getName(), pd1.getBirthDate());
} catch (Exception e) {
e.printStackTrace();
}
}
---
11.@JsonAnyGetter && @JsonANySetter
- 序列化對map欄位的處理
這兩個註解用於在序列化和反序列化時 map 結構的處理,具體說來:
- @JsonAnyGetter,加在 getField() 上,用於序列化時將此map欄位的鍵值對移至json中的鍵值對
- @JsonAnySetter,加在欄位上或者 setField() 都可以,加一個即可,用於反序列化時構造類實例,設置類實例屬性,將json中的非明確定義的鍵值對都設置到map結構的欄位中
package org.example;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import java.util.HashMap;
import java.util.Map;
public class PersonGetAndSet {
private String username;
private String pwd;
private int age;
// @JsonAnySetter // 加方法或者屬性都可以,但1個即可
private Map<String, String> map;
public PersonGetAndSet() {
this.map = new HashMap<>();
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@JsonAnyGetter // serialize, {"username":"Ada","pwd":"123456","age":26,"key1":"val1","key2":"val2"}
public Map<String, String> getMap() {
return map;
}
@JsonAnySetter // deserialize, pwd: 123456, age: 26, map: {key1=val1, key2=val2}
public void setMap(String key, String value) {
this.map.put(key, value);
}
}
---
public static void jsonGetterAndSetter() {
PersonGetAndSet pgs = new PersonGetAndSet();
pgs.setUsername("Ada");
pgs.setAge(26);
pgs.setPwd("123456");
pgs.setMap("key1", "val1");
pgs.setMap("key2", "val2");
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = null;
try {
jsonString = objectMapper.writeValueAsString(pgs);
System.out.println(jsonString);
} catch (Exception e) {
e.printStackTrace();
}
try {
PersonGetAndSet pgs1 = objectMapper.readValue(jsonString, PersonGetAndSet.class);
System.out.printf("person -> username: %s, pwd: %s, age: %d, map: %s\n", pgs1.getUsername(), pgs1.getPwd(), pgs1.getAge(), pgs1.getMap());
} catch (Exception e) {
e.printStackTrace();
}
}
---
12.@JsonNaming
- 序列化時輸出格式
@JsonNaming
加在類上,用以規範序列化時輸出的欄位鍵值的形式,主要有以下格式:
- SnakeCaseStrategy, 蛇形體, 如 first_name
- UpperCamelCaseStrategy, 大寫駝峰體,如 FirstName
- LowerCaseStratey, 小寫連體,如 firstname
- LowerDotCaseStratey, 小寫點分,如 first.name
package org.example;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
//@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class) // 蛇形體:{"first_name":"Matt","second_name":"Damon"}
//@JsonNaming(value = PropertyNamingStrategy.UpperCamelCaseStrategy.class) // {"FirstName":"Matt","SecondName":"Damon"}
//@JsonNaming(value = PropertyNamingStrategy.LowerCaseStrategy.class) // {"firstname":"Matt","secondname":"Damon"}
@JsonNaming(value = PropertyNamingStrategy.LowerDotCaseStrategy.class) // {"first.name":"Matt","second.name":"Damon"}
public class PersonNaming {
private String firstName;
private String secondName;
public PersonNaming() {
}
public PersonNaming(String firstName, String secondName) {
this.firstName = firstName;
this.secondName = secondName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getSecondName() {
return secondName;
}
public void setSecondName(String secondName) {
this.secondName = secondName;
}
public static void main(String[] args) {
PersonNaming pn = new PersonNaming();
pn.setFirstName("Matt");
pn.setSecondName("Damon");
ObjectMapper objectMapper = new ObjectMapper();
try {
String jsonString = objectMapper.writeValueAsString(pn);
System.out.println(jsonString);
} catch (Exception e) {
e.printStackTrace();
}
}
}
13.staic 和 transient 欄位
如果欄位屬性中有這兩個修飾符,則在序列化處理時忽略相關欄位。
參考: