package org.slf4j.instrumentation; import java.util.Map; import java.util.WeakHashMap; public class ToStringHelper { /** * Prefix to use at the start of the representation. Always used. */ private static final String ARRAY_PREFIX = "["; /** * Suffix to use at the end of the representation. Always used. */ private static final String ARRAY_SUFFIX = "]"; /** * String separating each element when rendering an array. To be compatible * with lists comma-space is used. */ private static final String ELEMENT_SEPARATOR = ", "; /** * unrenderableClasses is essentially a Set of Class objects which has for * some reason failed to render properly when invoked through a toString * method call. To avoid memory leaks a data structure using weak references * is needed, but unfortunately the runtime library does not contain a * WeakHashSet class, so the behavior is emulated with a WeakHashmap with * the class as the key, and a Long containing the value of * System.currentTimeMilis when an instance of the class failed to render. */ final static Map<Class<?>, Object> unrenderableClasses = new WeakHashMap<Class<?>, Object>(); /** * Returns o.toString() unless it throws an exception (which causes it to be * stored in unrenderableClasses) or already was present in * unrenderableClasses. If so, the same string is returned as would have * been returned by Object.toString(). Arrays get special treatment as they * don't have usable toString methods. * * @param o * incoming object to render. * @return */ public static String render(Object o) { if (o == null) { return String.valueOf(o); } Class<?> objectClass = o.getClass(); if (unrenderableClasses.containsKey(objectClass) == false) { try { if (objectClass.isArray()) { return renderArray(o, objectClass).toString(); } else { return o.toString(); } } catch (Exception e) { Long now = new Long(System.currentTimeMillis()); System.err.println("Disabling exception throwing class " + objectClass.getName() + ", " + e.getMessage()); unrenderableClasses.put(objectClass, now); } } String name = o.getClass().getName(); return name + "@" + Integer.toHexString(o.hashCode()); } /** * renderArray returns an array similar to a List. If the array type is an * object they are rendered with "render(object)" for each. If the array * type is a primitive each element is added directly to the string buffer * collecting the result. * * @param o * @param objectClass * @return */ private static StringBuffer renderArray(Object o, Class<?> objectClass) { Class<?> componentType = objectClass.getComponentType(); StringBuffer sb = new StringBuffer(ARRAY_PREFIX); if (componentType.isPrimitive() == false) { Object[] oa = (Object[]) o; for (int i = 0; i < oa.length; i++) { if (i > 0) { sb.append(ELEMENT_SEPARATOR); } sb.append(render(oa[i])); } } else { if (Boolean.TYPE.equals(componentType)) { boolean[] ba = (boolean[]) o; for (int i = 0; i < ba.length; i++) { if (i > 0) { sb.append(ELEMENT_SEPARATOR); } sb.append(ba[i]); } } else if (Integer.TYPE.equals(componentType)) { int[] ia = (int[]) o; for (int i = 0; i < ia.length; i++) { if (i > 0) { sb.append(ELEMENT_SEPARATOR); } sb.append(ia[i]); } } else if (Long.TYPE.equals(componentType)) { long[] ia = (long[]) o; for (int i = 0; i < ia.length; i++) { if (i > 0) { sb.append(ELEMENT_SEPARATOR); } sb.append(ia[i]); } } else if (Double.TYPE.equals(componentType)) { double[] ia = (double[]) o; for (int i = 0; i < ia.length; i++) { if (i > 0) { sb.append(ELEMENT_SEPARATOR); } sb.append(ia[i]); } } else if (Float.TYPE.equals(componentType)) { float[] ia = (float[]) o; for (int i = 0; i < ia.length; i++) { if (i > 0) { sb.append(ELEMENT_SEPARATOR); } sb.append(ia[i]); } } else if (Character.TYPE.equals(componentType)) { char[] ia = (char[]) o; for (int i = 0; i < ia.length; i++) { if (i > 0) { sb.append(ELEMENT_SEPARATOR); } sb.append(ia[i]); } } else if (Short.TYPE.equals(componentType)) { short[] ia = (short[]) o; for (int i = 0; i < ia.length; i++) { if (i > 0) { sb.append(ELEMENT_SEPARATOR); } sb.append(ia[i]); } } else if (Byte.TYPE.equals(componentType)) { byte[] ia = (byte[]) o; for (int i = 0; i < ia.length; i++) { if (i > 0) { sb.append(ELEMENT_SEPARATOR); } sb.append(ia[i]); } } } sb.append(ARRAY_SUFFIX); return sb; } }