apache 的 betwixt 组件可以实现 java 类到 xml 文档的转换,但有一定的局限性,如果需要一个写下面这个类的理由的话,“尽其能则用”吧!

(1) IBeanToXml.java 接口。

package com.flysoft.fuse4j.support.xbean;

/**
 * IBeanToXml 接口实现将任意对象转换为数据岛或XML的方法。
 * flysoft company.
 * @author Dingli.
 * 2008 Apr 22, 2008 5:56:26 PM
 */
public interface IBeanToXml
{
	/**
	 * 将一个类解析成 XML 格式。
	 * @param object 要进行解析的类。
	 * @param encoding 使用的字符集。
	 * @return 返回解析后的 XML 字符串。
	 */
	public String parseBeanToXml(Object object, String encoding);

	/**
	 * 将一个类解析成数据岛格式。
	 * @param id 数据岛的ID。
	 * @param object 要解析的对象。
	 * @param encoding 使用的字符集。
	 * @return 返回解析后的数据岛字符串。
	 */
	public String parseBeanToDataIsland(String id, Object object, String encoding);
}



(2) BeanToXmlParser.java 类。


package com.flysoft.fuse4j.support.xbean;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;

/**
 * BeanToXmlParser 类实现将任意对象转换为数据岛或XML,但对象不能循环引用自身。
 * flysoft company.
 * @author Dingli.
 * 2008 Apr 22, 2008 5:41:07 PM
 */
public class BeanToXmlParser implements IBeanToXml
{
	//log4j日志记录器。
	private static final Log logger = LogFactory.getLog(BeanToXmlParser.class);
	//简单日期格式化对象。
	private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

	/**
	 * 构建默认的 BeanToXmlParser 对象。
	 */
	public BeanToXmlParser()
	{}

