【问题标题】:Jackson deserialization on multiple typesJackson 对多种类型的反序列化
【发布时间】:2015-12-22 09:15:10
【问题描述】:

我有一个名为 Instance 的抽象类,然后是它的两个实现,UserInstanceHardwareInstance。我遇到的问题是,当我将 @POST 的其余端点调用到数据库中时,我理想地希望它像 .../rest/soexample/instance/create 一样,其中实例被传递到 REST 端点。如果Instance 不是具有多个实现的抽象,那会很好,但由于我有 2 个,我会收到Jackson.databind 错误。

" 问题:抽象类型要么需要映射到具体类型,要么具有自定义反序列化器,要么使用额外的类型信息进行实例化"

在查找解决方案后,我找到了一个 SO 答案,说我可以使用类似的东西:

@JsonDeserialize(as=UserInstance.class)

但这似乎只有在抽象类有一个实现时才有用。假设我不能调用它两次,因为它无法决定它是哪种类型的实例。

所以我想知道处理这种情况的最佳方法是什么?我应该创建不同的端点吗?喜欢:

.../rest/soexample/userinstance/create & .../rest/soexample/hardwareinstance/create

我不太确定,因为我是一个与 REST 相关的菜鸟,尽管我在积极尝试学习。谢谢!

【问题讨论】:

  • 您可以为该抽象类编写一个自定义反序列化程序,它必须根据字段以编程方式解析 JSON,并将正文解析为您想到的任何具体类。
  • 感谢您的建议。我以前从未这样做过。我应该在哪里放置自定义解串器?就像我会从.../rest/soexample/instance/create 的端点内部调用它吗?
  • REST 是一种非特定类型的应用程序,它并不能告诉我您正在使用什么服务器/客户端技术。我用我想到的解决方案发现了一个与您类似的 SO 问题:stackoverflow.com/questions/8210538/… 我通常会将反序列化器作为您尝试反序列化的对象的公共静态内部类。

标签: java json rest jackson deserialization


【解决方案1】:

这是我在同一个案例中所做的:

@JsonDeserialize(using = InstanceDeserializer.class)
public abstract class Instance {
    //.. methods
}

@JsonDeserialize(as = UserInstance.class)
public class UserInstance extends Instance {
    //.. methods
}

@JsonDeserialize(as = HardwareInstance.class)
public class HardwareInstance extends Instance {
    //.. methods
}

public class InstanceDeserializer extends JsonDeserializer<Instance> {
    @Override
    public Instance deserialize(JsonParser jp,  DeserializationContext ctxt) throws IOException, JsonProcessingException {
        ObjectMapper mapper = (ObjectMapper) jp.getCodec();
        ObjectNode root = (ObjectNode) mapper.readTree(jp);
        Class<? extends Instance> instanceClass = null;
        if(checkConditionsForUserInstance()) {
            instanceClass = UserInstance.class;
        } else { 
            instanceClass = HardwareInstance.class;
        }   
        if (instanceClass == null){
            return null;
        }
        return mapper.readValue(root, instanceClass );
    }
}

您使用@JsonDeserialize(using = InstanceDeserializer.class) 注释Instance 以指示用于反序列化抽象类的类。然后你需要指出每个子类将自己反序列化as,否则他们将使用父类反序列化器,你将得到一个StackOverflowError

最后,在InstanceDeserializer 中,您将反序列化的逻辑放入一个或另一个子类(例如checkConditionsForUserInstance())。

【讨论】:

  • checkConditionsForUserInstance() 方法中的逻辑应该是什么?我们在 ctxt 中得到这个实例信息吗?
  • 不,这只是您自己区分要反序列化 de Json 的类的一种方法。
  • 此时,你必须有一些机制来区分与Json关联的具体类。如果子类像您说的那样不受您的控制,也许您应该向 Json 添加一个额外的强制参数,告诉您您需要的具体类。您也可以检查 @JsonTypeInfo 注释,但我认为它不适合您的场景。最终,虽然相当复杂,但您可以使用反射扫描接口的所有实现类,并匹配哪个具有与 Json 相同的字段,然后反序列化为那个。我想不出别的了。
  • 非常感谢!!我确实通过在我的界面顶部使用 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type") 解决了这个问题。它在 json 中添加了一个 type 字段来保存它,并在反序列化时使用该值。所以它完全按照你的建议做。
  • 最后一行不应该是return mapper.convertValue(root, instanceClass);
猜你喜欢
  • 2014-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-18
  • 1970-01-01
  • 2012-07-24
相关资源
最近更新 更多