Map 与 Java Bean 之间的互换

简介: 通过反射实现过程并无甚复杂,通过反射实现接口。首先当然是遍历一下这些集合,无论 Map 还是 Bean。 /** * Bean 转换为 Map * @param obj * @return */public static Map bean2map(Object obj) { if...

通过反射实现

过程并无甚复杂,通过反射实现接口。首先当然是遍历一下这些集合,无论 Map 还是 Bean。

/**
 * Bean 转换为 Map
 * @param obj
 * @return
 */
public static Map<String, Object> bean2map(Object obj) {
	if (obj == null) 
		return null;
	
	Map<String, Object> map = new HashMap<>();

	for (Method method : obj.getClass().getMethods()) {
		String methodName = method.getName();
		
		if (methodName.startsWith("get")) {
			Object value = executeMethod(obj, method); // 反射获取值

			if (value != null) 
				map.put(getFieldName(methodName, "get"), value);
		}
	}

	return map;
}

/**
 * 调用方法,方法没有参数的
 * 
 * @param instance
 *            对象实例,bean
 * @param method
 *            方法对象

 * @return 执行结果
 */
public static Object executeMethod(Object instance, Method method) {
    try {
        return method.invoke(instance);
    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        return null;
    }
}

/**
 * 根据方法名称来截取属性名称
 * @param methodName
 *            方法名称
 * @param action
 *            set|get
 * @return
 */
public static String getFieldName(String methodName, String action) {
    methodName = methodName.replace(action, "");
    return Character.toString(methodName.charAt(0)).toLowerCase() + methodName.substring(1);
} 

对应地,就有 Map 转换为 Bean。

/**
 * Map 转换为 Bean
 * 
 * @param map
 * @param obj
 */
public static void map2bean(Map<String, Object> map, Object obj) {
    if (obj != null || map != null)
       return null;
    
    for (Method method : obj.getClass().getMethods()) {
        String methodName = method.getName();
        
        if (methodName.startsWith("set")) {
            methodName = getFieldName(methodName, "set");
            if (map.containsKey(methodName)) 
                executeMethod(obj, method, map.get(methodName));
        }
    }
}

/**
 * 调用方法
 * 
 * @param instance
 *            对象实例,bean
 * @param method
 *            方法对象
 * @param args
 *            参数列表
 * @return 执行结果
 */
public static Object executeMethod(Object instance, Method method, Object... args) {
	try {
		return method.invoke(instance, args);
	} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
		return null;
	}
}

将 map 中数据填入到 obj 中。obj 是 POJO。 如果 POJO 有这个 setter,那就根据 setter 中 setXxx 获取 xxx,作为 map 的 key 读取 map 的那個 value。

Object 2 Bean Value

bean2map 过程中,值放到 map 中没类型转换的问题,因为 map 的范型是 <String, Object>,这时 map 好比 O 型血,什么都是用它,但反之 map2bean 则不然 bean 的 setter方法是有类型要求的,因此你传入 Object 的参数并不一定能匹配。如果不转换很容易会出现 java.lang.IllegalArgumentException: argument type mismatch 的异常。于是我们类构建更复杂的 map2bean 函数,让类型差不多的也能通过转换,转变为真正符合类型要求的类型。

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.ajaxjs.util.DateTools;
import com.ajaxjs.util.LogHelper;
import com.ajaxjs.util.reflect.BeanUtil;
import com.ajaxjs.util.reflect.Reflect;
import com.ajaxjs.util.reflect.ReflectNewInstance;

/**
 * 将 map 数据通过反射保存到 pojo(bean) 中。
 * 
 * @author frank
 *
 * @param <T>
 *            实体类型
 */
public class Map2Pojo<T> extends BeanUtil {
	private static final LogHelper LOGGER = LogHelper.getLog(Map2Pojo.class);
	
	/**
	 * 实体类型类对象
	 */
	private Class<T> pojoClz;

	/**
	 * 用于数组的分隔符
	 */
	private char diver = ',';
	
	/**
	 * 
	 * @param pojoClz
	 *            实体类型类对象
	 */
	public Map2Pojo(Class<T> pojoClz) {
		this.pojoClz = pojoClz;
	} 
	
