/**
* Copyright 1996-2014 FoxBPM ORG.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author yangguangftlp
*/
package org.foxbpm.engine.impl.util;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.foxbpm.engine.exception.FoxBPMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.DOMException;
/**
* 配置文件转换对象
*
* @author yangguangftlp
* @date 2014年10月27日
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class XMLToObject {
protected static final Logger LOGGER = LoggerFactory.getLogger(XMLToObject.class);
public static final String GENERAL_M_PREFIX = "set";
public static final String BOOL_PREFIX = "is";
private static XMLToObject instance;
private XMLToObject() {
}
/**
* 获取实例
*
* @return
*/
public static XMLToObject getInstance() {
if (null == instance) {
synchronized (XMLToObject.class) {
if (null == instance) {
instance = new XMLToObject();
}
}
}
return instance;
}
/**
* 将xml转换Object
*
* @param in
* 文档对象
* @param objClass
* class
* @param flag
* 方法可见性 true public false all
* @return 返回 生成objClass 实例对象
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
* @throws DOMException
* @throws ClassNotFoundException
*/
public Object transform(InputStream in, Class objClass, boolean flag) {
if (null == in) {
throw new IllegalArgumentException("in is null!");
}
try {
SAXReader reader = new SAXReader();
return transform(reader.read(in), objClass, flag);
} catch (DocumentException e) {
LOGGER.error("从IO中读取文档出现错误!", e);
throw new FoxBPMException("从IO中读取文档出现错误!", e);
}
}
/**
* 将xml转换Object
*
* @param doc
* 文档对象
* @param objClass
* class
* @param flag
* 是否获取 objClass 继承的所有方法
* @return 返回 生成objClass 实例对象
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
* @throws DOMException
* @throws ClassNotFoundException
*/
public Object transform(Document doc, Class objClass, boolean flag) {
if (null == doc) {
throw new IllegalArgumentException("doc is null!");
}
if (null == objClass) {
throw new IllegalArgumentException("objClass is null!");
}
try {
return doRootElement(doc.getRootElement(), objClass.newInstance(), flag);
} catch (Exception e) {
LOGGER.error("解析文档出现错误!", e);
throw new FoxBPMException("解析文档出现错误!", e);
}
}
private Object doRootElement(Element root, Object obj, boolean flag) throws ClassNotFoundException,
IllegalAccessException, InvocationTargetException, InstantiationException {
if (null != root) {
Element element = null;
Method method = null;
Class paramType = null;
Object paramObj = null;
for (Iterator<Element> iterator = root.elements().iterator(); iterator.hasNext();) {
element = iterator.next();
method = getMethods(GENERAL_M_PREFIX, obj.getClass(), flag).get(generateMethodName(GENERAL_M_PREFIX, element.getName()));
if (null != method && method.getParameterTypes().length == 1) {
paramType = method.getParameterTypes()[0];
if (!paramType.isArray() && !paramType.isPrimitive()) {
paramObj = paramType.newInstance();
// 处理节点属性
doAttributes(element, paramObj, getMethods(GENERAL_M_PREFIX, paramType, flag));
// 将实例化的对象设置到对应obj属性中
method.invoke(obj, paramObj);
// 获取子节点
doChildElement(element.elements(), paramObj, flag);
}
}
}
}
return obj;
}
/**
* 通过节点名称构造方法名
*
* @param prefix
* get
* @param name
* 节点名称
* @return 返回方法名
*/
private String generateMethodName(String prefix, String name) {
StringBuffer sbuffer = new StringBuffer();
sbuffer.append(name.substring(name.indexOf(':') + 1));
// 处理boolean变量
if (sbuffer.toString().startsWith(BOOL_PREFIX)) {
sbuffer.delete(0, 2);
}
// 处理有些节点属性a:b 去掉a:
return new StringBuffer(prefix).append(Character.toUpperCase(sbuffer.charAt(0))).append(sbuffer.substring(1)).toString();
}
/**
* 处理属性
*
* @param element
* @param paramObj
* @param temp
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
private void doAttributes(Element element, Object paramObj, Map<String, Method> methods)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
// 处理element属性
Method method = null;
Attribute attribute = null;
for (int i = 0, length = element.attributeCount(); i < length; i++) {
attribute = element.attribute(i);
method = methods.get(generateMethodName(GENERAL_M_PREFIX, attribute.getName()));
if (null != method && method.getParameterTypes().length == 1) {
doAttributeValue(paramObj, method, attribute.getValue(), method.getParameterTypes()[0]);
}
}
}
/**
* 处理参数值
*
* @param pObj
* @param method
* @param value
* @param pType
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
private void doAttributeValue(Object pObj, Method method, String value, Class pType)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (String.class == pType) {
method.invoke(pObj, value);
} else if (boolean.class == pType) {
method.invoke(pObj, Boolean.valueOf(value));
} else {
// 暂不支持的类型
LOGGER.warn("不支持的类型是:" + pType);
}
}
/**
* 处理子节点
*
* @param nodeList
* @param obj
* @param flag
* @return
* @throws IllegalArgumentException
* @throws DOMException
* @throws IllegalAccessException
* @throws InvocationTargetException
* @throws InstantiationException
* @throws ClassNotFoundException
*/
private Object doChildElement(List<Element> elements, Object obj, boolean flag) throws InstantiationException,
IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException {
if (!elements.isEmpty()) {
Map<String, Method> methodMap = getMethods(GENERAL_M_PREFIX, obj.getClass(), flag);
Map<String, List<Object>> objMap = new HashMap<String, List<Object>>();
Element element = null;
Method method = null;
String methodName = null;
Object paramObj = null;
for (Iterator<Element> iterator = elements.iterator(); iterator.hasNext();) {
element = iterator.next();
methodName = generateMethodName(GENERAL_M_PREFIX, element.getName());
method = methodMap.get(methodName);
if (null != method && method.getParameterTypes().length == 1) {
paramObj = createParameterInstance(method);
if (!objMap.containsKey(methodName)) {
objMap.put(methodName, new ArrayList<Object>());
}
doAttributes(element, paramObj, getMethods(GENERAL_M_PREFIX, paramObj.getClass(), flag));
objMap.get(methodName).add(doChildElement(element.elements(), paramObj, flag));
}
}
// 这里处理子节点
for (Entry<String, List<Object>> entry : objMap.entrySet()) {
method = methodMap.get(entry.getKey());
// 处理数组
if (method.getParameterTypes()[0].isArray()) {
method.invoke(obj, (Object) copyOf(entry.getValue().toArray(), entry.getValue().size(), (Class) method.getParameterTypes()[0]));
} else /** 处理list集合 */
if (method.getParameterTypes()[0].isAssignableFrom(List.class)) {
method.invoke(obj, entry.getValue());
} else {
method.invoke(obj, entry.getValue().get(0));
}
}
}
return obj;
}
/**
* 根据参数类型创建实例
*
* @param method
* @return
*/
private Object createParameterInstance(Method method) {
Object paramObj = null;
Class<?> class1 = method.getParameterTypes()[0];
try {
if (class1.isArray()) {
paramObj = Class.forName(new StringBuffer().append(class1.getName()).delete(0, 2).reverse().deleteCharAt(0).reverse().toString()).newInstance();
} else if (class1.isAssignableFrom(List.class)) {
Type paramType = method.getGenericParameterTypes()[0];// 方法的参数列表
if (paramType instanceof ParameterizedType)/**//* 如果是泛型类型 */{
Type type = ((ParameterizedType) paramType).getActualTypeArguments()[0];// 泛型类型列表
if (type instanceof Class) {
paramObj = Class.forName(((Class) type).getName()).newInstance();
}
}
} else {
paramObj = class1.newInstance();
}
} catch (Exception e) {
LOGGER.error("根据参数类型实例对象出现错误!,参数类型:" + class1);
throw new FoxBPMException("根据参数类型实例对象出现错误!,参数类型:" + class1, e);
}
return paramObj;
}
/**
* 拷贝数组
*
* @param original
* 原数组
* @param newLength
* 新的长度
* @param newType
* 新的类型
* @return
*/
private <T, U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
T[] copy = ((Object) newType == (Object) Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
return copy;
}
/**
* 根据前缀获取class上的方法
*
* @param prefix
* 方法名前缀
* @param cls
* class
* @param flag
* true 获取public方法,false includes public, protected, default
* (package) access, and private methods
* @return 返回prefix前缀的所有方法
*/
private Map<String, Method> getMethods(String prefix, Class cls, boolean flag) {
Map<String, Method> methodMap = new HashMap<String, Method>();
Method[] methods = flag ? cls.getMethods() : cls.getDeclaredMethods();
if (null != methods) {
for (Method m : methods) {
if (m.getParameterTypes().length == 1 && m.getName().startsWith(prefix)
&& Modifier.PUBLIC == m.getModifiers()) {
methodMap.put(m.getName(), m);
}
}
}
return methodMap;
}
}