001 /* 002 Copyright (c) 2009 Olivier Chafik, All Rights Reserved 003 004 This file is part of JNAerator (http://jnaerator.googlecode.com/). 005 006 JNAerator is free software: you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation, either version 3 of the License, or 009 (at your option) any later version. 010 011 JNAerator is distributed in the hope that it will be useful, 012 but WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 GNU General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with JNAerator. If not, see <http://www.gnu.org/licenses/>. 018 */ 019 package com.ochafik.lang.reflect; 020 021 import java.io.PrintStream; 022 import java.lang.reflect.Array; 023 import java.lang.reflect.Field; 024 import java.lang.reflect.Method; 025 import java.util.Arrays; 026 import java.util.Collection; 027 import java.util.Comparator; 028 import java.util.Set; 029 import java.util.TreeSet; 030 031 import com.ochafik.io.StringBufferOutputStream; 032 import com.ochafik.lang.AssertUtils; 033 034 public class DebugUtils { 035 036 public static abstract class FieldAccessor { 037 public abstract Object access(Field f, Object target) throws IllegalArgumentException, IllegalAccessException; 038 //public Object access(Field f, Object target) throws IllegalArgumentException, IllegalAccessException { 039 //return f.get(target); 040 //} 041 } 042 043 public static final void print(Object o, FieldAccessor accessor) { 044 print(o, System.out, false, false, "", accessor); 045 } 046 047 public static final void printErr(Object o, FieldAccessor accessor) { 048 print(o, System.err, false, false, "", accessor); 049 } 050 051 public static final void println(Object o, FieldAccessor accessor) { 052 print(o, System.out, true, false, "", accessor); 053 } 054 055 public static final void printlnErr(Object o, FieldAccessor accessor) { 056 print(o, System.err, true, false, "", accessor); 057 } 058 059 public static final void print(Object o) { 060 print(o, System.out, false, false, "", null); 061 } 062 063 public static final void printErr(Object o) { 064 print(o, System.err, false, false, "", null); 065 } 066 067 public static final void println(Object o) { 068 print(o, System.out, true, false, "", null); 069 } 070 public static final void println(Object o, PrintStream out) { 071 print(o, out, true, false, "", null); 072 } 073 074 public static final void printlnErr(Object o) { 075 print(o, System.err, true, false, "", null); 076 } 077 078 protected static String escape(String s) { 079 return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\t", "\\t").replace("\r", ""); 080 } 081 public static final void printAsCharSequence(CharSequence o, PrintStream out, boolean lines, boolean startIndent, String indent, FieldAccessor accessor) { 082 out.print('"'); 083 out.print(escape(((CharSequence)o).toString())); 084 out.print('"'); 085 if (lines) out.println(); 086 } 087 088 public static final void printStructureInsides(Object o, PrintStream out, boolean lines, boolean startIndent, String indent, FieldAccessor accessor) { 089 Class<?> type = o.getClass(); 090 Set<Field> fields = getFields(type); 091 int i = 0; 092 for (Field f : fields) { 093 boolean inaccessibleValue = false; 094 Object v; 095 try { 096 //f.isAccessible() 097 v = accessor == null ? f.get(o) : accessor.access(f, o); 098 } catch (IllegalAccessException ex) { 099 // field is private and from a different package than the accessor ! Try using a getter 100 String fn = f.getName(); 101 try { 102 Method m = type.getMethod("get" + fn.substring(0,1).toUpperCase() + fn.substring(1), new Class[0]); 103 v = m.invoke(o, new Object[0]); 104 } catch (Exception e) { 105 inaccessibleValue = true; 106 v = null; 107 } 108 } catch (Exception e) { 109 throw new RuntimeException(e); 110 } 111 if (lines) { 112 out.print(indent); 113 } else if (i++ != 0) out.print("; "); 114 115 out.print(f.getName()); 116 out.print(" = "); 117 if (inaccessibleValue) { 118 out.print('?'); 119 } else { 120 print(v, out, lines, false, indent, accessor); 121 } 122 } 123 } 124 125 public static final void print(Object o, PrintStream out, boolean lines, boolean startIndent, String indent, FieldAccessor accessor) { 126 if (lines && startIndent) out.print(indent); 127 128 if (o == null) { 129 out.print(o); 130 if (lines) out.println(); 131 return; 132 } 133 Class<?> type = o.getClass(); 134 boolean isCollection = o instanceof Collection<?>; 135 136 if (o instanceof CharSequence) { 137 out.print('"'); 138 out.print(escape(o.toString())); 139 out.print('"'); 140 if (lines) out.println(); 141 return; 142 } else if (type == Character.class) { 143 out.print('\''); 144 out.print(escape(o.toString())); 145 out.print('\''); 146 if (lines) out.println(); 147 return; 148 } else if (!isCollection && hasToStringMethod(type)) { 149 out.print(o); 150 if (lines) out.println(); 151 return; 152 } 153 out.print(type.getSimpleName()); 154 out.print(" {"); 155 if (lines) out.println(); 156 157 String newIndent = indent + "\t"; 158 159 if (type.isArray()) { 160 for (int i = 0, n = Array.getLength(o); i < n; i++) { 161 if (!lines && i != 0) out.print(", "); 162 print(Array.get(o, i), out, lines, true, newIndent, accessor); 163 } 164 } else if (isCollection) { 165 int i = 0; 166 for (Object e : (Collection<?>)o) { 167 if (!lines && i++ != 0) out.print(", "); 168 print(e, out, lines, true, newIndent, accessor); 169 } 170 } else { 171 printStructureInsides(o, out, lines, startIndent, newIndent, accessor); 172 } 173 if (lines) out.print(indent); 174 out.print("}"); 175 if (lines) out.println(); 176 } 177 178 public static Set<Field> getFields(Class<?> type) { 179 Set<Field> fields = new TreeSet<Field>(new Comparator<Field>() { public int compare(Field o1, Field o2) { 180 return o1.getName().compareTo(o2.getName()); 181 }}); 182 fields.addAll(Arrays.asList(type.getFields())); 183 do { 184 fields.addAll(Arrays.asList(type.getDeclaredFields())); 185 } while ((type = type.getSuperclass()) != null); 186 return fields; 187 } 188 protected static void getFields_aux(Class<?> type, Set<Field> fields) { 189 190 } 191 192 public static boolean hasToStringMethod(Class<?> c) { 193 if (c == Object.class) return false; 194 for (Method m : c.getDeclaredMethods()) { 195 if (m.getName().equals("toString") && m.getParameterTypes().length == 0) { 196 return true; 197 } 198 } 199 return hasToStringMethod(c.getSuperclass()); 200 } 201 202 public static void main(String[] args) { 203 //print(new int[] { 1, 2, 3, 4}); 204 println(new Object[] { new AssertUtils.Test(), }, new FieldAccessor() { 205 public Object access(Field f, Object target) throws IllegalArgumentException, IllegalAccessException { 206 return f.get(target); 207 } 208 }); 209 } 210 211 public static String toString(Object object) { 212 StringBufferOutputStream out = new StringBufferOutputStream(); 213 print(object, new PrintStream(out), false, false,"", null); 214 return out.toString(); 215 } 216 217 }