Вернуть JSON с парой ключ-значение

Я использую этот код для генерации ответа от конечной точки REST:

if (result.hasErrors()) {
            List<String> errorsList = new ArrayList<>();
            List<FieldError> errors = result.getFieldErrors();
            for (FieldError error : errors ) {
                System.out.println("Validation error in field: " + error.getObjectName() 
                               + "! Validation error message: " + error.getDefaultMessage() 
                               + "! Rejected value:" + error.getRejectedValue());
                errorsList.add(error.getField() + ": " + error.getDefaultMessage());
            }

            return ResponseEntity.ok(new StringResponseDTO(errorsList));
        }

Объект:

@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
@JsonTypeName("response")
public class StringResponseDTO {

    private String redirect;

    private List<String> errors;

    public StringResponseDTO(String redirect) {
        super();
        this.redirect = redirect;
    }

    public StringResponseDTO(List<String> errors) {
        this.errors = errors;
    }

    ......
}

Теперь я получаю этот ответ:

{
  "response" : {
    "errors" : [ "expiration_year: must not be null", "default_transaction_type: must not be null"]
  }
}

Мне нужно изменить это так:

{
      "response" : {
        "errors" : [ "expiration_year": "must not be null", "default_transaction_type": "must not be null"]
      }
    }

Есть ли способ заархивировать его, не добавляя много символов ""?

List<String> errors должен быть Map<String, String>, но он будет преобразован в объект, так как массивы json не поддерживают ключи
Iłya Bursov 02.04.2019 22:56
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
839
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Символы " — это кавычки, и они необходимы как часть спецификации JSON. Что касается того, почему ваш JSON находится в формате, который вам не нужен, это связано с вашим кодом здесь (а также с вашим соответствующим StringResponseDTO):

errorsList.add(error.getField() + ": " + error.getDefaultMessage());

Вы добавляете строки в список. Вместо этого вы хотите создать список объектов. Каждый объект будет содержать свойство и строковое значение.

То, что вы предложили, недействительно JSON:

{
  "response" : {
  "errors" : [ "expiration_year": "must not be null", "default_transaction_type": "must not be null"]
      }
}

Вместо этого вам нужен этот формат (обратите внимание на символы объекта {):

{
   "response" : {
   "errors" : [ {"expiration_year": "must not be null"}, {"default_transaction_type": "must not be null"}]
      }
}
Ответ принят как подходящий

Формат, который вы указали в результате «требуется», недействителен.
Что вы можете сделать, так это использовать классы Jackson (или GSON, в зависимости от используемой вами библиотеки), например

(Обратите внимание, objectMapper является экземпляром ObjectMapper)

public class StringResponseDTO {
    private String redirect;
    private TreeNode errors;

    public StringResponseDTO(final String redirect) {
        this.redirect = redirect;
    }

    public StringResponseDTO(final Collection<? extends FieldError> errors) {
        this.errors =
                errors.stream()
                      .collect(Collector.of(
                              objectMapper::createObjectNode,
                              (json, e) -> json.put(e.getField(), e.getDefaultMessage()),
                              (json, toMerge) -> {
                                  json.setAll(toMerge);
                                  return json;
                              }
                      ));
    }

    public String getRedirect() {
        return redirect;
    }

    public TreeNode getErrors() {
        return errors;
    }
}

Это будет сериализовано в

{
    "redirect": "...",
    "errors": {
        "field1": "err field1",
        "field2": "err field2",
        "field3": "err field3"
    }
}

Или, если хотите, обычное Map<String, String> решение.

public class StringResponseDTO {
    private String redirect;
    private Map<String, String> errors;

    public StringResponseDTO(final String redirect) {
        this.redirect = redirect;
    }

    public StringResponseDTO(final Collection<? extends FieldError> errors) {
        this.errors =
                errors.stream()
                      .collect(Collectors.toMap(
                              FieldError::getField,
                              FieldError::getDefaultMessage
                      ));
    }

    public String getRedirect() {
        return redirect;
    }

    public Map<String, String> getErrors() {
        return errors;
    }
}

Который выведет то же самое

{
    "redirect": "...",
    "errors": {
        "field1": "err field1",
        "field2": "err field2",
        "field3": "err field3"
    }
}

Тебе решать.

Я получаю: конструктор StringResponseDTO(Map<String,String>) не определен

Peter Penzov 02.04.2019 23:33

@PeterPenzov, где ты видишь этот конструктор?

LppEdd 02.04.2019 23:34

Коллекция @PeterPenzov означает, что вам все равно нужно пройти в List<FieldError>, а не в Map

LppEdd 02.04.2019 23:35

Я получаю эту ошибку в этой строке return ResponseEntity.ok(new StringResponseDTO(errorsList));

Peter Penzov 02.04.2019 23:36

@PeterPenzov см. комментарий выше (коллекция означает, что вам все еще нужно пройти в List<FieldError>, а не в Map)

LppEdd 02.04.2019 23:37

@PeterPenzov, кстати, удалите «final var objectMapper = new ObjectMapper();». Это был остаток.

LppEdd 02.04.2019 23:38

Другие вопросы по теме