论坛首页 Java企业应用论坛

利用反射机制和DOM4J创建生成XML的通用类

浏览 6400 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (8) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-12-03  

最近的项目中用到了XML,所以就写了个对象转换为XML文件的通用类。

package com.creawor.cbsms.client.xml.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * Description: 反射机制工具类,根据传入的Obj,
 *              为生成xml文件提取所有属性和属性对应的值       
 * </p>
 * 
 * 
 * @author Administrator
 * @since  2008-12-1
 * @version
 */
public class ReflectionUtil {

	//所有的系统类型
	private static String[] allSysDefinedType = new String[] {
			"java.lang.String", "java.lang.Long", "long", "java.lang.Integer",
			"int", "java.lang.Short", "short", "java.lang.Byte", "byte",
			"java.lang.Float", "float", "java.lang.Double", "double",
			"java.util.Date", "java.lang,Char", "char", "java.lang.Boolean",
			"boolean", "java.sql.Timestamp" };

	private static String dateFormatString = "yyyy-MM-dd HH:mm:ss";

	//使用不可以是属性名前缀的*作为标识是否是用户自定义的类型
	private static String userDefiendTypePrefix = "*";

	/**
	 * 根据传入的对象将对象的属性和该属性对应的值放入map
	 * @param  obj
	 *           待映射属性和属性值的对象
	 * @param  unReflectProp
	 *           不需要映射属性和属性值的所有属性;
	 *           eg. CbsTargetTime对象中有DATE_FORMAT不需要映射则在该参数中添加
	 *               CbsTargetTime.DATE_FORMAT
	 *  
	 * @return Map
	 *           key = property name ; value = property value;
	 *           (如果属性为一个用户自定义类型的对象那么
	 *           key = '*' + 'user defined type';
	 *           value = map;map中key是属性,value是值,依次循环)
	 */
	public Map<String, Object> transformObjData2Map(Object obj,
			String[] unReflectProp) {
		Map<String, Object> rootMap = new HashMap<String, Object>();
		Map<String, Object> dataMap = new HashMap<String, Object>();
		rootMap.put(userDefiendTypePrefix + obj.getClass().getSimpleName(),
				dataMap); // 使用不可以是属性名前缀的*作为标识是否是用户自定义的类型
		this.getObjPro(obj, unReflectProp, dataMap, obj.getClass().getName());
		return rootMap;
	}

	/**
	 * 得到传入对象的每个属性域,
	 * 根据每个属性域得到属性域对应的值
	 * 
	 * @param obj 
	 *         待映射得到属性和值的对象
	 *         
	 * @param  unReflectProp
	 *         不需要映射属性和属性值的所有属性;
	 *         
	 * @param  className 
	 *         对象的类型名,如果传入对象为空时,用其新建一个对象
	 * @param dataMap
	 *         key=属性,value=属性的值
	 */

