jacksonに、ソースコードを制御できないプロパティを無視するように指示するにはどうすればよいですか?


112

一言で言えば、私のエンティティの1つに、「getBoundary」を呼び出すと例外をスローするGeometryCollectionがあります(この理由は別の本です。今のところ、これが機能する方法だとしましょう)。

ジャクソンにその特定のゲッターを含めないように伝える方法はありますか?コードを所有または制御するときに@JacksonIgnoreを使用できることはわかっています。しかし、そうではありません。ジャクソンは、親オブジェクトの連続的なシリアル化を通じてこのポイントに到達します。ジャクソンのドキュメントでフィルタリングオプションを見ました。それはもっともらしい解決策ですか?

ありがとう!

回答:


168

Jackson Mixinsを使用できます。例えば:

class YourClass {
  public int ignoreThis() { return 0; }    
}

このミックスインで

abstract class MixIn {
  @JsonIgnore abstract int ignoreThis(); // we don't need it!  
}

これとともに:

objectMapper.getSerializationConfig().addMixInAnnotations(YourClass.class, MixIn.class);

編集:

コメントのおかげで、Jackson 2.5以降ではAPIが変更され、次のように呼び出す必要があります。 objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)


1
プロパティがマシンで生成され、その名前にサポートされていない文字が含まれている場合はどうなりますか?お気に入り '@'?JVMでは可能ですが、Javaコンパイラではできません。ジャクソンはこれに対する解決策を持っていますか?
マーク

3
そして、ジャクソン2.2では、それはobjectMapper.addMixInAnnotations(Class<?> target, Class<?> mixinSource);
CorayThan

ゲッターの代わりにプロパティ名を指定して無視するにはどうすればよいですか?
Erran Morad

68

もう1つの可能性として、不明なプロパティをすべて無視する場合は、マッパーを次のように構成できます。

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

5
特定のプロパティのみを無視するようにobjectMapperを構成できればすばらしいと思います。つまり、「myfield」と言うことを除いて、すべての新しい/不明なフィールドの例外を報告します。次のようなものmapper.configure(DeserializationFeature.failOnUnknownPropertiesExcep(new String[] {"myField"}));
ms_27

これはまた、使用リーダーで構成することができることに留意されたいwithout()と:mapper.reader().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
ドリュースティーブンス

このメカニズムを使用しないことを強くお勧めします。ジャクソンの「厳格な」考え方は、不明/未処理のフィールドでエラーを発生させることの強みの1つであり、静的に型付けされた/コンパイル時に分析されるJavaの性質とよく一致しています。代わりに、無視されたフィールドの特定のセットの処理をオプトアウトする方がはるかに優れています。
1

26

Javaクラスの使用

new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

注釈の使用

@JsonIgnoreProperties(ignoreUnknown=true)

11

注釈ベースのアプローチが優れています。ただし、手動操作が必要な場合があります。このため、ObjectWriterのメソッドなしで使用できます。

ObjectMapper mapper   = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
ObjectWriter writer   = mapper.writer().withoutAttribute("property1").withoutAttribute("property2");
String       jsonText = writer.writeValueAsString(sourceObject);

9
このアプローチは私にはうまくいきませんが、mixinではうまくいきます。シリアライズ後も、無視されたプロパティを取得します。withoutAttribute()があるときにミックスインがあるのはなぜですか?
Erran Morad

9

すでに説明したように、ミックスインアノテーションはここでかなりうまく機能します。プロパティごとの@JsonIgnoreを超えた別の可能性は、決して含めてはならないタイプがある場合(つまり、GeometryCollectionプロパティのすべてのインスタンスを無視する必要がある場合)、@ JsonIgnoreTypeを使用することです。次に、それを直接追加するか(タイプを制御する場合)、または次のようにミックスインを使用します。

@JsonIgnoreType abstract class MixIn { }
// and then register mix-in, either via SerializationConfig, or by using SimpleModule

すべてが単一の 'IgnoredType getContext()'アクセサーを持っているクラスがたくさんある場合、これはより便利です(多くのフレームワークの場合です)。


5

同様の問題がありましたが、それはHibernateの双方向の関係に関連していました。私は、関係の一方の面を示し、プログラムでもう一方を無視したかったのですが、私が扱っていた見方によっては。それができない場合は、厄介なStackOverflowExceptionsになります。たとえば、これらのオブジェクトがある場合

public class A{
  Long id;
  String name;
  List<B> children;
}

public class B{
  Long id;
  A parent;
}

プログラムparentでAを見ている場合はB のフィールドを無視し、Bを見ているchildren場合はA のフィールドを無視します。

私はこれを行うためにミックスインを使い始めましたが、それはすぐに恐ろしくなります。データをフォーマットするためだけに存在する無駄なクラスがたくさんあります。私はこれをよりきれいな方法で処理するために自分のシリアライザを作成することになりました:https : //github.com/monitorjbl/json-view

無視するフィールドをプログラムで指定できます。

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(JsonView.class, new JsonViewSerializer());
mapper.registerModule(module);

List<A> list = getListOfA();
String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(B.class, match()
        .exclude("parent")));

また、ワイルドカードマッチャーを使用して、非常に簡略化されたビューを簡単に指定できます。

String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(A.class, match()
        .exclude("*")
         .include("id", "name")));

私の元のケースでは、このような単純なビューの必要性は、親/子について最低限を示すことでしたが、ロールベースのセキュリティにも役立ちました。オブジェクトに関する少ない情報を返すために必要な、オブジェクトの特権の少ないビュー。

これらはすべてシリアライザからのものですが、アプリでSpring MVCを使用していました。これらのケースを適切に処理するために、既存のSpringコントローラークラスにドロップできる統合を作成しました。

@Controller
public class JsonController {
  private JsonResult json = JsonResult.instance();
  @Autowired
  private TestObjectService service;

  @RequestMapping(method = RequestMethod.GET, value = "/bean")
  @ResponseBody
  public List<TestObject> getTestObject() {
    List<TestObject> list = service.list();

    return json.use(JsonView.with(list)
        .onClass(TestObject.class, Match.match()
            .exclude("int1")
            .include("ignoredDirect")))
        .returnValue();
  }
}

どちらもMaven Centralで利用できます。私はそれが他の誰かを助けることを願っています、これは私のケースに対して良い解決策を持っていなかったジャクソンの特に醜い問題です。


インポートとは何Match.match()ですか?
パスパチラジャマニカム

2

すべてのクラスの特定のプロパティを常に除外する場合は、setMixInResolverメソッドを使用できます。

    @JsonIgnoreProperties({"id", "index", "version"})
    abstract class MixIn {
    }

    mapper.setMixInResolver(new ClassIntrospector.MixInResolver(){
        @Override
        public Class<?> findMixInClassFor(Class<?> cls) {
            return MixIn.class;  
        }

        @Override
        public ClassIntrospector.MixInResolver copy() {
            return this;
        }
    });

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.