View Javadoc

1   /*
2   	Copyright (c) 2009 Olivier Chafik, All Rights Reserved
3   	
4   	This file is part of JNAerator (http://jnaerator.googlecode.com/).
5   	
6   	JNAerator is free software: you can redistribute it and/or modify
7   	it under the terms of the GNU General Public License as published by
8   	the Free Software Foundation, either version 3 of the License, or
9   	(at your option) any later version.
10  	
11  	JNAerator is distributed in the hope that it will be useful,
12  	but WITHOUT ANY WARRANTY; without even the implied warranty of
13  	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  	GNU General Public License for more details.
15  	
16  	You should have received a copy of the GNU General Public License
17  	along with JNAerator.  If not, see <http://www.gnu.org/licenses/>.
18  */
19  package com.ochafik.lang.reflect;
20  
21  import java.io.PrintStream;
22  import java.lang.reflect.Array;
23  import java.lang.reflect.Field;
24  import java.lang.reflect.Method;
25  import java.util.Arrays;
26  import java.util.Collection;
27  import java.util.Comparator;
28  import java.util.Set;
29  import java.util.TreeSet;
30  
31  import com.ochafik.io.StringBufferOutputStream;
32  import com.ochafik.lang.AssertUtils;
33  
34  public class DebugUtils {
35  
36  	public static abstract class FieldAccessor {
37  		public abstract Object access(Field f, Object target) throws IllegalArgumentException, IllegalAccessException;
38  		//public Object access(Field f, Object target) throws IllegalArgumentException, IllegalAccessException {
39  		//return f.get(target);
40  		//}
41  	}
42  
43  	public static final void print(Object o, FieldAccessor accessor) {
44  		print(o, System.out, false, false, "", accessor);
45  	}
46  
47  	public static final void printErr(Object o, FieldAccessor accessor) {
48  		print(o, System.err, false, false, "", accessor);
49  	}
50  
51  	public static final void println(Object o, FieldAccessor accessor) {
52  		print(o, System.out, true, false, "", accessor);
53  	}
54  
55  	public static final void printlnErr(Object o, FieldAccessor accessor) {
56  		print(o, System.err, true, false, "", accessor);
57  	}
58  
59  	public static final void print(Object o) {
60  		print(o, System.out, false, false, "", null);
61  	}
62  
63  	public static final void printErr(Object o) {
64  		print(o, System.err, false, false, "", null);
65  	}
66  
67  	public static final void println(Object o) {
68  		print(o, System.out, true, false, "", null);
69  	}
70  	public static final void println(Object o, PrintStream out) {
71  		print(o, out, true, false, "", null);
72  	}
73  
74  	public static final void printlnErr(Object o) {
75  		print(o, System.err, true, false, "", null);
76  	}
77  
78  	protected static String escape(String s) {
79  		return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\t", "\\t").replace("\r", "");
80  	}
81  	public static final void printAsCharSequence(CharSequence o, PrintStream out, boolean lines, boolean startIndent, String indent, FieldAccessor accessor) {
82  		out.print('"');
83  		out.print(escape(((CharSequence)o).toString()));
84  		out.print('"');
85  		if (lines) out.println();
86  	}
87  
88  	public static final void printStructureInsides(Object o, PrintStream out, boolean lines, boolean startIndent, String indent, FieldAccessor accessor) {
89  		Class<?> type = o.getClass();
90  		Set<Field> fields = getFields(type);
91  		int i = 0;
92  		for (Field f : fields) {
93  			boolean inaccessibleValue = false;
94  			Object v;
95  			try {
96  				//f.isAccessible()
97  				v = accessor == null ? f.get(o) : accessor.access(f, o);
98  			} catch (IllegalAccessException ex) {
99  				// 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 }