简体   繁体   中英

Java dealing with two custom deserializers

so this is a very weird situation that I came across and have no idea how to handle.

I have a service that contains logic to deserialize an object from a request sent to it. Now the object in question is being changed and a new deserialization method is implemented to deal with that (don't ask why, all I know is we just need to change the method of deserialization).

The problem is that this change needs to be backwards compatible so we should be able to deal with both types of objects. In order to do this, we need to be able to determine the correct deserializer to use depending on the type of object but how do we do that if the object is serialized into a byte buffer? Im out of ideas... Is there a different/better way of going about this change?

The service is in Java.

Edit 1: Clearing up my intentions .
The old object used a custom serializer and the new one uses an ObjectMapper JSON serializer. So my goal is to be able to detect if I am dealing with the old or new object so I can deserialize accordingly.
I can try to use the new deserializer and catch the JsonParseException it throws and in the catch block, use the old serializer but this is not the way I want to handle a JsonParseException.

Serializable classes should have a serialVersionUID that is static, final, and of type long. This is to ensure that the class of the object that was serialized is same as the class of the object being deserialized.

In order to achieve backward compatibility follow these steps:

  1. Ensure that whenever class structure is changed, you change the value of this field.
  2. Use your new custom serializer to deserialize the object.
  3. If the object is of the previous class you will get an InvalidClassException . Catch this exception and try to deserialize that object with the legacy deserializer inside catch block.

This ensures that your custom deserializer has backward compatability.

First of all, you need to identify a difference between the new and the old object. You'll use that to switch to the old de-serializer.
You'll also need a specific ObjectMapper for these two classes, old and new.

Create a Module , and register it

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

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

Prepare the new StdDeserializer , which will accept as constructor argument the old one.

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

The old 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);
    }
}

Now, simply call

objectMapper.readValue(v, Object.class);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM