一、反序列化抛出UnrecognizedPropertyException异常
@Test
public void testDeserializeWithUnknownField() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module());
String jsonString = "{"name":"Alice","optionalAge":25,"unknownField":true}";
// 此处会抛出UnrecognizedPropertyException
OptionalField optionalField = mapper.readValue(jsonString, OptionalField.class);
System.out.println(optionalField.getName());
System.out.println(optionalField.getOptionalAge().get());
}
private static class OptionalField {
private String name;
private Optional<Integer> optionalAge;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Optional<Integer> getOptionalAge() {
return optionalAge;
}
public void setOptionalAge(Optional<Integer> optionalAge) {
this.optionalAge = optionalAge;
}
}
问题原因
Json字符串中包含的字段未在Java类型中声明
解决方案
第一种方式是设置忽略这种错误,对于整个ObjectMapper对象生效。
new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
第二种方式是在Java类型上表明忽略未知的字段,这种方式只对此Java类型生效。
@JsonIgnoreProperties(ignoreUnknown = true)
public class Person{
private String name;
private int age;
}
二、序列化排除字段
这个实际上是开发过程中经常遇到的一个场景,就是我们的Java类型序列化后的json字符串想不包括某些字段。 可以使用@JsonIgnore标记需要排除的字段,参考下面的代码。
@Test
public void testSerializeIgnoreField() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module());
OptionalField optionalField = new OptionalField();
optionalField.setName("Alice");
optionalField.setOptionalAge(Optional.of(25));
optionalField.setIgnoreField("ignore");
String jsonString = mapper.writeValueAsString(optionalField);
Assertions.assertFalse((jsonString.contains("ignore")));
}
@JsonIgnoreProperties(ignoreUnknown = true)
private static class OptionalField {
private String name;
private Optional<Integer> optionalAge;
@JsonIgnore
private String ignoreField;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Optional<Integer> getOptionalAge() {
return optionalAge;
}
public void setOptionalAge(Optional<Integer> optionalAge) {
this.optionalAge = optionalAge;
}
public String getIgnoreField() {
return ignoreField;
}
public void setIgnoreField(String ignoreField) {
this.ignoreField = ignoreField;
}
}
三、反序列化抽象字段类型
通过自定义反序列化器实现,参考下面的代码
public class Wrapper {
private Vehicle vehicle;
public Vehicle getVehicle() {
return vehicle;
}
public void setVehicle(Vehicle vehicle) {
this.vehicle = vehicle;
}
}
public abstract class Vehicle {
protected String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
public class Car extends Vehicle{
private String name;
private int age;
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 class Bicycle extends Vehicle{
private String name;
private BigDecimal weight;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getWeight() {
return weight;
}
public void setWeight(BigDecimal weight) {
this.weight = weight;
}
}
// 自定义反序列化器
public class VehicleDeserializer extends StdDeserializer<Vehicle> {
public VehicleDeserializer() {
this(null);
}
protected VehicleDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Vehicle deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JacksonException {
JsonNode node = jp.getCodec().readTree(jp);
String type = node.get("type").asText();
if ("car".equals(type)) {
return jp.getCodec().treeToValue(node, Car.class);
} else if ("bicycle".equals(type)) {
return jp.getCodec().treeToValue(node, Bicycle.class);
} else {
throw new IllegalArgumentException("Unknown vehicle type: " + type);
}
}
}
@Test
public void abstractFieldDeserializableTest() throws Exception{
String json = "{"vehicle":{"type":"car","name":"car","age":1}}";
ObjectMapper mapper = new ObjectMapper();
// 注册反序列化器
SimpleModule module = new SimpleModule();
module.addDeserializer(Vehicle.class, new VehicleDeserializer());
mapper.registerModule(module);
Wrapper wrapper = mapper.readValue(json, Wrapper.class);
Assertions.assertTrue(wrapper.getVehicle().type.equals("car"));
}