Convert complex objects into xml


 There are many utilities like Xstream which can provide this functionality, but i did not find them easy to use, so i am putting this small utility to help unmarshelling complex objects into readable format for easier debugging.

Most of the tools rely on toString method overrides to unmarshall the objects and fail to unwrap the multilevel nesting.  

This code also converts strings containing xml or html into character data so that output remains readable in XML editors.

There are two helper flags, sample output is as follows.

1. SIMPLE_TYPED = false and CANONICAL_TYPED = false
 <ArrayList><String><String>mystery</String><Boolean><Boolean>true</Boolean><ArrayList><String><String>one</String><String><String>two</String></ArrayList></ArrayList>

2. SIMPLE_TYPED = true and CANONICAL_TYPED = false
 <ArrayList:java.util.ArrayList><String:java.lang.String><String:String>mystery</String:String><Boolean:java.lang.Boolean><Boolean:Boolean>true</Boolean:Boolean><ArrayList:java.util.ArrayList><String:java.lang.String><String:String>one</String:String><String:java.lang.String><String:String>two</String:String></ArrayList:java.util.ArrayList></ArrayList:java.util.ArrayList>

3.
SIMPLE_TYPED = false and CANONICAL_TYPED = true
 <ArrayList:java.util.ArrayList><String:java.lang.String><String:java.lang.String>mystery</String:java.lang.String><Boolean:java.lang.Boolean><Boolean:java.lang.Boolean>true</Boolean:java.lang.Boolean><ArrayList:java.util.ArrayList><String:java.lang.String><String:java.lang.String>one</String:java.lang.String><String:java.lang.String><String:java.lang.String>two</String:java.lang.String></ArrayList:java.util.ArrayList></ArrayList:java.util.ArrayList>


 4.SIMPLE_TYPED = true and CANONICAL_TYPED = true
 <ArrayList:java.util.ArrayList><String:java.lang.String><String:java.lang.String>mystery</String:java.lang.String><Boolean:java.lang.Boolean><Boolean:java.lang.Boolean>true</Boolean:java.lang.Boolean><ArrayList:java.util.ArrayList><String:java.lang.String><String:java.lang.String>one</String:java.lang.String><String:java.lang.String><String:java.lang.String>two</String:java.lang.String></ArrayList:java.util.ArrayList></ArrayList:java.util.ArrayList>

The source code is as follows:


