package com.ycsoft.daos.helper;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.springframework.util.Assert;
import com.ycsoft.commons.constants.DictKey;
import com.ycsoft.commons.helper.CollectionHelper;
import com.ycsoft.commons.helper.StringHelper;
import com.ycsoft.commons.helper.JsonHelper;
import com.ycsoft.commons.store.MemoryDict;
/**
* <p> 利用Java 1.5特性,提供对Apache BeanUtils 不足的封装 </p>
*
*/
@SuppressWarnings("unchecked")
public class BeanHelper extends org.apache.commons.beanutils.BeanUtils{
/**
* 将Bean转换为Map ,Bean的属性名称作为Map的key,属性值作为Map的value
* @return
*/
public static Map describe(Object bean) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
if(null == bean){
return null ;
}
Map map =BeanUtils.describe( bean ) ;
map.remove("class");
return map;
}
/**
* <p>
* 通过属性名称,获得该属性对应的Field类型, 循环向上转型,获取对象的DeclaredField, 如果没有找到,则会向上找到父类的模板类
* 依次向上,直到找到该属性为止,如果最终没有找到则返回NUll</p>
* @param clazz 属性对应类的模板
* @param propertyName 属性名称
* @return 属性对应的Field
* @throws NoSuchFieldException
*/
public static Field getDeclaredField(Class clazz, String propertyName)
throws NoSuchFieldException {
for (Class superClass = clazz; superClass != Object.class; superClass = superClass
.getSuperclass()) {
try {
return superClass.getDeclaredField(propertyName);
} catch (NoSuchFieldException e) {
}
}
return null;
}
/**
* <p>强行设置对象的属性值,忽略private、public修饰符</p>
* 没有调用setter方法,进行的设置。
* </p>
*/
public static void forceSetProperty(Object object, String propertyName,
Object newValue) throws Exception {
Field field = getDeclaredField(object.getClass(), propertyName);
boolean accessible = field.isAccessible();
field.setAccessible(true);
field.set(object, newValue);
field.setAccessible(accessible);
}
/**
* 强行获取对象变量值,忽略private,protected修饰符的限制.
* @throws NoSuchFieldException 如果没有该Field时抛出.
*/
public static Object forceGetProperty(Object object, String propertyName)
throws NoSuchFieldException {
Field field = getDeclaredField(object.getClass(), propertyName);
boolean accessible = field.isAccessible();
field.setAccessible(true);
Object result = null;
try {
result = field.get(object);
} catch (IllegalAccessException e) {
}
field.setAccessible(accessible);
return result;
}
/**
* <p> 根据给定的参数名,按照顺序将参数值添加至数组 </p>
* @param propertys 原属性的名称
* @param bean 目标对象
*/
public static List<Object> parseObjectValueToArray(List<String> propertyNames ,Object bean)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
List<Object>lst = new ArrayList<Object>();
for (String _s : propertyNames) {
lst.add(PropertyUtils.getProperty(bean, _s));
}
return lst;
}
/**
* 比较新旧两个Bean的属性变化.如果两个对象的Class不一样,且不是继承关系,则抛出异常.如果两个是继承关系,去基类的属性比较.
* @param theOldOne
* @param theNewOne
* @param properties 需要比较的属性.如果为空,则比较所有的属性.提供的属性bean里找不到,报错.
* @return
* @throws Exception
*/
public static String beanchange(Object theOldOne,Object theNewOne, String... properties ) throws Exception {
//两个都为空不能比,一个为空可以
boolean theOldIsNull = theOldOne==null;
boolean theNewIsNull = theNewOne==null;
if(theOldIsNull&&theNewIsNull){
return null;
}
Class<? extends Object> oldClass = theOldIsNull?null:theOldOne.getClass();
Class<? extends Object> newClass = theNewIsNull?null:theNewOne.getClass();
PropertyDescriptor [] fieldsDescriptors= null;
PropertyUtilsBean propertyUtils = BeanUtilsBean.getInstance().getPropertyUtils();
if(!theOldIsNull && !theNewIsNull){//两个都不为空
try{
Assert.isAssignable(oldClass, newClass, "比较的两个对象不同类且不是继承关系");
fieldsDescriptors = propertyUtils.getPropertyDescriptors(oldClass);
}catch (Exception e) {
Assert.isAssignable(newClass, oldClass, "比较的两个对象不同类且不是继承关系");
fieldsDescriptors = propertyUtils.getPropertyDescriptors(newClass);
}
}else if(theOldIsNull){//老的为空
fieldsDescriptors = propertyUtils.getPropertyDescriptors(newClass);
}else if(theNewIsNull){//新的为空
fieldsDescriptors = propertyUtils.getPropertyDescriptors(oldClass);
}
//安全的初始化两组对比的值
//开始比较,结果装入Map,外层,key是fieldName,内存以 "old" "new"为key
Map<String, Map<String, Object>> dataChanged = new HashMap<String, Map<String, Object>>();
if(properties ==null || properties.length == 0){
properties = new String [fieldsDescriptors.length -1];
List<String> fieldNameList = new ArrayList<String>();
for(int index =0;index<fieldsDescriptors.length;index++){
String name = fieldsDescriptors[index].getName();
if(!name.equals("class")){
fieldNameList.add(name);
}
}
properties = fieldNameList.toArray(new String[fieldNameList.size()]);
}
//比较值
for(String fieldName:properties){
Map<String, Object> changed = new HashMap<String, Object>();
Object oldValue = null;
Object newValue = null;
try{
oldValue = theOldIsNull?null:forceGetProperty(theOldOne, fieldName);//使用这个方法,如果属性不存在,抛错
newValue = theNewIsNull?null:forceGetProperty(theNewOne, fieldName);//使用这个方法,如果属性不存在,抛错
}catch (Exception e) {
throw new IllegalArgumentException("Bean的属性参数有错,bean里没有属性 '" + fieldName +"' ");
}
changed.put("old", oldValue);
changed.put("new", newValue);
dataChanged.put(fieldName, changed);
}
StringBuilder resultBuffer = new StringBuilder();
String format = "%s:%s=>%s";
for(Entry<String, Map<String, Object>> entry:dataChanged.entrySet()){
Map<String, Object> field = entry.getValue();
Object newVal = field.get("new");
Object oldVal = field.get("old");
newVal = null == newVal ? "":newVal;
oldVal = null == oldVal ? "":oldVal;
if (com.ycsoft.commons.helper.StringHelper.isEmpty(newVal.toString())
&& com.ycsoft.commons.helper.StringHelper.isEmpty(oldVal.toString())) {// 两个都为空,continue,null作为空字符串一样对待
continue;
}
String oldValStr = "null";
String newValStr = "null";
if(com.ycsoft.commons.helper.StringHelper.isEmpty(newVal.toString()) ){
if(oldVal.getClass().isAssignableFrom(Date.class)){
oldValStr = DateHelper.format((Date)oldVal);
}else{
oldValStr = oldVal.toString();
}
resultBuffer.append(String.format(format, entry.getKey(),oldValStr,newValStr)).append(",");
}else if(com.ycsoft.commons.helper.StringHelper.isEmpty(oldVal.toString()) ){
if(newVal.getClass().isAssignableFrom(Date.class)){
newValStr = DateHelper.format((Date)newVal);
}else{
newValStr = newVal.toString();
}
resultBuffer.append(String.format(format, entry.getKey(),oldValStr,newValStr)).append(",");
}else{
if(oldVal.getClass().isAssignableFrom(Date.class)){//两个类型必须一样
//TODO 空值判断。。。
oldValStr = DateHelper.format((Date)oldVal);
newValStr = DateHelper.format((Date)newVal);
}else{
oldValStr = oldVal.toString();
newValStr = newVal.toString();
}
boolean notChanged = !oldValStr.equals(newValStr) ;
if(notChanged){
resultBuffer.append(String.format(format, entry.getKey(),oldValStr,newValStr)).append(",");
}
}
}
String result = resultBuffer.toString();
if(result.length() != 0 ){
result = StringHelper.delEndChar(result, 1);
}
return result;
}
/**
* 比较两个集合类的变化.两个集合可以为空集合,不能为null.两个List的反省参数必须一致.</br>
* 如果fieldName为空,则认为传入的List的泛型参数类型是String.如果不是则抛出IllegalArgumentException.</br>
* 如果传入的两个List的泛型参数类型 <strong><font color="red">不是 String</font></strong>,则必须指定fieldName.否则抛出 IllegalArgumentException.</br>
* 如果传入的两个List的泛型参数类型 <strong><font color="red">是 String</font></strong>,则忽略fieldName.</br>
* 另外,不考虑list里面有重复的数据(如果不是Stirng的list,是指bean的fieldName属性没有相同的).
* @param oldList 老的集合.
* @param newList 新的集合.
* @param fields 要比较的字段名称,可以为空,为空的时候说明两个集合都是字符串.否则,取集合里的这个值.
* @param dictKey 字典键.
* @return
*/
public static <T> String listchange(List<T> oldList,List<T> newList,String ... fields) throws Exception{
if(fields!=null&&fields.length>0){
List<String> temp=new ArrayList<String>();
for(String o:fields){
if(o!=null&&!o.trim().equals("")){
temp.add(o);
}
}
fields=temp.toArray(new String[temp.size()]);
}
if ((oldList == null && newList == null)
|| (oldList == null && newList != null && newList.size() == 0)
|| (newList == null && oldList != null && oldList.size() == 0)) {//保证不同时为null 或者一个为null 一个为空
throw new IllegalArgumentException("两个集合不能都为空");
}
boolean dataChanged = false;
Map<String, String> oldValMap = new HashMap<String, String>();
Map<String, String> newValMap = new HashMap<String, String>();
Class oldParamType = null;
Class newParamType = null;
if(oldList ==null){
oldList = new ArrayList<T>();
dataChanged = true;
}else if(newList ==null){
newList = new ArrayList<T>();
dataChanged = true;
}
if( oldList.size() ==0 && newList.size() ==0 ){//空组,返回空字符串
return "";
}
if(oldList.size() == 0){
newParamType = newList.get(0).getClass();
}else if(newList.size() == 0){
oldParamType = oldList.get(0).getClass();
}else{
newParamType = newList.get(0).getClass();
oldParamType = oldList.get(0).getClass();
}
boolean isString = oldParamType == null ? newParamType.equals(String.class) :oldParamType.equals(String.class) ;
if( (fields ==null || fields.length ==0) && !isString){//传入List为字符串类型,fieldName 为空
throw new IllegalArgumentException("属性名为空的时候传入的List的参数类型应为 String");
}
for(T obj:oldList){
String valStr = "";
if(isString){
valStr = obj.toString();
oldValMap.put(valStr, valStr);
continue;
}
Object fieldValue = null;
try{
// fieldValue = forceGetProperty(obj, fields);
for(String field:fields){
fieldValue = forceGetProperty(obj, field);
if(fieldValue ==null){
fieldValue = "null";
}
if(fieldValue.getClass().isAssignableFrom(Date.class)){
valStr += DateHelper.format((Date)fieldValue) + "_";
}else{
valStr += fieldValue.toString() + "_";
}
}
}catch (Exception e) {
throw new IllegalArgumentException("List里的对象没有 '" + fields + "' 属性!");
}
/*
if(fieldValue == null){
throw new IllegalArgumentException("传入的数据错误!需要的属性 " + fields +" 的值为空 !");
}
*/
valStr = valStr.substring(0, valStr.length() -1);
oldValMap.put(valStr, valStr);
}
for(Object obj:newList){
String valStr = "";
if(isString){
valStr = obj.toString();
newValMap.put(valStr, valStr);
continue;
}
Object fieldValue = null;
try{
// fieldValue = forceGetProperty(obj, fields);
for(String field:fields){
fieldValue = forceGetProperty(obj, field);
if(fieldValue ==null){
fieldValue = "null";
}
if(fieldValue.getClass().isAssignableFrom(Date.class)){
valStr += DateHelper.format((Date)fieldValue) + "_";
}else{
valStr += fieldValue.toString() + "_";
}
}
}catch (Exception e) {
throw new IllegalArgumentException("List里的对象没有 '" + fields + "' 属性!");
}
/*
if(fieldValue == null){
throw new IllegalArgumentException("传入的数据错误!需要的属性 " + fields +" 的值为空 !");
}
*/
valStr = valStr.substring(0, valStr.length() -1);
newValMap.put(valStr, valStr);
}
if(!dataChanged){//都不为空的时候再比较下
if(newValMap.size() !=oldValMap.size()){
dataChanged = true;
}else{
for(String key : newValMap.keySet()){
if(oldValMap.get(key) == null){
dataChanged = true;
break;
}
}
}
}
String format = "%s %s=>%s";//属性名,旧值,新值
String fieldName = "";
if(dataChanged){
if(fields !=null && fields.length ==1){
fieldName = StringHelper.isEmpty(fields[0])? "":fields[0]+":";//如果是字符串,省略null
}
// String oldValStr = JsonHelper.fromObject(oldValMap.values());
String oldValStr = "[";
for(String str :oldValMap.values()){
oldValStr += str + ",{splitFlag}";
}
oldValStr = oldValStr.substring(0, oldValStr.length());
oldValStr += "]";
// String newValStr = JsonHelper.fromObject(newValMap.values());
String newValStr = "[";
for(String str :newValMap.values()){
newValStr += str + ",{splitFlag}";
}
newValStr = newValStr.substring(0, newValStr.length());
newValStr += "]";
return String.format(format, fieldName,oldValStr,newValStr);
}
return null;
}
}