仅适用于嵌套 class 的自定义 jackson 解串器

Custom jackson deserializer only for nested class

我有一个 vehicle Java class 定义如下:

public final class Vehicle {

    private Integer id;
    private String description;
    private Location start;
    private Location end;
    private List<Integer> capacity;
    private List<Integer> skills;
    private TimeWindow timeWindow;
    private List<Break> breaks;

    public Vehicle(Integer id, String description, Location start,
                   Location end, List<Integer> capacity,
                   List<Integer> skills, TimeWindow timeWindow,
                   List<Break> breaks) {
        this.id = id;
        this.description = description;
        this.start = start;
        this.end = end;
        this.capacity = capacity;
        this.skills = skills;
        this.timeWindow = timeWindow;
        this.breaks = breaks;
    }

TimeWindow 定义如下:

public final class Location {
    private final Double latitude;
    private final Double longitude;

    public Location(Double latitude, Double longitude) {
        this.latitude = latitude;
        this.longitude = longitude;
    }

现在,我得到的 JSON 没有为位置定义 latitudelongitudestartend);此信息仅编码为一个数组,请参见例如:

// vehicle.json
{
      "id" : 0,
      "description" : "vehicle 0",
      "start" : [
        12.304373066846503,
        51.62270653765847
      ],
      "end" : [
        12.304373066846503,
        51.62270653765847
      ],
      "capacity" : [
        9
      ],
      "skills" : [
      ],
      "time_window" : [
        1644188400,
        1644274800
      ],
      "breaks" : [
      ]
}

在那种情况下,我如何才能为 Location(与 TimeWindow 有同样的问题)编写自定义反序列化器?如果可能的话,我不想为整个 Vehicle class.

编写自定义解串器

我试过这个:


@JsonDeserialize(
        using = LocationJsonDeserializer.class
)
public final class Location {
// ....

public class LocationJsonDeserializer extends JsonDeserializer<Location> {

    @Override
    public Location deserialize(JsonParser p, DeserializationContext ctxt) {

        final var longitude = 0d;
        final var latitude = 0d;

        // what to do here? 
        return new Location(latitude, longitude);
    }

在我看来,我正在将整个 Vehicle 传递到我的 deserialize 方法中,而不仅仅是 Location 部分。我在这里做错了什么吗?使用 Jackson 这种方法可行吗?

您可以使用 @JsonCreator 标记和 Double[] 参数 startend 将构造函数添加到 Vehicle class。您还需要为每个参数添加 @JsonProperty 标记。

这是一个示例,为了简单起见,我没有包含参数 time_windowbreaks

@JsonCreator
public Vehicle(@JsonProperty("id") Integer id, 
        @JsonProperty("description") String description,
        @JsonProperty("start") Double[] start, 
        @JsonProperty("end") Double[] end,
        @JsonProperty("capacity") List<Integer> capacity, 
        @JsonProperty("skills") List<Integer> skills) {
    this(id, description, new Location(start[0], start[1]), 
            new Location(end[0], end[1]), capacity, skills);
}

在没有参数 time_windowbreaks 的问题中使用 json 进行测试:

String result = "{\"id\":0,\"description\":\"vehicle 0\",\"start\":[12.304373066846503,51.62270653765847],\"end\":[12.304373066846503,51.62270653765847],\"capacity\":[9],\"skills\":[]}";

ObjectMapper mapper = new ObjectMapper();

Vehicle vehicle = mapper.readValue(result, Vehicle.class);

String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(vehicle);

System.out.println(json);

输出:

{
  "id" : 0,
  "description" : "vehicle 0",
  "start" : {
    "latitude" : 12.304373066846503,
    "longitude" : 51.62270653765847
  },
  "end" : {
    "latitude" : 12.304373066846503,
    "longitude" : 51.62270653765847
  },
  "capacity" : [ 9 ],
  "skills" : [ ]
}