Jackson主要包含了3个模块:jackson-core、jackson-annotations、jackson-databind。有三种方式处理Json:1、使用底层的基于Stream的方式对Json的每一个小的组成部分进行控制。2、使用Tree Model,通过JsonNode处理单个Json节点。3、使用databind模块,直接对Java对象进行序列化和反序列化。通常来说,我们在日常开发中使用的是第3种方式。本文也是介绍第3种方式的序列化和反序列化。
依赖
com.fasterxml.jackson.core
jackson-core
com.fasterxml.jackson.core
jackson-annotations
com.fasterxml.jackson.core
jackson-databind
下面例子中所使用的对象:
@Data
@Accessors(chain = true)
public class EmployeeVo implements Serializable {
private Long id;
private String name;
private Short sex;
private Date birthday;
private String telephone;
private BigDecimal salary;
private Boolean isOfficial;
private String hobby;
public String getAbc() {
return "abc方法";
}
}
默认配置的对象序列化(ObjectMapper.writeValueAsString)
@Test
public void writeValueAsString() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
EmployeeVo employeeVo = new EmployeeVo();
employeeVo.setId(1000L)
.setName("haha")
.setBirthday(new Date())
.setSalary(new BigDecimal("19865.32"))
.setIsOfficial(true)
.setSex(new Short("0"))
.setTelephone("021-2546589");
System.out.println(objectMapper.writeValueAsString(employeeVo));
}
输出结果:
{"id":1000,"name":"haha","sex":0,"birthday":1592019533928,"telephone":"021-2546589","salary":19865.32,"isOfficial":true,"hobby":null,"abc":"abc方法"}
说明:
- 空值会输出null
- Date类型会输出时间戳
- 序列化依赖于getter方法,如果某个字段没有getter方法,那么该字段是不会被序列化的
- 通过getter的命名规约进行调用,若有getAbc()方法,没有abc属性则也会序列化输出"abc":""
默认配置的对象反序列化(ObjectMapper.readValue)
@Test
public void readValue() throws JsonProcessingException {
String jsonStr = "{\"id\":1000,\"name\":\"haha\",\"sex\":0,\"birthday\":1592013569703,\"salary\":19865.32,"isOfficial":true}";
ObjectMapper objectMapper = new ObjectMapper();
EmployeeVo employeeVo = objectMapper.readValue(jsonStr, EmployeeVo.class);
System.out.println(employeeVo);
}
输入出结果:
EmployeeVo(id=1000, name=haha, sex=0, birthday=Sat Jun 13 09:59:29 CST 2020, telephone=null, salary=19865.32, isOfficial=null, hobby=null)
说明:
- 时间戳可以反序列化成Date
- Long、String、Short、BigDecimal、Boolean类型默认都支持
常用配置
反序列化时忽略对象中不存在的json字段
假如对JSON字符串做反序列化时,JSON存在对象中没有属性,默认反序列化报错。如多了一个extra属性。
String jsonStr = "{\"id\":1000,\"name\":\"haha\",\"sex\":0,\"birthday\":1592013569703,\"salary\":19865.32,\"extra\":\"test123\"}";
报如下错误:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "extra" (class com.zmx.model.vo.EmployeeVo), not marked as ignorable (8 known properties: "hobby", "telephone", "isOfficial", "sex", "salary", "id", "birthday", "name"])
解决办法:
- 在EmployeeVo中添加extra属性(不可取)
- objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
- @JsonIgnoreProperties(ignoreUnknown = true) 用于类上,对于单个对象生效,而对于JSON字符串中存在的未知字段,在反序列化时忽略。
@JsonIgnoreProperties(ignoreUnknown = true)
public class EmployeeVo implements Serializable {
}
忽略字段
在序列化和反序列化时可以选择性让某些属性忽略,不会序列化也不会反序列化。
- @JsonIgnore 用于字段上,表示该字段在序列化和反序列化的时候都将被忽略。
@JsonIgnore
private String hobby;
- @JsonIgnoreProperties 主要用于类上。下面表示sex与birthday,反序列化和序列化均忽略
@JsonIgnoreProperties(value = {"sex", "birthday"})
null值属性序列化时优化处理
默认情况下序列化时,对NULL属性出成的JSON字符串会生成:"属性名":null。通过以下设置可以设置成不输出空值属性。
@JsonInclude(JsonInclude.Include.NON_NULL) 设置在类上面,对单个类生效。
@JsonInclude(JsonInclude.Include.NON_EMPTY),表示null和集合为空, @JsonInclude(JsonInclude.Include.NON_DEFAULT),表示为赋初值的情况(null,0,0.0,空集合,false);objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 设置在objectMapper上面,对objectMapper全局生效。
Date序列化和反序列化
- @JsonFormat (com.fasterxml.jackson.annotation.JsonFormat) 做用在类属性上面。
@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss",timezone = "GMT+8")
private Date birthday;
- 设置ObjectMapper.setDateFormat()
//去掉默认的时间戳格式
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//设置为东八区
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
//序列化时,日期的统一格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
对没有get,set方法的对象序列化和反序列化
@Test
public void writeValueAsString2() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
EmployeeVo employeeVo = new EmployeeVo();
employeeVo.setId(1000L).setName("haha").setBirthday(new Date()).setSalary(new BigDecimal("19865.32")).setIsOfficial(true).setSex(new Short("0"));
System.out.println(objectMapper.writeValueAsString(employeeVo));
}
结果:
{"id":1000,"name":"haha","sex":0,"birthday":1592029403004,"telephone":null,"salary":19865.32,"isOfficial":true,"hobby":null}
自己定义解析器
自定义序列化解析器
public class BigDecimalSerializer extends JsonSerializer {
@Override
public void serialize(BigDecimal bigDecimal, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
DecimalFormat decimalFormat = new DecimalFormat("#,##0.00");
jsonGenerator.writeString(decimalFormat.format(bigDecimal));
}
}
自定义反序列化解析器
public class BigDecimalDeSerializer extends JsonDeserializer {
@Override
public BigDecimal deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
DecimalFormat decimalFormat = new DecimalFormat("#,##0.00");
Number value = BigDecimal.ZERO;
try {
value = decimalFormat.parse(jsonParser.getText());
} catch (ParseException e) {
e.printStackTrace();
}
return new BigDecimal(value.longValue());
}
}
- 做用于局部类上面
@JsonSerialize(using = BigDecimalSerializer.class)
@JsonDeserialize(using = BigDecimalDeSerializer.class)
protected BigDecimal salary;
- 做用于全局
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(BigDecimal.class, new BigDecimalSerializer());
module.addDeserializer(BigDecimal.class, new BigDecimalDeSerializer());
objectMapper.registerModule(module);
其它配置
- @JsonIgnoreType 标注在类上,当该类作为其他类的属性时,该属性将被忽略。
- @JsonProperty 可以指定某个属性和json映射的名称。例如我们有个json字符串为{“user_name”:”aaa”},而java中命名要遵循驼峰规则,则为userName,这时通过@JsonProperty 注解来指定两者的映射规则即可。这个注解也比较常用。
- @JsonSetter 标注于 setter 方法上,类似 @JsonProperty ,也可以解决 json 键名称和 java pojo 字段名称不匹配的问题。
常用的ObjectMapper的设置
ObjectMapper objectMapper = new ObjectMapper();
//去掉默认的时间戳格式
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//设置为东八区
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
// 设置输入:禁止把POJO中值为null的字段映射到json字符串中
objectMapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
//空值不序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//反序列化时,属性不存在的兼容处理
objectMapper.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//序列化时,日期的统一格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//序列化日期时以timestamps输出,默认true
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//序列化枚举是以toString()来输出,默认false,即默认以name()来输出
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true);
//序列化枚举是以ordinal()来输出,默认false
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,false);
//类为空时,不要抛异常
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
//反序列化时,遇到未知属性时是否引起结果失败
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//单引号处理
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
//解析器支持解析结束符
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
参考于:
https://www.jianshu.com/p/af96d8a5769d
https://www.jianshu.com/p/67b6da565f81