当前位置:   article > 正文

Reflect 通过反射获取自定义注解值给另外一个对象赋值

reflector 反射赋值

Reflect 通过反射获取自定义注解值给另外一个对象赋值

一、大致介绍

  1. 1、今天刚完成这么一个功能模块,需求场景是这样的,我们需要对接许多银行的接口,我们解析银行XML报文后,根据每个银行每个接口我们会解析得到很多BankDTO;
  2. 2、然后我们需要在BankDTO挑出一些必要的字段放到另外一个 ResultDTO 中去,然后将 ResultDTO 的数据入库处理;
  3. 3、而且最关键的是,每个银行的字段五花八门,我们根本没办法统一字段,最初的办法我们是对每个 BankDTO 写了一个转换类转成 ResultDTO;
  4. 4、但是随着接入的银行越来越多了,开发效率也就慢慢的降下来了,然而我就在思考如何优化这个字段转换来转换去的笨重方法;
  5. 5、经过辗转反侧的思考,最终自己定义一个注解类,然后将这些注解安插在BankDTO上,而我们需要做的事情就是反射获取注解值然后给ResultDTO赋值即可;
  6. 6、原理就是这么简单,这样写好之后,银行一多,开发人员不够,我们找些不会开发的人员只要告诉他们如何写 BankDTO 对象即可,如何映射字段值即可,最后提交代码就搞定了;
  7. 7、而我在这里主要将一些类贴出来仅供大家参考,如果这种思路在大家工作中用得着的话,相信稍微复用我这思路,功能很快就能水到渠成;

二、实现步骤

