fastjson list转json字符串_从fastjson转jackson的血泪史
示例用法:// fastjson 序列化JSON.toJSONString(javaObj, SerializerFeature.WriteClassName);// 类似这样{"@type":"java.util.HashMap","data":{"@type":"...// fastjson 反序列化ParserConfig config = new ParserConfig() ;config.setAutoTypeSupport(true);Map map = JSON.parseObject(json, Map.class, config);
使用相同的特性。在 jackson 框架下,发现性能依然贼好!!最终决定,全面更换 jackson。
由于使用json的地方特别多。大致的更换方案是,完全重写 fastjson 相关的类。尽可能少改动项目现有代码。像 fastjson 中的 JSON, JSONObject, JSONArray 都保持原包名和 类名重写相关使用的方法。
重写完后,以为大功告成,去掉 fastjson的依赖,以为可以上线了!!万万没有想到,这只是万里长征的第一步!!也让我深深体会到 fastjson 的兼容性是有多么多么的好。各种神操作,让你在 jackson 中,都不知道如何改写。也怪我们使用 fastjson的方式太邪乎了!各种非常规使用。
下面讲几个特殊的解析:
javabean的属性是String, 反序列化时,传入这个属性的值是json对象或者json 数组;
属性是枚举,传入 json 对象;
属性是对象,传入是String,String是一个json串;
-
属性是集合,传入是单个json对象;jackson有配置可以使用configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)解决问题,但是这样影响处理属性是集合类型,而传入是String的问题。我就没有使用该特性。然后在自定义异常处理中统一处理该问题
以上举例的反序列化在jackson中直接报错,在网上未能找到相应问题的解决办法,但是最终通过跟踪报错的堆栈信息,进行调试后,发现可以添加一个异常处理的方法。解决这4个问题代码如下:// 问题示例描述public class Abc{ private String attrArr;// 问题1 传入json数组[{"a":"123123"}] private String attr;// 问题1 传入json对象{"a":"123123"} private SexEnum sexEnum;// 问题2 传入json对象{"value":1,"label":"男"} private BBB bbb; // 问题3 传入字符串"{\"b\":\"abc\"}" private List bbb; // 问题4 传入json对象{"b":"abc"} // ...get/set...方法 }public class BBB{ private String b; // ... get/set...方法 } 在fastjson 中是都可以正常转化
// 对应jackson 的版本 2.11.3, 早期版本可能没有该方法或者参数列表不一致objectMapper.addHandler(new CustomDeserializationProblemHandler());static class CustomDeserializationProblemHandler extends DeserializationProblemHandler { @Override public Object handleUnexpectedToken(DeserializationContext ctxt, JavaType targetType, JsonToken t, JsonParser p, String failureMsg) throws IOException { String json = p.getText(); if(targetType.isEnumType() && "{".equals(json)) { ObjectMapper mapper = (ObjectMapper) p.getCodec(); mapper.readTree(p);// 直接读取一个节点。这样就不会忽略之后的结点解析了,但是并不能正确反序列化枚举,需要通过注解实现 return null; } if(targetType.isCollectionLikeType() && "{".equals(json)) { ObjectMapper mapper = (ObjectMapper) p.getCodec(); Object obj = mapper.readValue(p, targetType.getContentType());// 把单个结点数据,转化为一个数组对象 List<Object> list = new ArrayList<Object>(); list.add(obj); return list; } if(targetType.getRawClass().equals(String.class) && "{".equals(json)) { ObjectMapper mapper = (ObjectMapper) p.getCodec(); TreeNode node = mapper.readTree(p);// 把一个对象json,转成一个字符串,有性能损失 return node.toString(); } if(targetType.getRawClass().equals(String.class) && "[".equals(json)) { ObjectMapper mapper = (ObjectMapper) p.getCodec(); TreeNode node = mapper.readTree(p);// 把一个对象json数组,转成一个字符串,有性能损失 return node.toString(); } if ((json.startsWith("{") && json.endsWith("}")) || (json.startsWith("[") && json.endsWith("]"))) { return JSON.parseObject(p.getText(), targetType); } return DeserializationProblemHandler.NOT_HANDLED; } }
-
日期类型反序列化支持多种格式;
在 fastjson 中,长整型、yyyy-MM-dd、yyyy-MM-dd HH:mm 等格式都能正确转化为日期。但是在 jackson 中默认长整型是可以正常转换的。但是另外两种并不能转换,解决办法如下:SimpleModule serializerModule = new SimpleModule("DateSerializer", PackageVersion.VERSION); serializerModule.addDeserializer(Date.class, new CustomDateDeSerializer()); objectMapper.registerModule(serializerModule);static class CustomDateDeSerializer extends DateDeserializers.DateDeserializer { private static final long serialVersionUID = 1L; @Override public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { if (p != null) { String calendatStr = p.getText(); if (calendatStr != null && calendatStr.indexOf("T") < 0 && calendatStr.length() == 19) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { return sdf.parse(calendatStr); } catch (ParseException e) { } } if (calendatStr != null && calendatStr.indexOf("T") < 0 && calendatStr.length() == 16) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); try { return sdf.parse(calendatStr); } catch (ParseException e) { } } if (calendatStr != null && calendatStr.length() == 10 && calendatStr.charAt(4) == '-' && calendatStr.charAt(7) == '-') { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); try { return sdf.parse(calendatStr); } catch (ParseException e) { } } } return super.deserialize(p, ctxt); } }
-
jackson最新版本中做类型保留,这样配置;
// jackson 2.11.3 配置该信息后,序列化和反序列化都会带有类信息objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)
-
枚举类型序列化是以类(即输出属性)形式输出;
// 在枚举上添加该注解@JsonFormat(shape = Shape.OBJECT)public enum SexEnum{ ..... }
最后分享一下关于JSON使用的愚见
1)如果项目中在使用 fastjson 但是没有使用SerializerFeature.WriteClassName特性,没有必要更换新的json 库。但是建议升级最新版本。因为不久前报过多次严重的安全漏洞。
2)保留类信息的方式,反序列化可能成为黑客攻击的入口。该种方式仅用于项目内部接口的调用。
3)应规范使用json 的序列化和反序列化。上边提到的第1点。不管在 fastjson还是上边提到的 jackson 解决方案都影响性能。
4)对于{"action":"add","data":{...大量信息....}}这样json想先确认action值,再对 data做相应类型的解析,建议新建一个类似class SimpleCommand{String action;...get/set...}这样只有 action 一个属性的类进行解析,然后根据 action 值再进行整个json的解析。速度更快一些。
(全文完)
↓↓↓推荐↓↓↓一码解千愁
上一篇: java中实体类转Json的2种方法
下一篇: java 工厂方法详解及实例代码