CHỈNH SỬA: Kìa, trong một bài đăng trên blog của những người bảo trì Jackson, có vẻ như 2.12 có thể thấy những cải tiến liên quan đến việc tiêm hàm tạo. (Phiên bản hiện tại tại thời điểm chỉnh sửa này là 2.11.1)
Cải thiện khả năng tự động phát hiện các trình tạo Hàm tạo, bao gồm giải quyết / giảm bớt các vấn đề với các trình tạo 1 đối số không rõ ràng (ủy quyền so với thuộc tính)
Điều này vẫn đúng với Jackson databind 2.7.0.
The Jackson @JsonCreator
chú thích 2,5 javadoc hoặc Jackson chú thích tài liệu ngữ pháp ( constructor s và nhà máy phương pháp s ) Hãy tin rằng thực sự mà người ta có thể đánh dấu nhiều nhà xây dựng.
Chú thích điểm đánh dấu có thể được sử dụng để xác định các phương thức khởi tạo và phương thức gốc để sử dụng cho việc khởi tạo các phiên bản mới của lớp được liên kết.
Nhìn vào đoạn mã nơi các hàm tạo được xác định, có vẻ như Jackson CreatorCollector
đang bỏ qua các hàm tạo bị quá tải vì nó chỉ kiểm tra đối số đầu tiên của hàm tạo .
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
là trình tạo phương thức khởi tạo được xác định đầu tiên.
newOne
là trình tạo hàm tạo quá tải.
Điều đó có nghĩa là mã như vậy sẽ không hoạt động
@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");
Nhưng mã này sẽ hoạt động:
@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");
Đây là một chút hacky và có thể không phải là bằng chứng trong tương lai .
Tài liệu mơ hồ về cách tạo đối tượng hoạt động; Tuy nhiên, từ những gì tôi thu thập được từ mã, có thể kết hợp các phương pháp khác nhau:
Ví dụ, người ta có thể có một phương thức nhà máy tĩnh được chú thích bằng @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");
Nó hoạt động nhưng nó không phải là lý tưởng. Cuối cùng, nó có thể có ý nghĩa, ví dụ: nếu json là động đó thì có lẽ người ta nên sử dụng một hàm tạo ủy nhiệm để xử lý các biến thể trọng tải một cách thanh lịch hơn nhiều so với nhiều hàm tạo chú thích.
Cũng lưu ý rằng Jackson sắp xếp thứ tự ưu tiên cho người sáng tạo , chẳng hạn như trong mã này:
@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");
Lần này Jackson sẽ không tăng một lỗi, nhưng Jackson sẽ chỉ sử dụng các đại biểu constructor Phone(Map<String, Object> properties)
, điều đó có nghĩa là Phone(@JsonProperty("value") String value)
không bao giờ được sử dụng.