2.1 反射工具类,参考网上代码做了稍微调整,整理成符合自己业务逻辑的公用工具类

  1. package com.springms.cloud.reflect.util;
  2. import org.slf4j.LoggerFactory;
  3. import java.io.File;
  4. import java.io.IOException;
  5. import java.lang.reflect.Field;
  6. import java.lang.reflect.Method;
  7. import java.net.URL;
  8. import java.util.ArrayList;
  9. import java.util.Arrays;
  10. import java.util.Enumeration;
  11. import java.util.List;
  12. /**
  13. * 反射工具类。
  14. *
  15. * @author hmilyylimh
  16. *
  17. * @version 0.0.1
  18. *
  19. * @date 2017/10/24
  20. */
  21. public class ReflectionUtil {
  22. private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(ReflectionUtil.class);
  23. /**
  24. * 循环向上转型, 获取对象的 DeclaredField。
  25. *
  26. * @param object : 子类对象,也就是实现类对象;
  27. * @param fieldName : 父类中的属性名;
  28. * @return 父类中的属性对象
  29. */
  30. public static Field getDeclaredField(Object object, String fieldName) {
  31. Field field = null;
  32. Class<?> clazz = object.getClass();
  33. for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
  34. try {
  35. field = clazz.getDeclaredField(fieldName);
  36. return field;
  37. } catch (Exception e) {
  38. // 这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
  39. // 如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
  40. // Logger.error("循环向上转型, 获取对象的 DeclaredField 异常, fieldName: {}, object: {}, \n\ne: {}", fieldName, object, CommonUtil.getExceptionStackTrace(e));
  41. }
  42. }
  43. return null;
  44. }
  45. /**
  46. * 循环向上转型, 获取当前对象以及父类所有对象的属性 Field 字段。
  47. *
  48. * @param objectClass
  49. * @return
  50. */
  51. public static List<Field> getDeclaredSuperFields(Class<?> objectClass) {
  52. List<Field> declaredFieldList = new ArrayList<Field>();
  53. Class<?> tempClass = objectClass;
  54. try {
  55. while(true){
  56. if(tempClass == Object.class){
  57. break;
  58. }
  59. declaredFieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
  60. tempClass = tempClass.getSuperclass();
  61. }
  62. } catch (Exception e) {
  63. // 这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
  64. // 如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
  65. Logger.error("循环向上转型, 获取当前对象以及父类所有对象的属性 Field 字段异常, objectClass: {}, \n\ne: {}", objectClass, e);
  66. }
  67. return declaredFieldList;
  68. }
  69. /**
  70. * 循环向上转型, 获取对象的 DeclaredMethod。
  71. *
  72. * @param object : 子类对象,也就是实现类对象;
  73. * @param methodName : 父类中的方法名;
  74. * @param parameterTypes : 父类中的方法参数类型;
  75. * @return 父类中的方法对象
  76. */
  77. public static Method getDeclaredMethod(Object object, String methodName, Class<?>... parameterTypes) {
  78. Method method = null;
  79. for (Class<?> clazz = object.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
  80. try {
  81. method = clazz.getDeclaredMethod(methodName, parameterTypes);
  82. return method;
  83. } catch (Exception e) {
  84. // 这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
  85. // 如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
  86. // Logger.error("循环向上转型, 获取对象的 DeclaredMethod 异常, methodName: {}, object: {}, parameterTypes: {}, \n\ne: {}", methodName, object, parameterTypes, CommonUtil.getExceptionStackTrace(e));
  87. }
  88. }
  89. return null;
  90. }
  91. /**
  92. * 获取 Field 字段的值。
  93. *
  94. * @param field
  95. * @param fieldParentObj
  96. * @return
  97. */
  98. public static Object getFieldValue(Field field, Object fieldParentObj) {
  99. Object value = null;
  100. try {
  101. field.setAccessible(true);
  102. value = field.get(fieldParentObj);
  103. } catch (Exception e) {
  104. Logger.error("获取 Field 字段的值异常, field: {}, fieldParentObj: {}, \n\ne: {}", field, fieldParentObj, e);
  105. }
  106. return value;
  107. }
  108. /**
  109. * 设置 Field 字段的值。
  110. *
  111. * @param field
  112. * @param fieldParentObj
  113. * @param newValueObj
  114. */
  115. public static void setFieldValue(Field field, Object fieldParentObj, Object newValueObj) {
  116. try {
  117. field.setAccessible(true);
  118. field.set(fieldParentObj, newValueObj);
  119. } catch (Exception e) {
  120. Logger.error("设置 Field 字段的值异常, field: {}, fieldParentObj: {}, newValueObj: {}, \n\ne: {}", field,
  121. fieldParentObj,
  122. newValueObj, e);
  123. }
  124. }
  125. /**
  126. * 获取当前对象中子对象的属性。
  127. *
  128. * @param parentObj:当前对象,需要搜索查询字段所属的父类对象;
  129. * @param searchFieldParentClass:查询字段所属字段的父类对象Class类型;
  130. * @param searchFieldName:查询字段名称;
  131. * @return new Object[] { searchFieldParentObject, searchField, searchFieldValue }
  132. */
  133. public static Object[] getChildAttr(Object parentObj, Class<?> searchFieldParentClass, String searchFieldName) {
  134. if (parentObj == null) {
  135. return null;
  136. }
  137. Class<?> parentObjClass = parentObj.getClass();
  138. Field foundedField = null;
  139. Object foundedFieldValue = null;
  140. Object[] result = null;
  141. try {
  142. foundedField = parentObjClass.getDeclaredField(searchFieldName);
  143. foundedField.setAccessible(true);
  144. foundedFieldValue = foundedField.get(parentObj);
  145. return new Object[]{parentObj, foundedField, foundedFieldValue};
  146. } catch (SecurityException e) {
  147. e.printStackTrace();
  148. } catch (NoSuchFieldException e) {
  149. // 此处异常捕获为:找不到属性名异常。
  150. // 注意在此处我们要手工去帮它找到field应该对象到哪个对象里的值,因为我们不知道它们之间的关系,所以需要手工指定关系,找哪个对象去关联
  151. result = getChildObjAttr(parentObj, parentObjClass, searchFieldParentClass, searchFieldName);
  152. } catch (IllegalArgumentException e) {
  153. Logger.error("获取当前对象中子对象的属性异常, searchFieldParentClass: {}, searchFieldName: {}, parentObj: {}, \n\ne: " +
  154. "{}", searchFieldParentClass, searchFieldName,
  155. parentObj, e);
  156. } catch (IllegalAccessException e) {
  157. Logger.error("获取当前对象中子对象的属性异常, searchFieldParentClass: {}, searchFieldName: {}, parentObj: {}, \n\ne: " +
  158. "{}", searchFieldParentClass, searchFieldName,
  159. parentObj, e);
  160. }
  161. return result;
  162. }
  163. /**
  164. * 获取 parentObj 对象中子类对象的属性。
  165. *
  166. * @param parentObj:当前对象,需要搜索查询字段所属的父类对象;
  167. * @param parentObjClass:当前对象类名称类型,需要搜索查询字段所属的父类类名称类型;
  168. * @param searchFieldParentClass:查询字段所属字段的父类对象Class类型;
  169. * @param searchFieldName:查询字段名称;
  170. * @return new Object[] { searchFieldParentObject, searchField, searchFieldValue }
  171. */
  172. private static Object[] getChildObjAttr(Object parentObj, Class<?> parentObjClass, Class<?>
  173. searchFieldParentClass, String
  174. searchFieldName) {
  175. Field[] childFields = parentObjClass.getDeclaredFields();
  176. Field childField = null;
  177. Class<?> childFieldType = null;
  178. for (int i = 0; i < childFields.length; i++) {
  179. childField = childFields[i];
  180. childFieldType = childField.getType();
  181. if (!childFieldType.isMemberClass()) {
  182. if (childFieldType.equals(searchFieldParentClass)) {
  183. return getChildObjAttrDetail(parentObj, childField, searchFieldName);
  184. }
  185. } else {
  186. return getChildAttr(getFieldValue(childField, parentObj), searchFieldParentClass, searchFieldName);
  187. }
  188. }
  189. return null;
  190. }
  191. /**
  192. * 获取 parentObj 对象中子类对象的明细属性。
  193. *
  194. * @param parentObj:当前对象,需要搜索查询字段所属的父类对象;
  195. * @param parentObjChildField:当前对象子对象,需要搜索查询字段所属的父类对象的子对象;
  196. * @param searchFieldName:查询字段名称;
  197. * @return new Object[] { searchFieldParentObject, searchField, searchFieldValue }
  198. */
  199. private static Object[] getChildObjAttrDetail(Object parentObj, Field parentObjChildField, String searchFieldName) {
  200. parentObjChildField.setAccessible(true);
  201. Object searchFieldParentObject = null;
  202. Class<?> childClass = null;
  203. Field searchField = null;
  204. Object searchFieldValue = null;
  205. try {
  206. searchFieldParentObject = parentObjChildField.get(parentObj);
  207. childClass = searchFieldParentObject.getClass();
  208. searchField = childClass.getDeclaredField(searchFieldName);
  209. searchField.setAccessible(true);
  210. searchFieldValue = searchField.get(searchFieldParentObject);
  211. return new Object[]{searchFieldParentObject, searchField, searchFieldValue};
  212. } catch (IllegalArgumentException e) {
  213. Logger.error("获取 parentObj 对象中子类对象的明细属性异常, searchFieldName: {}, parentObj: {}, parentObjChildField: {}, " +
  214. "\n\ne: " +
  215. "{}", searchFieldName, parentObj, parentObjChildField, e);
  216. } catch (SecurityException e) {
  217. Logger.error("获取 parentObj 对象中子类对象的明细属性异常, searchFieldName: {}, parentObj: {}, parentObjChildField: {}, " +
  218. "\n\ne: " +
  219. "{}", searchFieldName, parentObj, parentObjChildField, e);
  220. } catch (IllegalAccessException e) {
  221. Logger.error("获取 parentObj 对象中子类对象的明细属性异常, searchFieldName: {}, parentObj: {}, parentObjChildField: {}, " +
  222. "\n\ne: " +
  223. "{}", searchFieldName, parentObj, parentObjChildField, e);
  224. } catch (NoSuchFieldException e) {
  225. Logger.error("获取 parentObj 对象中子类对象的明细属性异常, searchFieldName: {}, parentObj: {}, parentObjChildField: {}, " +
  226. "\n\ne: " +
  227. "{}", searchFieldName, parentObj, parentObjChildField, e);
  228. }
  229. return null;
  230. }
  231. /**
  232. * 获取接口中所有实现类。
  233. *
  234. * @param interfaceClass
  235. * @return
  236. */
  237. public static List<Class<?>> getAllImplClasses(Class<?> interfaceClass) {
  238. if (!interfaceClass.isInterface()) {
  239. return null;
  240. }
  241. try {
  242. List<Class<?>> resultClassList = new ArrayList<Class<?>>();
  243. // 获得接口所在的当前包名
  244. String packageName = interfaceClass.getPackage().getName();
  245. // 获取接口所在处的包名下的所有实现类
  246. List<Class<?>> allClass = getClassesByPackageName(packageName);
  247. for (int i = 0; i < allClass.size(); i++) {
  248. if (interfaceClass.isAssignableFrom(allClass.get(i))) {
  249. if (!interfaceClass.equals(allClass.get(i))) {// 本身加不进去
  250. resultClassList.add(allClass.get(i));
  251. }
  252. }
  253. }
  254. return resultClassList;
  255. } catch (Exception e) {
  256. Logger.error("获取接口中所有实现类异常, interfaceClass: {}, \n\ne: {}", interfaceClass, e);
  257. return null;
  258. }
  259. }
  260. /**
  261. * 通过包名获取当前包名下所有的类。
  262. *
  263. * @param packageName
  264. * @return
  265. * @throws IOException
  266. * @throws ClassNotFoundException
  267. */
  268. private static List<Class<?>> getClassesByPackageName(String packageName) throws IOException,
  269. ClassNotFoundException {
  270. ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  271. String path = packageName.replace('.', '/');
  272. Enumeration<URL> resources = classLoader.getResources(path);
  273. List<File> dirs = new ArrayList<File>();
  274. while (resources.hasMoreElements()) {
  275. URL resource = resources.nextElement();
  276. dirs.add(new File(resource.getFile()));
  277. }
  278. List<Class<?>> resultClassList = new ArrayList<Class<?>>();
  279. for (File directory : dirs) {
  280. resultClassList.addAll(findClasses(directory, packageName));
  281. }
  282. return resultClassList;
  283. }
  284. /**
  285. * 通过路径以及包名,获取所有类。
  286. *
  287. * @param directory
  288. * @param packageName
  289. * @return
  290. * @throws ClassNotFoundException
  291. */
  292. private static List<Class<?>> findClasses(File directory, String packageName) throws ClassNotFoundException {
  293. List<Class<?>> resultClassList = new ArrayList<Class<?>>();
  294. if (!directory.exists()) {
  295. return resultClassList;
  296. }
  297. File[] files = directory.listFiles();
  298. for (File file : files) {
  299. if (file.isDirectory()) {
  300. assert !file.getName().contains(".");
  301. resultClassList.addAll(findClasses(file, packageName + '.' + file.getName()));
  302. } else if (file.getName().endsWith(".class")) {
  303. resultClassList.add(Class.forName(packageName + "." + file.getName().substring(0, file.getName()
  304. .length() - 6)));
  305. }
  306. }
  307. return resultClassList;
  308. }
  309. }

