Jacksonとカスタム基準を満たすフィールドのみを直列化する
1概要
このチュートリアルでは、特定のカスタム基準を満たしている場合にのみ、Jacksonを使用してフィールドをシリアル化する方法を説明します。
たとえば、正の値の場合にのみ整数値をシリアル化したいとし、そうでない場合は完全にスキップしたいとします。
あなたがもっと深く掘り下げて
あなたがジャクソン2
ですることができる** 他のクールなことを学びたいなら –
メインのジャクソンチュートリアル
に向かって進んでください。
2 Jacksonフィルタを使用してシリアル化プロセスを制御する
まず、
@ JsonFilter
アノテーションを使用して、エンティティにフィルタを定義する必要があります。
@JsonFilter("myFilter")
public class MyDto {
private int intValue;
public MyDto() {
super();
}
public int getIntValue() {
return intValue;
}
public void setIntValue(int intValue) {
this.intValue = intValue;
}
}
次に、カスタムの
PropertyFilter
を定義する必要があります。
PropertyFilter theFilter = new SimpleBeanPropertyFilter() {
@Override
public void serializeAsField
(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer)
throws Exception {
if (include(writer)) {
if (!writer.getName().equals("intValue")) {
writer.serializeAsField(pojo, jgen, provider);
return;
}
int intValue = ((MyDtoWithFilter) pojo).getIntValue();
if (intValue >= 0) {
writer.serializeAsField(pojo, jgen, provider);
}
} else if (!jgen.canOmitFields()) {//since 2.3
writer.serializeAsOmittedField(pojo, jgen, provider);
}
}
@Override
protected boolean include(BeanPropertyWriter writer) {
return true;
}
@Override
protected boolean include(PropertyWriter writer) {
return true;
}
};
このフィルタは
intValue
フィールドがその値に基づいて
シリアライズされるかどうか
を決定する実際のロジックを含みます。
次に、このフィルタを
ObjectMapper
にフックし、エンティティをシリアル化します。
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", theFilter);
MyDto dtoObject = new MyDto();
dtoObject.setIntValue(-1);
ObjectMapper mapper = new ObjectMapper();
String dtoAsString = mapper.writer(filters).writeValueAsString(dtoObject);
そして最後に、
intValue
フィールドが実際に整列化されたJSON出力の一部ではないことを確認できます。
assertThat(dtoAsString, not(containsString("intValue")));
3条件付きでオブジェクトをスキップする
それでは、プロパティ
value
に基づいてシリアル化しながらオブジェクトをスキップする方法について説明しましょう。プロパティ
hidden
が
true
であるすべてのオブジェクトをスキップします。
3.1. 隠しクラス
まず、私たちの
Hidable
インターフェースを見てみましょう。
@JsonIgnoreProperties("hidden")
public interface Hidable {
boolean isHidden();
}
そしてこのインターフェースを実装する2つの単純なクラス
Person
、
Address
があります。
個人
クラス:
public class Person implements Hidable {
private String name;
private Address address;
private boolean hidden;
}
そして
Address
クラス:
public class Address implements Hidable {
private String city;
private String country;
private boolean hidden;
}
注:
hidden
プロパティ自体がJSONに含まれないようにするために、
@ JsonIgnoreProperties(“ hidden”)
を使用しました
3.2. カスタムシリアライザ
次は – これが私たちのカスタムシリアライザです。
public class HidableSerializer extends JsonSerializer<Hidable> {
private JsonSerializer<Object> defaultSerializer;
public HidableSerializer(JsonSerializer<Object> serializer) {
defaultSerializer = serializer;
}
@Override
public void serialize(Hidable value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
if (value.isHidden())
return;
defaultSerializer.serialize(value, jgen, provider);
}
@Override
public boolean isEmpty(SerializerProvider provider, Hidable value) {
return (value == null || value.isHidden());
}
}
ご了承ください:
-
オブジェクトがスキップされない場合は、シリアル化を
デフォルトの注入されたシリアライザ
-
メソッド
isEmpty()
– をオーバーライドして、
隠しオブジェクトはプロパティです。プロパティ名もJSONから除外されます。
3.3.
BeanSerializerModifier
を使用する
最後に、次のように
BeanSerializerModifier
を使用してカスタムの
HidableSerializer
にデフォルトのシリアライザを挿入する必要があります。
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON__EMPTY);
mapper.registerModule(new SimpleModule() {
@Override
public void setupModule(SetupContext context) {
super.setupModule(context);
context.addBeanSerializerModifier(new BeanSerializerModifier() {
@Override
public JsonSerializer<?> modifySerializer(
SerializationConfig config, BeanDescription desc, JsonSerializer<?> serializer) {
if (Hidable.class.isAssignableFrom(desc.getBeanClass())) {
return new HidableSerializer((JsonSerializer<Object>) serializer);
}
return serializer;
}
});
}
});
3.4. 出力例
これは簡単な直列化の例です。
Address ad1 = new Address("tokyo", "jp", true);
Address ad2 = new Address("london", "uk", false);
Address ad3 = new Address("ny", "usa", false);
Person p1 = new Person("john", ad1, false);
Person p2 = new Person("tom", ad2, true);
Person p3 = new Person("adam", ad3, false);
System.out.println(mapper.writeValueAsString(Arrays.asList(p1, p2, p3)));
そして出力は次のとおりです。
----[ {
"name":"john"
},
{
"name":"adam",
"address":{
"city":"ny",
"country":"usa"
}
}]----
3.5. テスト
最後に – これがいくつかのテストケースです。
最初のケースでは、
何も隠されていません
:
@Test
public void whenNotHidden__thenCorrect() throws JsonProcessingException {
Address ad = new Address("ny", "usa", false);
Person person = new Person("john", ad, false);
String result = mapper.writeValueAsString(person);
assertTrue(result.contains("name"));
assertTrue(result.contains("john"));
assertTrue(result.contains("address"));
assertTrue(result.contains("usa"));
}
次に、
アドレスのみが隠されています
:
@Test
public void whenAddressHidden__thenCorrect() throws JsonProcessingException {
Address ad = new Address("ny", "usa", true);
Person person = new Person("john", ad, false);
String result = mapper.writeValueAsString(person);
assertTrue(result.contains("name"));
assertTrue(result.contains("john"));
assertFalse(result.contains("address"));
assertFalse(result.contains("usa"));
}
今、
人全体が隠されている
:
@Test
public void whenAllHidden__thenCorrect() throws JsonProcessingException {
Address ad = new Address("ny", "usa", false);
Person person = new Person("john", ad, true);
String result = mapper.writeValueAsString(person);
assertTrue(result.length() == 0);
}
4結論
このタイプの高度なフィルタリングは非常に強力で、Jacksonで複雑なオブジェクトを直列化するときに非常に柔軟にJSONをカスタマイズできます。
より柔軟ではあるがより複雑な代替方法は、JSON出力を制御するために完全にカスタム化されたシリアライザを使用することです。
これらすべての例とコードスニペットの実装は、https://github.com/eugenp/tutorials/tree/master/jackson#readme
にあります。
– これはEclipseベースのプロジェクトです。そのままインポートして実行するのは簡単です。