org.foxbpm.engine.impl.util.XMLToObject.java Source code

Java tutorial

Introduction

Here is the source code for org.foxbpm.engine.impl.util.XMLToObject.java

Source

/**
 * 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 20141027
 */
@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;
    }
}