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