https://www.baeldung.com/jackson

class hierarchies in Jackson

Annotation used for configuring details of if and how type information is used with JSON serialization and deserialization, to preserve information about actual class of Object instances. This is necessarily for polymorphic types, and may also be needed to link abstract declared types and matching concrete implementation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@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
public abstract class Vehicle {
private String make;
private String model;
}

@EqualsAndHashCode(callSuper = true)
@Data
public class Car extends Vehicle {
private int seatingCapacity;
private double topSpeed;
}

@EqualsAndHashCode(callSuper = true)
@Data
public class Truck extends Vehicle {
private double payloadCapacity;
}

// test
static Stream<Arguments> vehicleProvider() {
Car car = new Car();
car.setMake("Mercedes-Benz");
car.setModel("S500");
car.setTopSpeed(250.0);
car.setSeatingCapacity(5);
Truck truck = new Truck();
truck.setMake("Isuzu");
truck.setModel("NQR");
truck.setPayloadCapacity(7500.0);
return Stream.of(
arguments(car, "car"),
arguments(truck, "truck")
);
}

@SneakyThrows
@ParameterizedTest
@MethodSource("vehicleProvider")
void testVehicleJson(Vehicle vehicle, String type) {
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(vehicle);
//{"type":"car","make":"Mercedes-Benz","model":"S500","seatingCapacity":5,"topSpeed":250.0}
//{"type":"truck","make":"Isuzu","model":"NQR","payloadCapacity":7500.0}
assertTrue(jsonStr.contains(type));
}