Thanks to comments for pointing out the isAssignableFrom() function in Class. Also, now the resulting XML is valid with all the special characters (&, <, >, ' and ").
package own; import java.lang.reflect.*; import java.util.*; public class OptimizedReflectionMarshaller { // cache for getters private static HashMap gettersMap = new HashMap(); // cache for storing info on whether certain class implements Collection private static HashMap collectionsMap = new HashMap(); private static final String JAVA = "java."; private static final String JAVAX = "javax."; private static final Class[] EMPTYPARAMS = new Class[0]; /** * Info on a single field and the corresponding getter method */ private static class FieldMethodPair { private String fieldName; private Method getterMethod; public FieldMethodPair(String fieldName, Method getterMethod) { this.fieldName = fieldName; this.getterMethod = getterMethod; } public String getFieldName() { return fieldName; } public Method getGetterMethod() { return getterMethod; } } /** * Returns the marshalled XML representation of the parameter object */ public static String marshal(Object obj) { StringBuffer sb = new StringBuffer(); Class clazz = obj.getClass(); // get class name in lower letters (w/o package name) String className = clazz.getName(); int lastDotIndex = className.lastIndexOf("."); if (lastDotIndex >= 0) className = className.substring(lastDotIndex + 1); className = className.toLowerCase(); sb.append("<" + className + ">"); marshal(obj, sb); sb.append("</" + className + ">"); return sb.toString(); } /** * Returns getter function for the specified field */ private static Method getGetter(Class clazz, String fieldName) { try { // for example, for 'name' we will look for 'getName' String getMethodName = fieldName.substring(0, 1); getMethodName = getMethodName.toUpperCase(); getMethodName = "get" + getMethodName + fieldName.substring(1, fieldName.length()); Method getMethod = clazz.getMethod(getMethodName, EMPTYPARAMS); return getMethod; } catch (NoSuchMethodException nsme) { return null; } } /** * Returns a list of all fields that have getters */ private static List getAllGetters(Class clazz) { try { // check if have in cache if (gettersMap.containsKey(clazz.getName())) return (List) gettersMap.get(clazz.getName()); List fieldList = new LinkedList(); Class currClazz = clazz; while (true) { Field[] fields = currClazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field currField = fields[i]; int modifiers = currField.getModifiers(); // check if not static and has getter if (!Modifier.isStatic(modifiers)) { Method getterMethod = getGetter(clazz, currField .getName()); if (getterMethod != null) { FieldMethodPair fmp = new FieldMethodPair(currField .getName(), getterMethod); fieldList.add(fmp); } } } currClazz = currClazz.getSuperclass(); if (currClazz == null) break; } // store in cache gettersMap.put(clazz.getName(), fieldList); return fieldList; } catch (Exception exc) { exc.printStackTrace(); return null; } } /** * Checks whether the specified class implements Collection interface */ private static boolean isImplementsCollection(Class clazz) { String className = clazz.getName(); // check in cache if (collectionsMap.containsKey(className)) { return ((Boolean) collectionsMap.get(className)).booleanValue(); } boolean result = Collection.class.isAssignableFrom(clazz); // store in cache collectionsMap.put(className, new Boolean(result)); return result; } private static void appendFormatted(Object obj, StringBuffer sb) { String strRepresentation = obj.toString(); int len = strRepresentation.length(); for (int i = 0; i < len; i++) { char c = strRepresentation.charAt(i); switch (c) { case '&': sb.append("&"); break; case '<': sb.append("<"); break; case '>': sb.append(">"); break; case '\'': sb.append("'"); break; case '\"': sb.append("""); break; default: sb.append(c); } } } private static void marshal(Object obj, StringBuffer sb) { try { Class clazz = obj.getClass(); String className = clazz.getName(); // check if implements Collection if (isImplementsCollection(clazz)) { Collection cobj = (Collection) obj; Iterator it = cobj.iterator(); while (it.hasNext()) { Object eobj = it.next(); sb.append("<" + eobj.getClass().getName() + ">"); marshal(eobj, sb); sb.append("</" + eobj.getClass().getName() + ">"); } return; } // check for primitive types if (className.startsWith(JAVA) || className.startsWith(JAVAX)) { appendFormatted(obj, sb); return; } // otherwise put all fields with getters List allGetters = getAllGetters(clazz); Iterator itGetters = allGetters.iterator(); while (itGetters.hasNext()) { FieldMethodPair currGetter = (FieldMethodPair) itGetters.next(); String currFieldName = currGetter.fieldName; Method currentGetter = currGetter.getterMethod; // call method Object val = currentGetter.invoke(obj, EMPTYPARAMS); if (val != null) { sb.append("<" + currFieldName + ">"); // call recursively marshal(val, sb); sb.append("</" + currFieldName + ">"); } } } catch (Exception e) { e.printStackTrace(); } } }Feel free to use and modify.