【问题标题】:Provide custom object instance to Jackson without TypeInfo在没有 TypeInfo 的情况下向 Jackson 提供自定义对象实例
【发布时间】:2019-04-24 13:57:57
【问题描述】:

我正在尝试使用 Jackson 反序列化一些多态对象,但我不想在 JSON 中公开类型信息。所以,假设我们有“经典”动物场景:

public interface Animal {
    String talk();
}

public class Dog implements Animal {
    public String talk() { return "Woof!"; }
}

public class Cat implements Animal {
    public String talk() { return "Meow!"; }
}

我还有一个 Factory 接口和多个 Factory 实现:

public interface AnimalFactory {
    Animal newAnimal();
}

public class DogFactory implements AnimalFactory {
    public Animal newAnimal() { return new Dog(); }
}

public class CatFactory implements AnimalFactory {
    public Animal newAnimal() { return new Cat(); }
}

由于我不想通过在 JSON 中使用 @JsonTypeInfotype 参数来污染 JSON 的实现细节,所以我只知道两种选择:

  • Animal 上使用@JsonDeserialize(as = Dog.class),但这需要从API 到实现类的显式依赖;此外,它总是将 JSON 反序列化为 Dog,而我只想在运行时找到合适的具体实现,因为我不知道哪个具体实现可用;
  • 使用StdDeserializer 子类:
public class AnimalDeserializer extends StdDeserializer<Animal> {

    // Obtain through dependency injection or other mechanism
    private AnimalFactory animalFactory;

    public AnimalDeserializer() {
        this(null);
    }

    public AnimalDeserializer(Class<Animal> vc) {
        super(vc);
    }

    @Override
    public Animal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return animalFactory.newAnimal();
    }

这种方法可以让我在运行时定位实现,但它也需要我手动设置和获取任何字段,而不是依赖数据绑定(当然在这种特定情况下这将是微不足道的,但我的对象非常复杂而且我还有很多不同的接口,所以我真的需要依赖数据绑定)。

所以,我的问题是:我是否有另一种手动提供具体 Animal 实例的方法,然后让杰克逊执行其数据绑定魔术,而不是手动实现所有这些?作为参考,如果有人对 JAXB 有一定的经验,像 @XmlRegistry 这样我可以为给定接口指定工厂的东西会很棒。

谢谢!

编辑:可能不是很清楚,但我不想在 JSON 中放置 type 属性以进行反序列化,因为我不想在那里公开实现细节,所以 @JsonTypeInfo 不是不幸的是一个选项。

【问题讨论】:

    标签: java json jackson jackson-databind


    【解决方案1】:

    您可以使用@JsonTypeInfo@JsonSubtypes 自动支持多态性。

    @JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.PROPERTY,
        property = "type")
    @JsonSubTypes({
        @JsonSubTypes.Type(value = Cat.class, name = "cat"),
        @JsonSubTypes.Type(value = Dog.class, name = "dog")
    })
    
    public interface Animal {
        String talk();
    }
    

    【讨论】:

    • 但是这样我需要在我的 JSON 中添加一个 type 属性,如果你阅读了这篇文章,我首先要避免这种情况:) 编辑:我会无论如何,使帖子更清晰,感谢您的反馈
    猜你喜欢
    • 1970-01-01
    • 2014-04-04
    • 1970-01-01
    • 1970-01-01
    • 2013-02-18
    • 2023-03-05
    • 1970-01-01
    • 2012-10-06
    • 1970-01-01
    相关资源
    最近更新 更多