自动包装对象

可能大家都有遇到这样的情况,项目中有与数据库对应实体,但是传送给客户端的对象只需要实体中的某些字段,如果是采用json格式的话可以使用jackson的@JsonIgnore忽略掉不需要的字段。但是如果采用其他方式可能就没有这么好的现成功能,需要自己定义对应的vo或者dto,然后将实体的字段逐个取值赋给vo或者dto。这其中确实有让人感觉啰嗦的地方,实体与vo或者dto中的字段名基本是一一对应的,有没有某种方式让它把能够对应上的字段自动赋值,个别字段再特殊处理呢?答案是肯定的,用java的反射机制可以实现这个想法。以下为我写的一个工具类。

package com.shannonchou.framework.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import com.…….domain.Article;
import com.…….dto.pb.PBAboutArticle.PBArticle;

/**
 * 利用反射机制自动包装对象,比如将一个domain对象自动包装为dto、vo
 * 可以根据属性或者方法名对应,找不到对应项的字段不赋值,在debug模式下打印出找不到对应项的字段
 * 属性名对照规则:
 * 1.去除下划线
 * 2.全部转为小写
 * 比如 aField 与 a_field_ 都被处理为 afield,因此对应成功。
 * 方法名对照规则:
 * 1.将源对象的所有getter方法和目标对象的所有setter方法分别去掉方法名前的“get”和“set”。
 * 2.再去掉下划线,并全部转换为小写。
 * 3.然后将处理后的方法名对照,能对应上的就赋值。
 * 比如 getId() 与setId() 都被处理为id,因此对应成功。
 * @date 2013-7-23 下午4:38:19
 * @author shannonchou
 *
 */
public class AutoWrapper {
	private static Logger logger = Logger.getLogger(AutoWrapper.class);
	
	/**
	 * 自动将from实例包装为to对象的实例,根据属性对照
	 * @param from 来源实例
	 * @param to	目标对象
	 * @return	目标对象的实例
	 * @date 2013-7-23 下午7:24:04
	 * @author shannonchou
	 */
	public static Object autoWrapByFields(Object from, Class<?> to) {
		if (from == null) {
			logger.debug("parameter form is null");
			return null;
		}
		
		Object toObject = null;
		try {
			toObject= to.newInstance();
		} catch (InstantiationException e1) {
			logger.error("get instance fail:" + to.getName());
			e1.printStackTrace();
			return null;
		} catch (IllegalAccessException e1) {
			logger.error("get instance fail:" + to.getName());
			e1.printStackTrace();
			return null;
		}

		return autoWrapByFields(from, toObject);
	}
	
	/**
	 * 自动将from实例包装为to对象的实例,根据属性对照,
	 * 该方法用于目标对象没有默认构造函数的情况,直接由调用者完成目标对象的实例化
	 * @param from 来源实例
	 * @param to 目标实例
	 * @return
	 * @date 2013-7-23 下午7:29:36
	 * @author shannonchou
	 */
	public static Object autoWrapByFields(Object from, Object to) {
		if (from == null) {
			logger.debug("parameter form is null");
			return null;
		}
		Map<String, Field> fromFieldMap = fieldMap(from.getClass());
		Field[] toFields = to.getClass().getDeclaredFields();
		for (Field field : toFields) {
			Field fromField = null;
			fromField = fromFieldMap.get(flat(field.getName()));
			if (fromField == null) {
				logger.debug("no such field:" + field.getName());
				continue;
			}
			try {
				field.setAccessible(true);
				fromField.setAccessible(true);
				Object fieldValue = fromField.get(from);
				if (fieldValue != null) {
					field.set(to, fieldValue);
				}
			} catch (IllegalArgumentException e) {
				logger.error("set filed failed:" + field.getName());
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				logger.error("set filed failed:" + field.getName());
				e.printStackTrace();
			}
		}
		return to;
	}
	
	/**
	 * 将字符串转换为“平坦的”,无‘_’,全小写
	 * @param str
	 * @return
	 * @date 2013-7-23 下午8:01:18
	 * @author shannonchou
	 */
	public static String flat(String str) {
		str = StringUtils.remove(str, '_');
		return str.toLowerCase();
	}
	
	/**
	 * 获取对象的属性map,将field的名字平坦化作为key
	 * @param obj	对象
	 * @return
	 * @date 2013-7-23 下午8:25:59
	 * @author shannonchou
	 */
	public static Map<String, Field> fieldMap(Class<?> obj) {
		HashMap<String, Field> map = new HashMap<String, Field>();
		Field fileds[] = obj.getDeclaredFields();
		for (Field field : fileds) {
			map.put(flat(field.getName()), field);
		}
		return map;
	}
	
	/**
	 * 自动将from实例包装为to对象的实例,根据from的getter方法与to的setter方法对照
	 * @param from
	 * @param to
	 * @return
	 * @date 2013-7-24 下午5:02:43
	 * @author shannonchou
	 */
	public static Object autoWrapByMethod(Object from, Class<?> to) {
		if (from == null) {
			logger.debug("parameter form is null");
			return null;
		}
		
		Object toObject = null;
		try {
			toObject= to.newInstance();
		} catch (InstantiationException e1) {
			logger.error("get instance fail:" + to.getName());
			e1.printStackTrace();
			return null;
		} catch (IllegalAccessException e1) {
			logger.error("get instance fail:" + to.getName());
			e1.printStackTrace();
			return null;
		}
		
		return autoWrapByMethod(from, toObject);
	}
	