2.2 自定义注解类,主要用来安插在银行响应类BankDTO身上的;

  1. package com.springms.cloud.reflect.util;
  2. import java.lang.annotation.*;
  3. /**
  4. * 成员字段注解(注解加在解析银行返回的对象中)。
  5. *
  6. * @author hmilyylimh
  7. *
  8. * @version 0.0.1
  9. *
  10. * @date 2017/10/24
  11. *
  12. */
  13. @Target(ElementType.FIELD)
  14. @Retention(RetentionPolicy.RUNTIME)
  15. @Inherited
  16. public @interface CustomFieldAnnotation {
  17. /**
  18. * 自定义注解名称。
  19. *
  20. * @return
  21. */
  22. String customFieldName() default "";
  23. /**
  24. * 自定义注解类型。
  25. *
  26. * @return
  27. */
  28. CustomFieldType customFieldType() default CustomFieldType.PRIMITIVE;
  29. /**
  30. * 标识字段是否有效。
  31. *
  32. * @return
  33. */
  34. boolean isEnable() default true;
  35. /**
  36. * 是否重新刷写。
  37. *
  38. * @return
  39. */
  40. boolean isReWrite() default true;
  41. /**
  42. * 是否是子类属性,是的话,则根据后面的子类所属 Class 寻找字段属性。
  43. *
  44. * @return
  45. */
  46. boolean isChild() default false;
  47. /**
  48. * 自定义注解类型
  49. */
  50. public static enum CustomFieldType {
  51. /**
  52. * 未知类型
  53. */
  54. Unknow,
  55. /**
  56. * 原生类型
  57. */
  58. PRIMITIVE,
  59. /**
  60. * 类成员类型
  61. */
  62. CLASS,
  63. /**
  64. * 数组类型
  65. */
  66. ARRAY,
  67. /**
  68. * 列表类型
  69. */
  70. LIST;
  71. public static CustomFieldType valueof(String fieldType) {
  72. if (CustomFieldType.PRIMITIVE.toString().equalsIgnoreCase(fieldType)) {
  73. return PRIMITIVE;
  74. } else if (CustomFieldType.CLASS.toString().equalsIgnoreCase(fieldType)) {
  75. return CLASS;
  76. } else if (CustomFieldType.ARRAY.toString().equalsIgnoreCase(fieldType)) {
  77. return ARRAY;
  78. } else if (CustomFieldType.LIST.toString().equalsIgnoreCase(fieldType)) {
  79. return LIST;
  80. } else {
  81. return Unknow;
  82. }
  83. }
  84. }
  85. }

