利用Java反射机制将Map集合转成实体类

当有需要将Map的字段一一赋值到实体类时,发现一个一个字段取值和赋值操作比较繁琐,如果Map中数据类型不一致,还需要做类型强转。所以通过反射自动把Map的数据转成实体类中,可以让业务代码更加美观。

public static <T> T mapToEntity(Map<?, ?> map, Class<T> clazz) {
		// 验证Map和实体类Class对象是否为空
		Assert.notNull(map, "map cannot be null");
		Assert.notNull(clazz, "entity class cannot be null");
		try {
			List<Field> allFields = new ArrayList<>();
			T t = clazz.newInstance();
			Class<?> aClass = clazz;
			do {
				// 利用Java反射获取自身属性以及父类属性
				allFields.addAll(Stream.of(aClass.getDeclaredFields()).collect(Collectors.toList()));
				aClass = aClass.getSuperclass();
				// Object类为超级大类,到了Object类,继承关系已到了顶点,不需要处理了
			} while (!StringUtil.equals(aClass.getTypeName(), Object.class.getTypeName()));
			// 对实体类的属性进行遍历
			for (Field field : allFields) {
				// 获取属性名称
				String fieldName = field.getName();
				// 属性对应的实体类名称,这里需要一一对应,否则取不到值
				Object data = map.get(fieldName);
				// 按照Java约定的getter、setter方法命名规范,拼装setter方法名
				String methodName = StringUtil.format("set{}{}", fieldName.substring(0, 1).toUpperCase(), fieldName.substring(1));
				// 获取setter方法的Method对象
				Method method = clazz.getMethod(methodName, field.getType());
				// 利用Java反射调用实体对象的setter方法对属性进行赋值操作
				method.invoke(t, getData(data, field.getType()));
			}
			return t;
		} catch (InstantiationException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		} catch (NoSuchMethodException e) {
			throw new RuntimeException(e);
		} catch (InvocationTargetException e) {
			throw new RuntimeException(e);
		}
	}
	/**
	 * 这里的这个方法是为了兼容Sql语句查询后返回的Map。
	 * 在使用Mybatis查询后返回的数据类型为了兼容都使用了大类型,本来是int类型的数据
	 * 但还是返回了long类型,在这里就做了特殊处理,如果实体类中属性为int,Map中类型为Long时,
	 * 就对类型进行转换。在这里还可以做其他的兼容处理
	 */
	private static Object getData(Object data, Class<?> type) {
		String typeName = type.getTypeName();
		if (StringUtil.equals(typeName, Integer.class.getTypeName())) {
			if (data instanceof Long) {
				return ((Long) data).intValue();
			}
		}
		return data;
	}