| /** |
| * Copyright (c) 2004-2011 QOS.ch |
| * All rights reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sublicense, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| */ |
| 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 char ARRAY_SUFFIX = ']'; |
| |
| /** |
| * String separating each element when rendering an array. To be compatible |
| * with lists comma-space is used. |
| */ |
| |
| private static final char[] ELEMENT_SEPARATOR = ", ".toCharArray(); |
| |
| /** |
| * 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 StringBuilder renderArray(Object o, Class<?> objectClass) { |
| Class<?> componentType = objectClass.getComponentType(); |
| StringBuilder sb = new StringBuilder(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; |
| } |
| } |