Java Jackson десериализует простой массив Json или объект Json в один объект Java (POJO)

Я получаю данные из конечной точки API, которая возвращает данные в двух разных ожидаемых форматах json. Один из ответов - это успешный ответ, а один из ответов - неудачный. Остальные конечные точки в API похожи и также имеют формат успеха и отказа. Для большинства конечных точек я просто десериализую оба типа ответов в один объект Java, где для некоторых полей просто устанавливаются значения по умолчанию / нулевые значения, если они отсутствуют. Моя проблема с этой конечной точкой заключается в том, что успешный ответ представляет собой массив json, а ответ сбоя - это объект json. Я перепробовал все, чтобы иметь простой способ десериализовать оба этих возможных ответа в один объект java.

Пример успеха json.

[
    {
        "item1": "somevalue1",
        "item2": "somevalue2"
    },
    {
        "item1": "somevalue3",
        "item2": "somevalue4"
    },
    ..
    ..
]

Пример ошибки json

{
    "success": false,
    "errorMessage": "something went wrong "
}

Мой класс Java, который я сейчас использую, работает для десериализации успешного json, но не для неудачного json.

public class ResponseObject {
    public final boolean success;
    public final String errorMessage;
    public final List<MyItem> items;

    @JsonCreator
    public ResponseObject(ArrayList<MyItem> items) {
       this.items = items;
    }

}

И у меня также есть конструктор, который работает в случае неудачи, но не в случае успеха.

public class ResponseObject {
    public final boolean success;
    public final String errorMessage;
    public final List<MyItem> items;

    @JsonCreator
    public ResponseObject(@JsonProperty("success") Boolean success, @JsonProperty("errorMessage") String errorMessage){
        this.success = success == null;
        this.errorMessage = errorMessage;
        this.items = items;
    }

}

Мой код десериализации выглядит примерно так

ObjectReader objectReader = objectMapper.readerFor(ResponseObject.class);
Object json = objectReader.readValue(inputStream);

Какая бы стратегия я ни пыталась десериализовать в обоих случаях, в целом кажется, что она терпит неудачу. Если я попытаюсь включить массив json в конструктор с помощью @JsonProperty, у меня нет имени / значения для ссылки на массив элементов, и код выдает исключение.

Что мне нужно, так это способ десериализации обоих ответов в формат ResponseObject, который я обрисовал, когда я получаю ответ об успехе, поле успеха должно быть истинным, errorMessage должно иметь значение null, а элементы должны содержать список MyItem. Когда я получаю ответ об ошибке, успех должен быть ложным, сообщение errorMessage должно содержать строковое сообщение, а список элементов должен быть пустым.

Как я могу этого добиться? Или как еще я могу структурировать свой код для обработки нескольких ожидаемых форматов json? Я знаю, что могу выполнить десериализацию в TreeMap, проверить формат и затем снова преобразовать, например, в конечный объект, но я бы хотел пропустить этот промежуточный шаг.

Спасибо за любой совет, который может дать мне кто-нибудь по этому поводу :)


person Nick    schedule 14.12.2018    source источник


Ответы (2)


Если вы добавите POJO для сообщения об ошибке, вы можете добавить второй JsonCreator в свой объект ответа.

public class ErrorResponse {
    private boolean success;
    private String errorMessage;
    public boolean isSuccess() {
        return success;
    }
    public void setSuccess(boolean success) {
        this.success = success;
    }
    public String getErrorMessage() {
        return errorMessage;
    }
    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }
}

Измененный ResponseObject с 2 JsonCreator

public class ResponseObject {
    public final boolean success;
    public final String errorMessage;
    public final List<MyItem> items;

    @JsonCreator
    public ResponseObject(List<MyItem> items) {
       this.success = true;
       this.errorMessage = null;
       this.items = items;
    }

    @JsonCreator
    public ResponseObject(ErrorResponse error){
        this.success = error.isSuccess();
        this.errorMessage = error.getErrorMessage();
        this.items = null;
    }

}
person pcoates    schedule 16.12.2018
comment
Это полностью решило мою проблему и исходный вопрос. :) оно работает. - person Nick; 18.12.2018

Вы можете попробовать сделать суперкласс

public class ResponseObject {

    public final boolean success;
    public final String errorMessage;
    public final List<MyItem> items;

    ...
}

а затем организуйте сообщения об ошибках и успехах в

public class SuccesResponseObject extends ResponseObject {...}

а также

public class FailResponseObject extends ResponseObject {...}

с соответствующими конструкторами. Свойства будут расположены в суперклассе. При использовании классов вы должны ссылаться на них как на принадлежность к классу ResponseObject.

person SBylemans    schedule 14.12.2018