У меня есть запись 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"
}
Конечно, это возможно с помощью собственного сериализатора/десериализатора, но я ищу более простое решение, потому что у меня много разных классов с похожей проблемой.
@ernest_k Я добавил простой пример с конфигурацией по умолчанию ObjectMapper
.
Комбинация @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.InvalidDefinitionException: Invalid type definition for type `...$Aggregate`: Argument #0 of constructor [constructor for `...$Aggregate` (2 args), annotations: {interface [email protected].jackson.annotation.JsonCreator(mode=DEFAULT)} has no property name (and is not Injectable): can not use as property-based Creator
Я обновил ответ, чтобы он был более полным, если вы хотите, чтобы он работал в вашем случае, вы можете сделать это так или вам нужно забыть @JsonCreator
и добавить геттер / сеттер, тогда это может быть проще.
Спасибо за ответ и ссылки, теперь я лучше понимаю проблему. Вроде нет удобного решения, приходится идти на компромисс.
AggregateId
у меня не получается десериализоваться (ошибка пустых бобов, которая предположительно была устранена в jackson 2.12). Я что-то упускаю? Ваш код дает такой результат?