多层次的类如何使用Jackson序列化/反序列化(Inheritance with Jackson)

Have a look at working with class hierarchies in Jackson.
如何在Jackson中使用类层次结构。

Inclusion of Subtype Information

There are two ways to add type information when serializing and deserializing data objects, namely global default typing and per-class annotations.

Global Default Typing

@Data
@AllArgsConstructor
@NoArgsConstructor
public abstract class Vehicle {
    
    
    private String make;
    private String model;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car extends Vehicle {
    
    
    private int seatingCapacity;
    private double topSpeed;

    public Car(String make, String model, int seatingCapacity, double topSpeed) {
    
    
        super(make, model);
        this.seatingCapacity = seatingCapacity;
        this.topSpeed = topSpeed;
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Truck extends Vehicle {
    
    
    private double payloadCapacity;
    public Truck(String make, String model, double payloadCapacity) {
    
    
        super(make, model);
        this.payloadCapacity = payloadCapacity;
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Fleet {
    
    
    private List<Vehicle> vehicles;
}
安全白名单
PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder()
        .allowIfSubType("javabasic.enumprac")
        .allowIfSubType("java.util.ArrayList")
        .build();
        
ObjectMapper mapper = new ObjectMapper();
mapper.activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.NON_FINAL);

Car car = new Car("Mercedes-Benz", "S500", 5, 250.0);
Truck truck = new Truck("Isuzu", "NQR", 7500.0);
List<Vehicle> vehicles = new ArrayList<>();
vehicles.add(car);
vehicles.add(truck);
Fleet serializedFleet = new Fleet();
serializedFleet.setVehicles(vehicles);

String jsonDataString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(serializedFleet);
System.out.println(jsonDataString);
[ "javabasic.enumprac.Fleet", {
    
    
  "vehicles" : [ "java.util.ArrayList", [ [ "javabasic.enumprac.Car", {
    
    
    "make" : "Mercedes-Benz",
    "model" : "S500",
    "seatingCapacity" : 5,
    "topSpeed" : 250.0
  } ], [ "javabasic.enumprac.Truck", {
    
    
    "make" : "Isuzu",
    "model" : "NQR",
    "payloadCapacity" : 7500.0
  } ] ] ]
} ]
String JSON= "[ \"javabasic.enumprac.Fleet\", {\n" +
        "  \"vehicles\" : [ \"java.util.ArrayList\", [ [ \"javabasic.enumprac.Car\", {\n" +
        "    \"make\" : \"Mercedes-Benz\",\n" +
        "    \"model\" : \"S500\",\n" +
        "    \"seatingCapacity\" : 5,\n" +
        "    \"topSpeed\" : 250.0\n" +
        "  } ], [ \"javabasic.enumprac.Truck\", {\n" +
        "    \"make\" : \"Isuzu\",\n" +
        "    \"model\" : \"NQR\",\n" +
        "    \"payloadCapacity\" : 7500.0\n" +
        "  } ] ] ]\n" +
        "} ]";
        
Fleet deserializedFleet = mapper.readValue(JSON, Fleet.class);
System.out.println(deserializedFleet);
Fleet(vehicles=[Car(seatingCapacity=5, topSpeed=250.0), Truck(payloadCapacity=7500.0)])

Per-Class Annotations

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.PROPERTY,
        property = "type")
@JsonSubTypes({
    
    
        @JsonSubTypes.Type(value = Car.class, name = "car"),
        @JsonSubTypes.Type(value = Truck.class, name = "truck")
})
@Data
@AllArgsConstructor
@NoArgsConstructor
public abstract class Vehicle {
    
    
    private String make;
    private String model;
}

其他model不变

Car car = new Car("Mercedes-Benz", "S500", 5, 250.0);
Truck truck = new Truck("Isuzu", "NQR", 7500.0);
List<Vehicle> vehicles = new ArrayList<>();
vehicles.add(car);
vehicles.add(truck);
Fleet serializedFleet = new Fleet();
serializedFleet.setVehicles(vehicles); 
ObjectMapper mapper = new ObjectMapper();
String jsonDataString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(serializedFleet);
System.out.println(jsonDataString);
{
    
    
  "vehicles" : [ {
    
    
    "type" : "car",
    "make" : "Mercedes-Benz",
    "model" : "S500",
    "seatingCapacity" : 5,
    "topSpeed" : 250.0
  }, {
    
    
    "type" : "truck",
    "make" : "Isuzu",
    "model" : "NQR",
    "payloadCapacity" : 7500.0
  } ]
}
Fleet deserializedFleet = mapper.readValue(jsonDataString, Fleet.class);
System.out.println(deserializedFleet);
Fleet(vehicles=[Car(seatingCapacity=5, topSpeed=250.0), Truck(payloadCapacity=7500.0)])

Ignoring Properties from a Supertype

Sometimes, some properties inherited from superclasses need to be ignored during serialization or deserialization. This can be achieved by one of three methods: annotations, mix-ins and annotation introspection.

Annotations

有两种常用的Jackson注释来忽略属性,它们是@JsonIgnore@JsonIgnoreProperties

@JsonIgnore directly applied to type members.
@JsonIgnoreProperties applied to type and type member.

@JsonIgnoreProperties is more powerful
it can ignore properties inherited from supertypes that we do not have control of.
it can ignore many properties at once.

@Data
@AllArgsConstructor
@NoArgsConstructor
public abstract class Vehicle {
    
    
    private String make;
    private String model;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties({
    
     "model", "seatingCapacity" })
public class Car extends Vehicle {
    
    
    private int seatingCapacity;
    @JsonIgnore
    private double topSpeed;

    public Car(String make, String model, int seatingCapacity, double topSpeed) {
    
    
        super(make, model);
        this.seatingCapacity = seatingCapacity;
        this.topSpeed = topSpeed;
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Crossover extends Car {
    
    
    private double towingCapacity;

    public Crossover(String make, String model, int seatingCapacity, double topSpeed, double towingCapacity) {
    
    
        super(make, model, seatingCapacity, topSpeed);
        this.towingCapacity = towingCapacity;
    }
}
@Data
@AllArgsConstructor
public class Sedan extends Car {
    
    
    public Sedan(String make, String model, int seatingCapacity, double topSpeed) {
    
    
        super(make, model, seatingCapacity, topSpeed);
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Fleet {
    
    
    private List<Vehicle> vehicles;
}
Sedan sedan = new Sedan("Mercedes-Benz", "S500", 5, 250.0);
Crossover crossover = new Crossover("BMW", "X6", 5, 250.0, 6000.0);
List<Vehicle> vehicles = new ArrayList<>();
vehicles.add(sedan);
vehicles.add(crossover);

ObjectMapper mapper = new ObjectMapper();
String jsonDataString = mapper.writeValueAsString(vehicles);

System.out.println(jsonDataString);
[{
    
    "make":"Mercedes-Benz"},{
    
    "make":"BMW","towingCapacity":6000.0}]

Mix-ins

Mix-ins allow us to ignoring properties when serializing and deserializing without the need to directly apply annotations to a class.
This is especially useful when dealing with third-party classes

@Data
@AllArgsConstructor
@NoArgsConstructor
public abstract class Vehicle {
    
    
    private String make;
    private String model;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car extends Vehicle {
    
    
    private int seatingCapacity;
    private double topSpeed;

    public Car(String make, String model, int seatingCapacity, double topSpeed) {
    
    
        super(make, model);
        this.seatingCapacity = seatingCapacity;
        this.topSpeed = topSpeed;
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Crossover extends Car {
    
    
    private double towingCapacity;

    public Crossover(String make, String model, int seatingCapacity, double topSpeed, double towingCapacity) {
    
    
        super(make, model, seatingCapacity, topSpeed);
        this.towingCapacity = towingCapacity;
    }
}
@Data
@AllArgsConstructor
public class Sedan extends Car {
    
    
    public Sedan(String make, String model, int seatingCapacity, double topSpeed) {
    
    
        super(make, model, seatingCapacity, topSpeed);
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Fleet {
    
    
    private List<Vehicle> vehicles;
}
 public static void main(String[] args) throws JsonProcessingException {
    
    
     ObjectMapper mapper = new ObjectMapper();
     mapper.addMixIn(Car.class, CarMixIn.class);
     Sedan sedan = new Sedan("Mercedes-Benz", "S500", 5, 250.0);
     Crossover crossover = new Crossover("BMW", "X6", 5, 250.0, 6000.0);
     List<Vehicle> vehicles = new ArrayList<>();
     vehicles.add(sedan);
     vehicles.add(crossover);
     String jsonDataString = mapper.writeValueAsString(vehicles);
     System.out.println(jsonDataString);
 }
 
 private abstract class CarMixIn {
    
    
     @JsonIgnore
     public String make;
     @JsonIgnore
     public String topSpeed;
 }
原始值:
[{
    
    "make":"Mercedes-Benz","model":"S500","seatingCapacity":5,"topSpeed":250.0},{
    
    "make":"BMW","model":"X6","seatingCapacity":5,"topSpeed":250.0,"towingCapacity":6000.0}]

ignore以后得值
[{
    
    "model":"S500","seatingCapacity":5},{
    
    "model":"X6","seatingCapacity":5,"towingCapacity":6000.0}]

Annotation Introspection

the most powerful method to ignore supertype properties since it allows for detailed customization using the AnnotationIntrospector.

class IgnoranceIntrospector extends JacksonAnnotationIntrospector {
    
    
    public boolean hasIgnoreMarker(AnnotatedMember m) {
    
    
        return m.getDeclaringClass() == Vehicle.class && m.getName() == "model"
                || m.getDeclaringClass() == Car.class
                || m.getName() == "towingCapacity"
                || super.hasIgnoreMarker(m);
    }
}
Sedan sedan = new Sedan("Mercedes-Benz", "S500", 5, 250.0);
Crossover crossover = new Crossover("BMW", "X6", 5, 250.0, 6000.0);
List<Vehicle> vehicles = new ArrayList<>();
vehicles.add(sedan);
vehicles.add(crossover);

ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new IgnoranceIntrospector());
String jsonDataString = mapper.writeValueAsString(vehicles);
System.out.println(jsonDataString);
[{
    
    "make":"Mercedes-Benz"},{
    
    "make":"BMW"}]

Subtype Handling Scenarios

Conversion Between Subtypes

Jackson allows an object to be converted to aother type object.
it is most helpful when used between two subtypes of the same interface or class to secure values and functionality.

@Data
@AllArgsConstructor
@NoArgsConstructor
public abstract class Vehicle {
    
    
    private String make;
    private String model;
}

在Car和Truck的属性上添加@JsonIgnore注释以避免不兼容

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car extends Vehicle {
    
    
    @JsonIgnore
    private int seatingCapacity;
    @JsonIgnore
    private double topSpeed;

    public Car(String make, String model, int seatingCapacity, double topSpeed) {
    
    
        super(make, model);
        this.seatingCapacity = seatingCapacity;
        this.topSpeed = topSpeed;
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Truck extends Vehicle {
    
    
    @JsonIgnore
    private double payloadCapacity;
    public Truck(String make, String model, double payloadCapacity) {
    
    
        super(make, model);
        this.payloadCapacity = payloadCapacity;
    }
}
Car car = new Car("Benz", "S500", 5, 250.0);
Truck truck1 = new Truck("Isuzu", "NQR", 7500.0);

ObjectMapper mapper = new ObjectMapper();

String s = mapper.writeValueAsString(car);
System.out.println(s);

String s1 = mapper.writeValueAsString(truck1);
System.out.println(s1);

Truck truck = mapper.convertValue(car, Truck.class);
System.out.println(truck);
{
    
    "make":"Benz","model":"S500"}
{
    
    "make":"Isuzu","model":"NQR"}
Truck(payloadCapacity=0.0)

Deserialization Without No-arg Constructors

默认情况下,Jackson通过使用无参数构造函数来重新创建数据对象。
By default, Jackson recreates data objects by using no-arg constructors.

In a class hierarchy where a no-arg constructor must be added to a class and all those higher in the inheritance chain. In these cases, creator methods come to the rescue.
Specifically, all no-arg constructors are dropped, and constructors of concrete subtypes are annotated with @JsonCreator and @JsonProperty to make them creator methods.

@Data
@AllArgsConstructor
@NoArgsConstructor
public abstract class Vehicle {
    
    
    private String make;
    private String model;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car extends Vehicle {
    
    
    private int seatingCapacity;
    private double topSpeed;

    @JsonCreator
    public Car(
            @JsonProperty("make") String make,
            @JsonProperty("model") String model,
            @JsonProperty("seating") int seatingCapacity,
            @JsonProperty("topSpeed") double topSpeed) {
    
    
        super(make, model);
        this.seatingCapacity = seatingCapacity;
        this.topSpeed = topSpeed;
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Truck extends Vehicle {
    
    
    private double payloadCapacity;
    @JsonCreator
    public Truck(
            @JsonProperty("make") String make,
            @JsonProperty("model") String model,
            @JsonProperty("payload") double payloadCapacity) {
    
    
        super(make, model);
        this.payloadCapacity = payloadCapacity;
    }
}
Car car = new Car("Mercedes-Benz", "S500", 5, 250.0);
Truck truck = new Truck("Isuzu", "NQR", 7500.0);
List<Vehicle> vehicles = new ArrayList<>();
vehicles.add(car);
vehicles.add(truck);
Fleet serializedFleet = new Fleet();
serializedFleet.setVehicles(vehicles);

ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
String jsonDataString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(serializedFleet);
System.out.println(jsonDataString);
Fleet fleet = mapper.readValue(jsonDataString, Fleet.class);
System.out.println(fleet);
{
    
    
  "vehicles" : [ "java.util.ArrayList", [ [ "javabasic.enumprac.prac.Car", {
    
    
    "make" : "Mercedes-Benz",
    "model" : "S500",
    "topSpeed" : 250.0,
    "seatingCapacity" : 5
  } ], [ "javabasic.enumprac.prac.Truck", {
    
    
    "make" : "Isuzu",
    "model" : "NQR",
    "payloadCapacity" : 7500.0
  } ] ] ]
}

Fleet(vehicles=[Car(seatingCapacity=5, topSpeed=250.0), Truck(payloadCapacity=7500.0)])

-----------------------------------------------------------------------------读书笔记摘自 文章:Inheritance with Jackson

猜你喜欢

转载自blog.csdn.net/weixin_37646636/article/details/132113961