Джексон Десериализовать список объектов в карту

У меня есть собственный десериализатор

@Override
public Map<String, Car<?, ?>> deserialize(JsonParser p, DeserializationContext ctxt)
        throws IOException, JsonProcessingException {

    JsonNode carsNode = p.getCodec().readTree(p);
    Map<String, Car<?, ?>> CarsMap = new HashMap<String, Car<?, ?>>();
    ObjectMapper mapper = new ObjectMapper();

    for (JsonNode node : carsNode) {
        CarsMap.put(node.get("name").asText(), mapper.readValue(node.asText(), Car.class));
    }
    return CarsMap;
}

Думал, что это не работает, потому что Car — это базовый класс, и на карте должны быть Map String, SubClasses of Cars)

Введите JSON = [{"name": "honda", "type": "Regular , "speed": 60}]

это должно быть на карте, например Map.put("honda", RegularCar.class)


person user3100209    schedule 25.11.2017    source источник
comment
Мне просто интересно, почему вы не десериализуете в список автомобилей, а затем в отдельном методе/классе преобразуете его в карту?   -  person Pulkownik    schedule 25.11.2017
comment
@Pulkownik У меня действительно проблемы с десериализацией автомобиля mapper.readValue(node.asText(), Car.class), похоже, это не работает   -  person user3100209    schedule 25.11.2017
comment
как выглядит ваш класс автомобиля? Вы используете @JsonDeserialize?   -  person Pulkownik    schedule 25.11.2017
comment
@Pulkownik очень просто, если я desrielaize, используя фактический пример типа mapper.readvalue(data, Regularcar.class), который работает, но не работает с базовым классом mapper.readValue(data, car.class)   -  person user3100209    schedule 25.11.2017
comment
Итак, вы должны прочитать здесь davismol.net/2015/03/05/ для работы с подклассами в jackson.   -  person Pulkownik    schedule 25.11.2017


Ответы (1)


Вы можете аннотировать базовый класс Car, чтобы указать Джексону, какие подклассы создавать в соответствии со значением поля "type" в JSON. Например, если у вас есть RegularCar и ClassicCar, расширяющие Car.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, 
    property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = RegularCar.class, name = "Regular"),
    @JsonSubTypes.Type(value = ClassicCar.class, name = "Classic")
})
class Car {

Это позволит вам разобрать так:

String json = "{\"name\": \"honda\", \"type\": \"Regular , \"speed\": 60}";
Car car = mapper.readValue(json, Car.class);

где Car car фактически указывает на экземпляр RegularCar. Поскольку контейнер объявлен как Map<String, Car<?, ?>> CarsMap, это именно то, что вы хотите put туда, а затем соответствующим образом отобразить то, что вы get из Map.

person Manos Nikolaidis    schedule 26.11.2017
comment
Я хотел бы сделать это без аннотации, потому что тогда я тесно связан с Джексоном. - person user3100209; 27.11.2017
comment
@user3100209 user3100209 вы можете заменить @JsonSubTypes на Module, который программно регистрирует подтипы. Вы также можете использовать смешанные аннотации, чтобы связать @JsonTypeInfo с базовым классом, не добавляя его непосредственно в этот класс. - person StaxMan; 17.04.2018