1 package com.github.mygreen.supercsv.io;
2
3 import java.io.BufferedWriter;
4 import java.io.IOException;
5 import java.io.Writer;
6 import java.util.Arrays;
7 import java.util.Collection;
8 import java.util.List;
9 import java.util.Objects;
10 import java.util.Optional;
11 import java.util.Set;
12 import java.util.stream.Collectors;
13
14 import org.supercsv.exception.SuperCsvException;
15 import org.supercsv.prefs.CsvPreference;
16
17 import com.github.mygreen.supercsv.annotation.CsvPartial;
18 import com.github.mygreen.supercsv.builder.BeanMapping;
19 import com.github.mygreen.supercsv.builder.BeanMappingFactoryHelper;
20 import com.github.mygreen.supercsv.builder.ColumnMapping;
21 import com.github.mygreen.supercsv.builder.HeaderMapper;
22 import com.github.mygreen.supercsv.builder.LazyBeanMappingFactory;
23 import com.github.mygreen.supercsv.exception.SuperCsvBindingException;
24 import com.github.mygreen.supercsv.localization.MessageBuilder;
25
26
27
28
29
30
31
32
33
34
35
36
37 public class LazyCsvAnnotationBeanWriter<T> extends AbstractCsvAnnotationBeanWriter<T> {
38
39
40
41
42
43 private final BeanMapping<T> beanMapping;
44
45
46
47
48 private boolean initialized = false;
49
50
51
52
53
54
55
56
57
58
59
60 public LazyCsvAnnotationBeanWriter(final Class<T> beanType, final Writer writer, final CsvPreference preference,
61 final Class<?>... groups) {
62 super(writer, preference);
63
64 Objects.requireNonNull(beanType, "beanType should not be null.");
65
66 LazyBeanMappingFactoryanMappingFactory.html#LazyBeanMappingFactory">LazyBeanMappingFactory factory = new LazyBeanMappingFactory();
67 this.beanMapping = factory.create(beanType, groups);
68 this.validators.addAll(beanMapping.getValidators());
69
70 }
71
72
73
74
75
76
77
78
79
80
81
82 public LazyCsvAnnotationBeanWriter(final BeanMapping<T> beanMapping, final Writer writer, final CsvPreference preference,
83 final Class<?>... groups) {
84 super(writer, preference);
85
86 Objects.requireNonNull(beanMapping, "beanMapping should not be null.");
87
88 this.beanMapping = beanMapping;
89 this.validators.addAll(beanMapping.getValidators());
90
91 }
92
93
94
95
96 private IllegalStateException newNotInitialzedException() {
97 return new IllegalStateException(MessageBuilder.create("noinit.onLazyWrite").format());
98 }
99
100
101
102
103
104 public void init() {
105 init(new String[]{});
106 }
107
108
109
110
111
112
113 public void init(final String... headers) {
114
115 setupMappingColumns(headers);
116 this.beanMappingCache = BeanMappingCache.create(beanMapping);
117
118
119 this.initialized = true;
120
121 }
122
123
124
125
126
127
128
129
130 private void setupMappingColumns(final String[] headers) {
131
132 final List<ColumnMapping> columnMappingList = beanMapping.getColumns();
133 final HeaderMapper headerMapper = beanMapping.getHeaderMapper();
134
135
136 final int headerSize = headers.length;
137 for(int i=0; i < headerSize;i ++) {
138
139 final String header = headers[i];
140
141
142
143
144
145 List<ColumnMapping> undeterminedColumnList = columnMappingList.stream()
146 .filter(col -> !col.isDeterminedNumber())
147 .filter(col -> headerMapper.toMap(col, beanMapping.getConfiguration(), beanMapping.getGroups()).equals(header))
148 .collect(Collectors.toList());
149
150 final int columnNumber = i+1;
151 undeterminedColumnList.forEach(col -> col.setNumber(columnNumber));
152
153 }
154
155
156 columnMappingList.sort(null);
157
158
159
160
161
162 final Optional<CsvPartial> partialAnno = Optional.ofNullable(beanMapping.getType().getAnnotation(CsvPartial.class));
163 final List<ColumnMapping> undeterminedColumnList = columnMappingList.stream()
164 .filter(col -> !col.isDeterminedNumber())
165 .collect(Collectors.toList());
166
167 if(!undeterminedColumnList.isEmpty()) {
168 final Set<Integer> determinedNumbers = columnMappingList.stream()
169 .filter(col -> col.isDeterminedNumber())
170 .map(col -> col.getNumber())
171 .collect(Collectors.toSet());
172
173
174 partialAnno.ifPresent(anno -> Arrays.stream(anno.headers()).forEach(header -> determinedNumbers.add(header.number())));
175
176 int counter = 1;
177 for(ColumnMapping col : undeterminedColumnList) {
178 while(true) {
179 if(!determinedNumbers.contains(counter)) {
180 break;
181 }
182 counter++;
183 }
184
185 col.setNumber(counter);
186 determinedNumbers.add(counter);
187 }
188
189
190 columnMappingList.sort(null);
191
192 }
193
194
195 BeanMappingFactoryHelper.validateNonDeterminedColumnNumber(beanMapping.getType(), columnMappingList, headers);
196
197
198 BeanMappingFactoryHelper.validateDuplicatedColumnNumber(beanMapping.getType(), columnMappingList);
199
200
201 BeanMappingFactoryHelper.supplyLackedNumberMappingColumn(beanMapping.getType(), columnMappingList, partialAnno, headers, beanMapping.getConfiguration());
202
203 beanMapping.setColumns(columnMappingList);
204
205 }
206
207
208
209
210
211
212
213 public void writeHeader() throws IOException {
214 if(!initialized) {
215 throw newNotInitialzedException();
216 }
217
218 super.writeHeader(getDefinedHeader());
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233 public void writeAll(final Collection<T> sources) throws IOException {
234 writeAll(sources, false);
235 }
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251 public void writeAll(final Collection<T> sources, final boolean continueOnError) throws IOException {
252
253 Objects.requireNonNull(sources, "sources should not be null.");
254
255 if(!initialized) {
256 init();
257 }
258
259 if(beanMappingCache.getOriginal().isHeader() && getLineNumber() == 0) {
260 writeHeader();
261 }
262
263 for(T record : sources) {
264 try {
265 write(record);
266 } catch(SuperCsvBindingException e) {
267 if(!continueOnError) {
268 throw e;
269 }
270 }
271 }
272
273 flush();
274
275 }
276
277
278
279
280
281 @Override
282 public void write(final T source) throws IOException {
283
284 if(!initialized) {
285 throw newNotInitialzedException();
286 }
287
288 super.write(source);
289
290 }
291
292
293
294
295
296 @Override
297 public String[] getDefinedHeader() {
298 if(!initialized) {
299 throw newNotInitialzedException();
300 }
301
302 return super.getDefinedHeader();
303 }
304
305
306
307
308
309 @Override
310 public BeanMapping<T> getBeanMapping() {
311 if(!initialized) {
312 throw newNotInitialzedException();
313 }
314
315 return super.getBeanMapping();
316 }
317
318 }