【问题标题】:Does Jackson deserialise the second character to lowercase for a propertyJackson 是否将属性的第二个字符反序列化为小写
【发布时间】:2017-08-25 23:44:33
【问题描述】:

我们在服务代码中将模型定义为 -

@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class SomeData {

    public boolean tnAvailable;

    @NonNull
    public String sTempChange;

    public boolean isTnAvailable() {
       return faAvailable;
    }

    public void setTnAvailable(boolean faAvailable) {
        this.faAvailable = faAvailable;
    }

    @Nonnull
    public String getSTempChange() {
        return sTempChange;
    }

    public void setSTempChange(@Nonnull String sTempChange) {
        this.sTempChange = sTempChange;
    }

}

当查询响应中包含上述模型的api时,我们得到的响应为-

"someData": {
    "tnAvailable": true,
    "stempChange": "trial_001"
}

让我们惊讶的是响应属性中的stempChange(注意小写t)而不是sTempChange

在 API 调用期间序列化和反序列化对象时怀疑原因是 Jackson com.fasterxml.jackson.core:jackson-core:2.5.2,因为我们不要使用任何其他 getter-setter ot 包装器更改属性。 为什么会发生这种情况?序列化/反序列化是寻找这个的正确方向吗?

编辑 - 来自@Windle 的评论,试图解释这里的不同之处。我再次重复“虽然那里的问题与相同的情况几乎相关。但我期待在 fastxml 中实现这种实现和文档的原因。”

【问题讨论】:

标签: java json jackson deserialization fasterxml


【解决方案1】:

是的,它看起来对方法名称感到困惑。您可以使用 @JsonGetter 注释强制序列化名称

@JsonGetter("sTempChange")
public String getSTempChange() {
    return sTempChange;
}

【讨论】:

  • 我知道我可以强迫它。更想知道是什么混淆了它。
【解决方案2】:

处理 getter/setter 中的多个前导大写字母(如“getURL()”或“getFName()”)。 默认情况下,Jackson 将简单地将所有前导大写字母小写,给出“url”和“fname”。 但是如果你启用 MapperFeature.USE_STD_BEAN_NAMING(在 Jackson 2.5 中添加),它将遵循 Java Bean 命名约定,即仅小写单个大写前导字母;如果找到多个,什么也不做。 这将导致属性“URL”和“FName”。

【讨论】:

  • 将简单地将所有前导大写字母小写...问题是关于 sTempChange 单个前导小写字符后跟一个大写字符。跨度>
  • 从问题本身来看,让我们吃惊的是响应​​属性中的 stempChange(notice lowercase t) 而不是 sTempChange
  • @nullpointer 它由你的 getter/setter 决定。已被声明为 getSTempChange
【解决方案3】:

当我第一次尝试您的 SomeData 类并对其进行序列化时,我得到了以下结果:

{"tnAvailable":true,"sTempChange":"trial_000","stempChange":"trial_000"}

这意味着 jackson 不将您的 getter/setter 与 sTempChange 属性匹配,它们被视为不同的属性。为我的映射器添加以下配置后,我能够重现您的情况:

    ObjectMapper objectMapper = new ObjectMapper();

    objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
    objectMapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.ANY);
    objectMapper.setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.ANY);
    objectMapper.setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.ANY);

现在你的错误的原因是因为 Jackson 使用它自己的 bean 实用程序实现 (com.fasterxml.jackson.databind.util.BeanUtil),当一个实例被序列化时,当一个类处理字段、getter 和 setter 时使用它(由com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector 完成) /反序列化。感兴趣的方法是okNameForGetterokNameForSetter。在这些方法中,根据MapperFeature.USE_STD_BEAN_NAMING 使用了另外两种方法(它在所有方法中的stdNaming 参数中传递)。这两种方法的使用方式如下:

return stdNaming
                ? stdManglePropertyName(name, prefix.length())
                : legacyManglePropertyName(name, prefix.length());

stdManglePropertyName 遵循第 8.8 节中的 Java Beans 规范,而 legacyManglePropertyName 不遵循并且在 Jackson 2.5 之前的版本中使用。

现在,在通过这些方法运行 getter 和 setter 方法名称之后,但是您设置了 MapperFeature.USE_STD_BEAN_NAMINGsTempChange 属性的 getter/setter 名称错误。应该是getsTempChange(小写's')和getsTempChange(还是小写's')才能正确序列化和反序列化SomeData类的实例。

最后是一些测试代码:

import com.fasterxml.jackson.databind.ObjectMapper;


public class Test {

static class SomeData {

    public boolean tnAvailable;

    public String sTempChange;

    public String getsTempChange() {
        return sTempChange;
    }

    public void setsTempChange(String sTempChange) {
        this.sTempChange = sTempChange;
    }

    public boolean isTnAvailable() {
        return tnAvailable;
    }

    public void setTnAvailable(boolean tnAvailable) {
        this.tnAvailable = tnAvailable;
    }

}

public static void main(String[] args) {

    ObjectMapper objectMapper = new ObjectMapper();

//  objectMapper.configure(MapperFeature.USE_STD_BEAN_NAMING, true);

    SomeData someData = new SomeData();
    someData.setsTempChange("trial_000");
    someData.setTnAvailable(true);

//  objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
//  objectMapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.ANY);
//  objectMapper.setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.ANY);
//  objectMapper.setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.ANY);

    try {
        System.out.println("Serialize: " + objectMapper.writeValueAsString(someData));

        String json = "{ \"tnAvailable\": false, \"sTempChange\": \"trial_001\" }";

        SomeData anotherData = objectMapper.readValue(json, SomeData.class);

        System.out.println("Deserialize: " + anotherData.isTnAvailable() + ", " + anotherData.getsTempChange());

    } catch (Exception e) {
        e.printStackTrace();
    }

}

}

【讨论】:

  • 那该怎么办?
猜你喜欢
  • 2017-08-18
  • 2012-08-19
  • 2013-04-09
  • 2020-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-21
相关资源
最近更新 更多