Java Jackson是否将属性的第二个字符反序列化为小写
我们在服务代码中定义了一个模型-Java Jackson是否将属性的第二个字符反序列化为小写,java,json,jackson,deserialization,fasterxml,Java,Json,Jackson,Deserialization,Fasterxml,我们在服务代码中定义了一个模型- @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) public class SomeData { public boolean tnAvailable; @NonNull public String sTempChange; public boolean isTnAvailable() { return faAvailable; }
@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的评论,试图解释这里的不同之处。我再次重申“这个问题虽然与相同的情况有很大关系。但是我也期待着用fasterxml实现和编写文档的原因。”是的,它看起来在方法名称上有点混乱。您可以使用@JsonGetter注释强制序列化名称
@JsonGetter("sTempChange")
public String getSTempChange() {
return sTempChange;
}
是的,它看起来在方法名上有点混乱。您可以使用@JsonGetter注释强制序列化名称
@JsonGetter("sTempChange")
public String getSTempChange() {
return sTempChange;
}
处理getter/setter中的多个前导大写字母(如“getURL()”或“getFName()”)。 默认情况下,Jackson只需将所有前导大写字母小写,给出“url”和“fname”。 但是,如果您启用MapperFeature.USE_STD_BEAN_NAMING(在Jackson 2.5中添加),它将遵循Java BEAN命名约定所做的操作,即只使用小写字母和大写字母;如果找到多个,则不执行任何操作。
这将导致属性“URL”和“FName”。处理getter/setter中的多个前导大写字母(如“getURL()”或“getFName()”)。 默认情况下,Jackson只需将所有前导大写字母小写,给出“url”和“fname”。 但是,如果您启用MapperFeature.USE_STD_BEAN_NAMING(在Jackson 2.5中添加),它将遵循Java BEAN命名约定所做的操作,即只使用小写字母和大写字母;如果找到多个,则不执行任何操作。
这将导致属性“URL”和“FName”。当我第一次尝试您的
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
完成)当实例被序列化/反序列化时。感兴趣的方法是okNameForSetter
和okNameForSetter
。在这些方法中,根据MapperFeature,还使用了另外两种方法。使用\u STD\u BEAN\u 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\u STD\u BEAN\u NAMING
,您的sTempChange
属性的getter/setter命名错误。它应该是getsTempChange
(小写)和getsTempChange
(同样小写)来正确序列化和反序列化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();
}
}
}当我第一次尝试您的
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
完成)当实例被序列化/反序列化时。感兴趣的方法是okNameForSetter
和okNameForSetter
。在这些方法中,根据MapperFeature,还使用了另外两种方法。使用\u STD\u BEAN\u 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\u STD\u BEAN\u NAMING
,您的sTempChange
属性的getter/setter命名错误。它应该是getsTempChange
(小写)和getsTempChange
(同样小写)来正确序列化和反序列化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();
}
}
}我知道我可以强迫它。我更想知道是什么让它困惑。我知道我可以强迫它。更渴望知道是什么使它困惑。可能的重复-那一个有一个虽然=)@Windle问题,尽管那里几乎与相同的情况有关。但我期待着这一切的原因