Java 使用@JsonSubTypes反序列化以获得无值-缺少属性错误

Java 使用@JsonSubTypes反序列化以获得无值-缺少属性错误,java,json,jackson,Java,Json,Jackson,我将JSON反序列化如下: { "type":"a", "payload" : {...} } 其中有效负载类型取决于类型。我的班级: public class Sth<T extends Payload> { @JsonProperty("type") private String type; @Valid private T payload; @JsonTypeInfo( use = JsonTypeInfo.

我将JSON反序列化如下:

{
  "type":"a",
  "payload" : {...}
}
其中有效负载类型取决于类型。我的班级:

public class Sth<T extends Payload> {

    @JsonProperty("type")
    private String type;
    @Valid
    private T payload;

    @JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
        property = "type",
        visible = true,
        defaultImpl = NoClass.class)
    @JsonSubTypes({
        @JsonSubTypes.Type(value = APayload.class, name = "a"),
        @JsonSubTypes.Type(value = BPayload.class, name = "b"),
        @JsonSubTypes.Type(value = CPayload.class, name = "c")})
    public void setPayload(T payload) {
    this.payload = payload;
    }

    public void setType(String type) {
    this.type = type;
    }

}
它可以工作,但在没有有效载荷的情况下不工作:

{
  "type":"d",
}
如何使用最后一个示例使其工作

我得到的错误跟踪:

[error] Caused by: com.fasterxml.jackson.databind.JsonMappingException: Missing property 'payload' for external type id 'type
[error]  at [Source: N/A; line: -1, column: -1]
[error]     at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
[error]     at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:700)
[error]     at com.fasterxml.jackson.databind.deser.impl.ExternalTypeHandler.complete(ExternalTypeHandler.java:160)
[error]     at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeWithExternalTypeId(BeanDeserializer.java:690)
[error]     at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeWithExternalTypeId(BeanDeserializer.java:639)
[error]     at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:266)
[error]     at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:124)
[error]     at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:2965)
[error]     at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1587)
[error]     at com.fasterxml.jackson.databind.ObjectMapper.treeToValue(ObjectMapper.java:1931)
[error]     at play.libs.Json.fromJson(Json.java:47)

我相信我遇到了与您记录的相同的问题

我收到了以下异常

com.fasterxml.jackson.databind.JsonMappingException: Missing property 'content' 
  for external type id 'contentType
最后,我将注释添加到类型字段中,使其正常工作

public interface Content {
}

public class Post implements Content {
  public String content = "bar";
}

public class Foo {

  @JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
                include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
                property = "contentType")
  @JsonSubTypes({
    @JsonSubTypes.Type(value = Post.class, name = "post")
  })
  public Content content;

  @JsonTypeId
  public ContentType contentType;

  public enum ContentType {
    "post"
  }
}

我也遇到了这个问题,无法使用Jackson提供的机制(自定义
BeanDeserializer
BeanDeserializer
,等等)找到一个优雅的解决方案

它看起来像是外部类型ID处理方式中的一个bug。我通过以下方式解决了这个问题:

  • 将JSON字符串反序列化为
    JsonNode
  • 如果所需属性不存在,则手动插入
    null
    节点
  • JsonNode
    映射到我想要的值类型
  • 我的代码如下所示:

    public <T> T decode(String json, Class<T> type) throws IOException {
        JsonNode jsonNode = mapper.readTree(json);
    
        if (jsonNode.isObject() && (jsonNode.get("payload") == null  || jsonNode.get("payload").size() == 0)) {
            ObjectNode objectNode = (ObjectNode) jsonNode;
            objectNode.putNull("payload");
        }
    
        return mapper.treeToValue(jsonNode, type);
    }
    
    public T decode(字符串json,类类型)抛出IOException{
    JsonNode=mapper.readTree(json);
    if(jsonNode.isObject()&(jsonNode.get(“有效负载”)==null | | jsonNode.get(“有效负载”).size()=0)){
    ObjectNode ObjectNode=(ObjectNode)jsonNode;
    objectNode.putNull(“有效负载”);
    }
    返回mapper.treeToValue(jsonNode,type);
    }
    
    对此有明确的反序列化功能:

    new ObjectMapper().configure(
    DeserializationFeature.FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY, 
    false);
    

    我就是这么做的。我在Jackson论坛上问了同样的问题,AFAIK没有比这个更好的解决方案了。你错过了一个案子。当有效负载未设置或设置为{}时,Jackson无法正确反序列化对象,因此我编辑了您的答案并接受了它。@jasiustasiu您的编辑被拒绝了吗?你想更改什么?我不知道为什么我的编辑被拒绝。我再次编辑了你的答案,现在似乎有效了是的,我自己批准了。当你第一次编辑的时候,我不在,所以它被其他评论员拒绝了,可能是因为他们认为更改太大了。更改配置是一个很好的解决方案,但最好添加到应用程序属性中:
    spring.jackson.deserialization.FAIL\u ON\u MISSING\u EXTERNAL\u TYPE\u ID\u PROPERTY
    ,这是特定于spring引导的。如果您没有使用SpringBoot,您仍然需要配置对象映射器。
    new ObjectMapper().configure(
    DeserializationFeature.FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY, 
    false);