編集:見よ、ジャクソンのメンテナによるブログ投稿では、2.12はコンストラクタインジェクションに関して改善が見られるようです。(この編集時の現在のバージョンは2.11.1です)
あいまいな1引数コンストラクターの問題を解決/軽減するなど、コンストラクター作成者の自動検出を改善します(委任とプロパティ)
これは、Jackson databind2.7.0にも当てはまります。
ジャクソン@JsonCreator
注釈2.5 javadocのか、ジャクソン注釈文書の文法(コンストラクタの工場法の)1ができることを本当に信じて離すと自然にマークする複数のコンストラクタを。
コンストラクターとファクトリメソッドを、関連付けられたクラスの新しいインスタンスをインスタンス化するために使用するものとして定義するために使用できるマーカーアノテーション。
作成者が識別されるコードを見ると、JacksonCreatorCollector
はコンストラクターの最初の引数のみをチェックするため、オーバーロードされたコンストラクターを無視しているように見えます。
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");
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は、たとえば次のコードで、作成者を優先度順に並べていることに注意してください。
@JsonCreator
public Phone(@JsonProperty("value") String value) {
this.value = value;
}
@JsonCreator
public Phone(Map<String, Object> properties) {
value = (String) properties.get("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");
今回、Jacksonはエラーを発生させませんが、Jacksonはデリゲートコンストラクターのみを使用します。Phone(Map<String, Object> properties)
つまり、Phone(@JsonProperty("value") String value)
は使用されません。