	@SuppressWarnings("unchecked")
	private void getObjPro(Object obj, String[] unReflectProp, Map dataMap,
			String className) {
		try {
			Class clas;
			if (obj == null) {
				clas = Class.forName(className);
				obj = clas.newInstance();
			} else {
				clas = Class.forName(obj.getClass().getName());
			}

			//得到obj类的所有属性
			Field[] fileds = clas.getDeclaredFields();
			for (Field field : fileds) {
				String fieldName = field.getName();
				String fieldType = field.getType().getName();
				//如果该属性是不需要映射的属性则跳出循环
				if (!reflectPropOrNot(obj.getClass().getSimpleName() + "."
						+ fieldName, unReflectProp)) {
					continue;
				}
				//属性名的第一个字母大写,与get或者is组成方法名
				String firstCharUpper = fieldName.substring(0, 1).toUpperCase()
						+ fieldName.substring(1, fieldName.length());
				Method method;
				//如果是boolean型则方法名为is*;反之为get*
				if (isBooleanType(fieldType)) {
					method = clas.getMethod("is" + firstCharUpper, null);
				} else {
					method = clas.getMethod("get" + firstCharUpper, null);
				}

				if (isSysDefinedType(fieldType)) {
					//如果是系统类型则添加进入map
					String formatDateStr = isTimeType(fieldType, method, obj);
					if (formatDateStr != null) {
						dataMap.put(fieldName, formatDateStr);
						continue;
					}
					dataMap.put(fieldName,
							method.invoke(obj, null) == null ? "" : method
									.invoke(obj, null));

				} else {
					//如果不是系统类型对象则key = * + 属性名 ; value = map;循环迭代
					Map dateMap2 = new HashMap();
					this.getObjPro(method.invoke(obj, null), unReflectProp,
							dateMap2, fieldType);
					dataMap.put(userDefiendTypePrefix
							+ field.getType().getSimpleName(), dateMap2);
				}

			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			System.out.println("映射属性和属性所对应值出现异常!!");
			e.printStackTrace();

		}

	}

	/**
	 * 验证属性是否是要通过反射机制得到名称和值
	 * @param fieldName
	 *              待验证的属性
	 * @return
	 *        true  要利用反射机制的到属性名和值
	 *        false 不需要利用反射机制的到属性名和值
	 */
	private boolean reflectPropOrNot(String fieldName, String[] unReflectProp) {
		if (unReflectProp == null) {
			return true;
		}
		for (String propName : unReflectProp) {
			if (propName.equals(fieldName)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 验证属性的类型是否是系统定义的类型
	 * @param fieldType
	 *             待验证类型的名称
	 * @return
	 *        true  是系统定义的对象
	 *        false 用户定义的对象
	 */
	private boolean isSysDefinedType(String fieldType) {
		for (String type : allSysDefinedType) {
			if (fieldType.equals(type)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 如果该属性是日期属性则根据要输出的类型返回字符串,反之返回null
	 * @param fileType
	 * @param method
	 * @param obj
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	private String isTimeType(String fileType, Method method, Object obj)
			throws IllegalAccessException, InvocationTargetException {
		if (fileType.equals("java.util.Date")
				|| fileType.equals("java.sql.Timestamp")) {
			if (method.invoke(obj, null) == null) {
				return null;
			}
			SimpleDateFormat sdf = new SimpleDateFormat(dateFormatString);
			return sdf.format(method.invoke(obj, null));
		} else {
			return null;
		}
	}

	public boolean isBooleanType(String fieldType) {
		if (fieldType.equals("java.util.Boolean")
				|| fieldType.equals("boolean")) {
			return true;
		}
		return false;
	}

	public static void setDateFormatString(String dateFormatString) {
		ReflectionUtil.dateFormatString = dateFormatString;
	}

	public static String getUserDefiendTypePrefix() {
		return userDefiendTypePrefix;
	}

	public static void setUserDefiendTypePrefix(String userDefiendTypePrefix) {
		ReflectionUtil.userDefiendTypePrefix = userDefiendTypePrefix;
	}

}

 

 

package com.creawor.cbsms.client.xml.util;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

/**
 * <p>
 * Description: XML生成类,将传入的对象生成XML文件
 *                  
 * </p>
 * 
 * 
 * @author Administrator
 * @since  2008-12-1
 * @version
 */
public class XMLProcessor {

	private ReflectionUtil reflectionUtil;

	/**
	 * 建立一个XML文档,文档名由输入参数决定
	 * 
	 * @param obj      
	 * @param unReflectProp
	 * @param filename
	 *           
	 * @return 
	 */
	@SuppressWarnings("unchecked")
	public void createXMLFile(List<Object> objs, String[] unReflectProp,
			String filename) throws IndexOutOfBoundsException, IOException {
		reflectionUtil = new ReflectionUtil();
		// 建立Document对象
		Document document = DocumentHelper.createDocument();
		// 添加根节点进入Document
		Element rootElement = document.addElement(objs.get(0).getClass()
				.getSimpleName()
				+ "s");
		for (Object obj : objs) {
			Map<String, Object> rootMap = reflectionUtil.transformObjData2Map(
					obj, unReflectProp);
			String rootString = ReflectionUtil.getUserDefiendTypePrefix()
					+ obj.getClass().getSimpleName();
			map2Node((Map) rootMap.get(rootString), rootElement, rootString);
		}

		// 格式化输出XML,换行缩进
		OutputFormat format = OutputFormat.createPrettyPrint();
		// 设置字符集
		format.setEncoding("GBK");
		// 将document中的内容写入文件中
		XMLWriter writer = new XMLWriter(new FileWriter(new File(filename)),
				format);
		writer.write(document);
		writer.close();

	}

	/**
	 * 将映射为 对象的属性-->属性对应的值 的map转换为xml文件中的各个节点
	 * @param dataMap
	 *            
	 * @param objNode
	 *            父节点,map中创建的节点都是其子节点
	 * @param objClass
	 *            父节点的名称
	 */
	@SuppressWarnings("unchecked")
	private void map2Node(Map<String, Object> dataMap, Element objNode,
			String objName) {
		//第一个字符是*,创建*后面字符为名称的节点
		Element objElement = objNode.addElement(objName.substring(1));
		if (isAllSysType(dataMap)) {
			//如果该对象中全部是系统类型则全部添加到objElement节点下
			for (String propName : dataMap.keySet()) {
				createNextNode(objElement, propName, dataMap.get(propName) + "");
			}

		} else {
			//如果该对象中还有用户自定义类型则系统类型添加进入  objNameInfo节点下,用户自定义类型添加进入 自定义类型名成节点下
			Element infoNode = objElement.addElement(objName.substring(1)
					+ "Info");

			for (String propName : dataMap.keySet()) {
				if (propName.startsWith("*")) {
					map2Node((Map) dataMap.get(propName), objElement, propName);
				} else {
					createNextNode(infoNode, propName, dataMap.get(propName)
							+ "");
				}

			}
		}
	}

	/**
	 * 根据name和text创建elements的子节点
	 * 
	 * @param element
	 * @param nodeName
	 * @param text
	 */
	private void createNextNode(Element element, String nodeName, String text) {
		Element nextElement = element.addElement(nodeName);
		if (text == null) {
			return;
		}
		nextElement.setText(text);
	}

	/**
	 * 是否是系统类,如果前缀是*则是自定义类型
	 * @param dataMap
	 * @return
	 */
	private boolean isAllSysType(Map<String, Object> dataMap) {

		for (String propName : dataMap.keySet()) {
			if (propName.startsWith("*")) {
				return false;
			}
		}
		return true;
	}

	public ReflectionUtil getReflectionUtil() {
		return reflectionUtil;
	}

	public void setReflectionUtil(ReflectionUtil reflectionUtil) {
		this.reflectionUtil = reflectionUtil;
	}

}

 

package com.creawor.cbsms.client.xml.service;

import java.io.IOException;
import java.util.List;

import com.creawor.cbsms.client.xml.util.XMLProcessor;

/**
 * <p>
 * Description: 提供对象转换为XML的调用接口
 *                  
 * </p>
 * 
 * 
 * @author Administrator
 * @since  2008-12-2
 * @version
 */
public class Object2XMLHander {

	private XMLProcessor xmlProcessor;

	/**
	 * 生成一个XML文档,文档名由输入参数决定
	 * 
	 * @param objs
	 *          待转换为XML文件的对象集合
	 *          
	 * @param unReflectProp
	 *           不需要映射进入XML属性;如果全部要映射进入XML文件则传入null
	 *           eg. CbsTargetTime对象中有DATE_FORMAT不需要映射则在该参数中添加
	 *               CbsTargetTime.DATE_FORMAT
	 * 
	 * @param filename 
	 *           需建立Xml文件的完全路径和文件名
	 *           
	 * @return 返回操作结果, 
	 *         0表失败, 1表成功
	 */
	@SuppressWarnings("unchecked")
	public int createXMLFile(List objs, String[] unReflectProp, String filename) {
		try {
			xmlProcessor = new XMLProcessor();
			xmlProcessor.createXMLFile(objs, unReflectProp, filename);
			return 1;
		} catch (IndexOutOfBoundsException e) {
			// TODO Auto-generated catch block
			//System.out.println("传入的对象数组长度为零!");
			e.printStackTrace();
			return 0;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println("生成XML异常!");
			e.printStackTrace();
			return 0;
		}
	}

}

 

package com.creawor.cbsms.client.xml.test;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.creawor.cbsms.client.model.CbsMessage;
import com.creawor.cbsms.client.model.CbsTargetTime;
import com.creawor.cbsms.client.xml.service.Object2XMLHander;
import com.creawor.cbsms.client.xml.util.XMLProcessor;

public class MyTest {

	public static void main(String[] args) {
		CbsMessage message = new CbsMessage();
		message.setChannelId(1);
		message.setData("你好 world");
		message.setBcEndType(1);
		message.setMessageNum(12);

		CbsMessage message2 = new CbsMessage();
		message2.setChannelId(2);
		message2.setData("hello world2");
		message2.setBcEndType(2);
		message2.setMessageNum(122);
		CbsTargetTime ctt = new CbsTargetTime();
		ctt.setFixedTime("fixtime");
		Calendar cal = Calendar.getInstance();
		ctt.setEndDate(new Timestamp(cal.getTimeInMillis()));
		message.setCbsTargetTime(ctt);
		String[] unReflectProp = new String[] { "CbsTargetTime.DATE_FORMAT",
				"CbsTargetTime.TIME_FORMAT", "CbsTargetTime.DATE_TIME_FORMAT",
				"CbsTargetTime.TIME_TYPE_FIXED_TIME",
				"CbsTargetTime.TIME_TYPE_TOPIC",
				"CbsTargetTime.TIME_TYPE_BC_NOW",
				"CbsTargetTime.TIME_TYPE_REAL_TIME",
				"CbsTargetTime.TIME_TYPE_CRON_EXPRESSION",
				"CbsTargetTime.TIME_TYPE_RANGE" };
		List<CbsMessage> messages = new ArrayList<CbsMessage>();
		messages.add(message);
		messages.add(message2);
		UserInfo user = new UserInfo();
		user.setPassword("password");
		user.setUsername("username");
		ctt.setUser(user);
		Object2XMLHander hander = new Object2XMLHander();
		hander.createXMLFile(messages, unReflectProp, "E:\\maosenFirst2.xml");

	}

}

 

   发表时间:2008-12-03  
xstream 不好吗,好像两行代码就可以实现这个功能吧!
0 请登录后投票
   发表时间:2008-12-03  
有个东西叫XML系列化和反系列化吧?
0 请登录后投票
   发表时间:2008-12-03  
JAXB 也可以的
0 请登录后投票
   发表时间:2008-12-03  
xtream不错,很轻量,序列化和反序列化都相当简单。JAXB太笨重了。
0 请登录后投票
   发表时间:2008-12-03  
开头写了老大一个数组,为啥不用枚举?还有就是开源已经有很不错的了,可以参考一下。不过还是赞一下,技术没有好坏,只有好不好用
0 请登录后投票
   发表时间:2009-12-02  
推荐xtream
0 请登录后投票
   发表时间:2009-12-02  
代码还是很清晰的。
自己已经实现了,为什么还要用别人的。没干的话用现成的话还可以考虑。
0 请登录后投票
   发表时间:2009-12-02   最后修改:2009-12-02
yangfudong 写道
代码还是很清晰的。
自己已经实现了,为什么还要用别人的。没干的话用现成的话还可以考虑。

作为系统负责人,如果有开源好用,自己造好了轮子,我也会要求砸了用开源产品。开源产品背后是一个社区。帮你维护、测试、文档、培训人。你不可能会做得更好,而且以后招人也非常容易,不会有大的风险。
java平台发展到今天,更多应该是去整合各类成熟组件,能做好才是真正的牛!

这个还是推荐你使用xstream
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics