背景
今天在实际编码过程中碰到一个问题,需要将实体格式化转为JSON,然后再将JSON反序列化为数据库对象存储到数据库中。@JSONField注解用的不亦乐乎,然后测试的时候悲剧了,JSON换格式要求为“yyyyMMddHHmmss”,那么果断“@JSONField(name = “xxxxxxx”, format = “yyyyMMddHHmmss”)”。当将转换的JSON对方反序列化发现时间格式字段无法反序列化并报错。网上各种找资料发现阿里的fastjson反序列化并不支持format。心里一万头草泥马奔过。没办法别人不提供咱自己弄吧(网上的感觉都不那么靠谱),亲测有效,如有性能等高要求的请略过。
注如果需要实现多级嵌套实体JSON间转换,请自行改造递归,此处不提供
序第二个问题当@JSONField的name属性首字母为大写,同时实体使用lombok的@data、@get、@set(不愿意写get、set,也就是@JSONField直接写在属性上而不是写在get方法上)测试转换为JSON对象时首字母变小写了。
干货-代码
问题一代码
public static <T> T JosnToObject(String json, Class<T> clazz) {
JSONObject jsonObject = JSON.parseObject(json);
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName();
Object objValue = jsonObject.get(fieldName);
if (objValue != null) {
//如果是日期类型
if (field.getGenericType().getTypeName().equals("java.sql.Timestamp")) {
JSONField jsonField = field.getAnnotation(JSONField.class);
if (jsonField != null) {
String formtStr = jsonField.format();
String nowVal = objValue.toString();
switch (formtStr) {
case "yyyyMMddHHmmss":
if (nowVal.length() == nowVal.length()) {
nowVal = nowVal.substring(0, 4)
+ "-" + nowVal.substring(4, 6)
+ "-" + nowVal.substring(6, 8)
+ " " + nowVal.substring(8, 10)
+ ":" + nowVal.substring(10, 12)
+ ":" + nowVal.substring(12, 14);
}
break;
case "yyyyMMdd":
if (nowVal.length() == nowVal.length()) {
nowVal = nowVal.substring(0, 4)
+ "-" + nowVal.substring(4, 6)
+ "-" + nowVal.substring(6, 8)
+ " 00:00:00";
}
break;
default:
break;
}
jsonObject.put(fieldName, Timestamp.valueOf(nowVal));
}
}
}
}
return JSONObject.toJavaObject(jsonObject, clazz);
}
问题二代码
/**
* json 序列化
* @return
*/
public static <T extends Object> String objToJson(T obj,Class<T> clazz){
// 输出的JSON对象
JSONObject newObj = new JSONObject();
// 输入的JSON对象
JSONObject jsonObj = (JSONObject) JSON.toJSON(obj);
for(String key : jsonObj.keySet()){
for(Field field : clazz.getDeclaredFields()){
if(field.getName().toLowerCase().equals(key.toLowerCase())){
// 获取字段注解内容
JSONField annotation = field.getAnnotation(JSONField.class);
Object o = jsonObj.get(key);
if(o != null){
// 重新封装JSON对象
newObj.put(annotation.name(),o);
}
}
}
}
return newObj.toJSONString();
}
原理
- 问题一
- 将JSON转换为JSONObject对象
- 获取转换后实体所有属性
- 遍历实体属性
- 获取属性上JSONField注解对象
- 检测到format属性为需要重新格式化时
- 原值格式化为正确格式类型(源码只提供了时间格式,其他格式自行添加不赘述)
- 修改JSONObject对象中对应属性值为格式化后的值
- 调用JSONObject.toJavaObject转为实体返回
- 问题二
- 创建输出JSONObject对象
- json反序列化输入JSONObject对象
- 嵌套循环输入JSONObject对象与实体属性集合
- 名称转小写比对一致则替换
- 调用JSONObject.toJavaObject转为实体返回