Java处理两个自定义反序列化器

时间:2019-02-26 18:10:22

标签: java backwards-compatibility

这是我遇到的一个非常奇怪的情况,不知道如何处理。

我有一个服务,该服务包含用于从发送给它的请求中反序列化对象的逻辑。现在,正在讨论的对象正在更改,并且实现了一种新的反序列化方法来处理该问题(不要问为什么,我所知道的就是我们只需要更改反序列化方法即可)。

问题是此更改需要向后兼容,因此我们应该能够处理两种类型的对象。为此,我们需要能够根据对象的类型确定要使用的正确的反序列化器,但是如果将对象序列化为字节缓冲区,我们该怎么做呢?我没有主意...进行此更改是否有其他/更好的方法?

该服务使用Java。

编辑1:弄清我的意图
旧对象使用了自定义序列化程序,而新对象使用了ObjectMapper JSON序列化程序。因此,我的目标是能够检测到我是在处理旧对象还是新对象,以便可以进行反序列化。
我可以尝试使用新的反序列化器并捕获它抛出的JsonParseException,并在catch块中使用旧的序列化器,但这不是我要处理JsonParseException的方式。

2 个答案:

答案 0 :(得分:1)

可序列化的类应具有一个serialVersionUID,它是静态的,最终的且类型为long。 这是为了确保要序列化的对象的类与要反序列化的对象的类相同。

为了实现向后兼容,请执行以下步骤:

  1. 确保只要更改类结构,就可以更改此字段的值。
  2. 使用新的自定义序列化器反序列化对象。
  3. 如果对象属于上一类,则将获得 InvalidClassException 。捕获此异常,然后尝试使用catch块中的旧式解串器对该对象进行反序列化。

这可确保您的自定义解串器具有向后兼容性。

答案 1 :(得分:0)

首先,您需要确定新对象与旧对象之间的差异。您将使用它来切换到旧的反序列化器。
对于这两个新旧类,您还需要一个特定的ObjectMapper

创建一个Module,然后注册

final SimpleModule module = new SimpleModule();
module.addDeserializer(Object.class, new NewDeserializer(new OldDeserializer()));

final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);

准备新的StdDeserializer,它将接受旧的作为构造函数参数。

public class NewDeserializer extends StdDeserializer<Object> {
    private final StdDeserializer<Object> oldDeserializer;

    NewDeserializer(final StdDeserializer<Object> oldDeserializer) {
        super(NewObject.class);
        this.oldDeserializer = oldDeserializer;
    }

    @Override
    public Object deserialize(
            final JsonParser parser,
            final DeserializationContext context) throws IOException {
       final ObjectCodec codec = parser.getCodec();

       // Read the JSON document to a tree
       final TreeNode treeNode = codec.readTree(parser);

       // Identify if it is the new format, or the old one
       final TreeNode newField = treeNode.get("newField");

       if (newField == null) {
          // Delegate to the old de-serializer
          final JsonFactory factory = new JsonFactory(parser.getCodec());
          final JsonParser oldParser = factory.createParser(treeNode.toString());
          return oldDeserializer.deserialize(oldParser, context);
       }

       return codec.readValue(treeNode.traverse(), NewObject.class);
    }
}

旧的StdDeserializer

public class OldDeserializer extends StdDeserializer<Object> {
    OldDeserializer() {
        super(OldObject.class);
    }

    @Override
    public Object deserialize(
            final JsonParser parser,
            final DeserializationContext context) throws IOException {
        return parser.getCodec().readValue(parser, OldObject.class);
    }
}

现在,只需致电

objectMapper.readValue(v, Object.class);