jackson
jackson 的使用
引入包
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.1</version>
</dependency>
创建需要序列化的对象
@Data
public class Student {
private String name;
private Integer age;
private Date birthday;
private LocalDateTime start;
}
序列化
public class jacksonTest {
private static ObjectMapper objectMapper = new ObjectMapper();
static {
// 设置JSON包含
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
@Test
void jacksonTest(){
Student student = new Student();
student.setAge(20);
student.setBirthday(new Date());
student.setStart(LocalDateTime.now());
objectMapper.writerWithDefaultPrettyPrinter()
}
}
处理NULL值
设置JSON是否包含null,有两种方式
全局方式
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
针对某一个类,使用注解
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Student {
private String name;
private Integer age;
private Date birthday;
private LocalDateTime start;
}
处理Date格式
针对一个属性
在Bean对象的属性上使用@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
注解
@Data
public class Student {
@JsonInclude(JsonInclude.Include.NON_NULL)
private String name;
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
private Date birthday;
@JsonFormat(pattern = "yyyyMMdd HH:mm:ss",timezone = "GMT+8")
private LocalDateTime start;
}
标记完运行发现LocalDateTime类型对应的start是没有被序列化成想要的字符串
需要引入一个jsr310的包,是jackson对LocalDateTime等jar8时间日期处理的Model 在jackson中是作为Model生效的,Model需要注册。
- 先引入jsr310的包
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.13.1</version>
</dependency>
- 注册
public class JasksonTest {
private static ObjectMapper objectMapper = new ObjectMapper();
static {
// 设置JSON包含
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 自动通过SPI发现jackson的modle并注册
objectMapper.findAndRegisterModules();
}
@Test
void jasksonTest() throws JsonProcessingException {
Student student = new Student();
student.setAge(20);
student.setBirthday(new Date());
student.setStart(LocalDateTime.now());
System.out.println(objectMapper.writeValueAsString(student));;
}
}
- 再次查看
LocalDateTime设置全局
public class JasksonTest {
private static ObjectMapper objectMapper = new ObjectMapper();
static {
// 设置JSON包含
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
JavaTimeModule javaTimeModule = new JavaTimeModule();
// 反序列化时使用
javaTimeModule.addDeserializer(LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss")));
// 序列化时使用
javaTimeModule.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss")));
objectMapper.registerModule(javaTimeModule);
}
@Test
void jasksonTest() throws JsonProcessingException {
Student student = new Student();
student.setAge(20);
student.setBirthday(new Date());
student.setStart(LocalDateTime.now());
System.out.println(objectMapper.writeValueAsString(student));;
}
}
查看
注意
LocalDateTime的时间格式是到yyyyMMdd HH:mm:ss的如果只是yyyyMMdd,反序列化会报错
Cannot deserialize value of type java.time.LocalDateTime
from String "20220124"
Date类型也可以但不建议使用 objectMapper.setDateFormat(new SimpleDateFormat("yyyyMMdd HH:mm:ss"));
SimpleDateFormat不是线程安全的,而ObjectMapper是线程安全的。这样设置导致ObjectMapper线程不安全。
美化输出
objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
反序列化
忽略不存在的key
objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES,false);
泛型
public class JasksonTest {
private static ObjectMapper objectMapper = new ObjectMapper();
static {
// 设置JSON包含
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// objectMapper.findAndRegisterModules();
JavaTimeModule javaTimeModule = new JavaTimeModule();
// // 反序列化时使用
javaTimeModule.addDeserializer(LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss")));
// // 序列化时使用
javaTimeModule.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss")));
objectMapper.registerModule(javaTimeModule);
// 美化输出
objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
// 反序列化时忽略不存在的key
objectMapper
.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES,false);
}
@Test
void jasksonTest() throws JsonProcessingException {
Student student = new Student();
student.setAge(20);
student.setBirthday(new Date());
student.setStart(LocalDateTime.now());
ResponseDataBase<Student> response = new ResponseDataBase<>();
response.setData(student);
response.successful();
String data = objectMapper.writeValueAsString(response);
System.out.println(data);
ResponseDataBase<Student> dataResult =
objectMapper
.readValue(data, new TypeReference<ResponseDataBase<Student>>() {});
System.out.println(dataResult.getData().toString());
}
}
定制
驼峰转下划线
设置策略 userName 转成 user_name 输出 // 蛇形命名法
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
指定属性名称
使用注解@JsonProperty("address")
指定忽略属性
使用注解@JsonIgnore
使用Jackson做对象更新
对象更新,对象的合并。如果后者属性有值,则用后者,否则的值不变。
@Test
void jasksonTest2() throws JsonProcessingException {
Student orgUser = new Student();
orgUser.setName("user1");
orgUser.setAge(20);
orgUser.setBirthday(new Date());
Student newUser = new Student();
newUser.setName("user1");
newUser.setAge(22);
Student student = objectMapper.updateValue(orgUser, newUser);
System.out.println(student.toString());
}
age值被更新
遇到匈牙利命名法如何使用jackson序列化
匈牙利命名法(Hungarian notation),由1972年至1981年在施乐帕洛阿尔托研究中心工作的-程序员 查尔斯·西蒙尼发明,这位前辈后面成了微软的总设计师。
这个命名法的特点是,在命名前面增加类型的前缀,就像这样:
- c_name - 姓名,字符串(Char)类型
- n_age - 年龄,数字(Number)类型
- t_birthday - 生日,日期/时间(Time)类型
可不要小看这个命名法,当年可是很流行的,而且直到今天还是有一些系统仍然在沿用这个命名标准,比如微软的 Win32 API
重构目标,是要保持老系统表不动的情况下,完全重写。新系统是 Java 语言来开发,Java 可是驼峰命名标准的,当这个匈牙利命名法的表迁移到驼峰命名法的 Java 语言会怎么样?
比如 c_name 这个命名,到 Java 里之后,是改为 CName 呢,还是 cName 呢?好像怎么都有点奇怪,不过最后还是选择了 CName ,将类型的前缀完全大写,至少看着稍微正常一点,没那么反人类
- c_name -> CName
- n_age -> NAge
- t_birthday -> TBirthday
Jackson 很强大,支持配置属性的获取方式,可以配置 Visibility
来实现只通过 Field
而不通过 getter
来获取属性:
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE)
public class Book {
private Integer NId = 1;
private String CName = "John";
}
全局配置更方便:
ObjectMapper objectMapper = new ObjectMapper();
// 配置 field 为可见
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
// 配置 getter 不可见
objectMapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
完~
#序列化