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 java.io.Closeable;
20 import java.io.IOException;
21 import java.lang.reflect.Field;
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.Map;
25
26 import com.orangesignal.csv.CsvReader;
27 import com.orangesignal.csv.bean.CsvColumnNameMappingBeanTemplate;
28 import com.orangesignal.csv.bean.FieldUtils;
29
30
31
32
33
34
35
36 public class CsvColumnNameMappingBeanReader<T> implements Closeable {
37
38
39
40
41 private CsvReader reader;
42
43
44
45
46 private final CsvColumnNameMappingBeanTemplate<T> template;
47
48
49
50
51 private List<String> columnNames;
52
53 private Field[] fields;
54 private Map<String, Object[]> fieldColumnsMap;
55
56
57
58
59
60
61
62
63
64
65
66
67
68 public static <T> CsvColumnNameMappingBeanReader<T> newInstance(final CsvReader reader, final Class<T> type) {
69 return new CsvColumnNameMappingBeanReader<T>(reader, type);
70 }
71
72
73
74
75
76
77
78
79
80
81 public static <T> CsvColumnNameMappingBeanReader<T> newInstance(final CsvReader reader, final CsvColumnNameMappingBeanTemplate<T> template) {
82 return new CsvColumnNameMappingBeanReader<T>(reader, template);
83 }
84
85
86
87
88
89
90
91
92
93
94
95 public CsvColumnNameMappingBeanReader(final CsvReader reader, final Class<T> type) {
96 this(reader, new CsvColumnNameMappingBeanTemplate<T>(type));
97 }
98
99
100
101
102
103
104
105
106 public CsvColumnNameMappingBeanReader(final CsvReader reader, final CsvColumnNameMappingBeanTemplate<T> template) {
107 if (reader == null) {
108 throw new IllegalArgumentException("CsvReader must not be null");
109 }
110 if (template == null) {
111 throw new IllegalArgumentException("CsvColumnNameMappingBeanTemplate must not be null");
112 }
113 this.reader = reader;
114 this.template = template;
115 }
116
117
118
119
120
121
122
123 private void ensureOpen() throws IOException {
124 if (reader == null) {
125 throw new IOException("CsvReader closed");
126 }
127 }
128
129 private void ensureHeader() throws IOException {
130 synchronized (this) {
131 if (columnNames == null) {
132 columnNames = Collections.unmodifiableList(reader.readValues());
133 if (columnNames == null) {
134
135 throw new IOException("No header is available");
136 }
137 template.setupColumnMappingIfNeed();
138 fields = template.getType().getDeclaredFields();
139 fieldColumnsMap = template.createFieldAndColumnsMap();
140 }
141 }
142 }
143
144
145
146
147 @Override
148 public void close() throws IOException {
149 synchronized (this) {
150 ensureOpen();
151 reader.close();
152 reader = null;
153 columnNames = null;
154 fields = null;
155 fieldColumnsMap = null;
156 }
157 }
158
159
160
161
162
163
164
165
166
167
168 public List<String> getHeader() throws IOException {
169 synchronized (this) {
170 ensureOpen();
171 ensureHeader();
172 return columnNames;
173 }
174 }
175
176
177
178
179
180
181
182 public T read() throws IOException {
183 synchronized (this) {
184 ensureOpen();
185 ensureHeader();
186 final List<String> values = nextValues();
187 if (values == null) {
188 return null;
189 }
190 return convert(values);
191 }
192 }
193
194
195
196
197
198
199
200 public List<String> readValues() throws IOException {
201 synchronized (this) {
202 ensureOpen();
203 ensureHeader();
204 return nextValues();
205 }
206 }
207
208
209
210
211
212
213
214
215 public T toBean(final List<String> values) throws IOException {
216 synchronized (this) {
217 ensureOpen();
218 ensureHeader();
219 return convert(values);
220 }
221 }
222
223 private List<String> nextValues() throws IOException {
224 List<String> values;
225 while ((values = reader.readValues()) != null) {
226 if (template.isAccept(columnNames, values)) {
227 continue;
228 }
229 return values;
230 }
231 return null;
232 }
233
234 @SuppressWarnings("null")
235 private T convert(final List<String> values) throws IOException {
236 final T bean = template.createBean();
237 for (final Field f : fields) {
238 final Object[] columns = fieldColumnsMap.get(f.getName());
239 final int count = columns == null ? 0 : columns.length;
240
241 Object o = null;
242 if (count == 1) {
243 final int pos = columnNames.indexOf(columns[0]);
244 if (pos != -1) {
245 o = template.stringToObject(f, values.get(pos));
246 }
247 } else if (count > 1) {
248 final StringBuilder sb = new StringBuilder();
249 for (final Object column : columns) {
250 final int pos = columnNames.indexOf(column);
251 if (pos != -1) {
252 final String s = values.get(pos);
253 if (s != null) {
254 sb.append(s);
255 }
256 }
257 }
258 o = template.stringToObject(f, sb.toString());
259 }
260 if (o != null) {
261 FieldUtils.setFieldValue(bean, f, o);
262 }
263 }
264 return bean;
265 }
266
267
268
269
270
271
272
273
274
275
276 public CsvColumnNameMappingBeanTemplate<T> getTemplate() {
277 return template;
278 }
279
280 }