ジャクソン注釈の例
1. 概要
この記事では、Jackson Annotationsについて詳しく説明します。
既存の注釈を使用する方法、カスタム注釈を作成する方法、そして最後に、それらを無効にする方法を見ていきます。
参考文献:
Jacksonでのカスタムデシリアライゼーションの開始
Jacksonを使用して、デシリアライズプロセスを完全に制御して、カスタムJSONをJavaエンティティグラフにマッピングします。
2. ジャクソンシリアル化アノテーション
まず、シリアル化アノテーションを見てみましょう。
2.1. @JsonAnyGetter
@JsonAnyGetterアノテーションにより、Mapフィールドを標準プロパティとして柔軟に使用できます。
簡単な例を次に示します。ExtendableBeanエンティティには、nameプロパティと、キーと値のペアの形式の拡張可能な属性のセットがあります。
public class ExtendableBean {
public String name;
private Map properties;
@JsonAnyGetter
public Map getProperties() {
return properties;
}
}
このエンティティのインスタンスをシリアル化すると、Mapのすべてのキー値が標準のプレーンプロパティとして取得されます。
{
"name":"My bean",
"attr2":"val2",
"attr1":"val1"
}
そして、このエンティティのシリアル化が実際にどのように見えるかを以下に示します。
@Test
public void whenSerializingUsingJsonAnyGetter_thenCorrect()
throws JsonProcessingException {
ExtendableBean bean = new ExtendableBean("My bean");
bean.add("attr1", "val1");
bean.add("attr2", "val2");
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("attr1"));
assertThat(result, containsString("val1"));
}
オプションの引数enabledをfalseとして使用して、@JsonAnyGetter().を無効にすることもできます。この場合、MapはJSONとして変換され、後にproperties変数の下に表示されます。シリアル化。
2.2. @JsonGetter
@JsonGetterアノテーションは、メソッドをゲッターメソッドとしてマークするための@JsonPropertyアノテーションの代替です。
次の例では、メソッドgetTheName()をMyBeanエンティティのnameプロパティのgetterメソッドとして指定します。
public class MyBean {
public int id;
private String name;
@JsonGetter("name")
public String getTheName() {
return name;
}
}
そして、これが実際にどのように機能するかを次に示します。
@Test
public void whenSerializingUsingJsonGetter_thenCorrect()
throws JsonProcessingException {
MyBean bean = new MyBean(1, "My bean");
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, containsString("1"));
}
2.3. @JsonPropertyOrder
@JsonPropertyOrderアノテーションを使用してthe order of properties on serializationを指定できます。
MyBeanエンティティのプロパティのカスタム順序を設定しましょう。
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
public int id;
public String name;
}
そして、シリアル化の出力は次のとおりです。
{
"name":"My bean",
"id":1
}
そして簡単なテスト:
@Test
public void whenSerializingUsingJsonPropertyOrder_thenCorrect()
throws JsonProcessingException {
MyBean bean = new MyBean(1, "My bean");
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, containsString("1"));
}
@JsonPropertyOrder(alphabetic=true)を使用して、プロパティをアルファベット順に並べ替えることもできます。 そしてその場合、シリアル化の出力は次のようになります。
{
"id":1,
"name":"My bean"
}
2.4. @JsonRawValue
@JsonRawValueアノテーションはinstruct Jackson to serialize a property exactly as isにすることができます。
次の例では、@JsonRawValueを使用して、エンティティの値としてカスタムJSONを埋め込みます。
public class RawBean {
public String name;
@JsonRawValue
public String json;
}
エンティティのシリアル化の出力は次のとおりです。
{
"name":"My bean",
"json":{
"attr":false
}
}
そして簡単なテスト:
@Test
public void whenSerializingUsingJsonRawValue_thenCorrect()
throws JsonProcessingException {
RawBean bean = new RawBean("My bean", "{\"attr\":false}");
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, containsString("{\"attr\":false}"));
}
この注釈がアクティブかどうかを定義するオプションのブール引数valueを使用することもできます。
2.5. @JsonValue
@JsonValueは、ライブラリがインスタンス全体をシリアル化するために使用する単一のメソッドを示します。
たとえば、列挙型では、getNameに@JsonValueの注釈を付けて、そのようなエンティティがその名前でシリアル化されるようにします。
public enum TypeEnumWithValue {
TYPE1(1, "Type A"), TYPE2(2, "Type 2");
private Integer id;
private String name;
// standard constructors
@JsonValue
public String getName() {
return name;
}
}
私たちのテスト:
@Test
public void whenSerializingUsingJsonValue_thenCorrect()
throws JsonParseException, IOException {
String enumAsString = new ObjectMapper()
.writeValueAsString(TypeEnumWithValue.TYPE1);
assertThat(enumAsString, is(""Type A""));
}
2.6. @JsonRootName
@JsonRootName注釈は、ラッピングが有効になっている場合に、使用するルートラッパーの名前を指定するために使用されます。
ラッピングとは、Userを次のようなものにシリアル化する代わりに意味します。
{
"id": 1,
"name": "John"
}
次のようにラップされます。
{
"User": {
"id": 1,
"name": "John"
}
}
それでは、例を見てみましょう–we’re going to use the @JsonRootName annotation to indicate the name of this potential wrapper entity:
@JsonRootName(value = "user")
public class UserWithRoot {
public int id;
public String name;
}
デフォルトでは、ラッパーの名前はクラスの名前–UserWithRootになります。 アノテーションを使用することで、見た目がすっきりしたuser:が得られます
@Test
public void whenSerializingUsingJsonRootName_thenCorrect()
throws JsonProcessingException {
UserWithRoot user = new User(1, "John");
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
String result = mapper.writeValueAsString(user);
assertThat(result, containsString("John"));
assertThat(result, containsString("user"));
}
シリアル化の出力は次のとおりです。
{
"user":{
"id":1,
"name":"John"
}
}
Jackson 2.4以降、新しいオプションの引数namespaceをXMLなどのデータ形式で使用できるようになりました。 追加すると、完全修飾名の一部になります。
@JsonRootName(value = "user", namespace="users")
public class UserWithRootNamespace {
public int id;
public String name;
// ...
}
XmlMapperでシリアル化すると、出力は次のようになります。
1
John
2.7. @JsonSerialize
@JsonSerialize indicates a custom serializer to use whenマーシャリングthe entity.
簡単な例を見てみましょう。 @JsonSerializeを使用して、eventDateプロパティをCustomDateSerializerでシリアル化します。
public class EventWithSerializer {
public String name;
@JsonSerialize(using = CustomDateSerializer.class)
public Date eventDate;
}
シンプルなカスタムジャクソンシリアライザーは次のとおりです。
public class CustomDateSerializer extends StdSerializer {
private static SimpleDateFormat formatter
= new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
public CustomDateSerializer() {
this(null);
}
public CustomDateSerializer(Class t) {
super(t);
}
@Override
public void serialize(
Date value, JsonGenerator gen, SerializerProvider arg2)
throws IOException, JsonProcessingException {
gen.writeString(formatter.format(value));
}
}
これらをテストで使用してみましょう。
@Test
public void whenSerializingUsingJsonSerialize_thenCorrect()
throws JsonProcessingException, ParseException {
SimpleDateFormat df
= new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
String toParse = "20-12-2014 02:30:00";
Date date = df.parse(toParse);
EventWithSerializer event = new EventWithSerializer("party", date);
String result = new ObjectMapper().writeValueAsString(event);
assertThat(result, containsString(toParse));
}
3. ジャクソン逆シリアル化アノテーション
次へ–ジャクソンの逆シリアル化アノテーションについて見ていきましょう。
3.1. @JsonCreator
@JsonCreatorアノテーションを使用して、逆シリアル化で使用されるコンストラクター/ファクトリを調整できます。
取得する必要のあるターゲットエンティティと完全に一致しないJSONを逆シリアル化する必要がある場合に非常に役立ちます。
例を見てみましょう。次のJSONを逆シリアル化する必要があるとします。
{
"id":1,
"theName":"My bean"
}
ただし、ターゲットエンティティにはtheNameフィールドはありません。nameフィールドのみがあります。 ここで、エンティティ自体を変更する必要はありません。コンストラクターに@JsonCreatorアノテーションを付け、@JsonPropertyアノテーションも使用することで、マーシャリング解除プロセスをもう少し制御する必要があります。
public class BeanWithCreator {
public int id;
public String name;
@JsonCreator
public BeanWithCreator(
@JsonProperty("id") int id,
@JsonProperty("theName") String name) {
this.id = id;
this.name = name;
}
}
これを実際に見てみましょう:
@Test
public void whenDeserializingUsingJsonCreator_thenCorrect()
throws IOException {
String json = "{\"id\":1,\"theName\":\"My bean\"}";
BeanWithCreator bean = new ObjectMapper()
.readerFor(BeanWithCreator.class)
.readValue(json);
assertEquals("My bean", bean.name);
}
3.2. @JacksonInject
@JacksonInjectは、プロパティがJSONデータからではなく、インジェクションから値を取得することを示します。
次の例では、@JacksonInjectを使用してプロパティidを挿入します。
public class BeanWithInject {
@JacksonInject
public int id;
public String name;
}
そして、これがどのように機能するかです。
@Test
public void whenDeserializingUsingJsonInject_thenCorrect()
throws IOException {
String json = "{\"name\":\"My bean\"}";
InjectableValues inject = new InjectableValues.Std()
.addValue(int.class, 1);
BeanWithInject bean = new ObjectMapper().reader(inject)
.forType(BeanWithInject.class)
.readValue(json);
assertEquals("My bean", bean.name);
assertEquals(1, bean.id);
}
3.3. @JsonAnySetter
@JsonAnySetterを使用すると、Mapを標準プロパティとして柔軟に使用できます。 デシリアライゼーションでは、JSONのプロパティがマップに追加されるだけです。
これがどのように機能するかを見てみましょう。@JsonAnySetterを使用してエンティティExtendableBeanを逆シリアル化します。
public class ExtendableBean {
public String name;
private Map properties;
@JsonAnySetter
public void add(String key, String value) {
properties.put(key, value);
}
}
これは、逆シリアル化する必要があるJSONです。
{
"name":"My bean",
"attr2":"val2",
"attr1":"val1"
}
そして、これがすべてを結び付ける方法です。
@Test
public void whenDeserializingUsingJsonAnySetter_thenCorrect()
throws IOException {
String json
= "{\"name\":\"My bean\",\"attr2\":\"val2\",\"attr1\":\"val1\"}";
ExtendableBean bean = new ObjectMapper()
.readerFor(ExtendableBean.class)
.readValue(json);
assertEquals("My bean", bean.name);
assertEquals("val2", bean.getProperties().get("attr2"));
}
3.4. @JsonSetter
@JsonSetterは@JsonPropertyの代替であり、メソッドをセッターメソッドとしてマークします。
これは、the target entity class doesn’t exactly match that data以外のJSONデータを読み取る必要がある場合に非常に便利です。そのため、プロセスを調整して適合させる必要があります。
次の例では、メソッドsetTheName()をMyBeanエンティティのnameプロパティのセッターとして指定します。
public class MyBean {
public int id;
private String name;
@JsonSetter("name")
public void setTheName(String name) {
this.name = name;
}
}
これで、JSONデータを非整列化する必要がある場合-これは完全に機能します。
@Test
public void whenDeserializingUsingJsonSetter_thenCorrect()
throws IOException {
String json = "{\"id\":1,\"name\":\"My bean\"}";
MyBean bean = new ObjectMapper()
.readerFor(MyBean.class)
.readValue(json);
assertEquals("My bean", bean.getTheName());
}
3.5. @JsonDeserialize
@JsonDeserializeは、カスタムデシリアライザーの使用を示します。
それがどのように実行されるかを見てみましょう。@JsonDeserializeを使用してeventDateプロパティをCustomDateDeserializerで逆シリアル化します。
public class EventWithSerializer {
public String name;
@JsonDeserialize(using = CustomDateDeserializer.class)
public Date eventDate;
}
カスタムデシリアライザーは次のとおりです。
public class CustomDateDeserializer
extends StdDeserializer {
private static SimpleDateFormat formatter
= new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
public CustomDateDeserializer() {
this(null);
}
public CustomDateDeserializer(Class> vc) {
super(vc);
}
@Override
public Date deserialize(
JsonParser jsonparser, DeserializationContext context)
throws IOException {
String date = jsonparser.getText();
try {
return formatter.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
そして、これが連続したテストです:
@Test
public void whenDeserializingUsingJsonDeserialize_thenCorrect()
throws IOException {
String json
= "{"name":"party","eventDate":"20-12-2014 02:30:00"}";
SimpleDateFormat df
= new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
EventWithSerializer event = new ObjectMapper()
.readerFor(EventWithSerializer.class)
.readValue(json);
assertEquals(
"20-12-2014 02:30:00", df.format(event.eventDate));
}
3.6 @JsonAlias
@JsonAliasはone or more alternative names for a property during deserializationを定義します。
このアノテーションがどのように機能するかを簡単な例で見てみましょう。
public class AliasBean {
@JsonAlias({ "fName", "f_name" })
private String firstName;
private String lastName;
}
ここでは、POJOがあり、fName、f_name、firstNameなどの値を使用してJSONをPOJOのfirstName変数に逆シリアル化します。
そして、このアノテーションが期待通りに動作することを確認するテストがあります:
@Test
public void whenDeserializingUsingJsonAlias_thenCorrect() throws IOException {
String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}";
AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json);
assertEquals("John", aliasBean.getFirstName());
}
4. ジャクソンプロパティインクルージョンアノテーション
4.1. @JsonIgnoreProperties
@JsonIgnorePropertiesは、Jacksonが無視するプロパティまたはプロパティのリストをマークするクラスレベルのアノテーションです。
シリアル化からプロパティidを無視する簡単な例を見てみましょう。
@JsonIgnoreProperties({ "id" })
public class BeanWithIgnore {
public int id;
public String name;
}
そして、無視が発生することを確認するテストは次のとおりです。
@Test
public void whenSerializingUsingJsonIgnoreProperties_thenCorrect()
throws JsonProcessingException {
BeanWithIgnore bean = new BeanWithIgnore(1, "My bean");
String result = new ObjectMapper()
.writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, not(containsString("id")));
}
JSON入力の不明なプロパティを例外なく無視するために、@JsonIgnoreProperties annotationのignoreUnknown=trueを設定できます。
4.2. @JsonIgnore
@JsonIgnoreアノテーションは、フィールドレベルで無視されるプロパティをマークするために使用されます。
@JsonIgnoreを使用して、シリアル化からプロパティidを無視しましょう。
public class BeanWithIgnore {
@JsonIgnore
public int id;
public String name;
}
そして、idが正常に無視されたことを確認するテスト:
@Test
public void whenSerializingUsingJsonIgnore_thenCorrect()
throws JsonProcessingException {
BeanWithIgnore bean = new BeanWithIgnore(1, "My bean");
String result = new ObjectMapper()
.writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, not(containsString("id")));
}
4.3. @JsonIgnoreType
@JsonIgnoreTypeは、注釈付きタイプのすべてのプロパティを無視するようにマークします。
アノテーションを使用して、タイプNameのすべてのプロパティを無視するようにマークしましょう。
public class User {
public int id;
public Name name;
@JsonIgnoreType
public static class Name {
public String firstName;
public String lastName;
}
}
無視が正しく機能することを確認する簡単なテストは次のとおりです。
@Test
public void whenSerializingUsingJsonIgnoreType_thenCorrect()
throws JsonProcessingException, ParseException {
User.Name name = new User.Name("John", "Doe");
User user = new User(1, name);
String result = new ObjectMapper()
.writeValueAsString(user);
assertThat(result, containsString("1"));
assertThat(result, not(containsString("name")));
assertThat(result, not(containsString("John")));
}
4.4. @JsonInclude
@JsonIncludeを使用して、空/ null /デフォルト値のプロパティを除外できます。
例を見てみましょう–シリアル化からnullを除外します。
@JsonInclude(Include.NON_NULL)
public class MyBean {
public int id;
public String name;
}
完全なテストは次のとおりです。
public void whenSerializingUsingJsonInclude_thenCorrect()
throws JsonProcessingException {
MyBean bean = new MyBean(1, null);
String result = new ObjectMapper()
.writeValueAsString(bean);
assertThat(result, containsString("1"));
assertThat(result, not(containsString("name")));
}
4.5. @JsonAutoDetect
@JsonAutoDetectは、which properties are visible and which are notのデフォルトのセマンティクスをオーバーライドできます。
簡単な例を使用して、アノテーションがどのように非常に役立つかを見てみましょう。プライベートプロパティのシリアル化を有効にしましょう。
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class PrivateBean {
private int id;
private String name;
}
そしてテスト:
@Test
public void whenSerializingUsingJsonAutoDetect_thenCorrect()
throws JsonProcessingException {
PrivateBean bean = new PrivateBean(1, "My bean");
String result = new ObjectMapper()
.writeValueAsString(bean);
assertThat(result, containsString("1"));
assertThat(result, containsString("My bean"));
}
5. ジャクソンポリモーフィック型処理アノテーション
次へ–ジャクソンのポリモーフィック型処理アノテーションを見てみましょう。
-
@JsonTypeInfo –シリアル化に含めるタイプ情報の詳細を示します
-
@JsonSubTypes –注釈付きタイプのサブタイプを示します
-
@JsonTypeName –注釈付きクラスに使用する論理型名を定義します
より複雑な例を見て、3つすべて(@JsonTypeInfo、@JsonSubTypes,、@JsonTypeName –)を使用して、エンティティZooをシリアル化/逆シリアル化します。
public class Zoo {
public Animal animal;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public static class Animal {
public String name;
}
@JsonTypeName("dog")
public static class Dog extends Animal {
public double barkVolume;
}
@JsonTypeName("cat")
public static class Cat extends Animal {
boolean likesCream;
public int lives;
}
}
シリアル化を行う場合:
@Test
public void whenSerializingPolymorphic_thenCorrect()
throws JsonProcessingException {
Zoo.Dog dog = new Zoo.Dog("lacy");
Zoo zoo = new Zoo(dog);
String result = new ObjectMapper()
.writeValueAsString(zoo);
assertThat(result, containsString("type"));
assertThat(result, containsString("dog"));
}
ZooインスタンスをDogでシリアル化すると、次のようになります。
{
"animal": {
"type": "dog",
"name": "lacy",
"barkVolume": 0
}
}
次に、逆シリアル化について–次のJSON入力から始めましょう。
{
"animal":{
"name":"lacy",
"type":"cat"
}
}
そして、それがどのようにZooインスタンスにマーシャリングされないかを見てみましょう。
@Test
public void whenDeserializingPolymorphic_thenCorrect()
throws IOException {
String json = "{\"animal\":{\"name\":\"lacy\",\"type\":\"cat\"}}";
Zoo zoo = new ObjectMapper()
.readerFor(Zoo.class)
.readValue(json);
assertEquals("lacy", zoo.animal.name);
assertEquals(Zoo.Cat.class, zoo.animal.getClass());
}
6. ジャクソンの一般的な注釈
次へ–ジャクソンのより一般的な注釈のいくつかについて説明しましょう。
6.1. @JsonProperty
the @JsonProperty annotation to indicate the property name in JSONを追加できます。
非標準のゲッターとセッターを扱う場合は、@JsonPropertyを使用してプロパティnameをシリアル化/逆シリアル化します。
public class MyBean {
public int id;
private String name;
@JsonProperty("name")
public void setTheName(String name) {
this.name = name;
}
@JsonProperty("name")
public String getTheName() {
return name;
}
}
私たちのテスト:
@Test
public void whenUsingJsonProperty_thenCorrect()
throws IOException {
MyBean bean = new MyBean(1, "My bean");
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, containsString("1"));
MyBean resultBean = new ObjectMapper()
.readerFor(MyBean.class)
.readValue(result);
assertEquals("My bean", resultBean.getTheName());
}
6.2. @JsonFormat
@JsonFormatアノテーションは、日付/時刻値をシリアル化するときの形式を指定します。
次の例では、@JsonFormatを使用してプロパティeventDateの形式を制御します。
public class EventWithFormat {
public String name;
@JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "dd-MM-yyyy hh:mm:ss")
public Date eventDate;
}
そして、これがテストです:
@Test
public void whenSerializingUsingJsonFormat_thenCorrect()
throws JsonProcessingException, ParseException {
SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
String toParse = "20-12-2014 02:30:00";
Date date = df.parse(toParse);
EventWithFormat event = new EventWithFormat("party", date);
String result = new ObjectMapper().writeValueAsString(event);
assertThat(result, containsString(toParse));
}
6.3. @JsonUnwrapped
@JsonUnwrappedは、シリアル化/逆シリアル化するときにアンラップ/フラット化する必要がある値を定義します。
それがどのように機能するかを正確に見てみましょう。アノテーションを使用して、プロパティnameをアンラップします。
public class UnwrappedUser {
public int id;
@JsonUnwrapped
public Name name;
public static class Name {
public String firstName;
public String lastName;
}
}
このクラスのインスタンスをシリアル化してみましょう。
@Test
public void whenSerializingUsingJsonUnwrapped_thenCorrect()
throws JsonProcessingException, ParseException {
UnwrappedUser.Name name = new UnwrappedUser.Name("John", "Doe");
UnwrappedUser user = new UnwrappedUser(1, name);
String result = new ObjectMapper().writeValueAsString(user);
assertThat(result, containsString("John"));
assertThat(result, not(containsString("name")));
}
出力は次のようになります。静的にネストされたクラスのフィールドは、他のフィールドと一緒にラップ解除されます。
{
"id":1,
"firstName":"John",
"lastName":"Doe"
}
6.4. @JsonView
@JsonViewは、シリアル化/逆シリアル化のためにプロパティが含まれるビューを示します。
例では、それがどのように機能するかを正確に示します。@JsonViewを使用して、Itemエンティティのインスタンスをシリアル化します。
ビューから始めましょう:
public class Views {
public static class Public {}
public static class Internal extends Public {}
}
次に、ビューを使用したItemエンティティを示します。
public class Item {
@JsonView(Views.Public.class)
public int id;
@JsonView(Views.Public.class)
public String itemName;
@JsonView(Views.Internal.class)
public String ownerName;
}
最後に-完全なテスト:
@Test
public void whenSerializingUsingJsonView_thenCorrect()
throws JsonProcessingException {
Item item = new Item(2, "book", "John");
String result = new ObjectMapper()
.writerWithView(Views.Public.class)
.writeValueAsString(item);
assertThat(result, containsString("book"));
assertThat(result, containsString("2"));
assertThat(result, not(containsString("John")));
}
6.5. @JsonManagedReference, @JsonBackReference
The @JsonManagedReference and @JsonBackReference annotations can handle parent/child relationshipsおよびループを回避します。
次の例では、@JsonManagedReferenceと@JsonBackReferenceを使用してItemWithRefエンティティをシリアル化します。
public class ItemWithRef {
public int id;
public String itemName;
@JsonManagedReference
public UserWithRef owner;
}
UserWithRefエンティティ:
public class UserWithRef {
public int id;
public String name;
@JsonBackReference
public List userItems;
}
そしてテスト:
@Test
public void whenSerializingUsingJacksonReferenceAnnotation_thenCorrect()
throws JsonProcessingException {
UserWithRef user = new UserWithRef(1, "John");
ItemWithRef item = new ItemWithRef(2, "book", user);
user.addItem(item);
String result = new ObjectMapper().writeValueAsString(item);
assertThat(result, containsString("book"));
assertThat(result, containsString("John"));
assertThat(result, not(containsString("userItems")));
}
6.6. @JsonIdentityInfo
@JsonIdentityInfoは、値をシリアル化/逆シリアル化するときに、たとえば、無限再帰タイプの問題を処理するために、オブジェクトIDを使用する必要があることを示します。
次の例では、UserWithIdentityエンティティとaの双方向関係を持つItemWithIdentityエンティティがあります。
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class ItemWithIdentity {
public int id;
public String itemName;
public UserWithIdentity owner;
}
そして、UserWithIdentityエンティティ:
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class UserWithIdentity {
public int id;
public String name;
public List userItems;
}
さて、let’s see how the infinite recursion problem is handled:
@Test
public void whenSerializingUsingJsonIdentityInfo_thenCorrect()
throws JsonProcessingException {
UserWithIdentity user = new UserWithIdentity(1, "John");
ItemWithIdentity item = new ItemWithIdentity(2, "book", user);
user.addItem(item);
String result = new ObjectMapper().writeValueAsString(item);
assertThat(result, containsString("book"));
assertThat(result, containsString("John"));
assertThat(result, containsString("userItems"));
}
シリアル化されたアイテムとユーザーの完全な出力は次のとおりです。
{
"id": 2,
"itemName": "book",
"owner": {
"id": 1,
"name": "John",
"userItems": [
2
]
}
}
6.7. @JsonFilter
@JsonFilterアノテーションは、シリアル化中に使用するフィルターを指定します。
例を見てみましょう。まず、エンティティを定義し、フィルターをポイントします。
@JsonFilter("myFilter")
public class BeanWithFilter {
public int id;
public String name;
}
ここで、完全なテストで、フィルターを定義します。これは、nameを除く他のすべてのプロパティをシリアル化から除外します。
@Test
public void whenSerializingUsingJsonFilter_thenCorrect()
throws JsonProcessingException {
BeanWithFilter bean = new BeanWithFilter(1, "My bean");
FilterProvider filters
= new SimpleFilterProvider().addFilter(
"myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("name"));
String result = new ObjectMapper()
.writer(filters)
.writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, not(containsString("id")));
}
7. カスタムジャクソンアノテーション
次に、カスタムのJacksonアノテーションを作成する方法を見てみましょう。 We can make use of the @JacksonAnnotationsInside annotation:
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({ "name", "id", "dateCreated" })
public @interface CustomAnnotation {}
さて、エンティティで新しい注釈を使用する場合:
@CustomAnnotation
public class BeanWithCustomAnnotation {
public int id;
public String name;
public Date dateCreated;
}
既存の注釈を、簡単なカスタム注釈に結合し、速記として使用する方法を確認できます。
@Test
public void whenSerializingUsingCustomAnnotation_thenCorrect()
throws JsonProcessingException {
BeanWithCustomAnnotation bean
= new BeanWithCustomAnnotation(1, "My bean", null);
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, containsString("1"));
assertThat(result, not(containsString("dateCreated")));
}
シリアル化プロセスの出力:
{
"name":"My bean",
"id":1
}
8. ジャクソンミックスインアノテーション
次へ– JacksonMixInアノテーションの使用方法を見てみましょう。
MixInアノテーションを使用して、たとえば、タイプUserのプロパティを無視しましょう。
public class Item {
public int id;
public String itemName;
public User owner;
}
@JsonIgnoreType
public class MyMixInForIgnoreType {}
これを実際に見てみましょう:
@Test
public void whenSerializingUsingMixInAnnotation_thenCorrect()
throws JsonProcessingException {
Item item = new Item(1, "book", null);
String result = new ObjectMapper().writeValueAsString(item);
assertThat(result, containsString("owner"));
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(User.class, MyMixInForIgnoreType.class);
result = mapper.writeValueAsString(item);
assertThat(result, not(containsString("owner")));
}
9. ジャクソン注釈を無効にする
最後に、disable all Jackson annotationsの方法を見てみましょう。次の例のように、MapperFeature.USE_ANNOTATIONSを無効にすることでこれを行うことができます。
@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
public int id;
public String name;
}
これで、アノテーションを無効にした後、これらは効果がなく、ライブラリのデフォルトが適用されるはずです:
@Test
public void whenDisablingAllAnnotations_thenAllDisabled()
throws IOException {
MyBean bean = new MyBean(1, null);
ObjectMapper mapper = new ObjectMapper();
mapper.disable(MapperFeature.USE_ANNOTATIONS);
String result = mapper.writeValueAsString(bean);
assertThat(result, containsString("1"));
assertThat(result, containsString("name"));
}
注釈を無効にする前のシリアル化の結果:
{"id":1}
注釈を無効にした後のシリアル化の結果:
{
"id":1,
"name":null
}
10. 結論
このチュートリアルは、ジャクソンの注釈を深く掘り下げており、それらを正しく使用することで得られる柔軟性の種類のほんの一部に過ぎません。
これらすべての例とコードスニペットの実装は、GitHub projectにあります。これはMavenベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。