/**
 * @author Vaibhav Singh
 * Copyright : 2013
 */

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class ObjectToXML {

    private static boolean SIMPLE_TYPED = true;
    private static boolean CANONICAL_TYPED = false;
    private static Pattern MARKUP_PATTER = Pattern.compile("(<|(<(\\s)*/(\\s)*))((\\w)*|(\\W)*)(\\s)*(>)");

    public static void main(String a[]) throws Exception {
        Collection col1=new ArrayList();
        col1.add("one");
        col1.add("two");
     
        Collection col2=new ArrayList();
        col2.add("mystery");
        col2.add(true);
        col2.add(col1);
     
        System.out.println(convert(col2));
    }

    public static String convert(Object obj) throws Exception {
        return convert(null, obj);
    }

    public static String convert(String objName, Object obj) throws Exception {
        if (obj == null) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        if (objName == null) {
            objName = obj.getClass().getSimpleName();
        }
        if (isMapTyped(obj)) {
            return readMap(objName, obj);
        }
        if (isCollection(obj)) {
            return unWrapCollection(objName, obj);
        }
        if (isPrimitive(obj)) {
            return builder.append(readPrimitive(objName, obj)).toString();
        }
        builder.append("<" + getXMLMarker(objName, obj) + ">");
        Field fields[] = obj.getClass().getDeclaredFields();
        builder.append(readFields(fields, obj));
        // read the fields of the super classes
        Class supClass = obj.getClass().getSuperclass();
        Field supFields[] = supClass.getDeclaredFields();
        builder.append(readFields(supFields, obj));
        builder.append("</" + getXMLMarker(objName, obj) + ">");
        return builder.toString();
    }

    private static String readFields(Field[] fields, Object obj) throws Exception {
        StringBuilder builder = new StringBuilder();
        for (Field f : fields) {
            f.setAccessible(true);
            String fname = f.getName();
            if (isIgnoreableField(fname)) {
                continue;
            }
            Object valueObj = f.get(obj);
            String type = f.getGenericType().toString();
            if (valueObj == null) {
                builder.append("<" + getXMLMarker(f) + "/>");
            } else if (isPrimitive(valueObj)) {
                builder.append(readPrimitive(fname, valueObj));
            } else if (isCollection(valueObj)) {
                builder.append(unWrapCollection(fname, valueObj));
            } else {
                builder.append(convert(fname, f.get(obj)));
            }

        }
        return builder.toString();

    }

    private static String unWrapCollection(String fname, Object obj) throws Exception {
        StringBuilder builder = new StringBuilder();
        if (obj == null) {
            builder.append("<" + getXMLMarker(fname, obj) + "/>");
            return builder.toString();
        }
        builder.append("<" + getXMLMarker(fname, obj) + ">");
        Collection c = (Collection) obj;
        Iterator i = c.iterator();
        while (i.hasNext()) {
            Object ele = i.next();
            ele = ele.getClass().cast(ele);
            builder.append(convert(null, ele));
        }
        builder.append("</" + getXMLMarker(fname, obj) + ">");
        return builder.toString();
    }

    private static String readPrimitive(String fname, Object obj) {
        StringBuilder builder = new StringBuilder();
        String value = String.valueOf(obj);
        if (value == null) {
            builder.append("<" + getXMLMarker(fname, obj) + "/>");
        } else {
            builder.append("<" + getXMLMarker(fname, obj) + ">");
            builder.append(covertToCharcterData(value));
            builder.append("</" + getXMLMarker(fname, obj) + ">");
        }
        return builder.toString();
    }

    private static String readMap(String fname, Object obj) throws Exception {
        StringBuilder builder = new StringBuilder();
        if (obj == null)
            return builder.append("<" + getXMLMarker(fname, obj) + "/>").toString();
        Map map = (Map) obj;
        Set s = map.keySet();
        Iterator i = s.iterator();
        builder.append("<" + getXMLMarker(fname, obj) + ">");
        while (i.hasNext()) {
            builder.append("<entry>");
            Object key = i.next();
            key = key.getClass().cast(key);
            builder.append("<Key>");
            builder.append(convert(key));
            builder.append("</Key>");
            Object val = map.get(key);
            if (val == null) {
                builder.append("<Value/>");
            } else {
                builder.append("<Value>");
                builder.append(convert(val));
                builder.append("</Value>");
            }
            builder.append("</entry>");
        }
        builder.append("</" + getXMLMarker(fname, obj) + ">");
        return builder.toString();
    }

    private static boolean isMapTyped(Object obj) {
        if (obj instanceof Map) {
            return true;
        }
        return false;
    }

    private static boolean isCollection(Object obj) {
        if (Collection.class.isAssignableFrom(obj.getClass())) {
            return true;
        }
        if (obj instanceof java.util.Collection) {
            return true;
        }
        if (obj instanceof java.util.ArrayList) {
            return true;
        }

        return false;
    }

    public static boolean isPrimitive(Object object) {
        if (object instanceof Integer)
            return true;
        if (object instanceof Double)
            return true;
        if (object instanceof Boolean)
            return true;
        if (object instanceof Short)
            return true;
        if (object instanceof Float)
            return true;
        if (object instanceof Character)
            return true;
        if (object instanceof Long)
            return true;
        if (object instanceof String)
            return true;
        return false;
    }

    private static String getXMLMarker(String sourceCodeName, Object obj) {
        if (CANONICAL_TYPED) {
            String type = obj.getClass().getCanonicalName();
            return getFormatedName(sourceCodeName, type);
        }
        if (SIMPLE_TYPED) {
            String type = obj.getClass().getSimpleName();
            return getFormatedName(sourceCodeName, type);
        }
        return sourceCodeName;
    }

    private static String getXMLMarker(Field field) {
        String sourceCodeName = field.getName();
        if (CANONICAL_TYPED) {
            String type = field.getType().getCanonicalName();
            return getFormatedName(sourceCodeName, type);
        }
        if (SIMPLE_TYPED) {
            String type = field.getType().getSimpleName();
            return getFormatedName(sourceCodeName, type);
        }
        return sourceCodeName;
    }

    private static String getFormatedName(String part1, String part2) {
        return part1 + ":" + part2;
    }

    private static String covertToCharcterData(String data) {
 data = data.replace("&", "&amp;");
 Matcher m = MARKUP_PATTER.matcher(data);
 if (m.find()) {
  data = data + "    ";
  int startIndex = data.indexOf("<") - 1 < 0 ? 0 : data.indexOf("<") - 1;
  data = data.substring(0, startIndex) + "<![CDATA[" + data.substring(data.indexOf("<"));
  int lastEndCurl = data.lastIndexOf(">");
  int lastStartCurl = data.lastIndexOf("<");
  int lastCurl = (lastEndCurl < lastStartCurl) ? lastStartCurl : lastEndCurl;
  data = data.substring(0, lastCurl + 1) + "]]>" + data.substring(lastCurl + 1);
 } else if (data.contains("<")) {
  int firstStartCurl = data.indexOf("<");
  int lastStartCurl = data.lastIndexOf("<");
  if (firstStartCurl != lastStartCurl) {
   data = data.substring(0, firstStartCurl) + "<![CDATA[" + data.substring(firstStartCurl);
   lastStartCurl = data.lastIndexOf("<");
   data = data.substring(0, lastStartCurl + 1) + "]]>" + data.substring(lastStartCurl + 1);
  } else {
   String temp = data.substring(0, firstStartCurl) + "<![CDATA[";
   temp = temp + data.substring(firstStartCurl, firstStartCurl + 1) + "]]>" + data.substring(firstStartCurl + 1);
   data=temp;
  }
 }
 return data.trim();
 }

    private static boolean isIgnoreableField(String fname) {
        if ("serialVersionUID".equals(fname)) {
            return true;
        }
        return false;
    }
}

Comments

Popular posts from this blog

Caused by: java.sql.SQLTimeoutException: ORA-01013: user requested cancel of current operation

HashiCorp Vault Integration with Ansible Etower using approle

utility to extract date from text with java