1
2
3
4
5
6
7
8
9
10
11 package org.csveed.bean;
12
13 import java.beans.BeanInfo;
14 import java.beans.IntrospectionException;
15 import java.beans.Introspector;
16 import java.beans.PropertyDescriptor;
17 import java.lang.reflect.Field;
18 import java.text.NumberFormat;
19 import java.util.ArrayList;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Locale;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.TreeMap;
26
27 import org.csveed.bean.conversion.Converter;
28 import org.csveed.bean.conversion.CustomNumberConverter;
29 import org.csveed.bean.conversion.DateConverter;
30 import org.csveed.bean.conversion.EnumConverter;
31 import org.csveed.common.Column;
32 import org.csveed.report.CsvException;
33 import org.csveed.report.GeneralError;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37
38
39
40 public class BeanProperties implements Iterable<BeanProperty> {
41
42
43 private static final Logger LOG = LoggerFactory.getLogger(BeanProperties.class);
44
45
46 private List<BeanProperty> properties = new ArrayList<>();
47
48
49 private Map<Column, BeanProperty> indexToProperty = new TreeMap<>();
50
51
52 private Map<Column, BeanProperty> nameToProperty = new TreeMap<>();
53
54
55 private Class beanClass;
56
57
58 private BeanProperty headerValueProperty;
59
60
61 private BeanProperty headerNameProperty;
62
63
64
65
66
67
68
69 public BeanProperties(Class beanClass) {
70 this.beanClass = beanClass;
71 parseBean(beanClass);
72 }
73
74
75
76
77
78
79
80 private void parseBean(Class beanClass) {
81 final BeanInfo beanInfo;
82 try {
83 beanInfo = Introspector.getBeanInfo(beanClass);
84 } catch (IntrospectionException err) {
85 throw new RuntimeException(err);
86 }
87
88 PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
89
90
91
92 for (Field field : beanClass.getDeclaredFields()) {
93 PropertyDescriptor propertyDescriptor = getPropertyDescriptor(propertyDescriptors, field);
94 if (propertyDescriptor == null || propertyDescriptor.getWriteMethod() == null) {
95 LOG.info("Skipping {}.{}", beanClass.getName(), field.getName());
96 continue;
97 }
98 addProperty(propertyDescriptor, field);
99 }
100
101 if (beanClass.getSuperclass() != null) {
102 parseBean(beanClass.getSuperclass());
103 }
104 }
105
106
107
108
109
110
111
112
113
114 @SuppressWarnings("unchecked")
115 private void addProperty(PropertyDescriptor propertyDescriptor, Field field) {
116 BeanProperty beanProperty = new BeanProperty();
117 beanProperty.setPropertyDescriptor(propertyDescriptor);
118 beanProperty.setField(field);
119 if (Enum.class.isAssignableFrom(propertyDescriptor.getPropertyType())) {
120 beanProperty.setConverter(new EnumConverter(propertyDescriptor.getPropertyType()));
121 }
122 this.properties.add(beanProperty);
123 }
124
125
126
127
128
129
130
131
132
133
134
135 private PropertyDescriptor getPropertyDescriptor(PropertyDescriptor[] propertyDescriptors, Field field) {
136 for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
137 if (field.getName().equals(propertyDescriptor.getName())) {
138 return propertyDescriptor;
139 }
140 }
141 return null;
142 }
143
144
145
146
147
148
149
150
151
152 public void setRequired(String propertyName, boolean required) {
153 get(propertyName).setRequired(required);
154 }
155
156
157
158
159
160
161
162
163
164 public void setDate(String propertyName, String formatText) {
165 setConverter(propertyName, new DateConverter(formatText, true));
166 }
167
168
169
170
171
172
173
174
175
176 public void setLocalizedNumber(String propertyName, Locale locale) {
177 Class<? extends Number> numberClass = get(propertyName).getNumberClass();
178 if (numberClass == null) {
179 throw new CsvException(new GeneralError(
180 "Property " + beanClass.getName() + "." + propertyName + " is not a java.lang.Number"));
181 }
182 CustomNumberConverter converter = new CustomNumberConverter(numberClass, NumberFormat.getNumberInstance(locale),
183 true);
184 setConverter(propertyName, converter);
185 }
186
187
188
189
190
191
192
193
194
195 public void setConverter(String propertyName, Converter converter) {
196 get(propertyName).setConverter(converter);
197 }
198
199
200
201
202
203
204
205 protected void removeFromColumnIndex(BeanProperty property) {
206 while (indexToProperty.values().remove(property)) {
207
208 }
209 }
210
211
212
213
214
215
216
217 protected void removeFromColumnName(BeanProperty property) {
218 while (nameToProperty.values().remove(property)) {
219
220 }
221 }
222
223
224
225
226
227
228
229 public void ignoreProperty(String propertyName) {
230 BeanProperty property = get(propertyName);
231 properties.remove(property);
232 removeFromColumnIndex(property);
233 removeFromColumnName(property);
234 }
235
236
237
238
239
240
241
242 public void setHeaderValueProperty(String propertyName) {
243 this.headerValueProperty = get(propertyName);
244 this.headerValueProperty.setDynamicColumnProperty(true);
245 }
246
247
248
249
250
251
252
253 public void setHeaderNameProperty(String propertyName) {
254 this.headerNameProperty = get(propertyName);
255 this.headerNameProperty.setDynamicColumnProperty(true);
256 }
257
258
259
260
261
262
263 public BeanProperty getHeaderValueProperty() {
264 return this.headerValueProperty;
265 }
266
267
268
269
270
271
272 public BeanProperty getHeaderNameProperty() {
273 return this.headerNameProperty;
274 }
275
276
277
278
279
280
281
282
283
284 public void mapIndexToProperty(int columnIndex, String propertyName) {
285 BeanProperty property = get(propertyName);
286 removeFromColumnIndex(property);
287 property.setColumnIndex(columnIndex);
288 indexToProperty.put(new Column(columnIndex), property);
289 }
290
291
292
293
294
295
296
297
298
299 public void mapNameToProperty(String columnName, String propertyName) {
300 BeanProperty property = get(propertyName);
301 removeFromColumnName(property);
302 property.setColumnName(columnName);
303 nameToProperty.put(new Column(columnName.toLowerCase(Locale.getDefault())), property);
304 }
305
306
307
308
309
310
311
312
313
314 protected BeanProperty get(String propertyName) {
315 for (BeanProperty beanProperty : properties) {
316 if (beanProperty.getPropertyName().equals(propertyName)) {
317 return beanProperty;
318 }
319 }
320 throw new CsvException(
321 new GeneralError("Property does not exist: " + beanClass.getName() + "." + propertyName));
322 }
323
324
325
326
327
328
329
330
331
332 public BeanProperty fromIndex(Column column) {
333 return indexToProperty.get(column);
334 }
335
336
337
338
339
340
341
342
343
344 public BeanProperty fromName(Column column) {
345 return nameToProperty.get(column);
346 }
347
348 @SuppressWarnings("unchecked")
349 @Override
350 public Iterator<BeanProperty> iterator() {
351 return ((List<BeanProperty>) ((ArrayList<BeanProperty>) this.properties).clone()).iterator();
352 }
353
354
355
356
357
358
359 public Set<Column> columnIndexKeys() {
360 return this.indexToProperty.keySet();
361 }
362
363
364
365
366
367
368 public Set<Column> columnNameKeys() {
369 return this.nameToProperty.keySet();
370 }
371
372 }