编辑:看哪,在杰克逊的维护者的博客文章中,似乎 2.12 可能会看到构造函数注入方面的改进。(本次编辑时的当前版本是 2.11.1)
改进构造函数创建者的自动检测,包括解决/缓解含糊不清的 1 参数构造函数的问题(委托与属性)
这仍然适用于 Jackson 数据绑定 2.7.0。
Jackson@JsonCreator
注释 2.5 javadoc或Jackson 注释文档语法(构造函数和工厂方法)确实让人相信可以标记多个构造函数。
可用于将构造函数和工厂方法定义为用于实例化关联类的新实例的标记注释。
查看标识创建者的代码,看起来 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"); // 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 是动态的,那么也许应该考虑使用委托构造函数来比使用多个带注释的构造函数更优雅地处理有效负载变化。
另请注意,杰克逊按优先级对创建者进行排序,例如在此代码中:
// 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)
从未使用过。