今天看博客看到一篇文章,谈的是将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