こんにちは
最近、彼のSpringトレーニングプロジェクトで、Java Enterprise(Topjava)はコントローラーに応じてJSONのユーザーオブジェクトのシリアル化をカスタマイズするタスクに直面しました:コントローラーのREST APIの場合、UI上のディスプレイコントローラーではなく、ハッシュされたパスワード(
user.password
フィールド)を返す必要がありました。 TO( データ転送オブジェクト )だけでなく、Spring 4.2 + / Jackson 2.6でもJacksonのSerialization Viewsを使用することで、額の問題を解決できます。 しかし、記事には落とし穴があり、不注意な読者にとっては、ビューは期待どおりに機能しません。
その結果、どのように機能するかを理解するために、ジャクソンの実装を少し掘り下げなければなりませんでした。 これについて簡単に:
MapperFeature.DEFAULT_VIEW_INCLUSION
この記事には少し言及があります。
Spring MVCのデフォルト設定では、MapperFeature.DEFAULT_VIEW_INCLUSIONはfalseに設定されています。
これは、デフォルトでは、
@JsonView
アノテーションでマークされていないフィールド
@JsonView
除外されることを意味します。 しかし、
MapperFeature
コードを見ると、
MapperFeature
ことがわかります。
... * Default value is enabled, meaning that non-annotated * properties are included in all views if there is no * {@link com.fasterxml.jackson.annotation.JsonView} annotation. * * Feature is enabled by default. */ DEFAULT_VIEW_INCLUSION(true),
つまり、すべてが正反対です。マークされていないものはすべてオンになります。 また、UIに必要な[ユーザー]フィールドのみをマークした場合:
public class User ... @JsonView(View.UI.class) protected String email; @JsonView(View.UI.class) protected boolean enabled = true; protected String password;
@JsonView
タグ付き
@JsonView
メソッドを呼び出します
@JsonView(View.UI.class) @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public User get(@PathVariable("id") int id) { return ...; }
その結果には、マークされたユーザーフィールド(
email, enabled, ..
)と、残りすべて(
password
)の両方が含まれます。
FilteredBeanPropertyWriter
なぜなら UIコントローラから
password
フィールドを1つだけ除外したいのですが、それだけをマークするのが論理的です。 コード
jackson-databind-2.8.0
を見てください。コントローラーのリクエストとその結果のフィールドに
@JsonView
注釈が付けられている
@JsonView
、Jacksonは
FilteredBeanPropertyWriter.serializeAsField
介してシリアル化します
final Class<?> activeView = prov.getActiveView(); if (activeView != null) { int i = 0, len = _views.length; for (; i < len; ++i) { if (_views[i].isAssignableFrom(activeView)) break; } // not included, bail out: if (i == len) { _delegate.serializeAsOmittedField(bean, jgen, prov); return; } } _delegate.serializeAsField(bean, jgen, prov);
つまり オブジェクトフィールドをマークしたビューがViewコントローラーメソッドのスーパークラスと一致するか、スーパークラスである場合、フィールドはシリアル化されます。 それ以外の場合、スキップ
serializeAsOmittedField
ます(
serializeAsOmittedField
)。
解決策
要約すると:
- シリアル化コンテキストごとに1つのビューを作成します
public class View { public static class REST {} public static class UI {} }
- 存在する必要のあるビュー(REST)によってUIで除外されるユーザーフィールドにマークを付けます。
public class User ... protected String email; protected boolean enabled = true; @JsonView(View.REST.class) protected String password;
- 適切なコンテキストでUIコントローラーメソッドに注釈を付けます
@JsonView(View.UI.class) @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public User get(@PathVariable("id") int id) { return ...; }
これで、
password
フィールドは結果に含まれなくなり
password
。 RESTコントローラーでは、
@JsonView
を使用せずに実行できます。 すべてのユーザーフィールドがそこに含まれています。
ご清聴ありがとうございました!
@JsonView
がSpringアプリケーションをより美しくコンパクトにすることを願っています。