Плоский JSON в Джексоне для класса/записи с одним полем

У меня есть запись Java только с одним полем:

public record AggregateId(UUID id) {}

И класс с полем AggregateId (остальные поля удалены для удобочитаемости)

public class Aggregate {

    public final AggregateId aggregateId;

    @JsonCreator
    public Aggregate(
            @JsonProperty("aggregateId") AggregateId aggregateId
    ) {
        this.aggregateId = aggregateId;
    }
}

Реализация выше сериализует и десериализует JSON с данным примером:

ObjectMapper objectMapper = new ObjectMapper();
String content = """
        {
           "aggregateId": {
                "id": "3f61aede-83dd-4049-a6ff-337887b6b807"
            }
        }
        """;
Aggregate aggregate = objectMapper.readValue(content, Aggregate.class);
System.out.println(objectMapper.writeValueAsString(aggregate));

Как я могу изменить конфигурацию Джексона, чтобы заменить JSON на это:

{
    "aggregateId": "3f61aede-83dd-4049-a6ff-337887b6b807"
}

без отказа от отдельного класса для AggregateId и доступа через поля, без геттеров?

Я попробовал аннотацию @JsonUnwrapper, но это вызвало броски

Exception in thread "X" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
    Invalid type definition for type `X`: 
        Cannot define Creator parameter as `@JsonUnwrapped`: combination not yet supported at [Source: (String)"{
            "aggregateId": "3f61aede-83dd-4049-a6ff-337887b6b807"
        }"

или

Exception in thread "X" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
    Cannot define Creator property "aggregateId" as `@JsonUnwrapped`: 
        combination not yet supported at [Source: (String)"{
            "aggregateId": "3f61aede-83dd-4049-a6ff-337887b6b807"
        }"

Версия Джексона: 2.13.1

dependencies {
    compile "com.fasterxml.jackson.core:jackson-annotations:2.13.1"
    compile "com.fasterxml.jackson.core:jackson-databind:2.13.1"
}

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

AggregateId у меня не получается десериализоваться (ошибка пустых бобов, которая предположительно была устранена в jackson 2.12). Я что-то упускаю? Ваш код дает такой результат?
ernest_k 19.03.2022 13:31

@ernest_k Я добавил простой пример с конфигурацией по умолчанию ObjectMapper.

M. Dudek 19.03.2022 14:18
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
2
92
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Комбинация @JsonUnwrapped и @JsonCreator пока не поддерживается, поэтому мы можем сгенерировать такое решение:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.util.UUID;

public class AggregateTest {

    static record AggregateId(@JsonProperty("aggregateId") UUID id) {}

    static class Aggregate {

        @JsonUnwrapped
        @JsonProperty(access = JsonProperty.Access.READ_ONLY)
        public final AggregateId _aggregateId;
        public final String otherField;

        @JsonCreator
        public Aggregate(@JsonProperty("aggregateId") UUID aggregateId,
                         @JsonProperty("otherField") String otherField) {
            this._aggregateId = new AggregateId(aggregateId);
            this.otherField = otherField;
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        String rawJson =
            "{\"aggregateId\": \"1f61aede-83dd-4049-a6ff-337887b6b807\"," +
                    "\"otherField\": \"İsmail Y.\"}";
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        Aggregate aggregate = objectMapper
                .readValue(rawJson, Aggregate.class);
        System.out.println(objectMapper
                .writeValueAsString(aggregate));
    }
}

Здесь мы ненадолго избавимся от поля @JsonUnwrapped.

Мы получаем UUID с именем aggregateId и создаем AggregateId запись.

Подробные пояснения по этому поводу:

Ваш пример работает, когда у меня есть только поле AggregateId в Aggregate. Когда я добавляю другое поле, например public final String otherField у меня есть исключение: com.fasterxml.jackson.databind.exc.InvalidDefinitionExceptio‌​n: Invalid type definition for type `...$Aggregate`: Argument #0 of constructor [constructor for `...$Aggregate` (2 args), annotations: {interface [email protected].‌​jackson.annotation.J‌​sonCreator(mode=DEFA‌​ULT)} has no property name (and is not Injectable): can not use as property-based Creator

M. Dudek 19.03.2022 16:04

Я обновил ответ, чтобы он был более полным, если вы хотите, чтобы он работал в вашем случае, вы можете сделать это так или вам нужно забыть @JsonCreator и добавить геттер / сеттер, тогда это может быть проще.

İsmail Y. 19.03.2022 17:59

Спасибо за ответ и ссылки, теперь я лучше понимаю проблему. Вроде нет удобного решения, приходится идти на компромисс.

M. Dudek 19.03.2022 18:52

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