	/**
	 * 把单个原始数据 map 转换为单个实体
	 * 
	 * @param map
	 *            原始数据
	 * @param pojo
	 *            实体
	 * @param fields
	 *            反射出来的字段信息
	 */
	private T map2pojo(Map<String, Object> map, List<Field> fields) {
		T pojo = ReflectNewInstance.newInstance(pojoClz);
		if(pojo == null) return null;

		for (Field f : fields) {
			String key = f.getName(); // 字段名称
			Class<?> t = f.getType(); // 字段期望的类型
			Object value = map.get(key);

			if (value != null) {
//				System.out.println(key + ":" + map.get(key).getClass().getName());

				String methodName = "set" + firstLetterUpper(key);

				if (t == boolean.class) {
//					System.out.println("methodName:::::" + methodName);
					// 布尔型
					methodName = key.replace("is", "");
					methodName = "set" + firstLetterUpper(methodName);
//					System.out.println("methodName:::::" + "set" + Reflect.firstLetterUpper(methodName));
					
					if(value instanceof String) {
						value = (String)value;
						if(value.equals("yes") || value.equals("true") || value.equals("1")) {
							value = true;
						}
						
						if(value.equals("no") || value.equals("false") || value.equals("0")) {
							value = false;
						}
					}
					
					executeMethod(pojo, methodName, t, (boolean) value);
					
				} else if (t == int.class || t == Integer.class) {
					if(value.getClass() == String.class) 
						value = Integer.parseInt(value.toString());

					// 整形
					executeMethod(pojo, methodName, t, value);
					
				} else if (t == int[].class || t == Integer[].class) {
					// 复数
					if (value instanceof String) {
						int[] intArr = strArr2intArr(value);
						executeMethod(pojo, methodName, t, intArr);
					} else {
						LOGGER.info("what's this!!? " + value);
					}
					
				} else if (t == String.class) {
					// 字符型
					Reflect.executeMethod(pojo, methodName, t, value.toString());
				} else if (t == String[].class) {
					// 复数
					if (value instanceof String[]) {
						Reflect.executeMethod(pojo, methodName, t, value);
					} else if (value instanceof ArrayList) {
						@SuppressWarnings("unchecked")
						ArrayList<String> list = (ArrayList<String>) value;
						String[] arr = new String[list.size()];
						
						executeMethod(pojo, methodName, t, list.toArray(arr));
					} else if (value instanceof String) {
						String str = (String) value;
						executeMethod(pojo, methodName, t, str.split(getDiver() + ""));
					} else {
						LOGGER.info("what's this!!?" + value.getClass().getName());
					}
					
				} else if (t == long.class || t == Long.class) { 
					// LONG 型
					executeMethod(pojo, methodName, t, Long.valueOf(value.toString()));
					
				} else if (t == Date.class) {
					
					if (value instanceof java.sql.Timestamp) {
						long time = ((java.sql.Timestamp) value).getTime();
						executeMethod(pojo, methodName, t, new Date(time));
					} else {
						executeMethod(pojo, methodName, t, DateTools.Objet2Date(value));
					}
				} else {
					// System.out.println("------------" + t.getName());
					executeMethod(pojo, methodName, value);
				}
			}
		}

		return pojo;
	}

	/**
	 * '["1", "2", ...]' --> [1, 2, ...]
	 * @param value 
	 * @return
	 */
	private int[] strArr2intArr(Object value) {
		String str = (String) value;
		// 当它们每一个都是数字的字符串形式
		String[] strArr = str.split(getDiver() + "");
		int[] intArr = new int[strArr.length];
		
		for (int i = 0; i < strArr.length; i++) 
			intArr[i] = Integer.parseInt(strArr[i]);
		
		return intArr;
	}

	/**
	 * 把原始数据 map 转换为实体
	 * 
	 * @param maps
	 *            原始数据
	 * @param fields
	 *            反射出来的字段信息
	 * @return 转换后的实体列表
	 */
//	public List<T> map2pojo(List<Map<String, Object>> maps, List<Field> fields) {
//		List<T> list = new ArrayList<>();
////		T[] a = (T[])java.lang.reflect.Array.newInstance(pojoClz, maps.size());
////		list.toArray(T[]);
//		
//		for (Map<String, Object> map : maps) 
//			list.add(map2pojo(map, fields));
//		
//		return list;
//	}

	/**
	 * 把原始数据 maps 转换为实体
	 * 
	 * @param maps
	 *            原始数据
	 * @return 转换后的实体列表
	 */
	public List<T> map2pojo(List<Map<String, Object>> maps) {
		List<Field> fields = getDeclaredField(pojoClz);
		List<T> list = new ArrayList<>();
//		T[] a = (T[])java.lang.reflect.Array.newInstance(pojoClz, maps.size());
//		list.toArray(T[]);
		
		for (Map<String, Object> map : maps) 
			list.add(map2pojo(map, fields));
		
		return list;
		
//		return map2pojo(maps, Reflect.getDeclaredField(pojoClz));
	}
	
	/**
	 * 把原始数据 map 转换为实体
	 * 
	 * @param map
	 *            原始数据
	 * @return 转换后的实体
	 */
	public T map2pojo(Map<String, Object> map) {
		return map2pojo(map, getDeclaredField(pojoClz));
	}

	/**
	 * @return {@link #diver}
	 */
	public char getDiver() {
		return diver;
	}

	/**
	 * @param diver {@link #diver}
	 */
	public void setDiver(char diver) {
		this.diver = diver;
	}
}


通过 Bean 内省实现

