源码Git地址: https://github.com/git-simm/simm-framework.git (欢迎大家提交优化代码 ^_^)
一、业务场景
公司先有业务系统,后来觉得需要抽离公共的底层权限服务。再加上之前的业务对象命名不规范,这次想要一次搞定。面对这种场景,摆在我面前的有三套方案。
  1. 用底层权限服务提供的数据格式,把业务代码中不规范的引用都改一遍。影响面实在太广,放弃;
  2. 加一个数据适配层,从底层权限服务请求到json数据,定义一套匹配的pojo类型进行接收。之后再用适配方法,进行对象转换,得到适合系统使用的业务对象。这种搞法比较传统,代理层、适配器都需要自己人工处理。代码量还是较大,不够优雅;
  3. 利用反射+注解的方式,让程序自动去匹配不对等的属性,自行完成数据适配的过程。这种搞法就便捷多了,以后遇到名称不匹配的属性,我就直接添加个注解就行了。接下来就开撸吧。
二、实现目标
  1. 简单对象,属性都是简单类型,能够自动映射;
  2. 复杂的Class,要能递归进行自动映射;
  3. 复杂的List对象,要能递归进行自动映射;

三、实现方案

  • 核心转换实现类 :ProxyJsonUtil
  • 映射关系解析实现类: ProxyResolveUtil
  • 反射赋值工具类:ReflectUtil
  • 权限平台请求代理:AuthorityUtil

1. 新建两个注解 ProxyEntity、ProxyProp

/*** 代理实体(用于json序列化&反序列化)*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface ProxyEntity {//代理实体名String value() default "";
}/*** 代理属性(用于json序列化&反序列化)*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface ProxyProp {//属性名
    String value();
}

2、核心代码 反射+递归 进行字段映射

package simm.framework.jsonext;import org.springframework.data.util.Pair;
import simm.framework.jsonext.annotations.ProxyEntity;
import simm.framework.jsonext.annotations.ProxyProp;
import simm.framework.jsonext.entity.ProxyField;
import simm.framework.jsonext.entity.ProxyMsg;import java.lang.reflect.Field;
import java.util.*;/*** 代理信息解析工具*/
public class ProxyResolveUtil {/*** 同步锁*/private static Object _lock = new Object();/*** 代理类型缓存*///对类型缓存做线程安全处理private static Map<String,ProxyMsg> clazzCache = Collections.synchronizedMap(new HashMap<String,ProxyMsg>());/*** 获取代理信息* @param clazz* @return*/public static ProxyMsg getProxyMsg(Class clazz){String key = clazz.getName();if(clazzCache.containsKey(key)) return clazzCache.get(key);synchronized (_lock){//双重检查if(clazzCache.containsKey(key)) return clazzCache.get(key);//开始解析
            clazzCache.put(key,getClazzProxyMsg(clazz));}return clazzCache.get(key);}/*** 获取类型代理信息* @param clazz* @return*/private static ProxyMsg getClazzProxyMsg(Class clazz){ProxyEntity proxyEntity = (ProxyEntity) clazz.getAnnotation(ProxyEntity.class);if(proxyEntity==null) return null;ProxyMsg proxyMsg = new ProxyMsg();proxyMsg.setClazz(clazz);proxyMsg.setProxyName(proxyEntity.value());//解析字段信息List<ProxyField> propList = new ArrayList<>();List<Pair<String, String>> listConfig= new ArrayList<>();HashMap<String, String> mapConfig= new HashMap<>();for (Field field: clazz.getDeclaredFields()){ProxyProp proxyProp = field.getAnnotation(ProxyProp.class);if(proxyProp == null){mapConfig.put(field.getName(),field.getName());continue;}else{ProxyField pField = new ProxyField();pField.setField(field);pField.setFieldName(field.getName());pField.setProxyName(proxyProp.value());propList.add(pField);//beanutils 做属性拷贝时,使用该参数
                listConfig.add(Pair.of(pField.getProxyName(),pField.getFieldName()));mapConfig.put(pField.getProxyName(),pField.getFieldName());}}proxyMsg.setFields(propList);proxyMsg.setListConfig(listConfig);proxyMsg.setMapConfig(mapConfig);return proxyMsg;}
}

