java - Jackson 将子 JSON 反序列化为父属性

标签 java json jackson mapping parent-child

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

有什么办法可以解决这个问题

最佳答案

您可以为 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 { ... }

关于java - Jackson 将子 JSON 反序列化为父属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58094462/

相关文章:

java - 如何在使用 iText 创建的 PDF 中显示阿拉伯语

json - 使用 API 测试进行 Typescript JSON 模式验证

java - 从 POJO 数组成员的字符串表示形式反序列化

java - Spring MVC 和 Jackson 映射不返回 json 中的根元素

在 Tomcat 上运行项目时 Spring Filter ClassCastException

java - 高效的 10 次方 x 算法

java - 使用 Jersey 的 ExceptionMapper 忽略 web.xml 错误页面

java - 使用java在中缀到后缀应用程序中获取错误输出

ios - 如何检查 connectionDidFinishLoading 何时完成

java - 如何命名Java变量 "public"