Home > Blockchain >  Custom jackson deserializer only for nested class
Custom jackson deserializer only for nested class

Time:03-07

I have a vehicle Java class defined like this:

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 is defined like this:

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

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

Now, the JSON I am getting, does not define latitude and longitude for the location (start and end); this information is encoded as just an array, see e.g.:

// 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" : [
      ]
}

How can I write a custom deserializer for just Location (same problem with TimeWindow) in that case? If possible, I do not want to write a custom deserializer for the whole Vehicle class.

I tried this:


@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);
    }

It seems to me, that I am getting the whole Vehicle passed into my deserialize method, not just the Location part. Am I doing something wrong here? Is this approach feasible using Jackson?

CodePudding user response:

You can add a constructor to Vehicle class using @JsonCreator tag and a Double[] for parameters start and end. You also need to add @JsonProperty tag to each parameter.

Here's an example, for simplicity I didn't include parameters time_window and breaks.

@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);
}

Test using the json in the question without parameters time_window and breaks:

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);

Output:

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