View Javadoc
1   package org.pojomatic.formatter;
2   
3   import java.lang.reflect.AnnotatedElement;
4   import java.util.HashSet;
5   import java.util.Set;
6   
7   /**
8    * The default property formatter used by Pojomatic.  While the particulars of the formatting
9    * strategy are subject to change, the general principle is to provide a meaningful representation.
10   * In particular, arrays are formatted "deeply", rather than simply showing the default toString
11   * representation of Java arrays.
12   *
13   * @since 2.0
14   */
15  public class DefaultEnhancedPropertyFormatter implements EnhancedPropertyFormatter {
16  
17    /**
18     * {@inheritDoc}
19     */
20    @Override
21    public void initialize(AnnotatedElement element) {}
22  
23    @Override
24    final public String format(Object value) {
25      StringBuilder builder = new StringBuilder();
26      appendFormatted(builder, value);
27      return builder.toString();
28    }
29  
30    @Override
31    public void appendFormatted(StringBuilder builder, Object value) {
32      builder.append(value);
33    }
34  
35    @Override
36    public void appendFormattedPossibleArray(StringBuilder builder, Object value) {
37      if (value == null) {
38        builder.append("null");
39      }
40      else if (value.getClass().isArray()) {
41        Class<?> componentClass = value.getClass().getComponentType();
42        if (componentClass.isPrimitive()) {
43          if (Boolean.TYPE == componentClass) {
44            appendFormatted(builder, (boolean[]) value);
45          }
46          else if (Character.TYPE == componentClass) {
47            appendFormatted(builder, (char[]) value);
48          }
49          else if (Byte.TYPE == componentClass) {
50            appendFormatted(builder, (byte[]) value);
51          }
52          else if (Short.TYPE == componentClass) {
53            appendFormatted(builder, (short[]) value);
54          }
55          else if (Integer.TYPE == componentClass) {
56            appendFormatted(builder, (int[]) value);
57          }
58          else if (Long.TYPE == componentClass) {
59            appendFormatted(builder, (long[]) value);
60          }
61          else if (Float.TYPE == componentClass) {
62            appendFormatted(builder, (float[]) value);
63          }
64          else if (Double.TYPE == componentClass) {
65            appendFormatted(builder, (double[]) value);
66          }
67          else {
68            throw new IllegalStateException("unexpected primitive array base type: " + componentClass);
69          }
70        }
71        else {
72          appendFormatted(builder, (Object[]) value);
73        }
74      }
75      else {
76        appendFormatted(builder, value);
77      }
78    }
79  
80    @Override
81    public void appendFormatted(StringBuilder builder, Object[] array) {
82        appendFormattedDeep(builder, array, new HashSet<>());
83    }
84  
85    private void appendFormattedDeep(StringBuilder builder, Object[] array, Set<Object> dejaVu) {
86      if (array == null) {
87        builder.append("null");
88      }
89      else if (! dejaVu.add(array)) {
90        builder.append("[...]");
91      }
92      else {
93        builder.append('[');
94        int iMax = array.length - 1;
95        for (int i = 0; i <= iMax; i++) {
96          Object element = array[i];
97          if (element != null && element.getClass().isArray()) {
98            Class<?> componentType = element.getClass().getComponentType();
99            if (componentType.isPrimitive()) {
100             if (componentType == boolean.class) {
101               appendFormatted(builder, (boolean[]) element);
102             }
103             else if (componentType == byte.class) {
104               appendFormatted(builder, (byte[]) element);
105             }
106             else if (componentType == short.class) {
107               appendFormatted(builder, (short[]) element);
108             }
109             else if (componentType == char.class) {
110               appendFormatted(builder, (char[]) element);
111             }
112             else if (componentType == int.class) {
113               appendFormatted(builder, (int[]) element);
114             }
115             else if (componentType == long.class) {
116               appendFormatted(builder, (long[]) element);
117             }
118             else if (componentType == float.class) {
119               appendFormatted(builder, (float[]) element);
120             }
121             else if (componentType == double.class) {
122               appendFormatted(builder, (double[]) element);
123             }
124             else {
125               throw new IllegalArgumentException("Unexpected primitive type " + componentType.getName());
126             }
127           }
128           else {
129             appendFormattedDeep(builder, (Object[]) element, dejaVu);
130           }
131         }
132         else {
133           appendFormatted(builder, element);
134         }
135         if (i != iMax) {
136           builder.append(", ");
137         }
138       }
139       builder.append(']');
140     }
141   }
142 
143   @Override
144   public void appendFormatted(StringBuilder builder, boolean b) {
145     builder.append(b);
146   }
147 
148   @Override
149   public void appendFormatted(StringBuilder builder, byte b) {
150     builder.append(b);
151   }
152 
153   @Override
154   public void appendFormatted(StringBuilder builder, short s) {
155     builder.append(s);
156   }
157 
158   @Override
159   public void appendFormatted(StringBuilder builder, char c) {
160     builder.append('\'');
161     if (Character.isISOControl(c)) {
162       builder.append("\\u").append(String.format("%04x", (int)c));
163     }
164     else {
165       builder.append(c);
166     }
167     builder.append('\'');
168   }
169 
170   @Override
171   public void appendFormatted(StringBuilder builder, int i) {
172     builder.append(i);
173   }
174 
175   @Override
176   public void appendFormatted(StringBuilder builder, long l) {
177     builder.append(l);
178   }
179 
180   @Override
181   public void appendFormatted(StringBuilder builder, float f) {
182     builder.append(f);
183   }
184 
185   @Override
186   public void appendFormatted(StringBuilder builder, double d) {
187     builder.append(d);
188   }
189 
190   @Override
191   public void appendFormatted(StringBuilder builder, boolean[] array) {
192     if (array == null) {
193       builder.append("null");
194     }
195     else {
196       builder.append('[');
197       int iMax = array.length - 1;
198       for (int i = 0; i <= iMax; i++) {
199         appendFormatted(builder, array[i]);
200         if (i != iMax) {
201           builder.append(", ");
202         }
203       }
204       builder.append(']');
205     }
206   }
207 
208   @Override
209   public void appendFormatted(StringBuilder builder, byte[] array) {
210     if (array == null) {
211       builder.append("null");
212     }
213     else {
214       builder.append('[');
215       int iMax = array.length - 1;
216       for (int i = 0; i <= iMax; i++) {
217         appendFormatted(builder, array[i]);
218         if (i != iMax) {
219           builder.append(", ");
220         }
221       }
222       builder.append(']');
223     }
224   }
225 
226   @Override
227   public void appendFormatted(StringBuilder builder, short[] array) {
228     if (array == null) {
229       builder.append("null");
230     }
231     else {
232       builder.append('[');
233       int iMax = array.length - 1;
234       for (int i = 0; i <= iMax; i++) {
235         appendFormatted(builder, array[i]);
236         if (i != iMax) {
237           builder.append(", ");
238         }
239       }
240       builder.append(']');
241     }
242   }
243 
244   @Override
245   public void appendFormatted(StringBuilder builder, char[] array) {
246     if (array == null) {
247       builder.append("null");
248     }
249     else {
250       builder.append('[');
251       int iMax = array.length - 1;
252       for (int i = 0; i <= iMax; i++) {
253         appendFormatted(builder, array[i]);
254         if (i != iMax) {
255           builder.append(", ");
256         }
257       }
258       builder.append(']');
259     }
260   }
261 
262   @Override
263   public void appendFormatted(StringBuilder builder, int[] array) {
264     if (array == null) {
265       builder.append("null");
266     }
267     else {
268       builder.append('[');
269       int iMax = array.length - 1;
270       for (int i = 0; i <= iMax; i++) {
271         appendFormatted(builder, array[i]);
272         if (i != iMax) {
273           builder.append(", ");
274         }
275       }
276       builder.append(']');
277     }
278   }
279 
280   @Override
281   public void appendFormatted(StringBuilder builder, long[] array) {
282     if (array == null) {
283       builder.append("null");
284     }
285     else {
286       builder.append('[');
287       int iMax = array.length - 1;
288       for (int i = 0; i <= iMax; i++) {
289         appendFormatted(builder, array[i]);
290         if (i != iMax) {
291           builder.append(", ");
292         }
293       }
294       builder.append(']');
295     }
296   }
297 
298   @Override
299   public void appendFormatted(StringBuilder builder, float[] array) {
300     if (array == null) {
301       builder.append("null");
302     }
303     else {
304       builder.append('[');
305       int iMax = array.length - 1;
306       for (int i = 0; i <= iMax; i++) {
307         appendFormatted(builder, array[i]);
308         if (i != iMax) {
309           builder.append(", ");
310         }
311       }
312       builder.append(']');
313     }
314   }
315 
316   @Override
317   public void appendFormatted(StringBuilder builder, double[] array) {
318     if (array == null) {
319       builder.append("null");
320     }
321     else {
322       builder.append('[');
323       int iMax = array.length - 1;
324       for (int i = 0; i <= iMax; i++) {
325         appendFormatted(builder, array[i]);
326         if (i != iMax) {
327           builder.append(", ");
328         }
329       }
330       builder.append(']');
331     }
332   }
333 }