	/**
	 * 自动将from实例包装为to对象的实例,根据from的getter方法与to的setter方法对照,
	 * 该方法用于目标对象没有默认构造函数的情况,直接由调用者完成目标对象的实例化
	 * @param from 来源实例
	 * @param to 目标实例
	 * @return
	 * @date 2013-7-23 下午7:29:36
	 * @author shannonchou
	 */
	public static Object autoWrapByMethod(Object from, Object to) {
		if (from == null) {
			logger.debug("parameter form is null");
			return null;
		}

		Map<String, Method> toSetMap = setterMap(to.getClass());
		Map<String, Method> fromGetMap = getterMap(from.getClass());
		Iterator<String> iter = toSetMap.keySet().iterator();
		while (iter.hasNext()) {
			String toFlatName = iter.next();
			Method fromMethod = null;
			fromMethod = fromGetMap.get(toFlatName);
			if (fromMethod == null) {
				logger.debug("no such method(ignore case):get" + toFlatName);
				continue;
			}
				Method toMethod = toSetMap.get(toFlatName);
				toMethod.setAccessible(true);
				fromMethod.setAccessible(true);
				try {
					Object fromValue = fromMethod.invoke(from);
					if (fromValue != null) {
						toMethod.invoke(to, fromValue);
					}
				} catch (IllegalArgumentException e) {
					logger.debug("invoke method failed, parameter type mismatch, from:" + fromMethod.getName() + ", to:" + toMethod.getName());
				} catch (IllegalAccessException e) {
					logger.debug("invoke method failed, from:" + fromMethod.getName() + ", to:" + toMethod.getName());
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					logger.debug("invoke method failed, from:" + fromMethod.getName() + ", to:" + toMethod.getName());
					e.printStackTrace();
				}
		}
		return to;
	}
	
	/**
	 * 获取类的getter方法的map,key为方法名去除前面的get,然后平坦化,非get开头的方法不会纳入map中
	 * @param clazz
	 * @return
	 * @date 2013-7-24 下午4:34:46
	 * @author shannonchou
	 */
	public static Map<String, Method> getterMap(Class<?> clazz) {
		Map<String, Method> methodMap = new HashMap<String, Method>();
		Method[] methods = clazz.getDeclaredMethods();
		for (Method method : methods) {
			String noGetName = removeGet(method.getName());
			if (StringUtils.isNotBlank(noGetName)) {
				methodMap.put(noGetName, method);
			}
		}
		return methodMap;
	}
	
	/**
	 * 获取类的setter方法的map,key为方法名去除前面的set,然后平坦化,非set开头的方法不会纳入map中
	 * @param clazz
	 * @return
	 * @date 2013-7-24 下午4:34:46
	 * @author shannonchou
	 */
	public static Map<String, Method> setterMap(Class<?> clazz) {
		Map<String, Method> methodMap = new HashMap<String, Method>();
		Method[] methods = clazz.getDeclaredMethods();
		for (Method method : methods) {
			String noSetName = removeSet(method.getName());
			if (StringUtils.isNotBlank(noSetName)) {
				methodMap.put(noSetName, method);
			}
		}
		return methodMap;
	}
	
	/**
	 * 去除方法名前的“set”,并将其转为“平坦化”的,比如setTypeName被转为typename
	 * @param str
	 * @return	如果str为非set开头将返回null
	 * @date 2013-7-24 下午4:18:41
	 * @author shannonchou
	 */
	public static String removeSet(String str) {
		String flatName = flat(str);
		if (flatName.startsWith("set")) {
			return flatName.replaceFirst("set", "");
		} else {
			return null;
		}
	}
	
	/**
	 * 去除方法名前的“get”,并将其转为“平坦化”的,比如getTypeName被转为typename
	 * @param str
	 * @return	如果str为非get开头将返回null
	 * @date 2013-7-24 下午4:21:17
	 * @author shannonchou
	 */
	public static String removeGet(String str) {
		String flatName = flat(str);
		if (flatName.startsWith("get")) {
			return flatName.replaceFirst("get", "");
		} else {
			return null;
		}
	}
	
	public static void main(String[] args) {
		logger.setLevel(Level.DEBUG);
		Article article = new Article();
		article.setId(35L);
		article.setPublishTime(new Date());
		PBArticle pbArticle = ((PBArticle.Builder) autoWrapByMethod(article, PBArticle.newBuilder())).build();
		logger.info("id:" + pbArticle.getId());
	}
}

main方法中的例子是将一个实体赋值到一个Protocol Buffers对象中。

该类有4个方法可以使用:

1.public static Object autoWrapByFields(Object from, Class<?> to)

2.public static Object autoWrapByFields(Object from, Object to)

3.public static Object autoWrapByMethod(Object from, Class<?> to)

4.public static Object autoWrapByMethod(Object from, Object to)

1、2是根据字段名赋值,即便是private的也可以。3、4是根据方法名并通过getter、setter方法取值赋值,这是因为某些对象的getter、setter方法中会有些特殊处理,比如main方法中展示的Protocol Buffers对象,在调用其setter方法时它还会改变其他标志字段,如果直接给字段赋值的话由于没有改变标志位,它会认为该字段没有被赋过值。1、3是在方法中对to类进行实例化,因此需要保证有默认构造函数,2、4是对to实例赋值,可以用在to没有默认构造函数的情况下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值