编辑:看哪,在 Jackson 的维护者的 blog post 中,似乎 2.12 可能会看到构造函数注入方面的改进。 (本次编辑时的当前版本是 2.11.1)
改进对构造函数创建者的自动检测,包括解决/缓解模糊 1 参数构造函数的问题(委托与属性)
这仍然适用于 Jackson 数据绑定 2.7.0。
Jackson @JsonCreator annotation 2.5 javadoc 或 Jackson annotations documentation 语法(构造函数s 和工厂方法s)让人相信确实可以标记多个构造函数。
可用于将构造函数和工厂方法定义为用于实例化关联类的新实例的标记注释。
查看标识创建者的代码,Jackson CreatorCollector 似乎忽略了重载的构造函数,因为它仅checks the first argument of the constructor。
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 orders creators by priority,例如在此代码中:
// 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 只会使用 delegate 构造函数 Phone(Map<String, Object> properties),这意味着永远不会使用 Phone(@JsonProperty("value") String value)。