45

我想将 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);

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

4

4 回答 4

60

有多种方式;在 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解释了一些概念。

于 2011-03-31T17:13:59.380 回答
4

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

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

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

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

于 2017-07-03T20:30:25.557 回答
4

如果你不想用额外的字段污染你的 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);
于 2019-02-01T14:16:31.457 回答
2

该问题可以通过抽象类上的注释@JsonDeserialize 来解决,参考Jackson Exceptions Problems and Solutions https://www.baeldung.com/jackson-exception

于 2018-08-09T09:41:34.037 回答