如何将平面JSON转换为分层Java类?

时间:2019-01-27 07:32:15

标签: java json jackson jackson-databind

我需要将某些属性设置为子对象的平面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.line1                  和addressLine2 to Student.Address.line2

4 个答案:

答案 0 :(得分:3)

您可以通过以下方式定义数据类:

spring.datasource.url=jdbc:mysql://localhost:3306/db_name

spring.datasource.username=root
spring.datasource.password=

spring.datasource.testWhileIdle=true
spring.datasource.validationQuery = SELECT 1
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.show-sql=true

spring.jpa.hibernate.ddl-auto=update

spring.jpa.properties.hibernate.dialact=org.hibernate.dialact.MySQL5Dialact 

然后,您可以按通常的方式使用 public static class Student { String name; @JsonUnwrapped Address address; } public static class Address { @JsonProperty("addressLine1") String line1; @JsonProperty("addressLine2") String line2; } -无需任何其他技巧或解决方法:

Objectmapper

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

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

答案 1 :(得分:1)

编辑:当我的解决方案有效时,塞林德克的答案是最好的

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

  • 您的字段名称未加引号
  • 最后一行后面有一个逗号

我将使用带有未引用字段名称的JSON:

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

我可以想到2种方法:

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-使用代理对象(我希望使用该对象)

另一种方法是拥有一个代理类,您可以在其中反序列化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);

答案 2 :(得分:0)

在进行所有操作之前,请确保您的依赖项或库中有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和Json字符串具有完全相同的属性。这里不是cas。因此,for的循环和变量的利用。

阅读this了解更多详细信息

答案 3 :(得分:0)

您可以像这样使用ObjectMapper:

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

但是您还必须按如下所示修改Student类,并实现所有的getter和setter方法:

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

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