【问题标题】:Jackson JSON library: how to instantiate a class that contains abstract fieldsJackson JSON 库:如何实例化包含抽象字段的类
【发布时间】:2011-07-26 06:17:01
【问题描述】:

我想将 JSON 字符串转换为 java 对象,但该对象的类包含抽象字段,Jackson 无法实例化这些字段,并且不生成该对象。告诉它抽象类的某些默认实现的最简单方法是什么,例如

setDefault(AbstractAnimal.class, Cat.class);

或者根据 JSON 属性名来决定实现类,例如。对于 JSON 对象:

{
    ...
    cat: {...}
    ...
}

我只想写:

setImpl("cat", Cat.class);


我知道在 Jackson 中可以将类信息嵌入 JSON 中,但我不想使我使用的 JSON 格式复杂化。我想通过设置默认实现类或属性名称('cat')来决定使用哪个类 - 就像你在 XStream 库中编写的那样:

xStream.alias("cat", Cat.class);

有没有办法做到这一点,尤其是在一行中,还是需要更多代码?

【问题讨论】:

  • Java 中没有“抽象字段”之类的东西。
  • 我的意思是:class C { Animal animal; } 我想实例化 C,其中 Aniaml 是抽象的,我想在这个字段中放入一个扩展 Animal 的 Cat
  • 所以没有问题。没有规定变量是抽象类型。
  • 可以在 JSON 中嵌入类信息:@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type")。见 cmets stackoverflow.com/a/32777371/873282

标签: java json jackson deserialization


【解决方案1】:

如果你不想用额外的字段污染你的 JSON,也不想用注释污染你的类,你可以编写一个非常简单的模块和反序列化器,它使用你想要的默认子类。由于一些样板代码,它不止一行,但它仍然相对简单。

class AnimalDeserializer extends StdDeserializer<Animal> {
    public AnimalDeserializer() {
        super(Animal.class);
    }

    public Animal deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
        return jsonParser.readValueAs(Cat.class);
    }
}

class AnimalModule extends SimpleModule {
    {
        addDeserializer(Animal.class, new AnimalDeserializer());
    }
}

然后为 ObjectMapper 注册这个模块就可以了(Zoo 是具有 Animal 字段的容器类)。

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new AnimalModule());
return objectMapper.readValue(json, Zoo.class);

【讨论】:

  • 谢谢。拯救了我的一天。我有多个抽象类的实现,所以我不得不在自定义反序列化器中放置一个开关盒。
  • 模块的样板可以简化如下:objectMapper.registerModule(new SimpleModule().addDeserializer(Animal.class, new AnimalDeserializer()));
【解决方案2】:

这个问题可以通过抽象类上的注解@JsonDeserialize来解决 指杰克逊异常问题和解决方案 https://www.baeldung.com/jackson-exception

【讨论】:

    【解决方案3】:

    可以在此处找到带有非常清晰示例的完整答案:https://stackoverflow.com/a/30386694/584947

    Jackson 将此称为多态反序列化。

    它确实帮助我解决了我的问题。我有一个抽象类,我保存在数据库中,需要将其解组为类的具体实例(可以理解)。

    它将向您展示如何正确注释父抽象类,以及如何在解组时教杰克逊如何在运行时从可用的子类候选中进行选择。

    【讨论】:

      【解决方案4】:

      有多种方式;在 1.8 版本之前,最简单的方法可能是:

      @JsonDeserialize(as=Cat.class)
      public abstract class AbstractAnimal { ... }
      

      关于基于属性的决定,最好使用@JsonTypeInfo,它会自动嵌入(写入时)和使用类型信息。

      有多种类型信息(类名、逻辑类型名),以及包含机制(as-included-property、as-wrapper-array、as-wrapper-object)。此页面:https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization 解释了一些概念。

      【讨论】:

      • 注解也很不灵活,因为我无法动态决定我使用什么实现。
      • Wrt 修改类,这就是 Jackson 混合注释的用途。但正确的是,此注释仅用于只有一种实现类型的情况。 Jackson 1.8 将具有允许简单抽象类型 -> impl 类型映射的功能,这是值得的。
      • 混合注释完成了工作,感谢您指出正确的方向
      • 这只允许指定一个类?如果有 10 个呢?
      • 链接的 wiki 已关闭 - 新 URL 似乎是 github.com/FasterXML/jackson-docs/wiki/…
      猜你喜欢
      • 2015-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多