--- /dev/null
+package org.altusmetrum.AltosDroid;\r
+\r
+ import java.lang.reflect.Array;\r
+ import java.lang.reflect.Field;\r
+ import java.util.HashMap;\r
+\r
+ public class Dumper {\r
+ private static Dumper instance = new Dumper();\r
+\r
+ protected static Dumper getInstance() {\r
+ return instance;\r
+ }\r
+\r
+ class DumpContext {\r
+ int maxDepth = 0;\r
+ int maxArrayElements = 0;\r
+ int callCount = 0;\r
+ HashMap<String, String> ignoreList = new HashMap<String, String>();\r
+ HashMap<Object, Integer> visited = new HashMap<Object, Integer>();\r
+ }\r
+\r
+ public static String dump(Object o) {\r
+ return dump(o, 0, 0, null);\r
+ }\r
+\r
+ public static String dump(Object o, int maxDepth, int maxArrayElements, String[] ignoreList) {\r
+ DumpContext ctx = Dumper.getInstance().new DumpContext();\r
+ ctx.maxDepth = maxDepth;\r
+ ctx.maxArrayElements = maxArrayElements;\r
+\r
+ if (ignoreList != null) {\r
+ for (int i = 0; i < Array.getLength(ignoreList); i++) {\r
+ int colonIdx = ignoreList[i].indexOf(':');\r
+ if (colonIdx == -1)\r
+ ignoreList[i] = ignoreList[i] + ":";\r
+ ctx.ignoreList.put(ignoreList[i], ignoreList[i]);\r
+ }\r
+ }\r
+\r
+ return dump(o, ctx);\r
+ }\r
+\r
+ protected static String dump(Object o, DumpContext ctx) {\r
+ if (o == null) {\r
+ return "<null>";\r
+ }\r
+\r
+ ctx.callCount++;\r
+ StringBuffer tabs = new StringBuffer();\r
+ for (int k = 0; k < ctx.callCount; k++) {\r
+ tabs.append("\t");\r
+ }\r
+ StringBuffer buffer = new StringBuffer();\r
+ @SuppressWarnings("rawtypes")\r
+ Class oClass = o.getClass();\r
+\r
+ String oSimpleName = getSimpleNameWithoutArrayQualifier(oClass);\r
+\r
+ if (ctx.ignoreList.get(oSimpleName + ":") != null)\r
+ return "<Ignored>";\r
+\r
+ if (oClass.isArray()) {\r
+ buffer.append("\n");\r
+ buffer.append(tabs.toString().substring(1));\r
+ buffer.append("[\n");\r
+ int rowCount = ctx.maxArrayElements == 0 ? Array.getLength(o) : Math.min(ctx.maxArrayElements, Array.getLength(o));\r
+ for (int i = 0; i < rowCount; i++) {\r
+ buffer.append(tabs.toString());\r
+ try {\r
+ Object value = Array.get(o, i);\r
+ buffer.append(dumpValue(value, ctx));\r
+ } catch (Exception e) {\r
+ buffer.append(e.getMessage());\r
+ }\r
+ if (i < Array.getLength(o) - 1)\r
+ buffer.append(",");\r
+ buffer.append("\n");\r
+ }\r
+ if (rowCount < Array.getLength(o)) {\r
+ buffer.append(tabs.toString());\r
+ buffer.append(Array.getLength(o) - rowCount + " more array elements...");\r
+ buffer.append("\n");\r
+ }\r
+ buffer.append(tabs.toString().substring(1));\r
+ buffer.append("]");\r
+ } else {\r
+ buffer.append("\n");\r
+ buffer.append(tabs.toString().substring(1));\r
+ buffer.append("{\n");\r
+ buffer.append(tabs.toString());\r
+ buffer.append("hashCode: " + o.hashCode());\r
+ buffer.append("\n");\r
+ while (oClass != null && oClass != Object.class) {\r
+ Field[] fields = oClass.getDeclaredFields();\r
+\r
+ if (ctx.ignoreList.get(oClass.getSimpleName()) == null) {\r
+ if (oClass != o.getClass()) {\r
+ buffer.append(tabs.toString().substring(1));\r
+ buffer.append(" Inherited from superclass " + oSimpleName + ":\n");\r
+ }\r
+\r
+ for (int i = 0; i < fields.length; i++) {\r
+\r
+ String fSimpleName = getSimpleNameWithoutArrayQualifier(fields[i].getType());\r
+ String fName = fields[i].getName();\r
+\r
+ fields[i].setAccessible(true);\r
+ buffer.append(tabs.toString());\r
+ buffer.append(fName + "(" + fSimpleName + ")");\r
+ buffer.append("=");\r
+\r
+ if (ctx.ignoreList.get(":" + fName) == null &&\r
+ ctx.ignoreList.get(fSimpleName + ":" + fName) == null &&\r
+ ctx.ignoreList.get(fSimpleName + ":") == null) {\r
+\r
+ try {\r
+ Object value = fields[i].get(o);\r
+ buffer.append(dumpValue(value, ctx));\r
+ } catch (Exception e) {\r
+ buffer.append(e.getMessage());\r
+ }\r
+ buffer.append("\n");\r
+ } else {\r
+ buffer.append("<Ignored>");\r
+ buffer.append("\n");\r
+ }\r
+ }\r
+ oClass = oClass.getSuperclass();\r
+ oSimpleName = oClass.getSimpleName();\r
+ } else {\r
+ oClass = null;\r
+ oSimpleName = "";\r
+ }\r
+ }\r
+ buffer.append(tabs.toString().substring(1));\r
+ buffer.append("}");\r
+ }\r
+ ctx.callCount--;\r
+ return buffer.toString();\r
+ }\r
+\r
+ protected static String dumpValue(Object value, DumpContext ctx) {\r
+ if (value == null) {\r
+ return "<null>";\r
+ }\r
+ if (value.getClass().isPrimitive() ||\r
+ value.getClass() == java.lang.Short.class ||\r
+ value.getClass() == java.lang.Long.class ||\r
+ value.getClass() == java.lang.String.class ||\r
+ value.getClass() == java.lang.Integer.class ||\r
+ value.getClass() == java.lang.Float.class ||\r
+ value.getClass() == java.lang.Byte.class ||\r
+ value.getClass() == java.lang.Character.class ||\r
+ value.getClass() == java.lang.Double.class ||\r
+ value.getClass() == java.lang.Boolean.class) {\r
+\r
+ return value.toString();\r
+\r
+ } else {\r
+\r
+ Integer visitedIndex = ctx.visited.get(value);\r
+ if (visitedIndex == null) {\r
+ ctx.visited.put(value, ctx.callCount);\r
+ if (ctx.maxDepth == 0 || ctx.callCount < ctx.maxDepth) {\r
+ return dump(value, ctx);\r
+ } else {\r
+ return "<Reached max recursion depth>";\r
+ }\r
+ } else {\r
+ return "<Previously visited - see hashCode " + value.hashCode() + ">";\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ private static String getSimpleNameWithoutArrayQualifier(@SuppressWarnings("rawtypes") Class clazz) {\r
+ String simpleName = clazz.getSimpleName();\r
+ int indexOfBracket = simpleName.indexOf('['); \r
+ if (indexOfBracket != -1)\r
+ return simpleName.substring(0, indexOfBracket);\r
+ return simpleName;\r
+ }\r
+}\r