with type polymorphic only instantiated information additional java inheritance serialization jackson superclass

java - type - jackson inheritance



Serialización de Jackson: cómo ignorar las propiedades de la superclase (3)

El buen uso de la herencia es que las clases secundarias extienden o agregan funcionalidad. Así que la forma habitual es serializar los datos.

Un entorno de trabajo sería utilizar un Objeto de valor (VO) o un Objeto de transferencia de datos (DTO) con los campos que necesita para serializar. Pasos:

  • Cree una clase VO con los campos que deben ser serializados.
  • Utilice BeanUtils.copyProperties (destino VO, datos de origen) para copiar las propiedades
  • Serializar la instancia VO.

Quiero serializar una clase POJO que no está bajo mi control, pero quiero evitar serializar cualquiera de las propiedades que provienen de la superclase y no de la clase final. Ejemplo:

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

Puede adivinar por el ejemplo que esta clase es generada por JOOQ y que hereda de una clase base compleja UpdatableRecordImpl que también tiene algunos métodos similares a propiedades de bean, que causan problemas durante la serialización. Además, tengo varias clases similares, por lo que sería bueno evitar la duplicación de la misma solución para todos mis POJO generados.

He encontrado las siguientes soluciones posibles hasta ahora:

  • ignore los campos específicos que vienen de la superclase utilizando una técnica de mezcla como esta: ¿Cómo puedo decirle a Jackson que ignore una propiedad para la cual no tengo control sobre el código fuente?

    El problema con esto es que si la clase base cambia (por ejemplo, aparece un nuevo método getAnything ()), puede romper mi implementación.

  • implementar un serializador personalizado y manejar el problema allí. Esto me parece un poco excesivo.

  • como incidentalmente tengo una interfaz que describe exactamente las propiedades que quiero serializar, tal vez pueda mezclar en una anotación @JsonSerialize (as = IMyGenerated.class) ...? ¿Puedo usar esto para mi propósito?

Pero, desde el punto de vista de diseño puro, lo mejor sería poder decirle a Jackson que quiero serializar solo las propiedades de la clase final, e ignorar todas las heredadas. ¿Hay una manera de hacerlo?

Gracias por adelantado.


Puede anular los métodos de la superclase que le gustaría evitar que se generen y anotarlos con @JsonIgnore. La anulación cambia el control de la creación de propiedades a la subclase y permite su capacidad para filtrarla desde la salida.

Por ejemplo:

public class SomeClass { public void setField1(...); public Integer getField1(); public void setField2(...); public Integer getField2(); @Override @JsonIgnore public String superClassField1(...){ return super.superClassField1(); }; @Override @JsonIgnore public String superClassField2(...){ return super.superClassField2(); }; ... }


Puede registrar un intropector de anotación Jackson personalizado que ignoraría todas las propiedades que provienen de un super tipo determinado. Aquí hay un ejemplo:

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

Salida:

{"field2": "b"}