Джексон десериализует дочерний JSON в родительский атрибут - PullRequest
1 голос
/ 25 сентября 2019

Это мое требование.У меня ниже POJO.

class Car {
  private String brandName;
  private String color;
  private Model model;
}

class Model {
 private String modelName;
 private String year;
}

Если я получу ввод json, как показано ниже, то он должен быть де-сериализован и сопоставлен с обоими классами.

String json = "{\"brandName\" : \"Toyoto\", \"color\" : \"Silver\", \"model\" : {\"modelName\": \"Corolla\", \"year\": \"2019\"}}"
ObjectMapper mapper = new ObjectMapper();
Car car = mapper.readValue(json, Car.class);
assertEquals("Corolla", car.getModel().getModelName()); 

Этот случай в порядке.

Но если я передам дочерний JSON, это также должно работать без изменения класса отображения.

String json = "{\"modelName\": \"Corolla\", \"year\": \"2019\"}"
ObjectMapper mapper = new ObjectMapper();
Car car = mapper.readValue(json, Car.class);
assertEquals("Corolla", car.getModel().getModelName()); 

Любая идея, чтобы решить эту проблему

1 Ответ

1 голос
/ 25 сентября 2019

Вы можете реализовать свой собственный десериализатор для класса Car, например:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

import java.io.IOException;

/**
 * @author Ehsan Zaery Moghaddam (ezm@one.com)
 */
public class CarDeserializer extends StdDeserializer<Car> {

    public CarDeserializer() {
        this(null);
    }

    public CarDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public Car deserialize(JsonParser jp, DeserializationContext dctx)
            throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        Car c = new Car();
        Model cModel = new Model();

        if(node.has("brandName")) {
            //  the JSON string contains both car and model details
            c.setBrandName(node.get("brandName").asText());
            c.setColor(node.get("color").asText());

            JsonNode modelNode = node.get("model");
            cModel.setModelName(modelNode.get("modelName").asText());
            cModel.setYear(modelNode.get("year").asText());
        } else {
            // the JSON string just has model details
            cModel.setModelName(node.get("modelName").asText());
            cModel.setYear(node.get("year").asText());
        }

        c.setModel(cModel);

        return c;
    }
}

, и когда вы собираетесь вызывать API Джексона для фактической десериализации, зарегистрируйте свой десериализатор заранее:

String json = "{\"modelName\": \"Corolla\", \"year\": \"2019\"}";

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Car.class, new CarDeserializer());
mapper.registerModule(module);

Car car = mapper.readValue(json, Car.class);
assertEquals("Corolla", car.getModel().getModelName()); 

Это не требует изменения ваших POJO.Однако, если бы вы могли это сделать, у вас была возможность зарегистрировать свои собственные десериаллизаторы с помощью аннотации в вашем классе POJO, как показано ниже:

@JsonDeserialize(using = CarDeserializer.class)
public class Car { ... }
...