View Code

package simm.framework.jsonext;import java.lang.reflect.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;public class ReflectUtil {/*** 同步锁*/private static Object _lock = new Object();/*** 代理字段缓存*///对类型缓存做线程安全处理private static Map<String,Field> fieldCache = Collections.synchronizedMap(new HashMap<String,Field>());/*** 获取字段信息* @param entity* @param fieldName* @param <E>* @return*/public static <E> Field getField(E entity,String fieldName){String key = entity.getClass().getName()+"@"+fieldName;if(fieldCache.containsKey(key)) return fieldCache.get(key);synchronized (_lock){//双重检查if(fieldCache.containsKey(key)) return fieldCache.get(key);//开始解析Field f = null;try {f = entity.getClass().getDeclaredField(fieldName);f.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}fieldCache.put(key,f);}return fieldCache.get(key);}/*** 获取list 属性的 泛型类型* @param entity* @param fieldName* @return*/public static <E> Class<?> getActClazz(E entity, String fieldName){Field f = getField(entity,fieldName);if(f.getType() == java.util.List.class){// 如果是List类型,得到其Generic的类型Type genericType = f.getGenericType();if(genericType == null) return null;// 如果是泛型参数的类型if(genericType instanceof ParameterizedType){ParameterizedType pt = (ParameterizedType) genericType;//得到泛型里的class类型对象Class<?> genericClazz = (Class<?>)pt.getActualTypeArguments()[0];return genericClazz;}}return (Class<?>) f.getGenericType();}/*** 获取字段值* @param target* @param fieldName* @param <E>* @return* @throws Exception*/public static <E> Object getFieldVal(E target, String fieldName){try {return getField(target,fieldName).get(target);} catch (IllegalAccessException e) {e.printStackTrace();return null;}}/*** 设置字段值* @param target* @param fieldName* @param <E>* @return*/public static <E> void setFieldVal(E target, String fieldName,Object value) {try {getField(target,fieldName).set(target,value);} catch (IllegalAccessException e) {e.printStackTrace();}}
}

View Code

