【问题标题】:Cannot construct instance of - Jackson无法构造 - Jackson 的实例
【发布时间】:2012-09-26 20:54:41
【问题描述】:

我正在使用 Jackson,但遇到问题,当我尝试反序列化对象时,我收到以下错误:

com.fasterxml.jackson.databind.JsonMappingException: 
    Can not construct instance of net.MyAbstractClass, 
    problem: abstract types either need to be mapped to concrete types, 
        have custom deserializer, or be instantiated with additional type information

我的属性有问题:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT, property = "@id")
@JsonSubTypes({ @JsonSubTypes.Type(value = MyAbstractClass.class, name = "MyAbstractClass") })
@ManyToOne
private MyAbstractClass object;

谁能帮帮我?

【问题讨论】:

  • 另一个类似案例的讨论在stackoverflow.com/a/32777371/873282完成。特别有趣的是使用@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type") 的评论。那样的话,JSON 会大一些,但是很明确,应该使用哪种类型。

标签: java jackson


【解决方案1】:

你不能实例化一个抽象类,Jackson 也一样。 您应该向 Jackson 提供有关如何使用具体类型实例化 MyAbstractClass 的信息。

在 stackoverflow 上查看这个答案:Jackson JSON library: how to instantiate a class that contains abstract fields

也许还可以看到Jackson Polymorphic Deserialization

【讨论】:

  • 感谢您的帮助,我解决了:JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "class") property = "class",将在我的 JSON 中通知将使用哪个子类。
  • 注意,允许用户在反序列化过程中指定使用哪个类可能会导致this等漏洞。
  • 感谢您的参考:@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") 可以解决问题。就像 JPA 表标识符值一样。谢谢。
【解决方案2】:

反序列化时需要使用具体类而不是抽象类。 如果 Abstract 类有多个实现,那么在这种情况下,您可以按如下方式使用它 -

  @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes({ 
      @Type(value = Bike.class, name = "bike"), 
      @Type(value = Auto.class, name = "auto"), 
      @Type(value = Car.class, name = "car")
    })
    public abstract class Vehicle {
        // fields, constructors, getters, setters
    }

【讨论】:

  • 在这里为我工作。重要的是要提到Vehicle 有一个字段type,它将根据它定义的name 创建正确的对象。
  • 这对resteasy有效吗?对我来说 - 不是!
【解决方案3】:

您的@JsonSubTypes 声明没有意义:它需要列出实现(子)类,而不是类本身(这将毫无意义)。因此,您需要修改该条目以列出存在的子类;或者使用其他机制来注册子类(SimpleModule 有类似addAbstractTypeMapping 的东西)。

【讨论】:

    【解决方案4】:

    对我来说,没有为我尝试使用的 POJO 定义默认构造函数。创建默认构造函数修复了它。

    public class TeamCode {
    
        @Expose
        private String value;
    
        public String getValue() {
            return value;
        }
    
        **public TeamCode() {
        }**
    
        public TeamCode(String value) {
            this.value = value;
        }
    
        @Override
        public String toString() {
            return "TeamCode{" +
                    "value='" + value + '\'' +
                    '}';
        }
    
        public void setValue(String value) {
            this.value = value;
        }
    
    }
    

    【讨论】:

    • 也许添加一个可以帮助未来人们的例子?
    【解决方案5】:

    在您的具体示例中,问题在于您没有正确使用此构造:

    @JsonSubTypes({ @JsonSubTypes.Type(value = MyAbstractClass.class, name = "MyAbstractClass") })
    

    @JsonSubTypes.Type 应该包含抽象类的实际非抽象子类型。

    因此,如果您有:

    abstract class Parent 和具体的子类

    Ch1 extends ParentCh2 extends Parent

    那么你的注释应该是这样的:

    @JsonSubTypes({ 
              @JsonSubTypes.Type(value = Ch1.class, name = "ch1"),
              @JsonSubTypes.Type(value = Ch2.class, name = "ch2")
    })
    

    这里name 应该与您的“鉴别器”的值匹配:

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, 
    include = JsonTypeInfo.As.WRAPPER_OBJECT, 
    property = "type")
    

    property 字段中,这里等于type。所以type 将是键,而您在name 中设置的值将是值。

    所以,当json字符串来的时候,如果有这种形式:

    {
     "type": "ch1",
     "other":"fields"
    }
    

    Jackson 会自动将其转换为 Ch1 类。

    如果你发送这个:

    {
     "type": "ch2",
     "other":"fields"
    }
    

    你会得到一个Ch2 实例。

    【讨论】:

    • 很好的解释。必须输入 include = JsonTypeInfo.As.EXTERNAL_PROPERTY, 才能使它对我有用。
    • 这对resteasy有效吗?对我来说 - 不是!
    【解决方案6】:

    我在单独使用 lombok 的 @Data@Builder 注释时遇到了这个问题,我将其替换为:

    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    

    它解决了我的问题。

    【讨论】:

      【解决方案7】:

      使用 lombok 注释。

      @AllArgsConstructor
      @NoArgsConstructor
      @Builder
      @JsonPropertyOrder({"name", "id"})
      public class CreationUser {
          @Builder.Default
          @JsonProperty("name")
          String name = "";
      
          @Builder.Default
          @JsonProperty("id")
          String id = "";
      }
      

      【讨论】:

        【解决方案8】:

        使用@JsonDeserialize(contentAs= ConcreteCLass.class)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-04-21
          • 1970-01-01
          • 2018-07-29
          • 1970-01-01
          • 1970-01-01
          • 2021-07-17
          相关资源
          最近更新 更多