今天看博客看到一篇文章,谈的是将hibernate查询出来的数据组织到实体中,但他的例子中是按照顺序把值放到实体中,也就是说写的hql的字段顺序得和实体中定义的顺序一致, 于是我就想那要是不一致呢,除了hibernate提供的构造器返回实体的方式,其实我们还可以利用java的反射去封装,于是就在hibernate的工具类下试着封装了下,封装完了之后感觉没必要,这完全就可以提取出来变成一个独立的工具类,而不仅仅局限于hibernate了,这样既可以满足一个hql查询返回了多个实体中的字段属性,且这些属性都是我们用到的一个业务类的属性,也可以满足用sql查询出来的结果,也可以在日常开发中用于map转bean,不过这类情况很少。
于是有了下面这一段代码(毕业不到一年,代码写的不是很漂亮至少我这么认为 ) :
private static <T> T map2Bean(T t,Map map) throws Exception{
Class clazz = t.getClass();
//实例化类
T entity = (T)clazz.newInstance();
Set<String> keys = map.keySet();
//变量map 赋值
for(String key:keys){
String fieldName = key;
//判断是sql 还是hql返回的结果
if(key.equals(key.toUpperCase())){
//获取所有域变量
Field[] fields = clazz.getDeclaredFields();
for(Field field: fields){
if(field.getName().toUpperCase().equals(key)) fieldName=field.getName();
break;
}
}
//设置赋值
try {
//参数的类型 clazz.getField(fieldName)
Class<?> paramClass = clazz.getDeclaredField(fieldName).getType();
//拼装set方法名称
String methodName = "set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
//根据名称获取方法
Method method = clazz.getMethod(methodName, paramClass);
//调用invoke执行赋值
method.invoke(entity, map.get(key));
} catch (Exception e) {
//NoSuchMethod
}
}
return entity;
}
方法里就是通过反射将与map key值相同的类的属性赋值,有一个地方需要注意,就是clazz.getField(fieldName)与clazz.getDeclaredField(fieldName)的区别,前者是获取类中非private的域变量,而后者包括private,我们大多数情况下用到的都应该是后者,谁也不想把私有的域都排除掉嘛!
其实这里赋值有很多种方法,我们也可以获得域变量,通过 setAccessible方法取消Java语言检查,调用field.set(entity,value)方法直接操作域变量赋值,关于反射之前看过一篇文章写的很好,只是我的经验和水准有限吧,它之后的文章理解起来有些吃力,在这里把地址写下来,大家共同进步。
http://www.iteye.com/topic/1123081