1 /*
2 * Copyright 2016 Andrew Rucker Jones.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package com.opencsv.bean;
17
18 import com.opencsv.CSVWriter;
19 import com.opencsv.ICSVParser;
20 import com.opencsv.ICSVWriter;
21 import com.opencsv.bean.exceptionhandler.CsvExceptionHandler;
22 import com.opencsv.bean.exceptionhandler.ExceptionHandlerQueue;
23 import com.opencsv.bean.exceptionhandler.ExceptionHandlerThrow;
24 import org.apache.commons.collections4.ListValuedMap;
25 import org.apache.commons.collections4.MultiValuedMap;
26 import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
27 import org.apache.commons.lang3.ObjectUtils;
28 import org.apache.commons.lang3.StringUtils;
29
30 import java.io.Writer;
31 import java.lang.reflect.Field;
32 import java.util.Locale;
33 import java.util.ResourceBundle;
34
35 /**
36 * This is a builder for StatefulBeanToCsv, allowing one to set all parameters
37 * necessary for writing a CSV file.
38 *
39 * @param <T> The type of the beans being written
40 * @author Andrew Rucker Jones
41 * @since 3.9
42 */
43 public class StatefulBeanToCsvBuilder<T> {
44
45 private char separator = ICSVWriter.DEFAULT_SEPARATOR;
46 private char quotechar = ICSVWriter.DEFAULT_QUOTE_CHARACTER;
47 private char escapechar = ICSVWriter.DEFAULT_ESCAPE_CHARACTER;
48 private String lineEnd = CSVWriter.DEFAULT_LINE_END;
49 private MappingStrategy<T> mappingStrategy = null;
50 private final Writer writer;
51 private final ICSVWriter csvWriter;
52 private CsvExceptionHandler exceptionHandler = new ExceptionHandlerThrow();
53 private boolean orderedResults = true;
54 private Locale errorLocale = Locale.getDefault();
55 private boolean applyQuotesToAll = true;
56 private final ListValuedMap<Class<?>, Field> ignoredFields = new ArrayListValuedHashMap<>();
57 private String profile = StringUtils.EMPTY;
58
59 /**
60 * Default constructor - Being stateful the writer is required by the builder at the start and not added in later.
61 *
62 * @param writer - the writer that will be used to output the csv version of the bean.
63 */
64 public StatefulBeanToCsvBuilder(Writer writer) {
65 this.writer = writer;
66 this.csvWriter = null;
67 }
68
69 /**
70 * Being stateful the writer is required by the builder at the start and not added in later.
71 * By passing in the ICSVWriter you can create a writer with the desired ICSVParser to allow you to
72 * use the exact same parser for reading and writing.
73 *
74 * @param icsvWriter - the ICSVWriter that will be used to output the csv version of the bean.
75 * @since 4.2
76 */
77 public StatefulBeanToCsvBuilder(ICSVWriter icsvWriter) {
78 this.writer = null;
79 this.csvWriter = icsvWriter;
80 }
81
82 /**
83 * Sets the mapping strategy for writing beans to a CSV destination.
84 * <p>If the mapping strategy is set this way, it will always be used instead
85 * of automatic determination of an appropriate mapping strategy.</p>
86 * <p>It is perfectly legitimate to read a CSV source, take the mapping
87 * strategy from the read operation, and pass it in to this method for a
88 * write operation. This conserves some processing time, but, more
89 * importantly, preserves header ordering.</p>
90 *
91 * @param mappingStrategy The mapping strategy to be used for write operations
92 * @return this
93 */
94 public StatefulBeanToCsvBuilder<T> withMappingStrategy(MappingStrategy<T> mappingStrategy) {
95 this.mappingStrategy = mappingStrategy;
96 return this;
97 }
98
99 /**
100 * @see com.opencsv.CSVWriter#separator
101 * @param separator The field separator to be used when writing a CSV file
102 * @return this
103 */
104 public StatefulBeanToCsvBuilder<T> withSeparator(char separator) {
105 this.separator = separator;
106 return this;
107 }
108
109 /**
110 * @see com.opencsv.CSVWriter#quotechar
111 * @param quotechar The quote character to be used when writing a CSV file
112 * @return this
113 */
114 public StatefulBeanToCsvBuilder<T> withQuotechar(char quotechar) {
115 this.quotechar = quotechar;
116 return this;
117 }
118
119 /**
120 * @see com.opencsv.CSVWriter#escapechar
121 * @param escapechar The escape character to be used when writing a CSV file
122 * @return this
123 */
124 public StatefulBeanToCsvBuilder<T> withEscapechar(char escapechar) {
125 this.escapechar = escapechar;
126 return this;
127 }
128
129 /**
130 * @see com.opencsv.CSVWriter#lineEnd
131 * @param lineEnd The line ending to be used when writing a CSV file
132 * @return this
133 */
134 public StatefulBeanToCsvBuilder<T> withLineEnd(String lineEnd) {
135 this.lineEnd = lineEnd;
136 return this;
137 }
138
139 /**
140 * Sets the handler for recoverable exceptions that arise during the
141 * processing of records.
142 * <p>This is a convenience function and is maintained for backwards
143 * compatibility. Passing in {@code true} is equivalent to
144 * {@code withExceptionHandler(new ExceptionHandlerThrow())}
145 * and {@code false} is equivalent to
146 * {@code withExceptionHandler(new ExceptionHandlerQueue())}</p>
147 * <p>Please note that if both this method and
148 * {@link #withExceptionHandler(CsvExceptionHandler)} are called,
149 * the last call wins.</p>
150 * @see #withExceptionHandler(CsvExceptionHandler)
151 * @param throwExceptions Whether or not exceptions should be thrown while
152 * writing a CSV file. If not, they may be retrieved later by calling
153 * {@link com.opencsv.bean.StatefulBeanToCsv#getCapturedExceptions() }.
154 * @return this
155 */
156 public StatefulBeanToCsvBuilder<T> withThrowExceptions(boolean throwExceptions) {
157 if(throwExceptions) {
158 exceptionHandler = new ExceptionHandlerThrow();
159 }
160 else {
161 exceptionHandler = new ExceptionHandlerQueue();
162 }
163 return this;
164 }
165
166 /**
167 * Sets the handler for recoverable exceptions raised during processing of
168 * records.
169 * <p>If neither this method nor {@link #withThrowExceptions(boolean)} is
170 * called, the default exception handler is
171 * {@link ExceptionHandlerThrow}.</p>
172 * <p>Please note that if both this method and
173 * {@link #withThrowExceptions(boolean)} are called, the last call wins.</p>
174 *
175 * @param exceptionHandler The exception handler to be used. If {@code null},
176 * this method does nothing.
177 * @return {@code this}
178 * @since 5.2
179 */
180 public StatefulBeanToCsvBuilder<T> withExceptionHandler(CsvExceptionHandler exceptionHandler) {
181 if(exceptionHandler != null) {
182 this.exceptionHandler = exceptionHandler;
183 }
184 return this;
185 }
186
187 /**
188 * Sets whether results must be written in the same order in which
189 * they appear in the list of beans provided as input.
190 *
191 * @param orderedResults whether the lines written are in the same
192 * order they appeared in the input
193 * @return this
194 * @see StatefulBeanToCsv#setOrderedResults(boolean)
195 * @since 4.0
196 */
197 public StatefulBeanToCsvBuilder<T> withOrderedResults(boolean orderedResults) {
198 this.orderedResults = orderedResults;
199 return this;
200 }
201
202 /**
203 * Sets the locale to be used for all error messages.
204 * @param errorLocale Locale for error messages. If null, the default locale
205 * is used.
206 * @return this
207 * @see StatefulBeanToCsv#setErrorLocale(java.util.Locale)
208 * @since 4.0
209 */
210 public StatefulBeanToCsvBuilder<T> withErrorLocale(Locale errorLocale) {
211 this.errorLocale = ObjectUtils.defaultIfNull(errorLocale, Locale.getDefault());
212 return this;
213 }
214
215 /**
216 * Sets whether all outputs should be put in quotes.
217 * Defaults to {@code true}.
218 *
219 * @param applyQuotesToAll Whether all outputs should be quoted
220 * @return this
221 * @see com.opencsv.CSVWriter#writeNext(String[], boolean)
222 * @since 4.2
223 */
224 public StatefulBeanToCsvBuilder<T> withApplyQuotesToAll(boolean applyQuotesToAll) {
225 this.applyQuotesToAll = applyQuotesToAll;
226 return this;
227 }
228
229 /**
230 * Adds a {@link Field} to the list of fields opencsv should ignore
231 * completely.
232 * <p>May be called as many times as necessary.</p>
233 * @param type The class opencsv will encounter the field in during
234 * processing. In the case of inheritance, this may not be the
235 * declaring class.
236 * @param field The field opencsv is to ignore
237 * @return {@code this}
238 * @throws IllegalArgumentException If one of the parameters is
239 * {@code null} or {@code field} cannot be found in {@code type}.
240 * @since 5.0
241 * @see MappingStrategy#ignoreFields(MultiValuedMap)
242 */
243 public StatefulBeanToCsvBuilder<T> withIgnoreField(Class<?> type, Field field) throws IllegalArgumentException {
244 if(type != null && field != null && field.getDeclaringClass().isAssignableFrom(type)) {
245 ignoredFields.put(type, field);
246 }
247 else {
248 throw new IllegalArgumentException(ResourceBundle.getBundle(
249 ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale)
250 .getString("ignore.field.inconsistent"));
251 }
252 return this;
253 }
254
255 /**
256 * Selects a profile for deciding which configurations to use for the bean
257 * fields.
258 *
259 * @param profile The name of the profile to be used
260 * @return {@code this}
261 * @since 5.4
262 */
263 public StatefulBeanToCsvBuilder<T> withProfile(String profile) {
264 this.profile = profile;
265 return this;
266 }
267
268 /**
269 * Builds a StatefulBeanToCsv from the information provided, filling in
270 * default values where none have been specified.
271 * @return A new {@link StatefulBeanToCsv}
272 */
273 public StatefulBeanToCsv<T> build() {
274 StatefulBeanToCsv<T> sbtcsv;
275 if (writer != null) {
276 sbtcsv = new StatefulBeanToCsv<>(escapechar, lineEnd,
277 mappingStrategy, quotechar, separator, exceptionHandler,
278 writer, applyQuotesToAll, ignoredFields, profile);
279 } else {
280 sbtcsv = new StatefulBeanToCsv<>(mappingStrategy, exceptionHandler,
281 applyQuotesToAll, csvWriter, ignoredFields, profile);
282 }
283
284 sbtcsv.setOrderedResults(orderedResults);
285 sbtcsv.setErrorLocale(errorLocale);
286 return sbtcsv;
287 }
288 }