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;
}


目录
相关文章
|
2天前
|
存储 安全 Java
Java一分钟之-Map接口与HashMap详解
【5月更文挑战第10天】Java集合框架中的`Map`接口用于存储唯一键值对,而`HashMap`是其快速实现,基于哈希表支持高效查找、添加和删除。本文介绍了`Map`的核心方法,如`put`、`get`和`remove`,以及`HashMap`的特性:快速访问、无序和非线程安全。讨论了键的唯一性、`equals()`和`hashCode()`的正确实现以及线程安全问题。通过示例展示了基本操作和自定义键的使用,强调理解这些概念对编写健壮代码的重要性。
6 0
|
2天前
|
存储 Java
【JAVA基础篇教学】第十篇:Java中Map详解说明
【JAVA基础篇教学】第十篇:Java中Map详解说明
|
3天前
|
存储 安全 Java
Java容器类List、ArrayList、Vector及map、HashTable、HashMap
Java容器类List、ArrayList、Vector及map、HashTable、HashMap
|
12天前
|
消息中间件 安全 Java
在Spring Bean中,如何通过Java配置类定义Bean?
【4月更文挑战第30天】在Spring Bean中,如何通过Java配置类定义Bean?
20 1
|
12天前
|
Java
java Map删除值为null的元素
java Map删除值为null的元素
|
12天前
|
Java fastjson
Java将Map转换为实体类
Java将Map转换为实体类
|
18天前
|
存储 安全 Java
[Java基础面试题] Map 接口相关
[Java基础面试题] Map 接口相关
|
19天前
|
存储 算法 Java
盘点Java集合(容器)概览,Collection和Map在开发中谁用的最多?
盘点Java集合(容器)概览,Collection和Map在开发中谁用的最多?
30 0
|
20天前
|
Java 测试技术 Spring
|
1月前
|
存储 算法 安全
Java Map:键值对的奇妙之旅
Java Map:键值对的奇妙之旅
43 0
Java Map:键值对的奇妙之旅