1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.orangesignal.csv.bean;
18
19 import java.lang.reflect.Field;
20 import java.text.DecimalFormat;
21 import java.text.DecimalFormatSymbols;
22 import java.text.Format;
23 import java.text.SimpleDateFormat;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Currency;
27 import java.util.Date;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.Map;
32 import java.util.SortedMap;
33 import java.util.TimeZone;
34 import java.util.TreeMap;
35
36 import com.orangesignal.csv.annotation.CsvColumn;
37 import com.orangesignal.csv.annotation.CsvColumns;
38 import com.orangesignal.csv.annotation.CsvEntity;
39 import com.orangesignal.csv.filters.CsvNamedValueFilter;
40
41
42
43
44
45
46
47
48
49
50 public class CsvEntityTemplate<T> extends AbstractCsvBeanTemplate<T, CsvEntityTemplate<T>> implements CsvEntityOperation<CsvEntityTemplate<T>> {
51
52
53
54
55 private CsvNamedValueFilter filter;
56
57
58
59
60
61
62
63
64
65
66
67 public static <T> CsvEntityTemplate<T> newInstance(final Class<T> entityClass) {
68 return new CsvEntityTemplate<T>(entityClass);
69 }
70
71
72
73
74
75
76
77
78
79
80 public CsvEntityTemplate(final Class<T> entityClass) {
81 super(entityClass);
82 if (entityClass.getAnnotation(CsvEntity.class) == null) {
83 throw new IllegalArgumentException(String.format("No CsvEntity is available %s", entityClass.getName()));
84 }
85 }
86
87
88
89
90 @Override
91 public CsvEntityTemplate<T> filter(final CsvNamedValueFilter filter) {
92 this.filter = filter;
93 return this;
94 }
95
96
97
98
99
100
101
102
103
104
105
106 public boolean isAccept(final List<String> columnNames, final List<String> values) {
107 return filter != null && !filter.accept(columnNames, values);
108 }
109
110
111
112
113
114
115 public List<String> createColumnNames() {
116 final SortedMap<Integer, String> positionMap = new TreeMap<Integer, String>();
117 final List<String> adding = new ArrayList<String>();
118
119 for (final Field f : getType().getDeclaredFields()) {
120 final CsvColumns columns = f.getAnnotation(CsvColumns.class);
121 if (columns != null) {
122 for (final CsvColumn column : columns.value()) {
123 final int pos = column.position();
124 final String name = defaultIfEmpty(column.name(), f.getName());
125 if (pos >= 0) {
126 if (positionMap.containsKey(pos)) {
127 continue;
128 }
129 positionMap.put(pos, name);
130 } else {
131 adding.add(name);
132 }
133 }
134 }
135 final CsvColumn column = f.getAnnotation(CsvColumn.class);
136 if (column != null) {
137 final int pos = column.position();
138 final String name = defaultIfEmpty(column.name(), f.getName());
139 if (pos >= 0) {
140 if (positionMap.containsKey(pos)) {
141 continue;
142 }
143 positionMap.put(pos, name);
144 } else {
145 adding.add(name);
146 }
147 }
148 }
149
150 final int max = positionMap.size() > 0 ? positionMap.lastKey().intValue() + 1 : 0;
151 final String[] names = new String[max];
152 for (final Map.Entry<Integer, String> entry : positionMap.entrySet()) {
153 names[entry.getKey().intValue()] = entry.getValue();
154 }
155
156 final List<String> results = new ArrayList<String>(Arrays.asList(names));
157 if (adding.size() > 0) {
158 results.addAll(adding);
159 }
160 return results;
161 }
162
163
164
165
166
167
168
169 public List<String> createWritableColumnNames() {
170 final SortedMap<Integer, String> positionMap = new TreeMap<Integer, String>();
171 final List<String> adding = new ArrayList<String>();
172
173 for (final Field f : getType().getDeclaredFields()) {
174 final CsvColumns columns = f.getAnnotation(CsvColumns.class);
175 if (columns != null) {
176 for (final CsvColumn column : columns.value()) {
177 if (!column.access().isWriteable()) {
178 continue;
179 }
180 final int pos = column.position();
181 final String name = defaultIfEmpty(column.name(), f.getName());
182 if (pos >= 0) {
183 if (positionMap.containsKey(pos)) {
184 continue;
185 }
186 positionMap.put(pos, name);
187 } else {
188 adding.add(name);
189 }
190 }
191 }
192 final CsvColumn column = f.getAnnotation(CsvColumn.class);
193 if (column != null && column.access().isWriteable()) {
194 final int pos = column.position();
195 final String name = defaultIfEmpty(column.name(), f.getName());
196 if (pos >= 0) {
197 if (positionMap.containsKey(pos)) {
198 continue;
199 }
200 positionMap.put(pos, name);
201 } else {
202 adding.add(name);
203 }
204 }
205 }
206
207 final int max = positionMap.size() > 0 ? positionMap.lastKey().intValue() + 1 : 0;
208 final String[] names = new String[max];
209 for (final Map.Entry<Integer, String> entry : positionMap.entrySet()) {
210 names[entry.getKey().intValue()] = entry.getValue();
211 }
212
213 final List<String> results = new ArrayList<String>(Arrays.asList(names));
214 if (adding.size() > 0) {
215 results.addAll(adding);
216 }
217 return results;
218 }
219
220 public void prepare(final List<String> names, final Field[] fields) {
221 super.valueParserMapping(new HashMap<String, Format>(0));
222 super.valueFormatterMapping(new HashMap<Object, Format>(0));
223
224
225 for (final Field f : fields) {
226 final CsvColumns columns = f.getAnnotation(CsvColumns.class);
227 if (columns != null) {
228 for (final CsvColumn column : columns.value()) {
229 final Format format = createFormat(column, f);
230 if (format != null) {
231 setValueParser(f.getName(), format);
232 setValueFormatter(getPosition(column, f, names), format);
233 }
234 }
235 }
236 final CsvColumn column = f.getAnnotation(CsvColumn.class);
237 if (column != null) {
238 final Format format = createFormat(column, f);
239 if (format != null) {
240 setValueParser(f.getName(), format);
241 setValueFormatter(getPosition(column, f, names), format);
242 }
243 }
244 }
245 }
246
247
248
249 public static int getPosition(final CsvColumn column, final Field f, final List<String> names) {
250
251 int pos = column.position();
252
253 if (pos < 0 && names != null) {
254 pos = names.indexOf(defaultIfEmpty(column.name(), f.getName()));
255 }
256
257 if (pos == -1) {
258 throw new IllegalStateException(String.format("Invalid CsvColumn field %s", f.getName()));
259 }
260 return pos;
261 }
262
263 public static String defaultIfEmpty(final String str, final String defaultStr) {
264 return str == null || str.isEmpty() ? defaultStr : str;
265 }
266
267
268
269 private static Format createFormat(final CsvColumn column, final Field f) {
270 final String pattern = column.format();
271 if (pattern.isEmpty()) {
272 return null;
273 }
274
275 final Locale locale = column.language().isEmpty() ? Locale.getDefault() : new Locale(column.language(), column.country());
276 if (Date.class.isAssignableFrom(f.getType())) {
277 final SimpleDateFormat format = new SimpleDateFormat(pattern, locale);
278 if (!column.timezone().isEmpty()) {
279 format.setTimeZone(TimeZone.getTimeZone(column.timezone()));
280 }
281 return format;
282 }
283 final DecimalFormat format = new DecimalFormat(pattern, DecimalFormatSymbols.getInstance(locale));
284 if (!column.currency().isEmpty()) {
285 format.setCurrency(Currency.getInstance(column.currency()));
286 }
287 return format;
288 }
289
290 }