gpt4 book ai didi

java - 在使用 @JsonValue 反序列化类时,Jackson 更喜欢私有(private)构造函数而不是 @JsonCreator

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:15:02 34 4
gpt4 key购买 nike

我有一个带有私有(private)构造函数和静态工厂的简单类。我希望该类序列化为数字,所以我用 @JsonValue 注释了该字段的 getter。然而,Jackson 似乎更喜欢私有(private)构造函数而不是静态工厂,即使我用 @JsonCreator 注释静态工厂也是如此。如果我用 @JsonIgnore 注释私有(private)构造函数,它会起作用,但感觉有点不对劲。

我看到一些帖子声称 @JsonCreator 只有在参数用 @JsonProperty 注释时才有效;但是,序列化为 JSON 对象的对象似乎就是这种情况。此对象被序列化为数字,因此没有属性可提供给注释。

有什么我想念的吗?

示例类:

package com.example;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.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;
}
}

示例测试:

package com.example;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.Test;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.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);
}
}

最佳答案

事实上,如果参数是 Java 标准类型,Jackson 将使用构造方法覆盖 JsonCreator 方法。我会说这是 BasicDeserializerFactory#_handleSingleArgumentConstructor 方法中的错误。

所以,问题在于如果构造函数和静态工厂方法具有常规 Java 类型,则构造函数具有比静态工厂方法更高的优先级。解决方法很少。

将创作者可见性级别设置为 NON_PRIVATE:

@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NON_PRIVATE)
class NonNegative {

第二种方法是删除静态工厂方法并使用构造函数。我将 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;
}
}

另一种方法是使用@JsonIgnore 注释,但您提到您不喜欢这种方法:)

更新 我记录了一个错误:https://github.com/FasterXML/jackson-databind/issues/660

更新 Jackson bug 更喜欢构造函数而不是静态工厂方法已解决:https://github.com/FasterXML/jackson-databind/commit/257ae1c7a88c5ccec2882433a39c0df1de2b73aa

关于java - 在使用 @JsonValue 反序列化类时,Jackson 更喜欢私有(private)构造函数而不是 @JsonCreator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27571380/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com