处理 Jackson 中的 InvalidTypeIdException。

huangapple go评论73阅读模式
英文:

handle InvalidTypeIdException with jackson

问题

以下是已翻译的内容:

这是一个使用@JsonType和@JsonSubTypes进行注释的基类,其中需要一个必填的“type”字段。

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", visible = true)
@JsonSubTypes(value = {
    @JsonSubTypes.Type(value = SubA.class, name = "A"),
    @JsonSubTypes.Type(value = SubB.class, name = "B")
})
public abstract class Base {
    private String type;

    public String getType()
    {
        return type;
    }

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

下面是一个将上述类封装并在控制器中使用的类。这个封装类已经带有需要传递给上面的Base类的“type”。

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
class BaseWrapper {
    @NotBlank
    private String type;
    @NotNull
    @Valid
    private Base base;
}

最后,在控制器中进行了验证。

@PostMapping("/createBase")
public ResponseEntity<ResponseDto> createBase(@RequestBody @Valid BaseWrapper)
{    
    // ...
}

下面是一个在Spring Boot中与控制器验证一起使用的示例JSON:

{
  "type":"A",
  "base": {
     "type":"A",
     //字段A的内容
  }
}

如何才能像下面这样从基类内部移除重复的type呢?这会导致Jackson抛出InvalidIdException

{
  "type":"A",
  "base": {
     //字段A的内容
  }
}

我理解使用自定义反序列化器是一种方法,但这样一来,默认执行的JsonTypeInfo、JsonSubTypeInfo和所有验证将不再生效,而且需要手动编写所有内容。

是否有办法修复重复的type字段,以便只传播外部的Json type给内部,让Jackson能够理解呢?

英文:

Here is Base class annotated with JsonType and JsonSubTypes with mandatory "type" field required.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = &quot;type&quot;, visible = true)
@JsonSubTypes(value = {
    @JsonSubTypes.Type(value = SubA.class, name = &quot;A&quot;),
    @JsonSubTypes.Type(value = SubB.class, name = &quot;B&quot;)
})
public abstract class Base {
    private String type;

    public String getType()
    {
        return type;
    }

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

There is below class which wraps above class and is used in controller. This wrapper class is taking "type" already which need to be passed to class Base above

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
class BaseWrapper {
    @NotBlank
    private String type;
    @NotNull
    @Valid
    private Base base;

}

Finally , validation are here in controller

@PostMapping(&quot;/createBase&quot;)
public ResponseEntity&lt;ResponseDto&gt; createBase(@RequestBody @Valid BaseWrapper)
{    
    ...
}

Sample JSON that works with controller validations in spring boot -

{
  &quot;type&quot;:&quot;A&quot;,
  &quot;base&quot;: {
     &quot;type:&quot;A&quot;,
     //fields of A
  }
}

How can the duplicate type be removed from inside base itself like below. this gives InvalidIdException from Jackson.

{
  &quot;type&quot;:&quot;A&quot;,
  &quot;base&quot;: {
     //fields of A
  }
}

I understand using Custom Deserializer is one way but then JsonTypeInfo, JsonSubTypeInfo and all validations being done by default does not apply and everything has to be hand-crafted.

Can the type required twice be fixed so that only outer Json type is propagated to inner and Jackson understands it ?

答案1

得分: 1

你可以使用 JsonTypeInfo.As.EXTERNAL_PROPERTY,但请注意来自 javadoc 的说明:

> 类似于 PROPERTY 的包含机制,不同之处在于属性在层次结构中包含得更高,即作为与 JSON 对象类型处于同一级别的同级属性。请注意,此选择只能用于属性,而不能用于类型(类)。尝试将其用于类将导致基本 PROPERTY 的包含策略。

因此,这将不适用于类级别,而适用于包装器中的属性。

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
@Setter
public static class BaseWrapper {
    @NotBlank
    private String type;

    @NotNull
    @Valid
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type", visible = true)
    @JsonSubTypes(value = {
            @JsonSubTypes.Type(value = SubA.class, name = "A"),
            @JsonSubTypes.Type(value = SubB.class, name = "B")
    })
    private Base base;
}
英文:

You can use JsonTypeInfo.As.EXTERNAL_PROPERTY but note from javadoc:

> Inclusion mechanism similar to PROPERTY, except that property is
> included one-level higher in hierarchy, i.e. as sibling property at
> same level as JSON Object to type. Note that this choice can only be
> used for properties, not for types (classes). Trying to use it for
> classes will result in inclusion strategy of basic PROPERTY instead.

So this will not work on class level but on property in wrapper

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
@Setter
public static class BaseWrapper {
    @NotBlank
    private String type;

    @NotNull
    @Valid
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = &quot;type&quot;, visible = true)
    @JsonSubTypes(value = {
            @JsonSubTypes.Type(value = SubA.class, name = &quot;A&quot;),
            @JsonSubTypes.Type(value = SubB.class, name = &quot;B&quot;)
    })
    private Base base;

}

huangapple
  • 本文由 发表于 2020年3月17日 02:46:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/60711622.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定