РЕДАГУВАТИ : Ось, у дописі блогу , який підтримують Джексон, здається, 2.12 може побачити покращення щодо введення конструктора. (Поточна версія на момент редагування - 2.11.1)
Покращення автоматичного виявлення творців конструктора, включаючи вирішення / полегшення проблем із двозначними конструкторами з 1 аргументом (делегування проти властивостей)
Це все ще справедливо для Jackson databind 2.7.0.
Джексон @JsonCreator
анотації 2,5 Javadoc або Джексон анотацій документації граматик ( конструктор s і завод метод s ) Нехай вважає , що на насправді можна відзначити кілька конструкторів.
Анотація маркера, яка може бути використана для визначення конструкторів та фабричних методів як одного для створення нових екземплярів відповідного класу.
Дивлячись на код, де ідентифікуються творці , схоже, що Джексон 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");
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 такий динамічний, то, можливо, слід поглянути на використання конструктора делегатів, щоб обробляти зміни корисного навантаження набагато елегантніше, ніж із декількома анотованими конструкторами.
Також зверніть увагу, що Джексон упорядковує творців за пріоритетом , наприклад у цьому коді:
@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");
Цього разу Джексон не викличе помилки, але Джексон буде використовувати лише конструктор делегатівPhone(Map<String, Object> properties)
, що означає, що Phone(@JsonProperty("value") String value)
ніколи не використовується.