编辑:看哪,在杰克逊维护者的博客文章中,似乎2.12可能会看到有关构造函数注入的改进。(此编辑时的当前版本为2.11.1)
改进构造函数创建者的自动检测,包括解决/缓解模棱两可的一参数构造函数的问题(委托与属性)
对于Jackson数据绑定2.7.0仍然适用。
杰克逊@JsonCreator
注释2.5的javadoc或杰克逊的注释文档语法(构造函数小号和工厂方法小号)让确实认为,人们可以标记多个构造。
标记批注,可用于将构造函数和工厂方法定义为用于实例化关联类的新实例的标记。
查看确定创建者的代码,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");
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");
这次Jackson不会引发错误,但是Jackson只会使用委托构造函数Phone(Map<String, Object> properties)
,这意味着Phone(@JsonProperty("value") String value)
永远不会使用。