【问题标题】:Jackson deserialize child JSON to parent attributeJackson 将子 JSON 反序列化为父属性
【发布时间】:2020-01-25 09:56:04
【问题描述】:

这是我的要求。我有以下 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()); 

解决这个问题的任何想法

【问题讨论】:

    标签: java json jackson mapping parent-child


    【解决方案1】:

    您可以为 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
     */
    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;
        }
    }
    

    当您要调用 Jackson 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 { ... }
    

    【讨论】:

    • 感谢您的代码,虽然我之前想过这种方法,但我正在寻找一些更简单的方法,否则我需要像上面那样有很多自定义实现。
    猜你喜欢
    • 2012-08-19
    • 2013-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多