View Javadoc
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 }