ジャクソン–どのフィールドをシリアル化/逆シリアル化するかを決定します
1. 概要
この記事では、フィールドがJackson によってシリアル化/逆シリアル化されているかどうかにかかわらず、を制御できるさまざまな方法について説明します。
2. パブリックフィールド
フィールドがシリアライズ可能とデシリアライズ可能の両方であることを確認する最も簡単な方法は、フィールドをパブリックにすることです。
public、package-private、privateでシンプルなクラスを宣言しましょう
public class MyDtoAccessLevel {
private String stringValue;
int intValue;
protected float floatValue;
public boolean booleanValue;
// NO setters or getters
}
クラスの4つのフィールドのうち、パブリックbooleanValueのみがデフォルトでJSONにシリアル化されます。
@Test
public void givenDifferentAccessLevels_whenPublic_thenSerializable()
throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
MyDtoAccessLevel dtoObject = new MyDtoAccessLevel();
String dtoAsString = mapper.writeValueAsString(dtoObject);
assertThat(dtoAsString, not(containsString("stringValue")));
assertThat(dtoAsString, not(containsString("intValue")));
assertThat(dtoAsString, not(containsString("floatValue")));
assertThat(dtoAsString, containsString("booleanValue"));
}
3. ゲッターは非パブリックフィールドをシリアライズ可能およびデシリアライズ可能にします
ここで、フィールド(特に非公開フィールド)をシリアル化できるようにする別の簡単な方法は、そのフィールドにゲッターを追加することです。
public class MyDtoWithGetter {
private String stringValue;
private int intValue;
public String getStringValue() {
return stringValue;
}
}
stringValue フィールドはシリアル化可能であると予想されますが、他のプライベートフィールドはゲッターがないため、シリアル化可能ではありません。
@Test
public void givenDifferentAccessLevels_whenGetterAdded_thenSerializable()
throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
MyDtoGetter dtoObject = new MyDtoGetter();
String dtoAsString = mapper.writeValueAsString(dtoObject);
assertThat(dtoAsString, containsString("stringValue"));
assertThat(dtoAsString, not(containsString("intValue")));
}
直感的ではありませんが、ゲッターはプライベートフィールドも逆シリアル化可能にします。これは、ゲッターがあれば、フィールドはプロパティと見なされるためです。
それがどのように機能するかを見てみましょう:
@Test
public void givenDifferentAccessLevels_whenGetterAdded_thenDeserializable()
throws JsonProcessingException, JsonMappingException, IOException {
String jsonAsString = "{\"stringValue\":\"dtoString\"}";
ObjectMapper mapper = new ObjectMapper();
MyDtoWithGetter dtoObject = mapper.readValue(jsonAsString, MyDtoWithGetter.class);
assertThat(dtoObject.getStringValue(), equalTo("dtoString"));
}
4. セッターは非公開フィールドのみを逆シリアル化可能にします
ゲッターがプライベートフィールドをシリアル化可能と逆シリアル化可能にする方法を確認しました。 一方、セッターは非公開フィールドを逆シリアル化可能としてマークするだけです。
public class MyDtoWithSetter {
private int intValue;
public void setIntValue(int intValue) {
this.intValue = intValue;
}
public int accessIntValue() {
return intValue;
}
}
ご覧のとおり、今回はプライベートintValueフィールドにのみセッターがあります。 値にアクセスする方法はありますが、それは標準のゲッターではありません。
intValueのアンマーシャリングプロセスは正しく機能するはずです。
@Test
public void givenDifferentAccessLevels_whenSetterAdded_thenDeserializable()
throws JsonProcessingException, JsonMappingException, IOException {
String jsonAsString = "{\"intValue\":1}";
ObjectMapper mapper = new ObjectMapper();
MyDtoSetter dtoObject = mapper.readValue(jsonAsString, MyDtoSetter.class);
assertThat(dtoObject.anotherGetIntValue(), equalTo(1));
}
そして、前述したように、セッターはフィールドを逆シリアル化可能にするだけで、シリアル化可能にするべきではありません。
@Test
public void givenDifferentAccessLevels_whenSetterAdded_thenStillNotSerializable()
throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
MyDtoSetter dtoObject = new MyDtoSetter();
String dtoAsString = mapper.writeValueAsString(dtoObject);
assertThat(dtoAsString, not(containsString("intValue")));
}
5. すべてのフィールドをグローバルにシリアル化可能にする
たとえば、実際にはソースコードを直接変更できない場合があります。Jacksonが外部からの非公開フィールドを処理する方法を構成する必要があります。
この種のグローバル構成は、 AutoDetect 関数をオンにして、publicフィールドまたはgetter/setterメソッドのいずれかをシリアル化に使用するか、シリアル化をオンにすることで、ObjectMapperレベルで実行できます。すべてのフィールド:
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
次のテストケースは、 MyDtoAccessLevel のすべてのメンバーフィールド(非公開を含む)がシリアル化可能であることを確認します。
@Test
public void givenDifferentAccessLevels_whenSetVisibility_thenSerializable()
throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
MyDtoAccessLevel dtoObject = new MyDtoAccessLevel();
String dtoAsString = mapper.writeValueAsString(dtoObject);
assertThat(dtoAsString, containsString("stringValue"));
assertThat(dtoAsString, containsString("intValue"));
assertThat(dtoAsString, containsString("booleanValue"));
}
6. シリアル化/逆シリアル化でプロパティの名前を変更する
どのフィールドをシリアル化または逆シリアル化するかを制御するだけでなく、フィールドをJSONにマップして戻す方法を制御することもできます。 この構成についてはここで説明しました。
7. シリアル化または逆シリアル化のフィールドを無視する
このチュートリアルに続いて、シリアル化と逆シリアル化でフィールドを完全に無視する方法のガイドがあります。
ただし、両方のフィールドではなく、どちらかのフィールドを無視する必要がある場合もあります。 ジャクソンは、この興味深いユースケースにも対応できる柔軟性を備えています。
次の例は、JSONにシリアル化してはならない機密のパスワード情報を含むUserオブジェクトを示しています。
そこに到達するには、passwordのゲッターに@JsonIgnoreアノテーションを追加し、@JsonPropertyアノテーションを適用してフィールドの逆シリアル化を有効にします。セッター:
@JsonIgnore
public String getPassword() {
return password;
}
@JsonProperty
public void setPassword(String password) {
this.password = password;
}
これで、パスワード情報はJSONにシリアル化されなくなります。
@Test
public void givenFieldTypeIsIgnoredOnlyAtSerialization_whenUserIsSerialized_thenIgnored()
throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User userObject = new User();
userObject.setPassword("thePassword");
String userAsString = mapper.writeValueAsString(userObject);
assertThat(userAsString, not(containsString("password")));
assertThat(userAsString, not(containsString("thePassword")));
}
ただし、パスワードを含むJSONは、Userオブジェクトに正常に逆シリアル化されます。
@Test
public void givenFieldTypeIsIgnoredOnlyAtSerialization_whenUserIsDeserialized_thenCorrect()
throws JsonParseException, JsonMappingException, IOException {
String jsonAsString = "{\"password\":\"thePassword\"}";
ObjectMapper mapper = new ObjectMapper();
User userObject = mapper.readValue(jsonAsString, User.class);
assertThat(userObject.getPassword(), equalTo("thePassword"));
}
8. 結論
このチュートリアルでは、Jacksonがシリアル化/逆シリアル化され、プロセスで無視されるを選択する方法と、もちろんそれを完全に制御する方法の基本について説明します。
フィールドの無視、 JSON配列のJava配列またはコレクションへの逆シリアル化などの記事を詳しく調べることで、Jackson2を理解するための次のステップに進むこともできます。
これらすべての例とコードスニペットの実装は、 my github project にあります。これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。