How to transform a flat JSON to hierarchical java Class?

北城余情 提交于 2019-12-23 21:30:01

问题


I need to deserialize a flat JSON object to a Java object with some properties set to child object.

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

Class Student {
  String name;
  Address address;
}

Class Address {
 String line1;
 String line2;
}

How do I deserialize my JSON using Jackson into a Student object? I am not able to map addressLine1 to Student.Address.line1 and addressLine2 to Student.Address.line2


回答1:


You can define your data classes this way:

  public static class Student {
    String name;

    @JsonUnwrapped
    Address address;
  }

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

Then you can use the Objectmapper in the usual way - without any additional magic or workaround :

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

If your incoming json string is indeed in the format you provided (without quotes) then also add:

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



回答2:


EDIT: While my solutions work, Selindek's answer is best

Your Json is not valid according to https://jsonlint.com/ for 2 reasons:

  • Your field names are not quoted
  • You have a comma after the last line

I will assume this JSON, with unquoted field names:

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

I can think of 2 approaches:

1 - Straightforward Map processing

// 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 - Using a Proxy object (I would prefer this one)

An other approach would be to have a proxy class in which you can deserialize your JSON, and build your student from it:

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

}

And use it this way:

// 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());
}

NOTE

If you mistyped and indeed have quoted fields, ie:

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

Then you don't need that line

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



回答3:


Prior everything, make sure you have jackson-databind in your dependencies or libraries.

Here is what you can do :

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());
}

Direct deserialization in a class object would mean the Class and the Json string have the exact same properties. Which is not the cas here. Hence the looping with for and the utilisation of mutators.

Read this for more details




回答4:


You can use ObjectMapper like this:

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

But you also have to modify the Student class as follows with all the getters and setters implemented:

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

Then if you want you can refactor this into a new class as you need. Hope it helps.



来源:https://stackoverflow.com/questions/54386011/how-to-transform-a-flat-json-to-hierarchical-java-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!