	/*
	 * (non-Javadoc)
	 * @see com.flysoft.fuse4j.support.xbean.IBeanToXml#parseBeanToXml(java.lang.Object, java.lang.String)
	 */
	public String parseBeanToXml(Object object, String encoding)
	{
		try
		{
			//应为递归可能很消耗资源,先进行垃圾回收。
			System.gc();
			//传入的对象必须不能为空。
			if(object != null)
			{
				//获取传入对象的全类名。
				String classPath = object.getClass().getName();
				//获取传入对象的类名。
				String className = classPath.substring(classPath.lastIndexOf(".") + 1);
				//构建文档工厂类对象。
				DocumentFactory documentFactory = DocumentFactory.getInstance();
				//构建文档类对象。
				Document document = documentFactory.createDocument(encoding.toUpperCase());
				//添加根节点。
				document.addElement(className);
				//获取文档根节点。
				Element rootNode = document.getRootElement();
				//添加根元素的 "class" 属性。
				rootNode.addAttribute("class", classPath);
				//插入根元素。
				insertElement(rootNode, className.toLowerCase(), object);
				//返回表示该文档的 XML 字符串。
				return document.asXML();
			}
			else
			{
				return null;
			}
		}
		catch(Exception ex)
		{
			logger.error("Parse object to xml string fail", ex);
			return null;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see com.flysoft.fuse4j.support.xbean.IBeanToXml#parseBeanToDataIsland(java.lang.String, java.lang.Object, java.lang.String)
	 */
	public String parseBeanToDataIsland(String id, Object object, String encoding)
	{
		StringBuffer stringBuffer = new StringBuffer();
		stringBuffer.append("<xml id=\"{id}\">");
		stringBuffer.append(parseBeanToXml(object, encoding));
		stringBuffer.append("</xml>");
		return stringBuffer.toString().replaceAll("[{]id[}]", id);
	}

	/**
	 * 插入节点到父节点元素。
	 * @param parentNode 父节点元素。
	 * @param nodeName 要插入的节点名。
	 * @param object 要插入的节点对象。
	 */
	private void insertElement(Element parentNode, String nodeName, Object object)
	{
		//如果传入的对象为空,则转换为空字符串。
		object = (object == null)? "": object;
		//父元素节点和传入的对象均不能为空。
		if(parentNode != null)
		{
			//表示当前元素节点。
			Element currentNode = null;
			//获取传入对象的全类名。
			String classPath = object.getClass().getName();
			//获取传入对象的类名。
			String className = classPath.substring(classPath.lastIndexOf(".") + 1).toLowerCase();
			//传入的对象为基本数据类型。
			if(isBaseDataType(object.getClass()))
			{
				//如果节点名不为空,添加的元素名为节点名,否则为传入类的类名。
				currentNode = parentNode.addElement((nodeName != null && !nodeName.equals(""))? nodeName: className);
				//添加子节点的值。
				currentNode.addText((object instanceof Date)? BeanToXmlParser.simpleDateFormat.format(object): object.toString());
			}
			//传入的对象为集合类型。
			else if(object instanceof Collection)
			{
				//插入集合中的对象到元素。
				insertElementFromCollection(parentNode, object);
			}
			//传入的对象为Map类型。
			else if(object instanceof Map)
			{
				//插入Map中的对象到元素。
				insertElementFromMap(parentNode, object);
			}
			//其他类类型(自定义类型)。
			else
			{
				//插入自定义的对象到元素。
				insertElementFromOtherObject(parentNode, object);
			}
		}
	}

	/**
	 * 插入节点到父节点元素。
	 * @param parentNode 父节点元素。
	 * @param object 要插入的节点对象。
	 */
	private void insertElement(Element parentNode, Object object)
	{
		insertElement(parentNode, null, object);
	}

	/**
	 * 获取自定义对象中的元素做为节点插入父节点。
	 * @param parentNode 父节点。
	 * @param object 要获取元素的对象。
	 */
	private void insertElementFromOtherObject(Element parentNode, Object object)
	{
		//表示当前元素节点。
		Element currentNode = null;
		//表示字段名。
		String fieldName = null;
		//表示类中的getter方法名。
		String methodName = null;
		//表示通过getter方法取得的对象。
		Object fieldObject = null;
		//返回类所定义的字段。
		Field[] fields = object.getClass().getDeclaredFields();
		//遍历所有类字段对象。
		for(int i = 0; i < fields.length; i++)
		{
			//获取单个字段对象。
			Field field = fields[i];
			//获取字段名。
			fieldName = field.getName();
			//获取以getter起始的方法名。
			methodName = "get" + Character.toUpperCase(fieldName.charAt(0))+ fieldName.substring(1);
			try
			{
				//获取所有的方法对象。
				Method method = object.getClass().getMethod(methodName, null);
				//判断getter方法是否为public。
				if(Modifier.isPublic(method.getModifiers()))
				{
					//判断从getter方法获取的对象是否为空。
					if((fieldObject = method.invoke(object, null)) != null && !isBaseDataType(fieldObject.getClass()))
					{
						//用字段名为节点名添加一个节点元素到指定的父节点。
						currentNode = parentNode.addElement(fieldName);
						//添加该节点元素的"class"属性。
						currentNode.addAttribute("class", fieldObject.getClass().getName());
						//添加节点元素到当前新插入的节点下。
						insertElement(currentNode, fieldName, fieldObject);
					}
					else
					{
						//添加节点元素节点到父节点下。
						insertElement(parentNode, fieldName, fieldObject);
					}
				}
			}
			catch(NoSuchMethodException nex)
			{}
			catch(Exception ex)
			{
				logger.error("Get class field fail", ex);
			}
		}
	}

	/**
	 * 获取Map中的元素做为节点插入父节点。
	 * @param parentNode 父节点。
	 * @param object 要获取元素的对象。
	 */
	private void insertElementFromMap(Element parentNode, Object object)
	{
		//获取传入对象的全类名(包括包名)。
		String classPath = null;
		//获取传入对象的类名(不包括包名)。
		String className = null;
		//表示Map的键。
		Object key = null;
		//表示Map的值。
		Object value = null;
		//表示当前元素节点。
		Element currentNode = null;
		//转换Object为Map类型。
		Map map = (Map)object;
		//判断传入的对象是否为空。
		if(map != null)
		{
			//遍历所有键集合。
			for(Iterator keyIterator = map.keySet().iterator(); keyIterator.hasNext();)
			{
				//判断取得的Map中的键是否为空。
				if((key = keyIterator.next()) != null)
				{
					//判断子元素是否不为空。
					if((value = map.get(key)) != null)
					{
						//判断子元素是否不为基本数据类型。
						if(!isBaseDataType(value.getClass()))
						{
							//获取传入对象的全类名(包括包名)。
							classPath = value.getClass().getName();
							//获取传入对象的类名(不包括包名)。
							className = classPath.substring(classPath.lastIndexOf(".") + 1);
							//添加元素到当前元素。
							currentNode = parentNode.addElement(className);
							//添加元素的class属性。
							currentNode.addAttribute("class", classPath);
							//插入到当前元素。
							insertElement(currentNode, value);
						}
						else
						{
							//插入到父元素。
							insertElement(parentNode, key.toString(), value);
						}
					}
				}
			}
		}
	}

	/**
	 * 获取集合中的元素做为节点插入父节点。
	 * @param parentNode 父节点。
	 * @param object 要获取元素的对象。
	 */
	private void insertElementFromCollection(Element parentNode, Object object)
	{
		//表示当前元素节点。
		Element currentNode = null;
		//获取传入对象的全类名(包括包名)。
		String classPath = null;
		//获取传入对象的类名(不包括包名)。
		String className = null;
		//转换为集合接口对象。
		Collection collection = (Collection)object;
		//集合的子元素。
		Object subObject = null;
		//集合对象不能为空。
		if(collection != null)
		{
			//遍历所有的集合元素。
			for(Iterator iterator = collection.iterator(); iterator.hasNext();)
			{
				//判断获取的集合的子元素是否为空。
				if((subObject = iterator.next()) != null)
				{
					//判断子元素是否不为一个基本数据类型。
					if(!isBaseDataType(subObject.getClass()))
					{
						//获取传入对象的全类名(包括包名)。
						classPath = subObject.getClass().getName();
						//获取传入对象的类名(不包括包名)。
						className = classPath.substring(classPath.lastIndexOf(".") + 1);
						//添加元素到当前元素。
						currentNode = parentNode.addElement(className);
						//添加元素的class属性。
						currentNode.addAttribute("class", classPath);
						//插入到当前元素。
						insertElement(currentNode, subObject);
					}
					else
					{
						//插入到父元素。
						insertElement(parentNode, subObject);
					}
				}
			}
		}
	}

	/**
	 * 判断一个类是否为基本数据类型。
	 * @param clazz 要判断的类。
	 * @return true 表示为基本数据类型。
	 */
	private boolean isBaseDataType(Class clazz)
	{
		return
		(
			clazz.equals(String.class) ||
			clazz.equals(Integer.class)||
			clazz.equals(Byte.class) ||
			clazz.equals(Long.class) ||
			clazz.equals(Double.class) ||
			clazz.equals(Float.class) ||
			clazz.equals(Character.class) ||
			clazz.equals(Short.class) ||
			clazz.equals(BigDecimal.class) ||
			clazz.equals(BigInteger.class) ||
			clazz.equals(Boolean.class) ||
			clazz.equals(Date.class) ||
			clazz.isPrimitive()
		);
	}
}



用一个 main() 方法来简单表明如何使用。


public class MainClass
{
	public static void main(String[] args) throws Exception
	{
		try
		{
			List rootList = new ArrayList();
			List subList = new ArrayList();
			rootList.add("name");
			rootList.add(new Integer(100));
			rootList.add(new Float(100.1F));
			rootList.add(new Double(100.01D));
			subList.add(new Integer(100));
			subList.add(new Float(100.1F));
			subList.add(new Double(100.01D));
			rootList.add(subList);
			//java 类到 xml 文档的解析器。
			BeanToXmlParser beanToXmlParser = new BeanToXmlParser();
			//转换为 xml 字符串。
			System.out.println(beanToXmlParser.parseBeanToXml(rootList));
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
	}
}



千万不要问为什么我都是在贴代码,我是个实用主义者。如果你有好的点子,长篇大论一番后。那么,“please, share !”。一个 java 类就像一个故事,有自己的生命。构思良好的类不仅可以让你事半功倍,而且也极像一件艺术品。与其让别人听你的滔滔大论,不如直接让他们看你是如何做的。虽然“授人以鱼,不如授之以渔”,但“抛砖引玉”也未尝不可!



近来身体微恙,但对她的感觉却从来没有减少过,她的映像占据了我的大部分“硬盘空间”,以至于我的“硬盘”七零八落,需要“碎片整理”下了。她对我还是爱理不睬,虽然她就在我的左座,我有时候会偷偷瞄她(是不是我很没有出息),真希望有一天她能接受我,就像当初我接受 java 一样(虽然我不知道我是否选对),我会像喜欢 java 一样深深的爱护着她(感觉是不是在这里谈这些有点跑题了)。