java 杰克逊在使用 @JsonValue 反序列化类时更喜欢私有构造函数而不是 @JsonCreator
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27571380/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hymanson prefers private constructor over @JsonCreator when deserializing a class with @JsonValue
提问by NickAldwin
I have a simple class with a private constructor and a static factory. I want the class to serialize as a number, so I've annotated the getter for the field with @JsonValue
. However, Hymanson appears to prefer the private constructor over the static factory, even when I annotate the static factory with @JsonCreator
. It works if I annotate the private constructor with @JsonIgnore
, but that feels a bit off.
我有一个带有私有构造函数和静态工厂的简单类。我希望类序列化为一个数字,所以我用@JsonValue
. 然而,Hyman逊似乎更喜欢私有构造函数而不是静态工厂,即使我用@JsonCreator
. 如果我用 注释私有构造函数,它会起作用@JsonIgnore
,但感觉有点不对劲。
I've seen some posts claiming that @JsonCreator
only works if the parameters are annotated with @JsonProperty
; however, that seems to be the case for objects serialized as JSON objects. This object is being serialized as a number, and thus there is no property to supply to the annotation.
我看到一些帖子声称@JsonCreator
只有在参数被注释时才有效@JsonProperty
;但是,对于序列化为 JSON 对象的对象似乎就是这种情况。此对象被序列化为数字,因此没有要提供给注释的属性。
Is there something I'm missing?
有什么我想念的吗?
example class:
示例类:
package com.example;
import com.fasterxml.Hymanson.annotation.JsonCreator;
import com.fasterxml.Hymanson.annotation.JsonValue;
import com.google.common.base.Preconditions;
public class NonNegative {
private final double n;
private NonNegative(double n) {
this.n = n;
}
@JsonCreator
public static NonNegative checked(double n) {
Preconditions.checkArgument(n >= 0.0);
return new NonNegative(n);
}
@JsonValue
public double getValue() {
return n;
}
@Override
public int hashCode() {
return Objects.hash(n);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof NonNegative) {
NonNegative that = (NonNegative) obj;
return Objects.equals(n, that.n);
}
return false;
}
}
example tests:
示例测试:
package com.example;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import com.fasterxml.Hymanson.databind.JsonMappingException;
import com.fasterxml.Hymanson.databind.ObjectMapper;
public class NonNegativeTest {
private static final ObjectMapper MAPPER = new ObjectMapper();
@Test
public void itSerializesAndDeserializes() throws Exception {
NonNegative nonNegative = NonNegative.checked(0.5);
assertThat(MAPPER.readValue(MAPPER.writeValueAsString(nonNegative), NonNegative.class)).isEqualTo(nonNegative);
}
/* This test fails. */
@Test(expected = JsonMappingException.class)
public void itDoesNotDeserializeANegativeNumber() throws Exception {
MAPPER.readValue(MAPPER.writeValueAsString(-0.5), NonNegative.class);
}
}
回答by Ilya Ovesnov
Indeed Hymanson will override JsonCreator method with constructor method in case if parameter is Java standard type. I would say this is a bug in BasicDeserializerFactory#_handleSingleArgumentConstructor method.
实际上,如果参数是 Java 标准类型,Hymanson 将使用构造函数方法覆盖 JsonCreator 方法。我会说这是 BasicDeserializerFactory#_handleSingleArgumentConstructor 方法中的一个错误。
So, the problem is that constructor has higher priority then static factory method in case if that constructor and static factory method has regular Java type. There is few ways how to workaround it.
因此,问题是构造函数的优先级高于静态工厂方法,以防该构造函数和静态工厂方法具有常规 Java 类型。有几种方法可以解决它。
Set creator visibility level to NON_PRIVATE:
将创建者可见性级别设置为 NON_PRIVATE:
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NON_PRIVATE)
class NonNegative {
Second way is to delete static factory method and use constructor. I moved Preconditions.checkArgument to the constructor (it doesn't do much... Just throw an IllegalArgumentException if condition is not satisfied):
第二种方法是删除静态工厂方法并使用构造函数。我将 Preconditions.checkArgument 移动到构造函数(它没有做太多......如果条件不满足,则抛出 IllegalArgumentException ):
public class NonNegative {
private final double n;
private NonNegative(double n) {
Preconditions.checkArgument(n >= 0.0);
this.n = n;
}
@JsonValue
public double getValue() {
return n;
}
}
Another way is to use @JsonIgnore annotation but you mention that you don't like this approach :)
另一种方法是使用@JsonIgnore 注释,但您提到您不喜欢这种方法:)
UpdateI've logged a bug: https://github.com/FasterXML/Hymanson-databind/issues/660
更新我记录了一个错误:https: //github.com/FasterXML/Hymanson-databind/issues/660
UpdateHymanson bug that prefers constructor over static factory method was resolved: https://github.com/FasterXML/Hymanson-databind/commit/257ae1c7a88c5ccec2882433a39c0df1de2b73aa
解决了更喜欢构造函数而不是静态工厂方法的更新Hymanson 错误:https: //github.com/FasterXML/Hymanson-databind/commit/257ae1c7a88c5ccec2882433a39c0df1de2b73aa