2

I want to change an object just before JSON Serialization. To do it, I've created an interface, with change method, and any class that implements this interface will "try" to change itself. (yes, probably doing it like this is not optimal, but for example sake will do)

@JsonSerialize(using = ChangesValuesSerializer.class)
public interface ChangesValues {
    void changeValues();
}

Now, is ChangesValuesSerializer class I'm implementing serialize method. And want to know, how can I say Jackson, to call it's built in serializer on object.

class ChangesValuesSerializer extends JsonSerializer<ChangesValues> {

    @Override
    public void serialize(ChangesValues changesValues, JsonGenerator jsonGenerator,
            SerializerProvider serializerProvider) throws IOException,
            JsonProcessingException {

        changesValues.changeValues();

        // ***
        // ->> Just call Jacksons default serializer
        // ***
    }

}
ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
David
  • 3,190
  • 8
  • 25
  • 31

2 Answers2

6

You can use BeanSerializerModifier to get the access to the default serializer and override it with your own delegate. Inside the delegate you can change your serialised object and call the default serializer. Here is an example:

public class JacksonSerializeModifier {
    public static class Bean {
        public final String value;

        public Bean(final String value) {
            this.value = value;
        }

        public void foo() {
            System.out.println("foo() invoked");
        }
    }

    private static class MyBeanSerializerModifier extends BeanSerializerModifier {
        @Override
        public JsonSerializer<?> modifySerializer(
                final SerializationConfig serializationConfig,
                final BeanDescription beanDescription,
                final JsonSerializer<?> jsonSerializer) {
            return new ModifyingSerializer((JsonSerializer<Object>) jsonSerializer);
        }
    }

    private static class ModifyingSerializer extends JsonSerializer<Object> {
        private final JsonSerializer<Object> serializer;

        public ModifyingSerializer(final JsonSerializer<Object> jsonSerializer) {
            this.serializer  = jsonSerializer;
        }

        @Override
        public void serialize(
                final Object o,
                final JsonGenerator jsonGenerator,
                final SerializerProvider serializerProvider)
        throws IOException {
            if (o instanceof Bean) {
                ((Bean) o).foo();
            }
            serializer.serialize(o, jsonGenerator, serializerProvider);
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        SimpleModule module = new SimpleModule();
        module.setSerializerModifier(new MyBeanSerializerModifier());
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(module);
        System.out.println(mapper.writeValueAsString(new Bean("abc")));
    }
}

Output:

foo() invoked
{"value":"abc"}
Alexey Gavrilov
  • 10,593
  • 2
  • 38
  • 48
  • 1
    @Can you point in the wright direction for de-serialization ? – advocateofnone May 02 '17 at 09:46
  • If I put @JsonSerialize annotation at class level, modifySerializer is not getting called. My requirement is most of the times need to use JsonSerialize which is mentioned on top of class but some times need to serialize differently. is there any way? – Prashanth Debbadwar Dec 27 '17 at 09:38
0

In the event of an abstract class this is not doable.

You could go around it by adding another class that extends JSON serializer (i.e. BasicJSONSerializer) and call the method from there. i.e.

class BasicJSONSerializer extends JsonSerializer<ChangesValues> {}

class ChangesValuesSerializer extends JsonSerializer<ChangesValues> {

    @Override
    public void serialize(ChangesValues changesValues, JsonGenerator jsonGenerator,
        SerializerProvider serializerProvider) throws IOException,
        JsonProcessingException {

        changesValues.changeValues();

        new BasicJSONSerializer().serialize(changesValues, jsonGenerator, serializerProvider);
    }
}

but that seems like a hack and honestly a better design might be needed.

Ajk_P
  • 1,874
  • 18
  • 23