-
Notifications
You must be signed in to change notification settings - Fork 6.5k
【需求】支持按照成员变量声明顺序,做序列化字段排序 #3115
Comments
/**
* @author ylyue
* @since 2020年4月5日
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
* <p>使用FastJson优先于默认的Jackson做json解析
* <p>https://github.com/alibaba/fastjson/wiki/%E5%9C%A8-Spring-%E4%B8%AD%E9%9B%86%E6%88%90-Fastjson
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setDateFormat(JSON.DEFFAULT_DATE_FORMAT);
// config.setFeatures(Feature.OrderedField);
// config.setFeatures(Feature.SortFeidFastMatch);
config.setSerializerFeatures(
// SerializerFeature.SortField,
// SerializerFeature.MapSortField,
SerializerFeature.PrettyFormat,
SerializerFeature.BrowserCompatible,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullBooleanAsFalse,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullNumberAsZero,
SerializerFeature.WriteNullStringAsEmpty
);
converter.setFastJsonConfig(config);
converters.add(0, converter);
}
} 在测试FastJson优先于默认的Jackson做消息转换器时,发现不能实现按照成员变量声明顺序做序列化字段排序,所产生的需求。 |
把默认的SortField剔除可解决这个问题 |
感谢你提供的方法,但设置了之后,并非按照声明的成员变量顺序进行排序,好像会变成无规律可循了。 测试代码声明成员变量如下: public class FastJsonHttpMessageConverterDTO {
int inta;
Integer intb;
long longa;
Long longb;
boolean booleana;
Boolean booleanb;
String str;
Map<?, ?> map;
Map<?, ?> map2;
JSONObject jsonObject;
JSONObject jsonObject2;
String[] arrayStr;
long[] arrayLong;
List<?> list;
List<?> list2;
TestEnum testEnum;
Date date;
DateTime dateTime;
LocalDate localDate;
LocalTime localTime;
LocalDateTime localDateTime;
} jackson响应结果: {
"code": 200,
"msg": "成功",
"flag": true,
"count": 0,
"data": {
"inta": 0,
"intb": 0,
"longa": 0,
"longb": 0,
"booleana": false,
"booleanb": null,
"str": "",
"map": {},
"map2": {},
"jsonObject": {},
"jsonObject2": {},
"arrayStr": [],
"arrayLong": [],
"list": [],
"list2": [
null,
null,
"",
null
],
"testEnum": null,
"date": null,
"dateTime": null,
"localDate": null,
"localTime": null,
"localDateTime": null
}
} fastjson响应结果 {
"code": 200,
"msg": "成功",
"flag": true,
"count": null,
"data": {
"arrayLong": [],
"arrayStr": [],
"booleana": false,
"booleanb": null,
"date": null,
"dateTime": null,
"inta": 0,
"intb": null,
"jsonObject": {},
"jsonObject2": {},
"list": [],
"list2": [
null,
null,
"",
null
],
"localDate": null,
"localDateTime": null,
"localTime": null,
"longa": 0,
"longb": null,
"map": {},
"map2": {},
"str": "",
"testEnum": null
}
} 设置之后的响应结果: {
"code": 200,
"msg": "成功",
"flag": true,
"count": null,
"data": {
"map": {},
"date": null,
"map2": {},
"jsonObject2": {},
"arrayLong": [],
"list": [],
"list2": [
null,
null,
"",
null
],
"jsonObject": {},
"arrayStr": [],
"inta": 0,
"intb": null,
"booleana": false,
"longa": 0,
"longb": null,
"booleanb": null,
"localTime": null,
"testEnum": null,
"dateTime": null,
"localDate": null,
"localDateTime": null,
"str": ""
}
} |
@yl-yue public static void main(String[] args) {
FastJsonHttpMessageConverterDTO converterDTO = new FastJsonHttpMessageConverterDTO();
JSON.DEFAULT_GENERATE_FEATURE = JSON.DEFAULT_GENERATE_FEATURE &~ SerializerFeature.SortField.getMask();
System.out.println(JSON.toJSONString(converterDTO, SerializerFeature.PrettyFormat,
SerializerFeature.WriteMapNullValue));
}
public static class FastJsonHttpMessageConverterDTO {
public int inta;
public Integer intb;
public long longa;
public Long longb;
public boolean booleana;
public Boolean booleanb;
public String str;
public Map<?, ?> map;
public Map<?, ?> map2;
public JSONObject jsonObject;
public JSONObject jsonObject2;
public String[] arrayStr;
public long[] arrayLong;
public List<?> list;
public List<?> list2;
public Date date;
public DateTime dateTime;
public LocalDate localDate;
public LocalTime localTime;
public LocalDateTime localDateTime;
} 运行的结果
是可以按顺序输出的,但里面有一个前提,就是必须加上SerializerFeature.PrettyFormat,具体为什么我还没有具体去研究。抱歉我的疏忽给你带来了困扰。 这样做虽然可以保持顺序,但是不确定会不会带来其他的问题,所以这并不是一个标准的解决方案。 |
@xuqiming 不太确定是否是版本原因,我本地是1.2.73。 需要按照成员变量声明顺序排序,主要还是因为想使用FastJsonHttpMessageConverter替换MappingJackson2HttpMessageConverter。这样返回给前端的参数顺序是可控的,方便文档抒写与查看。 实际操作使用json并不关心顺序 |
经过测试。结论如下: 没有getter/setter 时,TypeUtils.computeGetters():1858 这里获取不到getter方法,然后到2168行获取fields数组。 但如果有getter/setter ,代码走到上面这处,根据map遍历结果来决定字段序列化顺序,这导致禁用排序后,每次序列化出来的顺序就是LinkedHashMap的插入顺序。而 这个map插入顺序,是按 clazz.getMethods() 返回来遍历的,而这个返回每次顺序不确定。 然后在 2173行 getFieldInfos()
|
再补充一下,gson和jackson为什么实现会和字段的定义顺序一致。
|
在网上搜了很久都无法解决,最终通过单步跟踪分析代码找到了解决办法,我这里是正确的: JSON.DEFAULT_GENERATE_FEATURE &= ~SerializerFeature.SortField.getMask();
SerializeConfig serializeConfig = new SerializeConfig(true);
System.out.println(JSON.toJSONString(javaObject, serializeConfig)); |
@rilyu 感谢提供有效示例,已测试通过。改天对排序与不排序的性能进行测试下 |
@rilyu 感谢,找了好久 |
100w次测试,性能呈千倍级下降啊 |
2.0.21 按照这个方法也不行
得到的还是
|
目前FastJson采用的是按字母排序,和
@JSONField
注解实现自定义排序,是否可以考虑支持一下同toString()
方法一样采用成员变量声明顺序做序列化字段排序 @wenshaoThe text was updated successfully, but these errors were encountered: