【问题标题】:Jackson serialization: how to ignore superclass propertiesJackson 序列化:如何忽略超类属性
【发布时间】:2015-01-12 18:21:06
【问题描述】:

我想序列化一个不受我控制的 POJO 类,但想避免序列化来自超类而不是最终类的任何属性。示例:

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

从例子中你可以猜到这个类是由JOOQ生成的,继承自一个复杂的基类UpdatableRecordImpl,它也有一些类似bean属性的方法,这会导致序列化过程中出现问题。另外,我有几个类似的类,所以最好避免为我生成的所有 POJO 重复相同的解决方案。

到目前为止,我已经找到了以下可能的解决方案:

  • 使用 mixin 技术忽略来自超类的特定字段,如下所示:How can I tell jackson to ignore a property for which I don't have control over the source code?

    这样做的问题是,如果基类发生变化(例如,其中出现了一个新的 getAnything() 方法),它可能会破坏我的实现。

  • 实现自定义序列化程序并在那里处理问题。这对我来说似乎有点矫枉过正。

  • 顺便说一句,我有一个接口,它准确描述了我想要序列化的属性,也许我可以混合一个 @JsonSerialize(as=IMyGenerated.class) 注释......?我可以将其用于我的目的吗?

但是,从纯设计的角度来看,最好的办法是能够告诉杰克逊我只想序列化最终类的属性,而忽略所有继承的属性。有没有办法做到这一点?

提前致谢。

【问题讨论】:

    标签: java inheritance serialization jackson superclass


    【解决方案1】:

    您可以注册一个自定义Jackson annotation intropector,它将忽略来自某个超类型的所有属性。这是一个例子:

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

    输出:

    { “字段2”:“b” }

    【讨论】:

    • 这个解决方案对我有用。太忽略复杂的 JOOQ 基类,我的hasIgnoreMarker 实现是return m.getDeclaringClass().getName().contains("org.jooq") || super.hasIgnoreMarker(m)
    【解决方案2】:

    您可以覆盖您希望阻止输出的超类方法并使用@JsonIgnore 对其进行注释。覆盖将属性创建的控制转移到子类,同时使其能够从输出中过滤它。

    例如:

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

    【讨论】:

    • 补充@AbhishekChatterjee 的观点,jackson 使用对象中的 getter 来确定要显示的内容,因此只有 getter 需要被覆盖。
    【解决方案3】:

    您也可以使用它来代替不必要的覆盖

    @JsonIgnoreProperties({ "aFieldFromSuperClass"})
    public class Child extends Base {
       private String id;       
       private String name; 
       private String category;
    } 
    

    【讨论】:

      【解决方案4】:

      继承的好处是子类扩展或添加功能。所以通常的做法是对数据进行序列化。

      解决方法是将值对象 (VO) 或数据传输对象 (DTO) 与您需要序列化的字段一起使用。步骤:

      • 使用应序列化的字段创建一个 VO 类。
      • 使用 BeanUtils.copyProperties(target VO, source data) 复制属性
      • 序列化 VO 实例。

      【讨论】:

      • 在这种情况下,这将是纯粹的复制粘贴。使用生成的类的重点是避免重复我的模式信息(字段、类型等)。理想情况下,一个字段的名称应该只输入一次——在我的 SQL 模式中(或者在 ORM 的情况下在手写的 POJO 中)。到目前为止,这在我的设计中或多或少是正确的,我不想打破它。
      • 否则需要重新定义子类上的字段,并标记为“不可序列化”。
      • @Ferenc:您可以让 jOOQ 为您生成所有这些 POJO / VO / DTO:jooq.org/doc/latest/manual/code-generation/codegen-pojos
      • 是的,这是另一种可能的解决方案——我已经使用了 POJO,所以 select 方法上的一个简单的 .into(MyGenerated.class) 也可以做到。谢谢!
      【解决方案5】:

      在您的基类中添加以下注释:

      @JsonInclude(Include.NON_NULL)
      

      【讨论】:

        猜你喜欢
        • 2012-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-02
        • 2019-10-22
        • 2017-03-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多