web-dev-qa-db-ja.com

ジャクソンのシリアル化:スーパークラスプロパティを無視する方法

私の制御下にない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によって生成され、シリアライズ中に問題を引き起こすBeanプロパティのようなメソッドも持つ複雑な基本クラスUpdatableRecordImplを継承していると推測できます。また、いくつかの類似したクラスがあるため、生成されたすべてのPOJOに同じソリューションを重複させないようにすることをお勧めします。

これまでに次の解決策を見つけました。

  • 次のようなミックスイン手法を使用して、スーパークラスからの特定のフィールドを無視します。 ソースコードを制御できないプロパティをジャックソンに無視させるにはどうすればよいですか?

    これに伴う問題は、基本クラスが変更された場合(たとえば、新しいgetAnything()メソッドがその中に出現した場合)、実装が中断される可能性があることです。

  • カスタムシリアライザーを実装し、そこで問題を処理します。これは少しやり過ぎだと思います。

  • 偶然にも、シリアル化するプロパティを正確に記述するインターフェイスがあります。おそらく、@ JsonSerialize(as = IMyGenerated.class)アノテーションを混在させることができます...?これを目的に使用できますか?

しかし、純粋な設計の観点からは、最終クラスのプロパティのみをシリアル化したいということをjacksonに伝え、継承されたプロパティをすべて無視できることが最善です。それを行う方法はありますか?

前もって感謝します。

26
Ferenc

カスタム Jackson注釈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));
    }

}

出力:

{"field2": "b"}

20
Alexey Gavrilov

出力を防止したいスーパークラスのメソッドをオーバーライドし、@ 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();
  };
...
}
11
ethesx

継承の適切な使用法は、子クラスが機能を拡張または追加することです。したがって、通常の方法はデータをシリアル化することです。

回避策は、シリアル化する必要があるフィールドで値オブジェクト(VO)またはデータ転送オブジェクト(DTO)を使用することです。手順:

  • シリアル化する必要があるフィールドでVOクラスを作成します。
  • BeanUtils.copyProperties(target VO、source data)を使用してプロパティをコピーします
  • VOインスタンスをシリアル化します。
2
jordiburgos

無駄なオーバーライドの代わりにこれも使用できます

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