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