利用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;
}