将平面 JSON 反序列化为复杂的 POJO

Deserialize flat JSON to complex POJO

我在 2.6.4 中使用 fasterxml 并通过我对给定输出没有影响的外部服务获得以下 JSON:

{
     "name": "dunnosName",
     "widthValue": 46.1,
     "heightValue": 56.1,
     "depthValue": 66.1,
     "unit": "mm"
}

并希望将其映射到以下 POJO:

public class Dunno {
    private String name;
    private ValueWithUnit width;
    private ValueWithUnit height;
    private ValueWithUnit depth;
}

public class ValueWithUnit {
    private Float value;
    private String unit;
}

我的例外映射应如下所示:

name -> Dunno.name

widthValue -> Dunno.width.value

heightValue -> Dunno.height.value

depthValue -> Dunno.depth.value

unit -> Dunno.width.unit

unit -> Dunno.height.unit

unit -> Dunno.depth.unit

是否可以使用fasterxml实现预期的映射?如果是这样,我必须实施哪些 fasterxml 注释或 类 才能实现此映射?

public class Dunno {
    private String name;
    private ValueWithUnit width;
    private ValueWithUnit height;
    private ValueWithUnit depth;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public ValueWithUnit getWidth() {
        return width;
    }

    public void setWidth(ValueWithUnit width) {
        this.width = width;
    }

    public ValueWithUnit getHeight() {
        return height;
    }

    public void setHeight(ValueWithUnit height) {
        this.height = height;
    }

    public ValueWithUnit getDepth() {
        return depth;
    }

    public void setDepth(ValueWithUnit depth) {
        this.depth = depth;
    }

    @Override
    public String toString() {
        return "Dunno{" +
                "name='" + name + '\'' +
                ", width=" + width +
                ", height=" + height +
                ", depth=" + depth +
                '}';
    }
}

public class ValueWithUnit {
    private Float value;
    private String unit;

    public ValueWithUnit(Float value, String unit) {
        this.value = value;
        this.unit = unit;
    }

    public Float getValue() {
        return value;
    }

    public void setValue(Float value) {
        this.value = value;
    }

    public String getUnit() {
        return unit;
    }

    public void setUnit(String unit) {
        this.unit = unit;
    }

    @Override
    public String toString() {
        return "ValueWithUnit{" +
                "value=" + value +
                ", unit='" + unit + '\'' +
                '}';
    }
}

public class TempDunno {
    private String name;
    private Float widthValue;
    private Float heightValue;
    private Float depthValue;
    private String unit;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Float getWidthValue() {
        return widthValue;
    }

    public void setWidthValue(Float widthValue) {
        this.widthValue = widthValue;
    }

    public Float getHeightValue() {
        return heightValue;
    }

    public void setHeightValue(Float heightValue) {
        this.heightValue = heightValue;
    }

    public Float getDepthValue() {
        return depthValue;
    }

    public void setDepthValue(Float depthValue) {
        this.depthValue = depthValue;
    }

    public String getUnit() {
        return unit;
    }

    public void setUnit(String unit) {
        this.unit = unit;
    }

    @Override
    public String toString() {
        return "TempDunno{" +
                "name='" + name + '\'' +
                ", widthValue=" + widthValue +
                ", heightValue=" + heightValue +
                ", depthValue=" + depthValue +
                ", unit='" + unit + '\'' +
                '}';
    }
}

public class Main {

    public static void main(String[] args) throws IOException {
        String json = "{\n" +
                "     \"name\": \"dunnosName\",\n" +
                "     \"widthValue\": 46.1,\n" +
                "     \"heightValue\": 56.1,\n" +
                "     \"depthValue\": 66.1,\n" +
                "     \"unit\": \"mm\"\n" +
                "}";

        System.out.println(getDunno(json));
    }

    private static Dunno getDunno(String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        TempDunno tmp = mapper.readValue(json, TempDunno.class);
        Dunno dunno = new Dunno();
        dunno.setName(tmp.getName());
        dunno.setHeight(new ValueWithUnit(tmp.getHeightValue(), tmp.getUnit()));
        dunno.setWidth(new ValueWithUnit(tmp.getWidthValue(), tmp.getUnit()));
        dunno.setDepth(new ValueWithUnit(tmp.getDepthValue(), tmp.getUnit()));
        return dunno;
    }
}

您不需要过渡 TempDunno。你需要一个Custom Deserializer。这是您将使用的教科书示例。将以下注释添加到 Dunno class:

@JsonDeserialize(using = DunnoDeserializer.class)

在这里,还有输入验证:

@SuppressWarnings("serial")
public class DunnoDeserializer extends StdDeserializer<Dunno>
{
    public DunnoDeserializer()
    {
        this(null);
    }

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

    @Override
    public Dunno deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException
    {
        Dunno dunno = new Dunno();
        // first parse the input into a map, which is more convenient to work with
        @SuppressWarnings("unchecked")
        Map<String, Object> values = jp.getCodec().readValue(jp, Map.class);
        dunno.name = values.containsKey("name") ? values.get("name").toString() : "empty";
        String unit = values.containsKey("unit") ? values.get("unit").toString() : "default-units";
        if (values.containsKey("widthValue")) {
            dunno.width = new ValueWithUnit();
            dunno.width.value = ((Number)values.get("widthValue")).floatValue();
            dunno.width.unit = unit;
        }
        if (values.containsKey("heightValue")) {
            dunno.height = new ValueWithUnit();
            dunno.height.value = ((Number)values.get("heightValue")).floatValue();
            dunno.height.unit = unit;
        }
        if (values.containsKey("depthValue")) {
            dunno.depth = new ValueWithUnit();
            dunno.depth.value = ((Number)values.get("depthValue")).floatValue();
            dunno.depth.unit = unit;
        }
        System.out.println(values);
        values.values().forEach(v -> System.out.println(v.getClass()));
        return dunno;
    }
}

测试方法:

public static void main(String[] args)
{
    String jsonString = "{ \"name\": \"dunnosName\"," + "\"widthValue\": 46.1," + "\"heightValue\": 56.1,"
            + "\"depthValue\": 66.1," + "\"unit\": \"mm\"}";

    ObjectMapper mapper = new ObjectMapper();
    try {
        Dunno d = (Dunno)mapper.readValue(jsonString, Dunno.class);
        System.out.format("%s: %.2f(%s) %.2f(%s) %.2f(%s)", 
                d.name, d.width.value, d.width.unit, d.height.value, d.height.unit, d.depth.value, d.depth.unit);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

给出预期输出:

dunnosName: 46.10(mm) 56.10(mm) 66.10(mm)