Как преобразовать плоский JSON в иерархический Java-класс? - PullRequest
0 голосов
/ 27 января 2019

Мне нужно десериализовать плоский объект JSON в объект Java с некоторыми свойствами, установленными для дочернего объекта.

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

Class Student {
  String name;
  Address address;
}

Class Address {
 String line1;
 String line2;
}

Как десериализовать мой JSON с использованием Джексона в Student объект?Я не могу отобразить addressLine1 to Student.Address.line1 и addressLine2 to Student.Address.line2

Ответы [ 4 ]

0 голосов
/ 27 января 2019

Вы можете определить свои классы данных следующим образом:

  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);
0 голосов
/ 27 января 2019

Вы можете использовать ObjectMapper следующим образом:

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

Но вы также должны изменить класс Student следующим образом со всеми реализованными методами получения и установки:

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

Тогда, если вы хотите, вы можете преобразовать это в новый класс, как вам нужно. Надеюсь, поможет.

0 голосов
/ 27 января 2019

РЕДАКТИРОВАТЬ: Пока мои решения работают, лучший ответ Селиндека

Ваш Json недействителен согласно https://jsonlint.com/ по 2 причинам:

  • Ваши имена полей не заключены в кавычки
  • У вас есть запятая после последней строки

Я приму этот 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 - Использование объекта Proxy (я бы предпочелвот этот)

Другой подход заключается в том, чтобы иметь прокси-класс, в котором вы можете десериализовать свой 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);
0 голосов
/ 27 января 2019

Прежде всего, убедитесь, что у вас есть 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());
}

Прямая десериализация в объекте класса будет означать, что класс и строка Json имеют одинаковые свойства.Которого здесь нет.Отсюда цикл с for и использование мутаторов.

Прочитайте this для получения более подробной информации

...