Map 与 Java Bean 之间的互换

通过反射实现

过程并无甚复杂,通过反射实现接口。首先当然是遍历一下这些集合,无论 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;
}
时间: 2024-10-27 04:24:28

Map 与 Java Bean 之间的互换的相关文章

java web-json Bean之间的转换问题

问题描述 json Bean之间的转换问题 我是个外行,大学学的是java虽然工作快6年了,可java写写代码这手艺一直没丢,但是我的代码很多都是野路子,怎么说呢,不优雅. 就像最近遇到个问题: 我的网址给一个提供Oauth2.0API 数据查询的一个网站. 我的方法是: 每次请求都一样,只期待对方网站返回特定格式的json. 然后用httpclient把那个json转化成一个String,然后一堆操作后变成一个bean对象. 这样给我带来很多麻烦,比如:1效率问题,2.我不能灵活的变化我想获取

使用servlet和Java Bean访问MySQL

mysql|servlet|访问 行环境: JDK 5.0 + Tomcat 5.5.4 JDK安装路径: D:\Java\jdk1.5.0_01 Tomcat安装路径:D:\Tomcat 5.5 设置环境变量(控制面板->系统->高级): java_home=D:\Java\jdk1.5.0_01 path=%JAVA_HOME%\bin classpath=.;D:\Java\jdk1.5.0_01\lib\dt.jar;D:\Java\jdk1.5.0_01\lib\tools.jar;

【spring set注入 注入集合】 使用set注入的方式注入List集合和Map集合/将一个bean注入另一个Bean

  Dao层代码: 1 package com.it.dao; 2 3 public interface SayHell { 4 public void sayHello(); 5 } View Code   Dao的Impl实现层: 1 package com.it.dao.impl; 2 3 import java.util.List; 4 import java.util.Map; 5 6 import com.it.dao.SayHell; 7 8 /** 9 * Spring如何知道s

实现xml信息到Java Bean的转化

xml 本文主要是关于使用commons-betwixt组件实现xml信息到Java Bean的转化的一些感受,实现这一功能的核心类是BeanReader,如果你看过betwixt的源代码,你会发现 public class BeanReader extends Digester{}       如果你细看一下BeanReader的源代码,betwixt在处理xml-->JavaBean转化时其实是调用Digester这个类的parse方法.但除了此方式可以实现转化的功能以外,BeanReade

MD5的Java Bean实现

MD5简介 MD5的全称是Message-Digest Algorithm 5,在90年代初由MIT的计算机科学实验室和RSA Data Security Inc发明,经MD2.MD3和MD4发展而来. Message-Digest泛指字节串(Message)的Hash变换,就是把一个任意长度的字节串变换成一定长的大整数.请注意我使用了"字节串"而不是"字符串"这个词,是因为这种变换只与字节的值有关,与字符集或编码方式无关. MD5将任意长度的"字节串&q

一个操作数据库的Java Bean……

数据|数据库 一个操作数据库的Java Bean,有兴趣的朋友看一下吧~~ package dbconnect; import java.sql.*; public class sqlconnection { String sDbDriver = "sun.jdbc.odbc.JdbcOdbcDriver"; String sConnStr = "jdbc:odbc:sqlconnect"; // sqlconnect 数据源名称: private Connecti

Java Bean 生成器

这是一个java bean生成器,利用一个文本文件(不妨称为bean定义文件)生成java bean. 开发过程中我们可能会用到很多数据对象(值对象),大都被封装成一个bean.虽然各大 IDE都提供了方便生成这种数据bean的工具,但都是一步一步填对话框式的,不像这个, 这个可以在一个文件里定义多个Bean,一次生成所有bean.当然它也有局限性,目前只会 简单的生成private数据域和public 的setter.getter:并且不会替你导入必要的包.但尽管如此, 也能大大方便数据bea

JSP调用Java Bean在网页上动态生成柱状图

js|动态|网页|柱状图 我们经常要在网页看到一些动态更新的图片,最常见的莫过于股票的K线图,本文试图通过一个简单的实例,向大家展示如何通过JSP 调用Java Bean在网页上动态生成柱状图. 背景:本人最近在为某统计局开发项目时,涉及到在网页上动态生成图片的问题,费了一天的时间,终于搞定,为帮助大家在以后遇到同样的问题时不走弯路,现将设计思想及源代码公布出来,与大家共勉.以下代码在Windows2000成功测试通过,Web应用服务器采用Allaire公司的Jrun3.0,如有疑问,敬请联系作

JSP+Java Bean访问MySQL数据库

js|mysql|访问|数据|数据库 运行环境: JDK 5.0 + Tomcat 5.5.4+MySQL4.1.8 JDK安装路径: D:\Java\jdk1.5.0_01Tomcat安装路径:D:\Tomcat 5.5 设置环境变量(控制面板->系统->高级):java_home=D:\Java\jdk1.5.0_01path=%JAVA_HOME%\binclasspath=.;D:\Java\jdk1.5.0_01\lib\dt.jar;D:\Java\jdk1.5.0_01\lib\