2.3 反射获取注解值并给 ResultDTO 赋值的解析器类,非常非常重要的类

  1. package com.springms.cloud.reflect.util;
  2. import org.apache.commons.lang3.StringUtils;
  3. import org.slf4j.LoggerFactory;
  4. import java.lang.reflect.Array;
  5. import java.lang.reflect.Field;
  6. import java.lang.reflect.ParameterizedType;
  7. import java.lang.reflect.Type;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10. /**
  11. * 注解反射解析器。
  12. *
  13. * @author hmilyylimh
  14. *
  15. * @version 0.0.1
  16. *
  17. * @date 2017/10/24
  18. *
  19. */
  20. public class AnnotationReflectParser {
  21. private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(AnnotationReflectParser.class);
  22. /**
  23. * 开始解析。
  24. *
  25. * @param bankObject:银行报文对象。
  26. * @param resultObject:解析后的通用对象。
  27. */
  28. public static boolean start(Object bankObject, Object resultObject) {
  29. try {
  30. convert(bankObject, resultObject);
  31. return true;
  32. } catch (Exception e) {
  33. Logger.error("开始解析出现最外层异常,bankObject: {}, resultObject: {}", bankObject, resultObject);
  34. return false;
  35. }
  36. }
  37. /**
  38. * 循环嵌套解析,该方法会被循环调用多次。
  39. *
  40. * @param bankObject:银行报文对象。
  41. * @param resultObject:解析后的通用对象。
  42. */
  43. private static void convert(Object bankObject, Object resultObject) {
  44. if (bankObject == null) {
  45. Logger.error("循环嵌套解析,传入 bankObject 为空, bankObject: {}, resultObject: {}", bankObject, resultObject);
  46. throw new RuntimeException("循环嵌套解析,传入 bankObject 为空");
  47. }
  48. if (resultObject == null) {
  49. Logger.error("循环嵌套解析,传入 resultObject 为空, bankObject: {}, resultObject: {}", bankObject, resultObject);
  50. throw new RuntimeException("循环嵌套解析,传入 resultObject 为空");
  51. }
  52. Class<?> bankObjClass = bankObject.getClass();
  53. List<Field> bankFields = ReflectionUtil.getDeclaredSuperFields(bankObjClass);
  54. if (bankFields == null || bankFields.isEmpty()) {
  55. Logger.error("循环嵌套解析,bankObject 对象内没有 Field 属性字段, bankObject: {}, resultObject: {}", bankObject,
  56. resultObject);
  57. return;
  58. }
  59. CustomFieldAnnotation customFieldAnnotation = null;
  60. CustomFieldAnnotation.CustomFieldType customFieldType = null;
  61. for (Field bankField : bankFields) {
  62. customFieldAnnotation = bankField.getAnnotation(CustomFieldAnnotation.class);
  63. // 过滤没有注解的字段
  64. if (customFieldAnnotation == null) {
  65. // Logger.error("循环嵌套解析,过滤没有注解的字段, bankField: {}, bankObject: {}, resultObject: {}", bankField, bankObject, resultObject);
  66. continue;
  67. }
  68. // 过滤已经禁用的字段
  69. if (!customFieldAnnotation.isEnable()) {
  70. Logger.error("循环嵌套解析,过滤已经禁用的字段, bankField: {}, bankObject: {}, resultObject: {}", bankField,
  71. bankObject, resultObject);
  72. continue;
  73. }
  74. // 过滤没有定义类型的字段
  75. customFieldType = customFieldAnnotation.customFieldType();
  76. if (customFieldType == null || customFieldType == CustomFieldAnnotation.CustomFieldType.Unknow) {
  77. Logger.error("循环嵌套解析,过滤没有定义类型的字段, bankField: {}, bankObject: {}, resultObject: {}", bankField,
  78. bankObject, resultObject);
  79. continue;
  80. }
  81. // 针对不同类型走不同分支处理
  82. switch (customFieldType) {
  83. case PRIMITIVE: {
  84. setPrimitiveType(bankField, bankObject, customFieldAnnotation, resultObject);
  85. break;
  86. }
  87. case CLASS: {
  88. setClassType(bankField, bankObject, customFieldAnnotation, resultObject);
  89. break;
  90. }
  91. case ARRAY: {
  92. setArrayType(bankField, bankObject, customFieldAnnotation, resultObject);
  93. break;
  94. }
  95. case LIST: {
  96. setListType(bankField, bankObject, customFieldAnnotation, resultObject);
  97. break;
  98. }
  99. case Unknow: {
  100. String msg = String.format("循环嵌套解析, 走进了没有逻辑处理的分支类型, customFieldName: %s, bankFieldName: %s",
  101. customFieldAnnotation.customFieldName(), bankField.getName());
  102. Logger.error(msg);
  103. throw new RuntimeException(msg);
  104. }
  105. }
  106. }
  107. }
  108. /**
  109. * 设置基本类型字段。
  110. *
  111. * @param bankField
  112. * @param bankFieldParentObj
  113. * @param customFieldAnnotation
  114. * @param resultObject
  115. */
  116. private static void setPrimitiveType(Field bankField, Object bankFieldParentObj, CustomFieldAnnotation
  117. customFieldAnnotation, Object resultObject) {
  118. try {
  119. String customFieldName = customFieldAnnotation.customFieldName();
  120. Object bankFieldValue = ReflectionUtil.getFieldValue(bankField, bankFieldParentObj);
  121. Object[] fieldMapping = AnnotationMapping.getGeneralFieldMapping().get(customFieldName);
  122. if (fieldMapping == null) {
  123. String msg = String.format("设置基本类型字段, 没有设置通用字段映射关系, customFieldName: %s, bankFieldName: %s",
  124. customFieldName, bankField.getName());
  125. Logger.error(msg);
  126. throw new RuntimeException(msg);
  127. }
  128. String commonMappingFieldName = (String) fieldMapping[0];
  129. if (StringUtils.isEmpty(commonMappingFieldName)) {
  130. String msg = String.format("设置基本类型字段, 通用对象中的属性字段为空, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName());
  131. Logger.error(msg);
  132. throw new RuntimeException(msg);
  133. }
  134. // 获取 resultObject 结果对象中 commonMappingFieldName 字段对象 Field
  135. // 从 resultObject 当前对象找,以及从 resultObject 父类找 commonMappingFieldName 属性字段
  136. Field commonMappingField = ReflectionUtil.getDeclaredField(resultObject, commonMappingFieldName);
  137. Object fieldParentObj = resultObject;
  138. if (customFieldAnnotation.isChild() || commonMappingField == null) {
  139. // 如果找不到的话,那么则尝试从 resultObject 对象的子对象递归子对象找 commonMappingFieldName 属性字段
  140. Class<?> commonMappingFieldSuperClass = (Class<?>) fieldMapping[1];
  141. Object[] childAttr = ReflectionUtil.getChildAttr(resultObject, commonMappingFieldSuperClass,
  142. commonMappingFieldName);
  143. if (childAttr == null) {
  144. String msg = String.format("设置基本类型字段, 在通用对象的子类中没有搜索到通用属性字段, customFieldName: %s, bankFieldName: %s, " +
  145. "commonMappingFieldName: %s", customFieldName, bankField.getName(), commonMappingFieldName);
  146. Logger.error(msg);
  147. throw new RuntimeException(msg);
  148. }
  149. fieldParentObj = childAttr[0];
  150. commonMappingField = (Field) childAttr[1];
  151. }
  152. // 给结果对象 resultObject 赋值,类型对等则直接赋值
  153. if (customFieldAnnotation.isReWrite()) {
  154. ReflectionUtil.setFieldValue(commonMappingField, fieldParentObj, bankFieldValue);
  155. } else if (commonMappingField.getType() == bankFieldValue.getClass()) {
  156. ReflectionUtil.setFieldValue(commonMappingField, fieldParentObj, bankFieldValue);
  157. }
  158. // 类型不对等的话,则记录错误日志
  159. else {
  160. Logger.error("设置基本类型字段, 类型不对等的话, 银行字段名称: {}, 通用对象字段名称: {}, bankFieldParentObj: {}, customFieldAnnotation: {}, " +
  161. "resultObject: {}", bankField.getName(), customFieldAnnotation.customFieldName(), bankFieldParentObj, customFieldAnnotation, resultObject);
  162. }
  163. } catch (Exception e) {
  164. Logger.error("设置基本类型字段异常, 银行字段名称: {}, 通用对象字段名称: {}, bankFieldParentObj: {}, customFieldAnnotation: {}, " +
  165. "resultObject: {}, \n\ne: " +
  166. "{}", bankField.getName(), customFieldAnnotation.customFieldName(), bankFieldParentObj, customFieldAnnotation, resultObject, e);
  167. throw new RuntimeException("设置基本类型字段异常");
  168. }
  169. }
  170. /**
  171. * 设置类成员类型字段。
  172. *
  173. * @param bankField
  174. * @param bankFieldParentObj
  175. * @param customFieldAnnotation
  176. * @param resultObject
  177. */
  178. private static void setClassType(Field bankField, Object bankFieldParentObj, CustomFieldAnnotation
  179. customFieldAnnotation, Object resultObject) {
  180. try {
  181. String customFieldName = customFieldAnnotation.customFieldName();
  182. Object bankFieldValue = ReflectionUtil.getFieldValue(bankField, bankFieldParentObj);
  183. if (bankFieldValue == null) {
  184. Logger.error("设置类成员类型字段,解析银行对象中 {} 属性字段值为空。", bankField.getName());
  185. return;
  186. }
  187. Class<?> bankFieldObjClass = bankFieldValue.getClass();
  188. Field[] bankFieldObjFields = bankFieldObjClass.getDeclaredFields();
  189. if (bankFieldObjFields == null || bankFieldObjFields.length == 0) {
  190. Logger.error("设置类成员类型字段,bankField 对象内没有 Field 属性字段, bankFieldName: {}, bankFieldParentObj: {}, " +
  191. "customFieldAnnotation: {}, resultObject: {}, ", bankField.getName(), bankFieldParentObj,
  192. customFieldAnnotation, resultObject);
  193. return;
  194. }
  195. // resultObject 该对象有数据,那么就得在 resultObject 中实例化对应的对象
  196. Object[] fieldMapping = AnnotationMapping.getGeneralFieldMapping().get(customFieldName);
  197. if (fieldMapping == null) {
  198. String msg = String.format("设置类成员类型字段, 没有设置通用字段映射关系, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName());
  199. Logger.error(msg);
  200. throw new RuntimeException(msg);
  201. }
  202. String commonMappingFieldName = (String) fieldMapping[0];
  203. if (StringUtils.isEmpty(commonMappingFieldName)) {
  204. String msg = String.format("设置类成员类型字段, 通用对象中的属性字段为空, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName());
  205. Logger.error(msg);
  206. throw new RuntimeException(msg);
  207. }
  208. // 从 resultObject 当前对象找,以及从 resultObject 父类找 commonMappingFieldName 属性字段
  209. Field commonMappingField = ReflectionUtil.getDeclaredField(resultObject, commonMappingFieldName);
  210. Object fieldParentObj = resultObject;
  211. if (commonMappingField == null) {
  212. // 如果找不到的话,那么则尝试从 resultObject 对象的子对象递归子对象找 commonMappingFieldName 属性字段
  213. Class<?> commonMappingFieldSuperClass = (Class<?>) fieldMapping[1];
  214. Object[] childAttr = ReflectionUtil.getChildAttr(resultObject, commonMappingFieldSuperClass,
  215. commonMappingFieldName);
  216. if (childAttr == null) {
  217. String msg = String.format("设置类成员类型字段, 在通用对象的子类中没有搜索到通用属性字段, customFieldName: %s, bankFieldName: %s, " +
  218. "commonMappingFieldName: %s", customFieldName, bankField.getName(), commonMappingFieldName);
  219. Logger.error(msg);
  220. throw new RuntimeException(msg);
  221. }
  222. fieldParentObj = childAttr[0];
  223. commonMappingField = (Field) childAttr[1];
  224. }
  225. // 获取 resultObject 结果对象中 Field 字段的值
  226. if (ReflectionUtil.getFieldValue(commonMappingField, fieldParentObj) == null) {
  227. Object newInstance = commonMappingField.getType().newInstance();
  228. ReflectionUtil.setFieldValue(commonMappingField, resultObject, newInstance);
  229. }
  230. convert(bankFieldValue, resultObject);
  231. } catch (Exception e) {
  232. Logger.error("设置类成员类型字段异常, bankField: {}, bankFieldParentObj: {}, customFieldAnnotation: {}, " +
  233. "resultObject: {}, \n\ne: " +
  234. "{}", bankField, bankFieldParentObj, customFieldAnnotation, resultObject, e);
  235. throw new RuntimeException("设置类成员类型字段异常");
  236. }
  237. }
  238. /**
  239. * 设置数组类型字段。
  240. *
  241. * @param bankField
  242. * @param bankFieldParentObj
  243. * @param customFieldAnnotation
  244. * @param resultObject
  245. */
  246. private static void setArrayType(Field bankField, Object bankFieldParentObj, CustomFieldAnnotation
  247. customFieldAnnotation, Object resultObject) {
  248. try {
  249. String customFieldName = customFieldAnnotation.customFieldName();
  250. Object bankFieldValue = ReflectionUtil.getFieldValue(bankField, bankFieldParentObj);
  251. if (bankFieldValue == null) {
  252. Logger.error("设置数组类型字段,解析银行对象中 {} 属性字段值为空。", bankField.getName());
  253. return;
  254. }
  255. int length = Array.getLength(bankFieldValue);
  256. if (length <= 0) {
  257. String msg = String.format("设置数组类型字段, 银行数组长度为空, customFieldName: %s, bankFieldName: %s",
  258. customFieldName, bankField.getName());
  259. Logger.error(msg);
  260. return;
  261. }
  262. // resultObject 该对象有数据,那么就得在 resultObject 中实例化对应的对象
  263. Object[] fieldMapping = AnnotationMapping.getGeneralFieldMapping().get(customFieldName);
  264. if (fieldMapping == null) {
  265. String msg = String.format("设置数组类型字段, 没有设置通用字段映射关系, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName());
  266. Logger.error(msg);
  267. throw new RuntimeException(msg);
  268. }
  269. String commonMappingFieldName = (String) fieldMapping[0];
  270. if (StringUtils.isEmpty(commonMappingFieldName)) {
  271. String msg = String.format("设置数组类型字段, 通用对象中的属性字段为空, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName());
  272. Logger.error(msg);
  273. throw new RuntimeException(msg);
  274. }
  275. // 从 resultObject 当前对象找,以及从 resultObject 父类找 commonMappingFieldName 属性字段
  276. Field commonMappingField = ReflectionUtil.getDeclaredField(resultObject, commonMappingFieldName);
  277. Object fieldParentObj = resultObject;
  278. if (commonMappingField == null) {
  279. // 如果找不到的话,那么则尝试从 resultObject 对象的子对象递归子对象找 commonMappingFieldName 属性字段
  280. Class<?> commonMappingFieldSuperClass = (Class<?>) fieldMapping[1];
  281. Object[] childAttr = ReflectionUtil.getChildAttr(resultObject, commonMappingFieldSuperClass,
  282. commonMappingFieldName);
  283. if (childAttr == null) {
  284. String msg = String.format("设置数组类型字段, 在通用对象的子类中没有搜索到通用属性字段, customFieldName: %s, bankFieldName: %s, " +
  285. "commonMappingFieldName: %s", customFieldName, bankField.getName(), commonMappingFieldName);
  286. Logger.error(msg);
  287. throw new RuntimeException(msg);
  288. }
  289. fieldParentObj = childAttr[0];
  290. commonMappingField = (Field) childAttr[1];
  291. }
  292. // 获取 resultObject 结果对象中 Field 字段的值
  293. if (ReflectionUtil.getFieldValue(commonMappingField, fieldParentObj) == null) {
  294. Class<?> elementType = commonMappingField.getType();
  295. String elementTypeName = elementType.getName();
  296. int startIndex = elementTypeName.indexOf("com");
  297. int endIndex = elementTypeName.lastIndexOf(";");
  298. String innerClassName = elementTypeName.substring(startIndex, endIndex);
  299. Class<?> innerClass = Class.forName(innerClassName);
  300. // 实例化数组
  301. Object newInstance = Array.newInstance(innerClass, length);
  302. // 数组赋值空对象
  303. Object[] arrays = (Object[]) newInstance;
  304. Object[] bankFieldValueArrays = (Object[]) bankFieldValue;
  305. for (int i = 0; i < length; i++) {
  306. arrays[i] = innerClass.newInstance();
  307. }
  308. // 将空数组赋值到 resultObject 结果对象中
  309. ReflectionUtil.setFieldValue(commonMappingField, fieldParentObj, newInstance);
  310. // 循环解析 bankFieldValueArrays 的值放到结果对象中对应的索引位置中
  311. for (int i = 0; i < length; i++) {
  312. Object itemResultObject = arrays[i];
  313. convert(bankFieldValueArrays[i], itemResultObject);
  314. }
  315. }
  316. } catch (Exception e) {
  317. Logger.error("设置数组类型字段异常, bankField: {}, bankFieldParentObj: {}, customFieldAnnotation: {}, " +
  318. "resultObject: {}, \n\ne: " +
  319. "{}", bankField, bankFieldParentObj, customFieldAnnotation, resultObject, e);
  320. throw new RuntimeException("设置数组类型字段异常");
  321. }
  322. }
  323. /**
  324. * 设置列表类型字段。
  325. *
  326. * @param bankField
  327. * @param bankFieldParentObj
  328. * @param customFieldAnnotation
  329. * @param resultObject
  330. */
  331. private static void setListType(Field bankField, Object bankFieldParentObj, CustomFieldAnnotation
  332. customFieldAnnotation, Object resultObject) {
  333. try {
  334. String customFieldName = customFieldAnnotation.customFieldName();
  335. Object bankFieldValue = ReflectionUtil.getFieldValue(bankField, bankFieldParentObj);
  336. if (bankFieldValue == null) {
  337. Logger.error("设置列表类型字段,解析银行对象中 {} 属性字段值为空。", bankField.getName());
  338. return;
  339. }
  340. List bankFieldValueList = (List) bankFieldValue;
  341. int size = bankFieldValueList.size();
  342. if (size <= 0) {
  343. String msg = String.format("设置列表类型字段, 银行列表长度为空, customFieldName: %s, bankFieldName: %s",
  344. customFieldName, bankField.getName());
  345. Logger.error(msg);
  346. return;
  347. }
  348. // resultObject 该对象有数据,那么就得在 resultObject 中实例化对应的对象
  349. Object[] fieldMapping = AnnotationMapping.getGeneralFieldMapping().get(customFieldName);
  350. if (fieldMapping == null) {
  351. String msg = String.format("设置列表类型字段, 没有设置通用字段映射关系, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName());
  352. Logger.error(msg);
  353. throw new RuntimeException(msg);
  354. }
  355. String commonMappingFieldName = (String) fieldMapping[0];
  356. if (StringUtils.isEmpty(commonMappingFieldName)) {
  357. String msg = String.format("设置列表类型字段, 通用对象中的属性字段为空, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName());
  358. Logger.error(msg);
  359. throw new RuntimeException(msg);
  360. }
  361. // 从 resultObject 当前对象找,以及从 resultObject 父类找 commonMappingFieldName 属性字段
  362. Field commonMappingField = ReflectionUtil.getDeclaredField(resultObject, commonMappingFieldName);
  363. Object fieldParentObj = resultObject;
  364. if (commonMappingField == null) {
  365. // 如果找不到的话,那么则尝试从 resultObject 对象的子对象递归子对象找 commonMappingFieldName 属性字段
  366. Class<?> commonMappingFieldSuperClass = (Class<?>) fieldMapping[1];
  367. Object[] childAttr = ReflectionUtil.getChildAttr(resultObject, commonMappingFieldSuperClass,
  368. commonMappingFieldName);
  369. if (childAttr == null) {
  370. String msg = String.format("设置列表类型字段, 在通用对象的子类中没有搜索到通用属性字段, customFieldName: %s, bankFieldName: %s, " +
  371. "commonMappingFieldName: %s", customFieldName, bankField.getName(), commonMappingFieldName);
  372. Logger.error(msg);
  373. throw new RuntimeException(msg);
  374. }
  375. fieldParentObj = childAttr[0];
  376. commonMappingField = (Field) childAttr[1];
  377. }
  378. Type genericType = commonMappingField.getGenericType();
  379. if(!(genericType instanceof ParameterizedType)){
  380. String msg = String.format("设置列表类型字段, 通用对象中的属性字段类型设置有误,设置的不是列表类型, customFieldName: %s, bankFieldName: %s", customFieldName, bankField.getName());
  381. Logger.error(msg);
  382. return;
  383. }
  384. // 获取 resultObject 结果对象中 Field 字段的值
  385. if (ReflectionUtil.getFieldValue(commonMappingField, fieldParentObj) == null) {
  386. ParameterizedType parameterizedType = (ParameterizedType)genericType;
  387. Class<?> innerClass = (Class) parameterizedType.getActualTypeArguments()[0];//得到对象list中实例的类型
  388. // 实例化数组
  389. List newInstance = new ArrayList();
  390. // 数组赋值空对象
  391. for (int i = 0; i < size; i++) {
  392. newInstance.add(innerClass.newInstance());
  393. }
  394. // 将空数组赋值到 resultObject 结果对象中
  395. ReflectionUtil.setFieldValue(commonMappingField, fieldParentObj, newInstance);
  396. // 循环解析 bankFieldValueArrays 的值放到结果对象中对应的索引位置中
  397. for (int i = 0; i < size; i++) {
  398. Object itemResultObject = newInstance.get(i);
  399. convert(bankFieldValueList.get(i), itemResultObject);
  400. }
  401. }
  402. } catch (Exception e) {
  403. Logger.error("设置列表类型字段异常, bankField: {}, bankFieldParentObj: {}, customFieldAnnotation: {}, " +
  404. "resultObject: {}, \n\ne: " +
  405. "{}", bankField, bankFieldParentObj, customFieldAnnotation, resultObject, e);
  406. throw new RuntimeException("设置列表类型字段异常");
  407. }
  408. }
  409. }

2.4 测试代码,如何调用起我们写的这套功能

  1. package com.springms.cloud.reflect;
  2. import com.springms.cloud.reflect.util.AnnotationReflectParser;
  3. import com.springms.cloud.reflect.util.xml.BeanXml;
  4. /**
  5. * 测试类。
  6. *
  7. * @author hmilyylimh
  8. *
  9. * @version 0.0.1
  10. *
  11. * @date 2017/10/24
  12. *
  13. */
  14. public class TestReflectDemo {
  15. public static void main(String[] args) {
  16. try {
  17. String xmlData = getXml();
  18. Class<?> beanClass = getBeanClassPath();
  19. Object respBankDTO = BeanXml.xml2Bean(xmlData, beanClass);
  20. ResultDTO resultObject = new ResultDTO();
  21. ResultDTO.Record record = new ResultDTO.Record();
  22. resultObject.setRecord(record);
  23. boolean finished = AnnotationReflectParser.start(respBankDTO, resultObject);
  24. System.out.println("finished: " + finished);
  25. System.out.println("=====================================");
  26. } catch (Exception e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. /**
  31. * 这里可以通过路径反射得到 Class 类,如果你的类有规律的话,那完成可以在这个地方通过设定规则出来得到类名路径。
  32. *
  33. * 那么我这里呢,就直接拿个例子来试试而已。
  34. *
  35. * @return
  36. */
  37. private static Class<?> getBeanClassPath() {
  38. String className = "com.springms.cloud.reflect.BankDTO";
  39. return getRespBeanClass(className);
  40. }
  41. private static String getXml() {
  42. String recvContent = "<?xml version='1.0' encoding='GB2312'?>\n" +
  43. "<packet>\n" +
  44. "<head>\n" +
  45. "<transCode>4469</transCode> \n" +
  46. "<signFlag>0</signFlag> \n" +
  47. "<packetID>1234567890</packetID> \n" +
  48. "<timeStamp>2004-07-28 16:14:29</timeStamp> \n" +
  49. "<returnCode>AAAAAAA</returnCode> \n" +
  50. "</head>\n" +
  51. "<body>\n" +
  52. "<acctNo>246333388999</acctNo>\n" +
  53. "<acctName>张三</acctName>\n" +
  54. "<acctBalance>199098777.97</acctBalance>\n" +
  55. "<subTotBalance>199098777.97</subTotBalance>\n" +
  56. "<lists name=\"LoopResult\">\n" +
  57. "<list>\n" +
  58. "<subAcctNo>1234567890000000</subAcctNo>\n" +
  59. "<subAcctBalance>234.56</subAcctBalance>\n" +
  60. "<subAcctName>账户名称甲</subAcctName>\n" +
  61. "</list>\n" +
  62. "</lists>\n" +
  63. "</body>\n" +
  64. "</packet>";
  65. return recvContent;
  66. }
  67. /**
  68. * 获取响应类名的 Class 对象。
  69. *
  70. * @return
  71. */
  72. private static Class<?> getRespBeanClass(String className) {
  73. Class<?> respClass = null;
  74. try {
  75. respClass = Class.forName(className);
  76. return respClass;
  77. } catch (ClassNotFoundException e) {
  78. throw new RuntimeException(className + " 该响应类路径不存在", e);
  79. }
  80. }
  81. }

2.5 总结

  1. 1、虽然这样写可以偷懒了,也可以招非开发人员直接上手撸代码直接开发功能模块,但是不方便的地方就是得发版升级;
  2. 2、后期想法,我们不是有 "Java运行时动态加载类" 这么一说么?后期准备将这一套代码放在某个目录上传,或者直接放到数据库存储,然后动态加载执行对应功能;
  3. 3、想法虽然不错,路漫漫其修远兮,慢慢努力吧,顺便祝各位猿猿们节日快乐;

三、下载地址

https://gitee.com/ylimhhmily/SpringCloudTutorial.git

SpringCloudTutorial交流QQ群: 235322432

SpringCloudTutorial交流微信群: 微信沟通群二维码图片链接

欢迎关注,您的肯定是对我最大的支持!!!

转载于:https://my.oschina.net/hmilyylimh/blog/1555754

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/256047
推荐阅读
相关标签
  

闽ICP备14008679号