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

erp*_*erp 14 java rest json jackson deserialization

我有一个抽象类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

我不太确定,因为我是一个noobie @ REST相关的东西,虽然积极尝试学习.谢谢!

car*_*ret 24

以下是我在同一案例中所做的事情:

@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 );
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 最后一行不应该是`return mapper.convertValue(root,instanceClass);` (4认同)
  • 此时,您必须有一些机制来区分与Json关联的具体类.如果像你说的那样无法控制子类,也许你应该向Json添加一个额外的必需参数,告诉你你需要的具体类.您也可以检查`@JsonTypeInfo`注释,但我认为它不适合您的场景.最终,虽然非常复杂,但您可以使用反射扫描接口的所有实现类,并匹配哪个具有与Json相同的字段,然后反序列化为该字段.我想不出别的什么. (2认同)
  • 非常感谢!!我确实通过在我的界面上使用@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,include = JsonTypeInfo.As.PROPERTY,property ="type")解决了这个问题.它在json中添加了一个类型字段,并且在反序列化时使用该值.所以它完全按照你的建议行事. (2认同)