我们在服务代码中定义了一个模型 -
@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
在响应的属性中。
怀疑原因是Jackson com.fasterxml.jackson.core:jackson-core: 2.5.2 ,同时在API调用期间对对象进行序列化和反序列化,因为我们不要使用任何其他getter-setter ot包装器来更改属性。 为什么会发生这种情况,并且序列化/反序列化是正确的方向来寻找它?
编辑 - 来自@Windle的评论,尝试解释这里有什么不同。我重新迭代“这个问题虽然在很大程度上与相同的情况有关。但我也很期待在fastxml中实现这种实现和文档的原因。”
答案 0 :(得分:4)
在getter / setter中处理多个首字母大写字母(例如“getURL()”或“getFName()”)。 默认情况下,杰克逊将简单地小写所有前导大写字母,给出“url”和“fname”。 但是,如果您启用 MapperFeature.USE_STD_BEAN_NAMING (在Jackson 2.5中添加),它将遵循Java Bean命名约定将执行的操作,这只是小写的单个大写前导字母;如果发现多个,什么也不做。 这将导致属性“URL”和“FName”。
答案 1 :(得分:3)
是的,看起来它对方法名称感到困惑。您可以使用@JsonGetter注释强制序列化名称
@JsonGetter("sTempChange")
public String getSTempChange() {
return sTempChange;
}
答案 2 :(得分:1)
当我第一次尝试你的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
完成)处理类时使用它们。一个实例被序列化/反序列化。感兴趣的方法是okNameForGetter
和okNameForSetter
。在这些方法中,根据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_NAMING
,都会错误地命名sTempChange
属性的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();
}
}
}