一尘不染

杰克逊对多种类型的反序列化

json

我有一个叫做抽象类Instance,然后两个是实现,UserInstanceHardwareInstance。我遇到的问题是,当我将a的其余端点调用@POST到数据库中时,理想情况下,我希望它像.../rest/soexample/instance/create将实例传递给REST端点的位置一样。如果Instance不是用一个以上的实现来抽象,那就没问题了,但是由于我有2个,所以我得到了一个Jackson.databind错误。

“问题:抽象类型要么需要映射到具体类型,要么具有自定义反序列化器,要么被其他类型信息实例化”

在找到解决方案之后,我找到了一个SO答案,说我可以使用类似以下内容的方法:

@JsonDeserialize(as=UserInstance.class)

但这似乎只有在抽象类的一种实现的情况下才有用。假设我不能两次调用它,因为没有办法让它决定实例的类型。

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

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

尽管我积极尝试学习,但我不太确定,因为我是与REST相关的noobie。谢谢!


阅读 221

收藏
2020-07-27

共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 );
    }
}

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

最后,在内部,InstanceDeserializer您将逻辑反序列化为一个或另一个子类(checkConditionsForUserInstance()例如)。

2020-07-27