Как десериализировать json массив объектов как массив json строк? - PullRequest
2 голосов
/ 07 апреля 2020

Рассмотрим json input:

{
    companies: [
        {
            "id": 1,
            "name": "name1"
        },
        {
            "id": 1,
            "name": "name1"
        }
    ],
    nextPage: 2
}

Как десериализовать это в класс:

public class MyClass {
    List<String> companies;
    Integer nextPage;
}

Где List<String> companies; состоит из строк:

{"id": 1,"name": "name1"}
{"id": 1,"name": "name1"}

@JsonRawValue не работает для List<String> companies;

Есть ли способ настроить сериализацию Джексона для сохранения массива компаний с необработанной строкой json только с аннотациями? (Например, без написания кастомного десериализатора)

1 Ответ

0 голосов
/ 09 апреля 2020

Для вашей проблемы не существует решения только для аннотаций. Каким-то образом вам нужно конвертировать JSON Object в java.lang.String и вам нужно указать это преобразование.

Вы можете:

  1. Написать собственный десериализатор, который, вероятно, является наиболее очевидным решением, но запрещен в вопрос.
  2. Зарегистрируйте пользовательский com.fasterxml.jackson.databind.deser.DeserializationProblemHandler и обработайте ситуацию com.fasterxml.jackson.databind.exc.MismatchedInputException более сложным способом.
  3. Реализуйте интерфейс com.fasterxml.jackson.databind.util.Converter и преобразуйте JsonNode в String. Это полуаннотационный способ решения проблемы, но мы не реализуем худшую часть - десериализацию.

Давайте сразу же go до пункта 2.

2. DeserializationProblemHandler

Решение довольно простое:

ObjectMapper mapper = new ObjectMapper();
mapper.addHandler(new DeserializationProblemHandler() {
    @Override
    public Object handleUnexpectedToken(DeserializationContext ctxt, JavaType targetType, JsonToken t, JsonParser p, String failureMsg) throws IOException {
        if (targetType.getRawClass() == String.class) {
            // read as tree and convert to String
            return p.readValueAsTree().toString();
        }
        return super.handleUnexpectedToken(ctxt, targetType, t, p, failureMsg);
    }
});

Считать целый фрагмент JSON как TreeNode и преобразовать его в String, используя метод toString. Полезно, toString генерирует действительные JSON. Недостатком этого решения является глобальная область действия для данного ObjectMapper экземпляра.

3. Пользовательский конвертер

Это решение требует реализации интерфейса com.fasterxml.jackson.databind.util.Converter, который преобразует com.fasterxml.jackson.databind.JsonNode в String:

class JsonNode2StringConverter implements Converter<JsonNode, String> {
    @Override
    public String convert(JsonNode value) {
        return value.toString();
    }

    @Override
    public JavaType getInputType(TypeFactory typeFactory) {
        return typeFactory.constructType(new TypeReference<JsonNode>() {
        });
    }

    @Override
    public JavaType getOutputType(TypeFactory typeFactory) {
        return typeFactory.constructType(new TypeReference<String>() {
        });
    }
}

, и теперь вы можете использовать аннотацию, как показано ниже:

@JsonDeserialize(contentConverter = JsonNode2StringConverter.class)
private List<String> companies;

Решения 2. и 3. Решить эту проблему почти одинаково - прочитать узел и преобразовать его обратно в JSON, но использовать разные подходы.

Если вы хотите избежать десериализации и В процессе сериализации вы можете взглянуть на решение, предоставленное в этой статье: Десериализация JSON свойства как строки с Джексоном и взглянуть на:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...