1 package com.github.mygreen.supercsv.io;
2
3 import java.io.Reader;
4 import java.io.Writer;
5 import java.util.Objects;
6 import java.util.Optional;
7 import java.util.function.Supplier;
8
9 import org.supercsv.comment.CommentMatcher;
10 import org.supercsv.encoder.CsvEncoder;
11 import org.supercsv.io.ITokenizer;
12 import org.supercsv.prefs.CsvPreference;
13 import org.supercsv.quote.NormalQuoteMode;
14 import org.supercsv.quote.QuoteMode;
15
16 import com.github.mygreen.supercsv.builder.BeanMapping;
17 import com.github.mygreen.supercsv.builder.Configuration;
18 import com.github.mygreen.supercsv.builder.FixedSizeBeanMappingFactory;
19 import com.github.mygreen.supercsv.util.ArgUtils;
20 import com.github.mygreen.supercsv.util.MemorizingSupplier;
21
22
23
24
25
26
27
28
29
30 public class FixedSizeCsvPreference<T> {
31
32
33
34
35
36 private CsvPreference csvPreference;
37
38 private BeanMappingCache<T> beanMappingCache;
39
40 private TokenizerFactory<T> tokenizerFactory;
41
42 private Configuration configuration;
43
44 private FixedSizeCsvPreference(final Builder<T> builder) {
45 Objects.requireNonNull(builder, "builder should not be null.");
46
47 this.csvPreference = buildCsvPreference(builder);
48 this.tokenizerFactory = builder.tokenizerFactory;
49 this.configuration = builder.configuration;
50
51 FixedSizeBeanMappingFactoryanMappingFactory.html#FixedSizeBeanMappingFactory">FixedSizeBeanMappingFactory factory = new FixedSizeBeanMappingFactory();
52 factory.setConfiguration(configuration);
53 this.beanMappingCache = BeanMappingCache.create(factory.create(builder.beanType, builder.groups));
54 }
55
56
57
58
59
60
61
62 private CsvPreference buildCsvPreference(final Builder<T> builder) {
63
64
65 CsvPreference.Builder preferenceBuilder = new CsvPreference.Builder('"', ',', builder.endOfLineSymbols)
66 .useQuoteMode(builder.quoteMode)
67 .useEncoder(builder.encoderFactory.create(MemorizingSupplier.of(() -> beanMappingCache.getOriginal())))
68 .ignoreEmptyLines(builder.ignoreEmptyLines)
69 .surroundingSpacesNeedQuotes(false);
70
71 builder.commentMatcher.ifPresent(matcher -> {
72 preferenceBuilder.skipComments(matcher);
73 });
74
75 return preferenceBuilder.build();
76 }
77
78
79
80
81
82
83
84
85 public static <T> Builder<T> builder(final Class<T> beanType, final Class<?>... groups) {
86 return new Builder<>(beanType, groups);
87 }
88
89
90
91
92
93 public CsvPreference getCsvPreference() {
94 return csvPreference;
95 }
96
97
98
99
100
101 public BeanMappingCache<T> getBeanMappingCache() {
102 return beanMappingCache;
103 }
104
105
106
107
108
109 public Configuration getConfiguration() {
110 return configuration;
111 }
112
113
114
115
116
117
118
119 public ITokenizer createTokenizer(final Reader reader) {
120 return tokenizerFactory.create(reader, csvPreference, beanMappingCache.getOriginal());
121 }
122
123
124
125
126
127
128 public FixedSizeCsvAnnotationBeanReader<T> csvReader(final Reader reader) {
129 return new FixedSizeCsvAnnotationBeanReader<>(reader, this);
130 }
131
132
133
134
135
136
137 public FixedSizeCsvAnnotationBeanWriter<T> csvWriter(final Writer writer) {
138 return new FixedSizeCsvAnnotationBeanWriter<>(writer, this);
139 }
140
141
142
143
144
145
146 public interface TokenizerFactory<T> {
147
148
149
150
151
152
153
154
155
156 ITokenizer create(Reader reader, CsvPreference preference, BeanMapping<T> beanMapping);
157 }
158
159
160
161
162
163
164
165 public interface CsvEncoderFactory<T> {
166
167
168
169
170
171
172
173 CsvEncoder create(Supplier<BeanMapping<T>> beanMappingSupplier);
174 }
175
176
177
178
179
180
181
182
183 public static class Builder<T> {
184
185 private final Class<T> beanType;
186
187 private final Class<?>[] groups;
188
189
190 private String endOfLineSymbols;
191
192
193 private boolean ignoreEmptyLines;
194
195 private QuoteMode quoteMode;
196
197
198 private TokenizerFactory<T> tokenizerFactory;
199
200
201 private CsvEncoderFactory<T> encoderFactory;
202
203
204
205
206 private Optional<CommentMatcher> commentMatcher;
207
208 private Configuration configuration;
209
210
211
212
213
214
215
216 public Builder(final Class<T> beanType, final Class<?>... groups) {
217 Objects.requireNonNull(beanType, "beanType should not be null.");
218
219 this.beanType = beanType;
220 this.groups = groups;
221 }
222
223
224
225
226
227
228
229
230 public Builder<T> endOfLineSymbols(final String endOfLineSymbols) {
231 ArgUtils.notEmpty(endOfLineSymbols, "endOfLineSymbols");
232
233 this.endOfLineSymbols = endOfLineSymbols;
234 return this;
235 }
236
237
238
239
240
241
242 public Builder<T> ignoreEmptyLines(final boolean ignoreEmptyLines) {
243 this.ignoreEmptyLines = ignoreEmptyLines;
244 return this;
245 }
246
247
248
249
250
251
252
253 public Builder<T> quoteMode(final QuoteMode quoteMode) {
254 Objects.requireNonNull(quoteMode, "quoteMode should not be null.");
255
256 this.quoteMode = quoteMode;
257 return this;
258 }
259
260
261
262
263
264
265
266 public Builder<T> tokenizerFactory(final TokenizerFactory<T> tokenizerFactory) {
267 Objects.requireNonNull(tokenizerFactory, "tokenizerFactory should not be null.");
268
269 this.tokenizerFactory = tokenizerFactory;
270 return this;
271 }
272
273
274
275
276
277
278
279 public Builder<T> encoderFactory(final CsvEncoderFactory<T> encoderFactory) {
280 Objects.requireNonNull(encoderFactory, "encoderFactory should not be null.");
281
282 this.encoderFactory = encoderFactory;
283 return this;
284 }
285
286
287
288
289
290
291 public Builder<T> skipComment(final CommentMatcher commentMatcher) {
292 this.commentMatcher = Optional.of(commentMatcher);
293 return this;
294
295 }
296
297
298
299
300
301
302
303 public Builder<T> configuration(final Configuration configuration) {
304 Objects.requireNonNull(configuration, "configuration should not be null.");
305
306 this.configuration = configuration;
307 return this;
308 }
309
310
311
312
313
314
315 public FixedSizeCsvPreference<T> build() {
316
317 if (endOfLineSymbols == null) {
318 endOfLineSymbols = "\r\n";
319 }
320
321 if (quoteMode == null) {
322 quoteMode = new NormalQuoteMode();
323 }
324
325 if (commentMatcher == null) {
326 commentMatcher = Optional.empty();
327 }
328
329 if (tokenizerFactory == null) {
330 tokenizerFactory = new TokenizerFactory<T>() {
331
332 @Override
333 public ITokenizer create(Reader reader, CsvPreference preference, BeanMapping<T> beanMapping) {
334 return new FixedSizeTokenizer(reader, preference, beanMapping);
335 }
336 };
337
338 }
339
340 if (encoderFactory == null) {
341 encoderFactory = new CsvEncoderFactory<T>() {
342
343 @Override
344 public CsvEncoder create(Supplier<BeanMapping<T>> beanMappingSupplier) {
345 return new FixedSizeCsvEncoder<T>(beanMappingSupplier);
346 }
347 };
348
349 }
350
351 if (configuration == null) {
352 configuration = new Configuration();
353 }
354
355 return new FixedSizeCsvPreference<>(this);
356 }
357
358 }
359
360 }