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 }