eskatos
eskatos

Reputation: 4464

How to write a catch-all (de)serializer for Jackson

Writing a custom serializer is pretty easy when you know the type in advance. For eg. MyType one can write a MyTypeSerializer extends StdSerializer<MyType>. See http://wiki.fasterxml.com/JacksonHowToCustomSerializers

But, let's say that:

  1. I have objects of several types (interfaces) going through Jackson serialization.
  2. I don't know the type of theses objets in advance.
  3. I can't add annotations on theses types.
  4. all theses objets can be cast to a common type I know so that I can get its state data, type that is not part of their interface.

This means I need to write a Serializer that should handle all types ("catch-all") and can decide if it supports it (4.). I've naïvely tried a CatchAllSerializer extends StdSerializer<Object> but it's not triggered at all.

How do one write/register a serializer that will catch all types, can decide if it support a given type and provide serialization mechanism?

Upvotes: 3

Views: 884

Answers (1)

Alexey Gavrilov
Alexey Gavrilov

Reputation: 10853

You can set a BeanSerializerModifier for the ObjectMapper to override all the bean serializers on your a delegating serializer that decides which form of serialization to use depending on the object type.

Here is an example:

public class JacksonSerializerModifier {
    public static interface A {

    }
    public static class B implements A {
        public String field1 = "value1";

        @Override
        public String toString() {
            return field1;
        }
    }
    public static class C implements A {
        public String field2 = "value2";

        @Override
        public String toString() {
            return field2;
        }
    }
    public static class D  {
        public String field3 = "value3";
    }

    private static class MyTypeSerializer extends JsonSerializer<Object> {
        private final JsonSerializer<Object> delegate;

        @SuppressWarnings("unchecked")
        public MyTypeSerializer(JsonSerializer<?> delegate) {
            this.delegate = (JsonSerializer<Object>) delegate;
        }

        @Override
        public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
                throws IOException {
            if (value instanceof A) {
                jgen.writeString(value.toString());
            } else {
                delegate.serialize(value, jgen, provider);
            }
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        SimpleModule module = new SimpleModule();
        module.setSerializerModifier(new BeanSerializerModifier() {
            @Override
            public JsonSerializer<?> modifySerializer(SerializationConfig config,
                                                      BeanDescription beanDesc,
                                                      JsonSerializer<?> serializer) {

                return new MyTypeSerializer(serializer);
            }
        });
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(module);
        System.out.println(mapper.writeValueAsString(Arrays.asList(new B(), new C(), new D())));
    }

}

Output:

["value1","value2",{"field3":"value3"}]

Upvotes: 2

Related Questions