package simm.framework.jsonext;import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.TypeUtils;
import org.springframework.data.util.Pair;
import simm.framework.jsonext.entity.ProxyMsg;import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;public class ProxyJsonUtil {/*** 批量拷贝* @param source* @param clazz* @param <E>* @param deepCopy 是否需要递归处理* @return*/public static <E> List<E> cast(List<JSONObject> source, Class<E> clazz,boolean deepCopy) {List<E> result = new ArrayList<>();for (JSONObject t : source) {E object = cast(t, clazz, deepCopy);result.add(object);}return result;}/*** 单条拷贝* @param source* @param clazz* @param <E>* @return*/public static <E> E cast(JSONObject source, Class<E> clazz, boolean deepCopy) {return copyProperties(source, clazz, deepCopy);}/*** 拷贝属性* @param source* @param clazz* @param <E>* @param deepCopy* @return*/private static <E> E copyProperties(JSONObject source, Class<E> clazz, boolean deepCopy) {try {E object = TypeUtils.castToJavaBean(source, clazz, ParserConfig.getGlobalInstance());copyProperties(source, object, deepCopy);return object;} catch (Exception e) {e.printStackTrace();return null;}}/*** JsonObject属性值拷贝* @param source* @param target* @param <E>* @param deepCopy*/private static <E> void copyProperties(JSONObject source,E target, boolean deepCopy) throws Exception {if(deepCopy){//深层递归,处理子对象赋值
            proxyEntityCast(source, target, deepCopy);}//代理字段赋值
        proxyFieldCast(source, target);}/*** 深层递归,处理子对象赋值* @param source* @param target* @param deepCopy* @param <E>* @throws Exception*/private static <E> void proxyEntityCast(JSONObject source, E target, boolean deepCopy) throws Exception {ProxyMsg msg = ProxyResolveUtil.getProxyMsg(target.getClass());Map<String,String> map = msg.getMapConfig();for (Map.Entry<String, Object> entry : source.entrySet()){//映射实体不包含该属性,则退出代理赋值if(!map.containsKey(entry.getKey()))continue;//获取映射实体的字段名String fieldName = map.get(entry.getKey());Object value = entry.getValue();if(value instanceof JSONArray){jsonArrayCast(target, deepCopy, fieldName, (JSONArray) value);}else if(value instanceof JSONObject){jsonObjectCast(target, deepCopy, fieldName, (JSONObject) value);}}}/*** JSONObject转换处理* @param target* @param deepCopy* @param fieldName* @param value* @param <E>* @throws Exception*/private static <E> void jsonObjectCast(E target, boolean deepCopy, String fieldName, JSONObject value) throws Exception {//属性是一个JSONObject 对象Object fieldTarget = ReflectUtil.getFieldVal(target, fieldName);if(fieldTarget == null){Type fieldType = ReflectUtil.getField(target, fieldName).getGenericType();ReflectUtil.setFieldVal(target, fieldName,copyProperties(value,(Class)fieldType,deepCopy));}else{//递归为JsonObject属性赋值
            copyProperties(value,fieldTarget,deepCopy);}}/*** JSONArray 字段处理* @param target* @param deepCopy* @param fieldName* @param value* @param <E>* @throws Exception*/private static <E> void jsonArrayCast(E target, boolean deepCopy, String fieldName, JSONArray value) throws Exception {//属性是一个 JSONArray 的列表对象//获取需要被赋值的目标对象Object fieldTarget = ReflectUtil.getFieldVal(target, fieldName);//目标对象为空,退出运行Class<?> fieldGenericClazz = ReflectUtil.getActClazz(target,fieldName);if(fieldTarget == null){fieldTarget = new ArrayList();ReflectUtil.setFieldVal(target, fieldName,fieldTarget);}JSONArray tempList = value;if(fieldTarget instanceof List){// 如果是List类型,得到其Generic的类型List<Object> temps = (List<Object>)fieldTarget;for(int i=0;i<tempList.size();i++){//递归为JsonObject属性赋值if(temps.size()<=i){//自动创建新对象
                    temps.add(copyProperties((JSONObject)tempList.get(i),fieldGenericClazz,deepCopy));}else{copyProperties((JSONObject)tempList.get(i),temps.get(i),deepCopy);}}}}/*** 代理字段赋值* @param source* @param target* @param <E>*/private static <E> void proxyFieldCast(JSONObject source, E target) {//代理字段赋值ProxyMsg msg = ProxyResolveUtil.getProxyMsg(target.getClass());for (Pair<String, String> pair : msg.getListConfig()) {String key = pair.getFirst();if(!source.containsKey(key)) continue;Object value = source.get(key);if(value instanceof JSONArray || value instanceof JSONObject) continue;ReflectUtil.setFieldVal(target, pair.getSecond(),value);}}
}

View Code

转载于:https://www.cnblogs.com/MrSi/p/9452328.html