后来发现反射性能不是很好,于是我们试试 Java Bean 的内省功能也可以转换。

/**
 * map 转实体
 *
 * @param map
 * @param clz
 *            实体类
 * @return 实体 bean 对象
 */
public static <T> T map2Bean(Map<String, Object> map, Class<T> clz) {
    T bean = ReflectNewInstance.newInstance(clz);
    
    try {
        BeanInfo beanInfo = Introspector.getBeanInfo(clz);

        for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
            String key = property.getName();

            if (map.containsKey(key)) {
                Object value = map.get(key);
                // 得到property对应的setter方法
                Method setter = property.getWriteMethod();
                setter.invoke(bean, value);
            }
        }
    } catch (IntrospectionException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        e.printStackTrace();
    }
    return bean;
}

/**
 * Bean 转为 Map
 *
 * @param bean
 *            实体 bean 对象
 * @return
 */
public static <T> Map<String, Object> bean2Map(T bean) {
    Map<String, Object> map = new HashMap<String, Object>();
    
    try {
        BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
        
        for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
            String key = property.getName();
            
            // 过滤 class 属性
            if (!key.equals("class")) {
                // 得到 property 对应的 getter 方法
                Method getter = property.getReadMethod();
                Object value = getter.invoke(bean);
                map.put(key, value);
            }
        }
    } catch (IntrospectionException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        e.printStackTrace();
    }
        
    return map;
}


目录
相关文章
|
11月前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
205 2
|
11月前
|
存储 Java
告别混乱!用Java Map优雅管理你的数据结构
【10月更文挑战第17天】在软件开发中,随着项目复杂度增加,数据结构的组织和管理至关重要。Java中的Map接口提供了一种优雅的解决方案,帮助我们高效、清晰地管理数据。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,有效提升了代码质量和维护性。
197 2
|
4月前
|
安全 Java API
【Java性能优化】Map.merge()方法:告别繁琐判空,3行代码搞定统计累加!
在日常开发中,我们经常需要对Map中的值进行累加统计。}else{代码冗长,重复调用get()方法需要显式处理null值非原子操作,多线程下不安全今天要介绍的方法,可以让你用一行代码优雅解决所有这些问题!方法的基本用法和优势与传统写法的对比分析多线程安全版本的实现Stream API的终极优化方案底层实现原理和性能优化建议一句话总结是Java 8为我们提供的Map操作利器,能让你的统计代码更简洁、更安全、更高效!// 合并两个列表});简单累加。
416 0
|
10月前
|
存储 Java API
Java交换map的key和value值
通过本文介绍的几种方法,可以在Java中实现Map键值对的交换。每种方法都有其优缺点,具体选择哪种方法应根据实际需求和场景决定。对于简单的键值对交换,可以使用简单遍历法或Java 8的Stream API;对于需要处理值不唯一的情况,可以使用集合存储或Guava的Multimap。希望本文对您理解和实现Java中的Map键值对交换有所帮助。
204 1
|
11月前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第19天】本文介绍了Java编程中重要的数据结构——Map,通过问答形式讲解了Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的使用和性能优化技巧,适合初学者和进阶者学习。
376 4
|
11月前
|
存储 Java API
优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。
【10月更文挑战第19天】本文介绍了如何优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。内容包括Map的初始化、使用Stream API处理Map、利用merge方法、使用ComputeIfAbsent和ComputeIfPresent,以及Map的默认方法。这些技巧不仅提高了代码的可读性和维护性,还提升了开发效率。
358 3
|
11月前
|
存储 Java API
详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
【10月更文挑战第19天】深入剖析Java Map:不仅是高效存储键值对的数据结构,更是展现设计艺术的典范。本文从基本概念、设计艺术和使用技巧三个方面,详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
193 3
|
11月前
|
存储 缓存 安全
在Java的Map家族中,HashMap和TreeMap各具特色
【10月更文挑战第19天】在Java的Map家族中,HashMap和TreeMap各具特色。HashMap基于哈希表实现,提供O(1)时间复杂度的高效操作,适合性能要求高的场景;TreeMap基于红黑树,提供O(log n)时间复杂度的有序操作,适合需要排序和范围查询的场景。两者在不同需求下各有优势,选择时需根据具体应用场景权衡。
113 2
|
11月前
|
存储 安全 Java
Java Map新玩法:深入探讨HashMap和TreeMap的高级特性
【10月更文挑战第19天】Java Map新玩法:深入探讨HashMap和TreeMap的高级特性,包括初始容量与加载因子的优化、高效的遍历方法、线程安全性处理以及TreeMap的自然排序、自定义排序、范围查询等功能,助你提升代码性能与灵活性。
92 2
|
11月前
|
存储 Java 开发者
Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效
【10月更文挑战第19天】在软件开发中,随着项目复杂度的增加,数据结构的组织和管理变得至关重要。Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,帮助开发者告别混乱,提升代码质量。
109 1

热门文章

最新文章