1 package com.github.mygreen.supercsv.builder;
2
3 import java.lang.reflect.Field;
4 import java.lang.reflect.Method;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.List;
8 import java.util.Objects;
9 import java.util.Optional;
10 import java.util.stream.Collectors;
11
12 import org.supercsv.cellprocessor.ift.CellProcessor;
13 import org.supercsv.exception.SuperCsvReflectionException;
14
15 import com.github.mygreen.supercsv.annotation.CsvBean;
16 import com.github.mygreen.supercsv.annotation.CsvColumn;
17 import com.github.mygreen.supercsv.annotation.CsvPartial;
18 import com.github.mygreen.supercsv.annotation.CsvPostRead;
19 import com.github.mygreen.supercsv.annotation.CsvPostWrite;
20 import com.github.mygreen.supercsv.annotation.CsvPreRead;
21 import com.github.mygreen.supercsv.annotation.CsvPreWrite;
22 import com.github.mygreen.supercsv.annotation.DefaultGroup;
23 import com.github.mygreen.supercsv.exception.SuperCsvInvalidAnnotationException;
24 import com.github.mygreen.supercsv.localization.MessageBuilder;
25 import com.github.mygreen.supercsv.validation.CsvValidator;
26
27
28
29
30
31
32
33
34 public class BeanMappingFactory {
35
36 private Configurationfiguration.html#Configuration">Configuration configuration = new Configuration();
37
38
39
40
41 public BeanMappingFactory() {
42
43 }
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public <T> BeanMapping<T> create(final Class<T> beanType, final Class<?>... groups) {
58
59 Objects.requireNonNull(beanType);
60
61 final BeanMapping<T> beanMapping = new BeanMapping<>(beanType);
62 beanMapping.setConfiguration(configuration);
63
64
65 final CsvBean beanAnno = beanType.getAnnotation(CsvBean.class);
66 if(beanAnno == null) {
67 throw new SuperCsvInvalidAnnotationException(beanAnno, MessageBuilder.create("anno.notFound")
68 .varWithClass("property", beanType)
69 .varWithAnno("anno", CsvBean.class)
70 .format());
71 }
72
73
74 buildHeaderMapper(beanMapping, beanAnno);
75
76
77 buildValidators(beanMapping, beanAnno, groups);
78
79
80 buildColumnMappingList(beanMapping, beanType, groups);
81
82
83 buildCallbackMethods(beanMapping, beanType, beanAnno);
84
85 return beanMapping;
86 }
87
88
89
90
91
92
93
94
95 protected <T> void buildHeaderMapper(final BeanMapping<T> beanMapping, final CsvBean beanAnno) {
96
97 final HeaderMapper../com/github/mygreen/supercsv/builder/HeaderMapper.html#HeaderMapper">HeaderMapper headerMapper = (HeaderMapper) configuration.getBeanFactory().create(beanAnno.headerMapper());
98 beanMapping.setHeaderMapper(headerMapper);
99
100 beanMapping.setHeader(beanAnno.header());
101 beanMapping.setValidateHeader(beanAnno.validateHeader());
102
103 }
104
105
106
107
108
109
110
111
112
113 @SuppressWarnings({"unchecked"})
114 protected <T> void buildValidators(final BeanMapping<T> beanMapping, final CsvBean beanAnno, final Class<?>[] groups) {
115
116
117 final List<CsvValidator<T>> validators = Arrays.stream(beanAnno.validators())
118 .map(v -> (CsvValidator<T>)configuration.getBeanFactory().create(v))
119 .collect(Collectors.toList());
120 beanMapping.addAllValidators(validators);
121
122 beanMapping.setSkipValidationOnWrite(configuration.isSkipValidationOnWrite());
123 beanMapping.setGroups(groups);
124
125 }
126
127
128
129
130
131
132
133
134
135 protected <T> void buildColumnMappingList(final BeanMapping<T> beanMapping, final Class<T> beanType, final Class<?>[] groups) {
136
137 final List<ColumnMapping> columnMappingList = new ArrayList<>();
138 for(Field field : beanType.getDeclaredFields()) {
139
140 final CsvColumn columnAnno = field.getAnnotation(CsvColumn.class);
141 if(columnAnno != null) {
142 columnMappingList.add(createColumnMapping(field, columnAnno, groups));
143 }
144
145 }
146
147
148 columnMappingList.sort(null);
149 validateColumnAndSupplyPartialColumn(beanType, columnMappingList);
150 beanMapping.addAllColumns(columnMappingList);
151
152 }
153
154
155
156
157
158
159
160
161
162 @SuppressWarnings({"rawtypes", "unchecked"})
163 protected ColumnMapping createColumnMapping(final Field field, final CsvColumn columnAnno, final Class<?>[] groups) {
164
165 final FieldAccessorldAccessor.html#FieldAccessor">FieldAccessor fieldAccessor = new FieldAccessor(field, configuration.getAnnoationComparator());
166
167 final ColumnMappingumnMapping.html#ColumnMapping">ColumnMapping columnMapping = new ColumnMapping();
168 columnMapping.setField(fieldAccessor);
169 columnMapping.setNumber(columnAnno.number());
170
171 if(columnAnno.label().isEmpty()) {
172 columnMapping.setLabel(field.getName());
173 } else {
174 columnMapping.setLabel(columnAnno.label());
175 }
176
177
178 ProcessorBuilder builder;
179 if(columnAnno.builder().length == 0) {
180
181 builder = configuration.getBuilderResolver().resolve(fieldAccessor.getType());
182 if(builder == null) {
183
184 builder = new GeneralProcessorBuilder();
185 }
186
187 } else {
188
189 try {
190 builder = (ProcessorBuilder) configuration.getBeanFactory().create(columnAnno.builder()[0]);
191
192 } catch(Throwable e) {
193 throw new SuperCsvReflectionException(
194 String.format("Fail create instance of %s with attribute 'builderClass' of @CsvColumn",
195 columnAnno.builder()[0].getCanonicalName()), e);
196 }
197 }
198
199
200 columnMapping.setCellProcessorForReading(
201 (CellProcessor)builder.buildForReading(field.getType(), fieldAccessor, configuration, groups).orElse(null));
202
203 columnMapping.setCellProcessorForWriting(
204 (CellProcessor)builder.buildForWriting(field.getType(), fieldAccessor, configuration, groups).orElse(null));
205
206 if(builder instanceof AbstractProcessorBuilder) {
207 columnMapping.setFormatter(((AbstractProcessorBuilder)builder).getFormatter(fieldAccessor, configuration));
208 }
209
210 return columnMapping;
211
212 }
213
214
215
216
217
218
219 protected void validateColumnAndSupplyPartialColumn(final Class<?> beanType, final List<ColumnMapping> list) {
220
221 final Optional<CsvPartial> partialAnno = Optional.ofNullable(beanType.getAnnotation(CsvPartial.class));
222
223 if(list.isEmpty()) {
224 throw new SuperCsvInvalidAnnotationException(MessageBuilder.create("anno.notFound")
225 .varWithClass("property", beanType)
226 .varWithAnno("anno", CsvColumn.class)
227 .format());
228 }
229
230
231 BeanMappingFactoryHelper.validateDuplicatedColumnNumber(beanType, list);
232
233
234 BeanMappingFactoryHelper.supplyLackedNumberMappingColumn(beanType, list, partialAnno, new String[0]);
235
236 }
237
238
239
240
241
242
243
244 protected ColumnMapping createPartialColumnMapping(int columnNumber, final Optional<CsvPartial> partialAnno) {
245
246 final ColumnMappingumnMapping.html#ColumnMapping">ColumnMapping columnMapping = new ColumnMapping();
247 columnMapping.setNumber(columnNumber);
248 columnMapping.setPartialized(true);
249
250 String label = String.format("column%d", columnNumber);
251 if(partialAnno.isPresent()) {
252 for(CsvPartial.Header header : partialAnno.get().headers()) {
253 if(header.number() == columnNumber) {
254 label = header.label();
255 }
256 }
257 }
258 columnMapping.setLabel(label);
259
260 return columnMapping;
261
262 }
263
264
265
266
267
268
269
270
271
272 protected <T> void buildCallbackMethods(final BeanMapping<T> beanMapping, final Class<T> beanType, final CsvBean beanAnno) {
273
274
275 for(Method method : beanType.getDeclaredMethods()) {
276
277 if(method.getAnnotation(CsvPreRead.class) != null) {
278 beanMapping.addPreReadMethod(new CallbackMethod(method));
279 }
280
281 if(method.getAnnotation(CsvPostRead.class) != null) {
282 beanMapping.addPostReadMethod(new CallbackMethod(method));
283 }
284
285 if(method.getAnnotation(CsvPreWrite.class) != null) {
286 beanMapping.addPreWriteMethod(new CallbackMethod(method));
287 }
288
289 if(method.getAnnotation(CsvPostWrite.class) != null) {
290 beanMapping.addPostWriteMethod(new CallbackMethod(method));
291 }
292 }
293
294
295 final List<Object> listeners = Arrays.stream(beanAnno.listeners())
296 .map(l -> configuration.getBeanFactory().create(l))
297 .collect(Collectors.toList());
298 beanMapping.addAllListeners(listeners);
299
300 for(Object listener : listeners) {
301 for(Method method : listener.getClass().getDeclaredMethods()) {
302 if(method.getAnnotation(CsvPreRead.class) != null) {
303 beanMapping.addPreReadMethod(new ListenerCallbackMethod(listener, method));
304 }
305
306 if(method.getAnnotation(CsvPostRead.class) != null) {
307 beanMapping.addPostReadMethod(new ListenerCallbackMethod(listener, method));
308 }
309
310 if(method.getAnnotation(CsvPreWrite.class) != null) {
311 beanMapping.addPreWriteMethod(new ListenerCallbackMethod(listener, method));
312 }
313
314 if(method.getAnnotation(CsvPostWrite.class) != null) {
315 beanMapping.addPostWriteMethod(new ListenerCallbackMethod(listener, method));
316 }
317 }
318 }
319
320 beanMapping.getPreReadMethods().sort(null);
321 beanMapping.getPostReadMethods().sort(null);
322 beanMapping.getPreWriteMethods().sort(null);
323 beanMapping.getPostWriteMethods().sort(null);
324
325 }
326
327
328
329
330
331 public Configuration getConfiguration() {
332 return configuration;
333 }
334
335
336
337
338
339 public void setConfiguration(Configuration configuraton) {
340 this.configuration = configuraton;
341 }
342
343 }