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 一样深深的爱护着她(感觉是不是在这里谈这些有点跑题了)。