Search code examples
javainheritanceserializationjacksonsuperclass

Jackson serialization: how to ignore superclass properties


I want to serialize a POJO class which is not under my control, but want to avoid serializing any of the properties which are coming from the superclass, and not from the final class. Example:

public class MyGeneratedRecord extends org.jooq.impl.UpdatableRecordImpl<...>,
    example.generated.tables.interfaces.IMyGenerated {
  public void setField1(...);
  public Integer getField1();

  public void setField2(...);
  public Integer getField2();
...
}

You can guess from the example that that this class is generated by JOOQ, and inherits from a complex base class UpdatableRecordImpl which also has some bean property-like methods, which cause problems during the serialization. Also, I have several similar classes, so it would be good to avoid duplicating the same solution for all of my generated POJOs.

I have found the following possible solutions so far:

  • ignore the specific fields coming from superclass using mixin technique like this: How can I tell jackson to ignore a property for which I don't have control over the source code?

    The problem with this is that if the base class changes (e.g., a new getAnything() method appears in it), it can break my implementation.

  • implement a custom serializer and handle the issue there. This seems a bit overkill to me.

  • as incidentally I have an interface which describes exactly the properties I want to serialize, maybe I can mixin a @JsonSerialize(as=IMyGenerated.class) annotation...? Can I use this for my purpose?

But, from pure design point of view, the best would be to be able to tell jackson that I want to serialize only the final class' properties, and ignore all the inherited ones. Is there a way to do that?

Thanks in advance.


Solution

  • You can register a custom Jackson annotation intropector which would ignore all the properties that come from the certain super type. Here is an example:

    public class JacksonIgnoreInherited {
    
        public static class Base {
            public final String field1;
    
            public Base(final String field1) {
                this.field1 = field1;
            }
        }
    
        public static class Bean extends Base {
            public final String field2;
    
            public Bean(final String field1, final String field2) {
                super(field1);
                this.field2 = field2;
            }
        }
    
        private static class IgnoreInheritedIntrospector extends JacksonAnnotationIntrospector {
            @Override
            public boolean hasIgnoreMarker(final AnnotatedMember m) {
                return m.getDeclaringClass() == Base.class || super.hasIgnoreMarker(m);
            }
        }
    
        public static void main(String[] args) throws JsonProcessingException {
            final ObjectMapper mapper = new ObjectMapper();
            mapper.setAnnotationIntrospector(new IgnoreInheritedIntrospector());
            final Bean bean = new Bean("a", "b");
            System.out.println(mapper
                            .writerWithDefaultPrettyPrinter()
                            .writeValueAsString(bean));
        }
    
    }
    

    Output:

    { "field2" : "b" }