首页 > 解决方案 > 杰克逊中的多态反序列化为特定字段设置值 null

问题描述

问题陈述
是当我通过邮递员发送以下 JSON 时,要反序列化为以下给定 POJO 的 JSON 将 credentialType 的值设置为 null

{
"credential": [
    {
        "@type": "mobile",
        "credentialName": "cred-2",
        "email": "s@s.com"
    },
    {
        "@type": "card",
        "credentialNumber": "1"
    }
]

}

预期结果
我想要实现的是,对于上述 JSON,凭证类型应设置为 MobileCredentialDto 的 MOBILE 或 CardCredentialDto 的 CARD

@Getter

公共类 SecureDto {

private  List<CredentialDto> credential;

@JsonCreator
public HandoutDto(@JsonProperty("credential") final List<CredentialDto> credential) {
    this.credential = Collections.unmodifiableList(credential);
}

}

@Getter
public class SecureDto {

    private  List<CredentialDto> credential;

    @JsonCreator
    public HandoutDto(@JsonProperty("credential") final List<CredentialDto> credential) {
        this.credential = Collections.unmodifiableList(credential);
    }
}


@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
@JsonSubTypes({
        @JsonSubTypes.Type(value = CardCredentialDto.class, name = "card"),
        @JsonSubTypes.Type(value = MobileCredentialDto.class, name = "mobile"),
})
@Getter
@Setter
public class CredentialDto {
    private CredentialType credentialType;

    @JsonCreator
    public CredentialDto(@JsonProperty("credentialType") final String credentialType) {
        this.credentialType = CredentialType.valueOf(credentialType);
    }

    public CredentialDto() {

    }

      public void setCredentialType(final CredentialType credentialType) {
        this.credentialType = CredentialType.MOBILE;
    }
}

@Getter
@Setter
public class MobileCredentialDto extends CredentialDto {
    private String credentialName;
    private String email;

    public MobileCredentialDto(final String credentialId,
                               final String state,
                               final String credentialNumber,
                               final String credentialName,
                               final String email) {
        super(credentialId, state, credentialNumber, CredentialType.MOBILE.name());
        this.credentialName = credentialName;
        this.email = email;
    }

    public MobileCredentialDto() {

    }

    public String getCredentialName() {
        return credentialName;
    }

    public String getEmail() {
        return email;
    }
}


@Getter
@Setter
public class CardCredentialDto extends CredentialDto {

    public CardCredentialDto(final String credentialId,
                             final String state,
                             final String credentialNumber) {
        super(credentialId, state, credentialNumber,CredentialType.CARD.name());
    }

    public CardCredentialDto() {

    }
}

public enum CredentialType {
    MOBILE("MOBILE"),
    CARD("CARD");

    private final String name;

    CredentialType(final String name) {
        this.name = name;
    }
}

标签: javainheritancejackson

解决方案


我找到了答案。

我所做的是在 JsonTypeInfo 中设置了 visible = true。简而言之,通过设置 visible = true 允许杰克逊执行以下操作

关于类型标识符可见性的注意事项:默认情况下,类型标识符的反序列化(在读取 JSON 期间使用)完全由 Jackson 处理,并且不会传递给反序列化程序。但是,如果需要,可以定义属性 visible = true 在这种情况下,属性将在反序列化时按原样传递给反序列化器(并通过 setter 或字段设置)。

请参阅此处的文档以获得更多理解。 https://fasterxml.github.io/jackson-annotations/javadoc/2.4/com/fasterxml/jackson/annotation/JsonTypeInfo.html

下面是代码

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME , 
visible = true,
property = "credentialType")
@JsonSubTypes({
        @JsonSubTypes.Type(value = CardCredentialDto.class, name = "card"),
        @JsonSubTypes.Type(value = MobileCredentialDto.class, name = "mobile"),
})
@Getter
@Setter
public class CredentialDto {
   @JsonProperty(value = "credentialType")
    private CredentialType credentialType;

    @JsonCreator
    public CredentialDto(@JsonProperty("credentialType") final String credentialType) {
        this.credentialType = CredentialType.valueOf(credentialType);
    }

    public CredentialDto() {

    }

      public void setCredentialType(final CredentialType credentialType) {
        this.credentialType = CredentialType.MOBILE;
    }
}

json看起来像这样

{
    "credential": [
        {
            "credentialType": "mobile",
            "credentialName": "cred-2",
            "email": "s@s.com"
        },
        {
            "credentialType": "card",
            "credentialNumber": "1"
        }
    ]
}

推荐阅读