JSON不对称反序列化映射方案相关推荐

  1. C#开发笔记之19-如何用C#实现优雅的Json解析(序列化/反序列化)方案?

    本文由 比特飞 原创发布,欢迎大家踊跃转载. 转载请注明本文地址:C#开发笔记之19-如何用C#实现优雅的Json解析(序列化/反序列化)方案? | .Net中文网. C#开发笔记概述 另外可参考文章 ...

  2. 序列化对象C++对象的JSON序列化与反序列化探索

    新手发帖,很多方面都是刚入门,有错误的地方请大家见谅,欢迎批评指正 一:背景 作为一名C++开发人员,我始终很期待能够像C#与JAVA那样,可以省力的进行对象的序列化与反序列化,但到现在为止,还没有找 ...

  3. JSON序列化和反序列化还有这种玩法

    Mixin对于前端开发者可不陌生,Vue.React等知名前端框架都使用了Mixin.而对于后端开发,尤其是Java后端开发来说Mixin却是一个很陌生的概念.今天来我们通过Jackson让后端开发者 ...

  4. C#开发笔记之21-C#解析Json(序列化/反序列化)的最佳实践。

    本文由 比特飞 原创发布,欢迎大家踊跃转载. 转载请注明本文地址:C#开发笔记之21-C#解析Json(序列化/反序列化)的最佳实践. | .Net中文网. C#开发笔记概述 另外可参考文章:C#开发 ...

  5. 一文读懂Json序列化与反序列化

    一文读懂Json序列化与反序列化 一文读懂Json序列化与反序列化 #mermaid-svg-tVjnnlFu6ZBDpGOQ {font-family:"trebuchet ms" ...

  6. 【Unity百宝箱】游戏中的用户数据存档 | Json序列化和反序列化 | 数据加密和解密 | 干货游戏教程

    目录 框架设计 工具选用 逻辑书写 框架使用 框架优化 数据加密 总结 最后 Hi 大家好,我是游戏区Bug打工人小棋. 在游戏开发过程中,我们经常有存储用户数据的这一需求,比方说:游戏音量.关卡进度 ...

  7. DotNet的JSON序列化与反序列化

    JSON(JavaScript Object Notation)JavaScript对象表示法,它是一种基于文本,独立于语言的轻量级数据交换格式.在现在的通信中,较多的采用JSON数据格式,JSON有 ...

  8. Windows页目录自映射方案

    在Windows的虚拟内存管理方案中,有一个设计值得特别一提,那就是Windows页目录自映射机制.Dave Probert很早在一份讲义中提到了这一机制(称为self-mapping page ta ...

  9. C#中JSON序列化和反序列化

    有一段时间没有到博客园写技术博客了,不过每天逛逛博客园中大牛的博客还是有的,学无止境-- 最近在写些调用他人接口的程序,用到了大量的JSON.XML序列化和反序列化,今天就来总结下json的序列化和反 ...

  10. json 反序列化 父子类型_Jaskson精讲第7篇-类继承关系下的JSON序列化与反序列化JsonTypeInfo...

    Jackson是Spring Boot(SpringBoot)默认的JSON数据处理框架,但是其并不依赖于任何的Spring 库.有的小伙伴以为Jackson只能在Spring框架内使用,其实不是的, ...

最新文章

  1. 上面一个星星下面一个r_中国第一个王朝不是夏朝?山西出土一个破陶壶,上面俩字揭开谜题...
  2. [职业生涯]你和你的工作
  3. osg画线_osg 基本几何图元
  4. Android之Toolbar的三个问题:修改左边箭头颜色、怎样修改右边以及子activity中的toolbar添加返回箭头
  5. C++设计模式之三 单例模式
  6. AD数据库的备份与还原
  7. 软件测试--selenium脚本编写注意点(二)
  8. java代码获取gc信息,如何监视Java垃圾回收
  9. GridView 中 DataFormatString 的使用
  10. mysql 给表填充数据库_mysql---为测试数据库填充大量数据
  11. python入门教程汇总
  12. mapbox绘制航线图
  13. java规则引擎Drools实战
  14. Linux学习整理-终端快捷键(常用)
  15. 中国被动元件市场规模调研与发展趋势预测报告2022版
  16. MSTAR648方案遥控器配置
  17. 椭圆部分面积计算公式及微积分推导过程
  18. 【IOI2000】 邮局
  19. 按国家归类的海淘网站大全
  20. 纸张折叠多少次能够和珠穆朗玛峰峰一样高

热门文章

  1. windows安装生成苹果证书
  2. Unity3D探索之路-C#与js脚本间的相互调用
  3. 概率论与数理统计学习笔记——第二讲——事件的相互关系及运算
  4. 乾坤未定,你我皆是黑马
  5. Altium Designer使用-----铺铜规则设置(AD20)
  6. 流计算 Oceanus 操作效率提升指南(一)
  7. 螺旋方阵使用C++的简单实现
  8. 100Wqps异地多活,得物是怎么架构的?
  9. 某计算机系统的内存容量配置为128,2015年9月教育部统考《计算机应用基础》模拟试卷(6)满分答案...
  10. 初学者指南:GRUB-系统引导管理器