一、现象
1.Accept值设置为application/json,或不设置值均可以返回正常JSON
{
"ResponseStatusObject": {
"Id": "1",
"LocalTime": "20191227141606",
"RequestURL": "/VIID/Subscribes/1",
"StatusCode": "7",
"StatusString": "JSON格式无效"
}
}
2.Accept设置为application/*+json后,返回的JSON中实体字段首字母变成小写
{
"ResponseStatusObject": {
"id": "1",
"statusCode": "7",
"requestURL": "/VIID/Subscribes/1",
"statusString": "JSON格式无效",
"localTime": "20191227141437"
}
}
二、原因
查看项目中是否配置了消息转换器,比如配置了FastJsonHttpMessageConverter用来替换默认的MappingJackson2HttpMessageConverter。
由于配置FastJsonHttpMessageConverter时只适配了application/json,所以Accept为/或application/json的可以通过此转换器进行转换。如下:
// 添加支持的MediaTypes;不添加时默认为*/*,也就是默认支持全部
List<MediaType> fastMediaTypes = new ArrayList<>();
//这里只支持了application/json
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
而application/*+json由于没有适配并且方法上加上了@ResponseBody注解,所有还会走默认的MappingJackson2HttpMessageConverter,所以会出现这种诡异的问题。MappingJackson2HttpMessageConverter对pojo类型序列化的处理转换逻辑如下:
Jackson2在初始化序列器时,对pojo类型对象会收集其属性信息,属性包括成员变量及方法,然后属性名称和处理过后的方法名称做为key保存到一个LinkedHashMap中。收集过程中会调用com.fasterxml.jackson.databind.util.BeanUtil中的legacyManglePropertyName方法用来处理方法名称,它会将get/set方法前缀,即get或set去掉,并将其后面的连续大写字符转换成小写字符返回。例如: getNEWString会转变成newstring返回。你的属性名称如果有这样的"nSmallSellCount",lombok自动生成的get方法就会是这样的"getNSmallSellCount",处理过后就是这样的"nsmallSellCount",这与属性nSmallSellCount并不冲突,可以同时存在于HashMap中。收集完属性信息后,下面的步骤中会删除掉非可见的属性,一般指的是私有成员变量,这时,名称为"nSmallSellCount"的成员变量属性会被删除掉,这样的序列化结果是不会有问题的,但,如果加了@JsonProperty注释,Jackson2会认为这个属性是可见的,不必会删除,这时这两个表示同一个值得属性就会被一同序列化。
三、解决方案(两种选择其一即可)
1.在要转换的POJO类中标注@JsonProperty注解,指定想要转换成的名字。
注意:此种方案有个问题就是如果将注解标注在字段上,那么转成JSON后字段会出现重复问题,具体原因可以参考上面的转换逻辑。将注解标注在get\set方法上面即可。(如果使用了lombok,就只能手动编写get\set方法了)
2.在配置的消息转换器中增加对application/*+json的支持即可。
MediaType mediaType = new MediaType("application", "viid+json", StandardCharsets.UTF_8);
fastMediaTypes.add(mediaType);