Monday, February 18, 2013

Custom XML Generator

This is a simple XML Generator that can be used to send in any object (tested with List and custom objects) and get the XML out of it. This could be useful while building java to xml transformations for any objects.

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class XMLGeneratorImpl {

    public static final String GET_METHOD = "get";
    public static final String IS_METHOD = "is";
    public static final String EMPTY = "";
    public static final String START_TAG = "<";
    public static final String END_TAG = ">";
    public static final String SLASH = "/";

    private boolean trimPackageNames;

    private static final Set<Class> WRAPPER_TYPES = new HashSet(Arrays.asList(
            Boolean.class, Character.class, Byte.class, Short.class,
            Integer.class, Long.class, Float.class, Double.class, Void.class,
            String.class));

    private enum ObjectFormat {
        PRIMITIVE, OBJECT, LIST, MAP, SET, ARRAY;
    }

    public String toXML(Object input) {
        ObjectFormat format = getFormat(input);
        return convertToXml(input, format);
    }

    private String convertToXml(Object input, ObjectFormat format) {
        StringBuilder xml = new StringBuilder();
        String objectName = getObjectName(input);
        switch (format) {
        case OBJECT:
            xml.append(START_TAG).append(objectName).append(END_TAG);
            xml.append(getXMLFromObject(input));
            xml.append(START_TAG).append(SLASH).append(objectName)
                    .append(END_TAG);
            break;
        case ARRAY:
            xml.append(getXMLFromArray(input));
            break;
        case LIST:
            xml.append(getXMLFromList(input));
            break;
        case PRIMITIVE:
            xml.append(getXMLFromPrimitive(null, input));
            break;
        default:
            throw new IllegalArgumentException("Unsupported request object");
        }

        return xml.toString();
    }

    private String getXMLFromPrimitive(String key, Object input) {
        StringBuilder xml = new StringBuilder();
        String xmlTag = key == null ? getObjectName(input) : key;
        xml.append(START_TAG).append(xmlTag).append(END_TAG)
                .append(input.toString()).append(START_TAG).append(SLASH)
                .append(xmlTag).append(END_TAG);
        return xml.toString();
    }

    private String getXMLFromObject(Object input) {
        StringBuilder xml = new StringBuilder();
        List<Method> methods = getAllowedMethods(input);
        for (Method method : methods) {
            xml.append(getXMLValue(input, method));
        }
        return xml.toString();
    }

    private String getXMLFromArray(Object input) {
        StringBuilder xml = new StringBuilder();
        Object[] objects = (Object[]) input;
        for (Object object : objects) {
            ObjectFormat of = getFormat(object);
            xml.append(convertToXml(object, of));
        }
        return xml.toString();
    }

    private String getXMLFromList(Object input) {
        StringBuilder xml = new StringBuilder();
        List objects = (List) input;
        for (Object object : objects) {
            ObjectFormat of = getFormat(object);
            xml.append(convertToXml(object, of));
        }
        return xml.toString();
    }

    private List<Method> getAllowedMethods(Object input) {
        List<Method> getters = new ArrayList<Method>();
        Method[] methods = input.getClass().getDeclaredMethods();
        for (Method method : methods) {
            if (isGetterMethod(method)) {
                getters.add(method);
            }
        }
        return getters;
    }

    private boolean isGetterMethod(Method method) {
        boolean getter = false;
        if (method.getName().startsWith(GET_METHOD)
                || method.getName().startsWith(IS_METHOD)) {
            getter = true;
        }
        return getter;
    }

    private String getXMLValue(Object input, Method method) {
        StringBuilder xml = new StringBuilder();
        try {
            Object value = method.invoke(input, null);
            String xmlTagName = getObjectName(null, method);
            if (value != null) {
                ObjectFormat of = getFormat(value);
                switch (of) {
                case PRIMITIVE:
                    xml.append(START_TAG).append(xmlTagName).append(END_TAG)
                            .append(value).append(START_TAG).append(SLASH)
                            .append(xmlTagName).append(END_TAG);
                    break;
                case OBJECT:
                    xml.append(convertToXml(value, of));
                    break;
                case LIST:
                case MAP:
                case SET:
                case ARRAY:
                    xml.append(START_TAG).append(xmlTagName).append(END_TAG)
                            .append(convertToXml(value, of)).append(START_TAG)
                            .append(SLASH).append(xmlTagName).append(END_TAG);
                    break;
                }
            }
        } catch (IllegalArgumentException e) {
            // TODO: handle exception
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return xml.toString();
    }

    private ObjectFormat getFormat(Object input) {
        ObjectFormat format = ObjectFormat.OBJECT;
        Class clazz = input.getClass();
        if (isWrapperType(clazz)) {
            format = ObjectFormat.PRIMITIVE;
        } else if (clazz.getName().contains("List")) {
            format = ObjectFormat.LIST;
        }
        return format;
    }

    private boolean isWrapperType(Class clazz) {
        return WRAPPER_TYPES.contains(clazz);
    }

    private String getXMLTagName(Method method) {
        String xmlTagName = null;

        if (method.getName().startsWith(GET_METHOD)) {
            xmlTagName = method.getName().substring(3);
        } else {
            xmlTagName = method.getName().substring(2);
        }

        return xmlTagName;
    }

    public boolean isTrimPackageNames() {
        return trimPackageNames;
    }

    public void setTrimPackageNames(boolean trimPackageNames) {
        this.trimPackageNames = trimPackageNames;
    }

    private String getObjectName(Object input) {
        return getObjectName(input, null);
    }

    private String getObjectName(Object input, Method method) {
        String xmlTagName = EMPTY;
        if (input != null) {
            xmlTagName = input.getClass().getName();
            if (trimPackageNames && xmlTagName.indexOf(".") != -1) {
                xmlTagName = xmlTagName
                        .substring(xmlTagName.lastIndexOf(".") + 1);
            }
        } else if (method != null) {
            xmlTagName = getXMLTagName(method);
            if (trimPackageNames && xmlTagName.indexOf(".") != -1) {
                xmlTagName = xmlTagName
                        .substring(xmlTagName.lastIndexOf(".") + 1);
            }
        }
        return xmlTagName;
    }
}