Bug 274423

Summary: [toString] toString wizard should support nested arrays
Product: [Eclipse Project] JDT Reporter: Benjamin Muskalla <b.muskalla>
Component: UIAssignee: JDT-UI-Inbox <jdt-ui-inbox>
Status: ASSIGNED --- QA Contact:
Severity: enhancement    
Priority: P3 CC: daniel_megert, mateusz.matela
Version: 3.5   
Target Milestone: ---   
Hardware: All   
OS: All   
Whiteboard:

Description Benjamin Muskalla CLA 2009-04-29 16:33:02 EDT
I20090428-0100

Currently the toString wizard only supports simple arrays and ignores nested arrays.

Snippet:
---------------
public class A {
    int[][] a = new int[1][1];

    public static void main(String[] args) {
        A x = new A();
        x.a[0][0] = 1;
        System.out.println(x);
    }

}

---------------
Comment 1 Mateusz Matela CLA 2009-05-09 13:18:09 EDT
A simple solution would be to use Arrays.deepToString() instead of Arrays.toString() and change the helper method arrayToString() a bit to support multidimensional arrays. But this way we would still ignore arrays included in collections and maps. Also, with "Limit number of items..." option it might be worth to consider collections and maps containing other collections/maps. And here things get complicated. To support all these possibilities, the helper method would have to get long and clumsy:

public String toString(Object o, List<Object> seen, int maxLen) {
	if (seen == null) {
		seen = new ArrayList<Object>();
	} else if (seen.contains(o)) {
		return ("[...]");
	}
	seen.add(o);
	Object o2 = o;
	StringBuilder buf = new StringBuilder();
	buf.append(o instanceof Map<?, ?> ? "{" : "[");
	try {
		if (o == null) {
			return "null";
		} else if (o instanceof Collection<?>) {
			o2 = ((Collection<?>) o).toArray();
		} else if (o instanceof Map<?, ?>) {
			o2 = ((Map<?, ?>) o).entrySet().toArray();
		}
		Class<?> clazz = o2.getClass();
		for (int i = 0; i < maxLen; i++) {
			if (clazz.isArray()) {
				if (clazz == byte[].class) {
					buf.append(((byte[]) o2)[i]);
				} else if (clazz == short[].class) {
					buf.append(((short[]) o2)[i]);
				} else if (clazz == int[].class) {
					buf.append(((int[]) o2)[i]);
				} else if (clazz == long[].class) {
					buf.append(((long[]) o2)[i]);
				} else if (clazz == char[].class) {
					buf.append(((char[]) o2)[i]);
				} else if (clazz == float[].class) {
					buf.append(((float[]) o2)[i]);
				} else if (clazz == double[].class) {
					buf.append(((double[]) o2)[i]);
				} else if (clazz == boolean[].class) {
					buf.append(((boolean[]) o2)[i]);
				} else {
					buf.append(toString(((Object[]) o2)[i], seen, maxLen));
				}
			} else if (o2 instanceof Entry<?, ?>) {
				Entry<?, ?> e = (Entry<?, ?>) o2;
				return toString(e.getKey(), seen, maxLen) + "="
						+ toString(e.getValue(), seen, maxLen);
			} else {
				return o2.toString();
			}
			buf.append(", ");
		}
		buf.append("...");
	} catch (IndexOutOfBoundsException e) {
		if (buf.length() >= 2) {
			buf.setLength(buf.length() - 2);
		}
	} finally {
		seen.remove(o);
	}
	return buf.append(o instanceof Map<?, ?> ? "}" : "]").toString();
}

It would be possible in some circumstances to make this method shorter (when it can be determined that arrays will not contain collections and/or vice versa), but in general I don't see any simpler way.

What do you think?
Comment 2 Dani Megert CLA 2009-05-11 03:44:57 EDT
>A simple solution would be to use Arrays.deepToString() instead of
>Arrays.toString() 
This is not available in 1.4.

There's no hurry in this bug as we won't address it for 3.5 (we're in RC mode now).