如何将平面 JSON 转换为分层 java Class?

How to transform a flat JSON to hierarchical java Class?

我需要将平面 JSON 对象反序列化为 Java 对象,并将某些属性设置为子对象。

{
 "name": "abcd",
 "addressLine1": "123",
 "addressLine2": "1111"
}

Class Student {
  String name;
  Address address;
}

Class Address {
 String line1;
 String line2;
}

如何使用 Jackson 将我的 JSON 反序列化为 Student 对象? 我无法映射 addressLine1 to Student.Address.line1addressLine2 to Student.Address.line2

首先,确保你的依赖项或库中有 jackson-databind

您可以执行以下操作:

String jsonInput = // You JSON String here;
TypeReference<HashMap<String, String>> typeRef 
  = new TypeReference<HashMap<String, String>>() {};
Map<String, String> map = mapper.readValue(jsonInput, typeRef);

Student student = new Student();
Address address = new Address();

for (Map.Entry<String, String> entry : map.entrySet())
{
    if(((String)entry.getKey()).equals("addressLine1")){
    student.setName(map.get("name"));
    student.setAddress(map.get("addressLine1"));
    }

    if(((String)entry.getKey()).equals("addressLine2")){
    address.setLine1(map.get("addressLine1"));
    address.setLine2(map.get("addressLine2"));
    }
    //System.out.println(entry.getKey() + "/" + entry.getValue());
}

class 对象中的直接反序列化意味着 Class 和 Json 字符串具有完全相同的属性。这不是这里的cas。因此使用 for 进行循环并使用修改器。

阅读this了解更多详情

您可以像这样使用 ObjectMapper:

ObjectMapper objectMapper = new ObjectMapper();
Student student = objectMapper.readValue(json, Student.class);

但是您还必须如下修改 Student class 并实现所有 getter 和 setter:

Class Student{
    String name;
    String addressLine1;
    String addressLine2;
} 

然后,如果您愿意,可以根据需要将其重构为新的 class。希望能帮助到你。

编辑:虽然我的解决方案有效,但 Selindek 的回答是最好的

根据 https://jsonlint.com/,您的 Json 无效,原因有两个:

  • 您的字段名称未被引用
  • 你在最后一行后有一个逗号

我假设这个 JSON,字段名称不带引号:

{
    name: "abcd",
    addressLine1: "123",
    addressLine2: "1111"
}

我可以想到两种方法:

1 - 简单的地图处理

// Create your mapper, and configure it to allow unquoted field names
ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

// Parse the JSON to a Map
TypeReference<HashMap<String, String>> typeRef
        = new TypeReference<HashMap<String, String>>() {};
Map<String, String> jsonAsMap = null;
try {
    jsonAsMap = mapper.readValue(yourJsonString, typeRef);
} catch (Exception e) {
    System.out.println("Something went wrong:" + e.getMessage());
}


// Read the data from the map and build your objects
Student student = null;
if(jsonAsMap != null) {

    Address address = new Address();
    address.setLine1(jsonAsMap.get("addressLine1"));
    address.setLine2(jsonAsMap.get("addressLine2"));

    student = new Student();
    student.setName(jsonAsMap.get("name"));
    student.setAddress(address);

    System.out.println(student.getName());
    System.out.println(student.getAddress().getLine1());
    System.out.println(student.getAddress().getLine2());
}

2 - 使用代理对象(我更喜欢这个)

另一种方法是拥有一个代理 class,您可以在其中反序列化您的 JSON,并从中构建您的学生:

class RawStudent {
    private String name, addressLine1, addressLine2;

    public Student toStudent() {
        Address address = new Address();
        address.setLine1(addressLine1);
        address.setLine2(addressLine2);

        Student student = new Student();
        student.setName(name);
        student.setAddress(address);

        return student;
    }

    // GETTERS / SETTERS

}

并这样使用:

// Create your mapper, and configure it to allow unquoted field names
ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

// Parse the JSON to a RawStudent object
RawStudent rawStudent = null;
try {
    rawStudent = mapper.readValue(jsonUnquoted, RawStudent.class);
} catch (Exception e) {
    System.out.println("Something went wrong:" + e.getMessage());
}


// Read the data from the map and build your objects
Student student = null;
if (rawStudent != null) {

    student = rawStudent.toStudent();

    System.out.println(student.getName());
    System.out.println(student.getAddress().getLine1());
    System.out.println(student.getAddress().getLine2());
}

注意

如果您输入错误并且确实有引用字段,即:

{
    "name": "abcd",
    "addressLine1": "123",
    "addressLine2": "1111"
}

那么你不需要那行

mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

您可以这样定义数据类:

  public static class Student {
    String name;

    @JsonUnwrapped
    Address address;
  }

  public static class Address {
    @JsonProperty("addressLine1")
    String line1;
    @JsonProperty("addressLine2")
    String line2;
  }

然后您可以按常规方式使用 Objectmapper - 无需任何额外的魔法或解决方法:

Student student = mapper.readValue(json, Student.class);

如果您传入的 json 字符串确实是您提供的格式(不带引号),那么还要添加:

mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);