1 /** 2 * Copyright (c) 2004-2011 QOS.ch 3 * All rights reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 */ 25 package org.slf4j.instrumentation; 26 27 import java.util.Map; 28 import java.util.WeakHashMap; 29 30 public class ToStringHelper { 31 32 /** 33 * Prefix to use at the start of the representation. Always used. 34 */ 35 private static final String ARRAY_PREFIX = "["; 36 37 /** 38 * Suffix to use at the end of the representation. Always used. 39 */ 40 private static final char ARRAY_SUFFIX = ']'; 41 42 /** 43 * String separating each element when rendering an array. To be compatible 44 * with lists comma-space is used. 45 */ 46 47 private static final char[] ELEMENT_SEPARATOR = ", ".toCharArray(); 48 49 /** 50 * unrenderableClasses is essentially a Set of Class objects which has for 51 * some reason failed to render properly when invoked through a toString 52 * method call. To avoid memory leaks a data structure using weak references 53 * is needed, but unfortunately the runtime library does not contain a 54 * WeakHashSet class, so the behavior is emulated with a WeakHashmap with 55 * the class as the key, and a Long containing the value of 56 * System.currentTimeMilis when an instance of the class failed to render. 57 */ 58 59 final static Map<Class<?>, Object> unrenderableClasses = new WeakHashMap<Class<?>, Object>(); 60 61 /** 62 * Returns o.toString() unless it throws an exception (which causes it to be 63 * stored in unrenderableClasses) or already was present in 64 * unrenderableClasses. If so, the same string is returned as would have 65 * been returned by Object.toString(). Arrays get special treatment as they 66 * don't have usable toString methods. 67 * 68 * @param o 69 * incoming object to render. 70 * @return 71 */ 72 73 public static String render(Object o) { 74 if (o == null) { 75 return String.valueOf(o); 76 } 77 Class<?> objectClass = o.getClass(); 78 79 if (unrenderableClasses.containsKey(objectClass) == false) { 80 try { 81 if (objectClass.isArray()) { 82 return renderArray(o, objectClass).toString(); 83 } else { 84 return o.toString(); 85 } 86 } catch (Exception e) { 87 Long now = new Long(System.currentTimeMillis()); 88 89 System.err.println("Disabling exception throwing class " + objectClass.getName() + ", " + e.getMessage()); 90 91 unrenderableClasses.put(objectClass, now); 92 } 93 } 94 String name = o.getClass().getName(); 95 return name + "@" + Integer.toHexString(o.hashCode()); 96 } 97 98 /** 99 * renderArray returns an array similar to a List. If the array type is an 100 * object they are rendered with "render(object)" for each. If the array 101 * type is a primitive each element is added directly to the string buffer 102 * collecting the result. 103 * 104 * @param o 105 * @param objectClass 106 * @return 107 */ 108 private static StringBuilder renderArray(Object o, Class<?> objectClass) { 109 Class<?> componentType = objectClass.getComponentType(); 110 StringBuilder sb = new StringBuilder(ARRAY_PREFIX); 111 112 if (componentType.isPrimitive() == false) { 113 Object[] oa = (Object[]) o; 114 for (int i = 0; i < oa.length; i++) { 115 if (i > 0) { 116 sb.append(ELEMENT_SEPARATOR); 117 } 118 sb.append(render(oa[i])); 119 } 120 } else { 121 if (Boolean.TYPE.equals(componentType)) { 122 boolean[] ba = (boolean[]) o; 123 for (int i = 0; i < ba.length; i++) { 124 if (i > 0) { 125 sb.append(ELEMENT_SEPARATOR); 126 } 127 sb.append(ba[i]); 128 } 129 } else if (Integer.TYPE.equals(componentType)) { 130 int[] ia = (int[]) o; 131 for (int i = 0; i < ia.length; i++) { 132 if (i > 0) { 133 sb.append(ELEMENT_SEPARATOR); 134 } 135 sb.append(ia[i]); 136 } 137 138 } else if (Long.TYPE.equals(componentType)) { 139 long[] ia = (long[]) o; 140 for (int i = 0; i < ia.length; i++) { 141 if (i > 0) { 142 sb.append(ELEMENT_SEPARATOR); 143 } 144 sb.append(ia[i]); 145 } 146 } else if (Double.TYPE.equals(componentType)) { 147 double[] ia = (double[]) o; 148 for (int i = 0; i < ia.length; i++) { 149 if (i > 0) { 150 sb.append(ELEMENT_SEPARATOR); 151 } 152 sb.append(ia[i]); 153 } 154 } else if (Float.TYPE.equals(componentType)) { 155 float[] ia = (float[]) o; 156 for (int i = 0; i < ia.length; i++) { 157 if (i > 0) { 158 sb.append(ELEMENT_SEPARATOR); 159 } 160 sb.append(ia[i]); 161 } 162 } else if (Character.TYPE.equals(componentType)) { 163 char[] ia = (char[]) o; 164 for (int i = 0; i < ia.length; i++) { 165 if (i > 0) { 166 sb.append(ELEMENT_SEPARATOR); 167 } 168 sb.append(ia[i]); 169 } 170 } else if (Short.TYPE.equals(componentType)) { 171 short[] ia = (short[]) o; 172 for (int i = 0; i < ia.length; i++) { 173 if (i > 0) { 174 sb.append(ELEMENT_SEPARATOR); 175 } 176 sb.append(ia[i]); 177 } 178 } else if (Byte.TYPE.equals(componentType)) { 179 byte[] ia = (byte[]) o; 180 for (int i = 0; i < ia.length; i++) { 181 if (i > 0) { 182 sb.append(ELEMENT_SEPARATOR); 183 } 184 sb.append(ia[i]); 185 } 186 } 187 } 188 sb.append(ARRAY_SUFFIX); 189 return sb; 190 } 191 } 192