EDIT : Jackson のメンテナーによるブログ投稿を見ると、2.12 ではコンストラクター インジェクションに関して改善が見られるようです。(この編集時の現在のバージョンは 2.11.1 です)
あいまいな 1 引数のコンストラクター (委譲とプロパティ) に関する問題の解決/軽減を含む、コンストラクター作成者の自動検出を改善します。
これは、Jackson データバインド 2.7.0 でも当てはまります。
Jackson@JsonCreator
アノテーション 2.5 javadocまたはJackson アノテーション ドキュメントの文法 (コンストラクターとファクトリー メソッド) は、複数のコンストラクターをマークできると実際に信じさせます。
関連するクラスの新しいインスタンスをインスタンス化するために使用するものとして、コンストラクターとファクトリ メソッドを定義するために使用できるマーカー アノテーション。
作成者が識別されるコードを見ると、Jacksonはコンストラクターの最初の引数のみをチェックするため、オーバーロードされたコンストラクターCreatorCollector
を無視しているように見えます。
Class<?> oldType = oldOne.getRawParameterType(0);
Class<?> newType = newOne.getRawParameterType(0);
if (oldType == newType) {
throw new IllegalArgumentException("Conflicting "+TYPE_DESCS[typeIndex]
+" creators: already had explicitly marked "+oldOne+", encountered "+newOne);
}
oldOne
最初に特定されたコンストラクタ作成者です。
newOne
オーバーロードされたコンストラクタ作成者です。
つまり、そのようなコードは機能しません
@JsonCreator
public Phone(@JsonProperty("value") String value) {
this.value = value;
this.country = "";
}
@JsonCreator
public Phone(@JsonProperty("country") String country, @JsonProperty("value") String value) {
this.value = value;
this.country = country;
}
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\"}", Phone.class).value).isEqualTo("+336"); // raise error here
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\"}", Phone.class).value).isEqualTo("+336");
しかし、このコードは機能します:
@JsonCreator
public Phone(@JsonProperty("value") String value) {
this.value = value;
enabled = true;
}
@JsonCreator
public Phone(@JsonProperty("enabled") Boolean enabled, @JsonProperty("value") String value) {
this.value = value;
this.enabled = enabled;
}
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\"}", Phone.class).value).isEqualTo("+336");
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\",\"enabled\":true}", Phone.class).value).isEqualTo("+336");
これは少しハックであり、将来的に証明されない可能性があります。
ドキュメントは、オブジェクトの作成がどのように機能するかについてあいまいです。私がコードから収集したものから、異なる方法を混在させることが可能であるということです:
たとえば、静的ファクトリ メソッドに注釈を付けることができます。@JsonCreator
@JsonCreator
public Phone(@JsonProperty("value") String value) {
this.value = value;
enabled = true;
}
@JsonCreator
public Phone(@JsonProperty("enabled") Boolean enabled, @JsonProperty("value") String value) {
this.value = value;
this.enabled = enabled;
}
@JsonCreator
public static Phone toPhone(String value) {
return new Phone(value);
}
assertThat(new ObjectMapper().readValue("\"+336\"", Phone.class).value).isEqualTo("+336");
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\"}", Phone.class).value).isEqualTo("+336");
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\",\"enabled\":true}", Phone.class).value).isEqualTo("+336");
動作しますが、理想的ではありません。最終的には、それは理にかなっている可能性があります。たとえば、JSON がそれほど動的である場合、デリゲート コンストラクターを使用して、複数の注釈付きコンストラクターよりもはるかにエレガントにペイロードのバリエーションを処理する必要があります。
また、Jacksonは作成者を優先順位で注文することに注意してください。たとえば、このコードでは次のようになります。
// Simple
@JsonCreator
public Phone(@JsonProperty("value") String value) {
this.value = value;
}
// more
@JsonCreator
public Phone(Map<String, Object> properties) {
value = (String) properties.get("value");
// more logic
}
assertThat(new ObjectMapper().readValue("\"+336\"", Phone.class).value).isEqualTo("+336");
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\"}", Phone.class).value).isEqualTo("+336");
assertThat(new ObjectMapper().readValue("{\"value\":\"+336\",\"enabled\":true}", Phone.class).value).isEqualTo("+336");
今回、Jackson はエラーを発生させませんが、Jackson はデリゲートコンストラクターのみを使用します。Phone(Map<String, Object> properties)
つまり、Phone(@JsonProperty("value") String value)
は使用されません。