杰克逊平 JSON class/record 一场

Flat JSON in Jackson for class/record with one field

我有一个只有一个字段的 Java 记录:

public record AggregateId(UUID id) {}

还有一个带有 AggregateId 字段的 class(为了便于阅读,删除了其他字段)

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));

我如何更改 Jackson 配置以将 JSON 替换为:

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

不放弃 AggregateId 的单独 class 并通过字段访问,没有 getters?

我尝试了 @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"
}

当然,可以使用自定义 serializer/deserializer,但我正在寻找更简单的解决方案,因为我有许多不同的 class 有类似问题。

目前还不支持@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 字段。

我们得到名称为 aggregateIdUUID 并创建一个 AggregateId 记录.

详细解释: