Jackson之ObjectMapper常用用法
Jackson之ObjectMapper, 我全都要 🚋
- ObjectMapper的使用
- 基本使用
- 其他用法
- 自定义序列化和反序列化
- 运行时动态地修改类的序列化和反序列化行为
- 多态序列化和反序列化
- 转换
- 序列化和反序列化选项
- Jackson常用注解
- @JsonProperty
- @JsonIgnore
- @JsonFormat
- @JsonTypeInfo 和 @JsonSubTypes
- @JsonAlias
- @JsonRawValue
ObjectMapper的使用
基本使用
ObjectMapper 是 Jackson 序列化和反序列化 JSON 和 Java 对象的核心类,提供了许多用于定制序列化和反序列化的方法和配置选项。
以下是 ObjectMapper 的基本使用示例:
- 序列化示例:
// 创建 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 将 Java 对象序列化为 JSON 字符串
String jsonString = objectMapper.writeValueAsString(obj);
- 反序列化示例:
// 创建 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 将 JSON 字符串反序列化为 Java 对象
MyClass myObj = objectMapper.readValue(jsonString, MyClass.class);
其中,writeValueAsString
方法用于将 Java 对象序列化为 JSON 字符串,readValue
方法用于将 JSON 字符串反序列化为 Java 对象。这里的 MyClass
表示需要反序列化成的 Java 对象类型。
在进行序列化和反序列化时,ObjectMapper 会自动根据 Java 对象的属性和 JSON 的键值对进行映射,进行相应的转换。例如,Java 对象的属性名为 propertyName
,JSON 中的键名为 keyName
,则 ObjectMapper 会自动将它们进行对应,将 propertyName
的值序列化为 keyName
的值。
除了以上基本用法,ObjectMapper 还提供了很多其他的序列化和反序列化方法和配置选项,例如定制序列化规则、处理 JSON 中的日期格式、处理空值等等。
- 定制序列化规则
可以使用 Jackson 提供的注解来定制序列化规则,如 @JsonInclude、@JsonIgnore、@JsonProperty 等。也可以通过实现 JsonSerializer 接口来自定义序列化规则
- 处理 JSON 中的日期格式
可以使用 Jackson 提供的注解 @JsonFormat 来控制日期格式,也可以通过自定义序列化器来控制日期格式
- 处理空值
可以使用 Jackson 提供的注解 @JsonInclude 来控制序列化时是否包含空值,也可以通过配置 ObjectMapper 来控制是否包含空值
其他用法
自定义序列化和反序列化
注解:可以在类或属性上添加注解来自定义序列化和反序列化的行为,例如@JsonSerialize和@JsonDeserialize。
public class Person {
@JsonSerialize(using = CustomDateSerializer.class)
private Date birthday;
@JsonDeserialize(using = CustomDateDeserializer.class)
private Date registerTime;
// getters and setters
}
public class CustomDateSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
gen.writeString(sdf.format(value));
}
}
public class CustomDateDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateStr = p.getText();
try {
return sdf.parse(dateStr);
} catch (ParseException e) {
throw new IOException("Failed to parse date: " + dateStr, e);
}
}
}
运行时动态地修改类的序列化和反序列化行为
Mixin:通过Mixin机制,可以在运行时动态地修改类的序列化和反序列化行为。
public class Person {
private String name;
private int age;
// getters and setters
}
public interface PersonMixin {
@JsonProperty("full_name")
String getName();
@JsonIgnore
int getAge();
}
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixIn(Person.class, PersonMixin.class);
多态序列化和反序列化
多态:使用@JsonTypeInfo和@JsonSubTypes注解,可以支持多态序列化和反序列化。
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = Rectangle.class, name = "rectangle"),
@JsonSubTypes.Type(value = Circle.class, name = "circle")
})
public abstract class Shape {
// ...
}
public class Rectangle extends Shape {
// ...
}
public class Circle extends Shape {
// ...
}
ObjectMapper objectMapper = new ObjectMapper();
Shape rectangle = new Rectangle();
Shape circle = new Circle();
String rectangleJson = objectMapper.writeValueAsString(rectangle);
String circleJson = objectMapper.writeValueAsString(circle);
转换
转换:使用ObjectMapper的convertValue方法,可以将一个对象转换为另一个类型的对象。
public class Person {
private String name;
private int age;
// getters and setters
}
public class PersonDto {
private String name;
private int age;
// getters and setters
}
ObjectMapper objectMapper = new ObjectMapper();
Person person = new Person("John", 20);
PersonDto personDto = objectMapper.convertValue(person, PersonDto.class);
序列化和反序列化选项
ObjectMapper提供了许多序列化和反序列化选项,可以通过ObjectMapper的各种方法进行配置。例如,可以通过configure方法设置SerializationFeature和DeserializationFeature等选项
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
String json = objectMapper.writeValueAsString(person);
以下是一些常用的属性配置及其作用:
- SerializationFeature.WRITE_DATES_AS_TIMESTAMPS: 序列化日期时是否使用时间戳,默认为 true,即使用时间戳,设为 false 可以将日期格式化成字符串。
- SerializationFeature.FAIL_ON_EMPTY_BEANS: 序列化空对象时是否抛出异常,默认为 true。
- SerializationFeature.INDENT_OUTPUT: 是否缩进输出,默认为 false。
- SerializationFeature.WRITE_NULL_MAP_VALUES: 是否序列化 null 值属性,默认为 true。
- DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES: 反序列化时是否抛出异常,当遇到未知属性时,默认为 true。
- DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL: 是否将未知的枚举值反序列化成 null,默认为 false。
- DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT: 是否将空字符串反序列化成 null,默认为 false。
- JsonParser.Feature.ALLOW_COMMENTS: 是否允许 JSON 中包含注释,默认为 false。
- JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES: 是否允许 JSON 中的属性名不使用双引号包围,默认为 false。
除了上述常用的属性配置外,ObjectMapper 还提供了很多其他的配置选项,如时间格式化、空值处理、注解处理等,可以根据实际情况进行选择和定制化。
Jackson常用注解
Jackson 是一个用于序列化和反序列化 Java 对象与 JSON 数据的库,它提供了很多注解来定制序列化和反序列化的过程。以下是 Jackson 常用的注解及其作用:
- @JsonInclude:控制序列化时是否包含某些属性,用于过滤 null 值或默认值;
- @JsonIgnore:排除某些属性不参与序列化或反序列化;
- @JsonProperty:指定属性在序列化后的名称;
- @JsonFormat:控制日期、时间、数字等类型的序列化和反序列化格式;
- @JsonTypeInfo:支持多态序列化和反序列化;
- @JsonSubTypes:定义多态类型的子类;
- @JsonAlias:定义属性的别名,用于兼容不同版本的 JSON 数据格式;
- @JsonRawValue:将属性值作为原始 JSON 数据序列化。
这些注解可以在类、属性或者 getter/setter 方法上使用,以达到控制序列化和反序列化的效果。
@JsonProperty
这个注解用于将一个属性或方法序列化或反序列化为指定的名称。
例如,定义一个 Person 类:
public class Person {
@JsonProperty("name")
private String fullName;
private int age;
public Person(String fullName, int age) {
this.fullName = fullName;
this.age = age;
}
// getters and setters
}
在这个示例中,我们使用 @JsonProperty 注解将 fullName 属性序列化为 “name”,而不是默认的 “fullName”。
@JsonIgnore
这个注解用于忽略某个属性或方法,不进行序列化或反序列化。
例如,定义一个 Student 类:
public class Student {
private String name;
private int age;
@JsonIgnore
private String password;
public Student(String name, int age, String password) {
this.name = name;
this.age = age;
this.password = password;
}
// getters and setters
}
在这个示例中,我们使用 @JsonIgnore 注解忽略 password 属性,不进行序列化或反序列化。
@JsonFormat
这个注解用于指定日期、时间等属性的序列化和反序列化格式。
例如,定义一个 Order 类:
public class Order {
private String id;
private Date createTime;
public Order(String id, Date createTime) {
this.id = id;
this.createTime = createTime;
}
// getters and setters
}
在这个示例中,我们使用 @JsonFormat 注解指定 createTime 属性的序列化格式:
public class Order {
private String id;
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
private Date createTime;
public Order(String id, Date createTime) {
this.id = id;
this.createTime = createTime;
}
// getters and setters
}
在这个示例中,我们指定 createTime 属性的序列化格式为 “yyyy-MM-dd HH:mm:ss”,时区为 “GMT+8”
- @JsonInclude
这个注解用于指定序列化时包含哪些属性,排除哪些属性。
例如,定义一个 Book 类:
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Book {
private String title;
private String author;
private String isbn;
private Integer pages;
public Book(String title, String author, String isbn, Integer pages) {
this.title = title;
this.author = author;
this.isbn = isbn;
this.pages = pages;
}
// getters and setters
}
在这个示例中,我们使用 @JsonInclude 注解指定序列化时只包含非空属性,排除为 null 的属性。这个示例中,序列化时只包含 title、author、isbn 这三个属性。
@JsonTypeInfo 和 @JsonSubTypes
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "animalType")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public abstract class Animal {
private String name;
// getter and setter
}
public class Dog extends Animal {
private String breed;
// getter and setter
}
public class Cat extends Animal {
private boolean hasClaws;
// getter and setter
}
// 序列化
Animal dog = new Dog();
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(dog);
// 输出结果
{
"name":null,
"animalType":"dog",
"breed":null
}
// 反序列化
String json = "{\"name\":\"Lucy\",\"animalType\":\"dog\",\"breed\":\"Golden Retriever\"}";
Animal animal = mapper.readValue(json, Animal.class);
// 输出结果
Dog{name='Lucy', breed='Golden Retriever'}
在上面的例子中,使用了 @JsonTypeInfo 和 @JsonSubTypes 注解实现了多态序列化和反序列化。@JsonTypeInfo 用来指定类型信息的序列化和反序列化方式,使用 JsonTypeInfo.Id.NAME 表示使用名称作为类型标识,并通过 property 属性指定类型标识的属性名。@JsonSubTypes 用来指定具体的子类型,使用 @JsonSubTypes.Type 注解指定子类型的类和类型标识。
@JsonAlias
@JsonAlias 注解可以指定多个属性名称作为别名
反序列化时被用来匹配。如果匹配到任意一个别名,则该别名对应的属性值就会被赋值给当前属性
需要注意的是,如果同时存在多个别名匹配到了同一个属性,序列化以最后一个匹配到的别名对应的值为准
public class Person {
@JsonAlias({"name", "personName"})
private String name;
private int age;
// getter and setter
}
// 序列化
Person person = new Person();
person.setName("Tom");
person.setAge(20);
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(person);
// 输出结果
{"personName":"Tom","age":20}
// 反序列化
String json = "{\"name\":\"Lucy\",\"age\":18}";
Person person = mapper.readValue(json, Person.class);
// 输出结果
Person{name='Lucy', age=18}
在上面的例子中,使用了 @JsonAlias 注解来指定多个属性名的映射关系,用于序列化和反序列化。在序列化时,会使用注解中的任意一个属性名作为映射关系;在反序列化时,也会根据注解中的属性名进行映射
@JsonRawValue
@JsonRawValue注解表示一个属性值应该被直接写入JSON而不是被序列化为双引号中的字符串。它可以用于String属性或属性的getter方法上。使用这个注解需要注意安全问题,因为原始值不会被转义,可能会产生安全漏洞
假设有一个User类,其中有一个注解为@JsonRawValue的String类型属性。
public class User {
private String name;
@JsonRawValue
private String info;
public User(String name, String info) {
this.name = name;
this.info = info;
}
public String getName() {
return name;
}
public String getInfo() {
return info;
}
}
当我们序列化User对象时,info属性的值会直接被写入JSON中。