static A clone(A o) { new ArrayDeque q; Object x = clone_impl(o, new IdentityHashMap, q); while (!q.isEmpty()) q.poll().run(); return (A) x; } static Object clone_impl(Object o, final IdentityHashMap seen, final ArrayDeque q) ctex { if (o == null) return o; Object y = seen.get(o); if (y != null) return y; if (o instanceof List) { //print("Cloning list: " + o); final List l = new ArrayList(); seen.put(o, l); for (final Object x : (List) o) q.add(runnable { l.add(clone_impl(x, seen, q)); }); return l; } if (o instanceof Map) { final Map m = o instanceof TreeMap ? new TreeMap() : new HashMap(); seen.put(o, m); for (O entry : ((Map) o).entrySet()) { final Map.Entry e = (Map.Entry) entry; q.add(runnable { m.put(clone_impl(e.getKey(), seen, q), clone_impl(e.getValue(), seen, q)); }); } return m; } if (o instanceof String || o instanceof Number || o instanceof Boolean) return o; if (o instanceof Object[]) { final Object[] l = (Object[]) o; final Object[] l2 = l.clone(); seen.put(o, l2); for (int i = 0; i < l.length; i++) { final int _i = i; q.add(runnable { l2[_i] = clone_impl(l[_i], seen, q); }); } return l2; } // clone an arbitrary custom object // TODO: use Constructor object and setAccessible //print("Cloning custom: " + o); final Object clone = nuObjectWithoutArguments(o.getClass()); seen.put(o, clone); Class c = o.getClass(); while (c != Object.class) { Field[] fields = c.getDeclaredFields(); for (final Field field : fields) { if ((field.getModifiers() & Modifier.STATIC) != 0) continue; field.setAccessible(true); final Object value = field.get(o); q.add(runnable { field.set(clone, clone_impl(value, seen, q)); }); } c = c.getSuperclass(); } return clone; }