1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.orangesignal.csv.io;
18
19 import static com.orangesignal.csv.bean.CsvEntityTemplate.getPosition;
20 import static com.orangesignal.csv.bean.FieldUtils.setFieldValue;
21
22 import java.io.Closeable;
23 import java.io.IOException;
24 import java.lang.reflect.Array;
25 import java.lang.reflect.Field;
26 import java.util.Collections;
27 import java.util.List;
28
29 import com.orangesignal.csv.CsvReader;
30 import com.orangesignal.csv.annotation.CsvColumn;
31 import com.orangesignal.csv.annotation.CsvColumnException;
32 import com.orangesignal.csv.annotation.CsvColumns;
33 import com.orangesignal.csv.annotation.CsvEntity;
34 import com.orangesignal.csv.bean.CsvEntityTemplate;
35
36
37
38
39
40
41
42 public class CsvEntityReader<T> implements Closeable {
43
44
45
46
47 private CsvReader reader;
48
49
50
51
52 private final CsvEntityTemplate<T> template;
53
54
55
56
57 private List<String> columnNames;
58
59 private Field[] fields;
60
61
62
63
64
65
66
67
68
69
70
71
72
73 public static <T> CsvEntityReader<T> newInstance(final CsvReader reader, final Class<T> entityClass) {
74 return new CsvEntityReader<T>(reader, entityClass);
75 }
76
77
78
79
80
81
82
83
84
85
86 public static <T> CsvEntityReader<T> newInstance(final CsvReader reader, final CsvEntityTemplate<T> template) {
87 return new CsvEntityReader<T>(reader, template);
88 }
89
90
91
92
93
94
95
96
97
98
99
100 public CsvEntityReader(final CsvReader reader, final Class<T> entityClass) {
101 this(reader, new CsvEntityTemplate<T>(entityClass));
102 }
103
104
105
106
107
108
109
110
111 public CsvEntityReader(final CsvReader reader, final CsvEntityTemplate<T> template) {
112 if (reader == null) {
113 throw new IllegalArgumentException("CsvReader must not be null");
114 }
115 if (template == null) {
116 throw new IllegalArgumentException("CsvEntityTemplate must not be null");
117 }
118 this.reader = reader;
119 this.template = template;
120 }
121
122
123
124
125
126
127
128 private void ensureOpen() throws IOException {
129 if (reader == null) {
130 throw new IOException("CsvReader closed");
131 }
132 }
133
134 private void ensureHeader() throws IOException {
135 synchronized (this) {
136 if (columnNames == null) {
137
138 final List<String> names;
139 if (template.getType().getAnnotation(CsvEntity.class).header()) {
140 names = reader.readValues();
141 } else {
142 names = template.createColumnNames();
143 }
144
145 fields = template.getType().getDeclaredFields();
146 template.prepare(names, fields);
147 columnNames = Collections.unmodifiableList(names);
148 }
149 }
150 }
151
152
153
154
155 @Override
156 public void close() throws IOException {
157 synchronized (this) {
158 ensureOpen();
159 reader.close();
160 reader = null;
161 columnNames = null;
162 fields = null;
163 }
164 }
165
166
167
168
169
170
171
172
173
174
175 public List<String> getHeader() throws IOException {
176 synchronized (this) {
177 ensureOpen();
178 ensureHeader();
179 return columnNames;
180 }
181 }
182
183
184
185
186
187
188
189
190 public T read() throws IOException {
191 synchronized (this) {
192 ensureOpen();
193 ensureHeader();
194 final List<String> values = nextValues();
195 if (values == null) {
196 return null;
197 }
198 return convert(values);
199 }
200 }
201
202
203
204
205
206
207
208 public List<String> readValues() throws IOException {
209 synchronized (this) {
210 ensureOpen();
211 ensureHeader();
212 return nextValues();
213 }
214 }
215
216
217
218
219
220
221
222
223
224 public T toEntity(final List<String> values) throws IOException {
225 synchronized (this) {
226 ensureOpen();
227 ensureHeader();
228 return convert(values);
229 }
230 }
231
232 private List<String> nextValues() throws IOException {
233 List<String> values;
234 while ((values = reader.readValues()) != null) {
235 if (template.isAccept(columnNames, values)) {
236 continue;
237 }
238 return values;
239 }
240 return null;
241 }
242
243 private T convert(final List<String> values) throws IOException {
244 final T entity = template.createBean();
245 for (final Field field : fields) {
246 Object object = null;
247 final CsvColumns columns = field.getAnnotation(CsvColumns.class);
248 if (columns != null) {
249 if (field.getType().isArray()) {
250 object = Array.newInstance(field.getType().getComponentType(), columns.value().length);
251 int arrayIndex = 0;
252 for (final CsvColumn column : columns.value()) {
253 if (!column.access().isReadable()) {
254 continue;
255 }
256 String value;
257 final int pos = getPosition(column, field, columnNames);
258 if (pos != -1) {
259 value = values.get(pos);
260 } else {
261 value = null;
262 }
263 if (value == null && !column.defaultValue().isEmpty()) {
264
265 value = column.defaultValue();
266 }
267 if (value == null && column.required()) {
268
269 throw new CsvColumnException(String.format("[line: %d] %s must not be null", reader.getStartLineNumber(), columnNames.get(pos)), values);
270 }
271 Array.set(object, arrayIndex++, template.stringToObject(field, value));
272 }
273 } else {
274 final StringBuilder sb = new StringBuilder();
275 for (final CsvColumn column : columns.value()) {
276 if (!column.access().isReadable()) {
277 continue;
278 }
279 final int pos = getPosition(column, field, columnNames);
280 if (pos != -1) {
281 final String s = values.get(pos);
282 if (s != null) {
283 sb.append(s);
284 } else if (!column.defaultValue().isEmpty()) {
285
286 sb.append(column.defaultValue());
287 } else if (column.required()) {
288
289 throw new CsvColumnException(String.format("[line: %d] %s must not be null", reader.getStartLineNumber(), columnNames.get(pos)), values);
290 }
291 }
292 }
293 object = template.stringToObject(field, sb.toString());
294 }
295 }
296 final CsvColumn column = field.getAnnotation(CsvColumn.class);
297 if (column != null && column.access().isReadable()) {
298 final int pos = getPosition(column, field, columnNames);
299 if (pos != -1) {
300 String value = values.get(pos);
301 if (value == null && !column.defaultValue().isEmpty()) {
302
303 value = column.defaultValue();
304 }
305 if (value == null && column.required()) {
306
307 throw new CsvColumnException(String.format("[line: %d] %s must not be null", reader.getStartLineNumber(), columnNames.get(pos)), values);
308 }
309 object = template.stringToObject(field, value);
310 }
311 }
312 if (object != null) {
313 setFieldValue(entity, field, object);
314 }
315 }
316 return entity;
317 }
318
319
320
321
322
323
324
325
326
327
328 public CsvEntityTemplate<T> getTemplate() {
329 return template;
330 }
331
332 }