EDYCJA : Oto w poście na blogu opiekunów Jacksona wygląda na to, że 2.12 może zobaczyć ulepszenia w odniesieniu do wstrzykiwania konstruktora. (Aktualna wersja w momencie tej edycji to 2.11.1)
Ulepsz automatyczne wykrywanie twórców konstruktorów, w tym rozwiązywanie / łagodzenie problemów z niejednoznacznymi konstruktorami 1-argumentowymi (delegowanie a właściwości)
To nadal jest prawdą w przypadku indeksu Jackson w wersji 2.7.0.
The Jackson @JsonCreator
adnotacja 2,5 javadoc lub Jacksona adnotacje dokumentacja gramatyki ( konstruktor s i metoda fabryki s ) Pozwól uwierzyć, że rzeczywiście można oznaczyć wielu konstruktorów.
Adnotacja znacznika, której można użyć do zdefiniowania konstruktorów i metod fabrycznych jako jednej do użycia do tworzenia wystąpień nowych wystąpień skojarzonej klasy.
Patrząc na kod, w którym zidentyfikowani są twórcy , wygląda na to, że Jackson CreatorCollector
ignoruje przeciążone konstruktory, ponieważ sprawdza tylko pierwszy argument konstruktora .
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
jest pierwszym zidentyfikowanym twórcą konstruktora.
newOne
jest przeciążonym twórcą konstruktora.
Oznacza to, że taki kod nie zadziała
@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");
Ale ten kod zadziała:
@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");
Jest to trochę hakerskie i może nie być przyszłościowe .
Dokumentacja jest niejasna o tym, jak działa tworzenie obiektów; z tego, co wyciągam z kodu, wynika jednak, że można mieszać różne metody:
Na przykład można mieć statyczną metodę fabryki z adnotacją @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");
Działa, ale nie jest idealny. Ostatecznie może to mieć sens, np. Jeśli JSON jest tak dynamiczny, to może należałoby spróbować użyć konstruktora delegata do obsługi zmian ładunku znacznie bardziej elegancko niż w przypadku wielu konstruktorów z adnotacjami.
Zwróć też uwagę, że Jackson porządkuje twórców według priorytetów , na przykład w tym kodzie:
@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");
Tym razem Jackson nie zgłosi błędu, ale Jackson użyje tylko konstruktora delegataPhone(Map<String, Object> properties)
, co oznacza, że Phone(@JsonProperty("value") String value)
nigdy nie zostanie użyty.