1 /***
2 * Copyright (C) 2008 rweber <quietgenie@users.sourceforge.net>
3 *
4 * This file is part of CsvObjectMapper.
5 *
6 * CsvObjectMapper is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CsvObjectMapper is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with CsvObjectMapper. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /***
21 *
22 */
23 package com.projectnine.csvmapper;
24
25 import java.util.List;
26
27 import org.apache.commons.chain.Command;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 /***
32 * This class represents the mapping between one CSV field and one property of
33 * an Object.
34 *
35 * @author robweber
36 *
37 */
38 public class CsvFieldMapping implements Cloneable {
39 /***
40 * Log stuff.
41 */
42 private static final Log log = LogFactory.getLog(CsvFieldMapping.class);
43
44 /***
45 * The name of the property or the JEXL expression to which the CSV field
46 * value will be stored.
47 */
48 private String csvToObjectExpression;
49
50 /***
51 * The name of the JEXL expression to be used to map a property of an object
52 * back to a CSV field.
53 */
54 private String objectToCsvExpression;
55
56 /***
57 * The column index is zero-indexed. It is a reference to the column of the
58 * CSV field that is being mapped.
59 *
60 * One of either column index or bean name will be set. If both are set, the
61 * bean name setting takes precedence.
62 */
63 private int columnIndex;
64
65 /***
66 * The bean name is a reference to another CSV Object Mapping.
67 *
68 * One of either column index or bean name will be set. If both are set, the
69 * bean name setting takes precedence.
70 */
71 private String beanName;
72
73 /***
74 * The Field Formatter is used to apply a particular "formatting" or
75 * conversion on the String value of the CSV field.
76 */
77 private CsvFieldFormatter formatter;
78
79 /***
80 * The validation command serves to validate the value of the RAW CSV Field
81 * String value (i.e. pre-formatting). In most cases, the validation command
82 * will be an instance of {@link CsvFieldValidator}. However, a
83 * {@link Chain} of {@link CsvFieldValidator}s may also be used here.
84 */
85 private Command validationCommand;
86
87 /***
88 // * Used to indicate that the property name specified refers to a "complex"
89 // * property. That is, the property may be a string of bean style
90 // properties,
91 // * but the last node in the string is the name of a single argument
92 // method.
93 // *
94 // * Yes, this is hokey. That is why JEXL is preferred now.
95 // *
96 // * @deprecated Use a JEXL expression (i.e. getFooList().add(%ARGUMENT%)).
97 // */
98
99
100 /***
101 * If the header is printed when the {@link ObjectToCsvMapper} is used, this
102 * is the value that will be used for this field.
103 */
104 private String csvFieldHeader;
105
106 /***
107 // * Get the name of the property or expression.
108 // *
109 // * @return
110 // * @deprecated use {@link #getCsvToObjectExpression()} instead.
111 // */
112
113
114
115
116 /***
117 // * @param csvToObjectExpression
118 // * the csvToObjectExpression to set
119 // * @deprecated use {@link #setCsvToObjectExpression(String)} instead.
120 // */
121
122
123
124
125 /***
126 * Get the value of the column index.
127 *
128 * @return the value of the column index.
129 */
130 public final int getColumnIndex() {
131 return columnIndex;
132 }
133
134 /***
135 * @param columnIndex
136 * the columnIndex to set
137 */
138 public final void setColumnIndex(final int columnIndex) {
139 this.columnIndex = columnIndex;
140 }
141
142 /***
143 * @param formatter
144 * the formatter to set
145 */
146 public final void setFormatter(final CsvFieldFormatter formatter) {
147 this.formatter = formatter;
148 }
149
150 /***
151 // * This method returns the "adjusted" (post validation and formatting)
152 // * property value. If there is a problem with validation or formatting, a
153 // * {@link ValidationException} is thrown. While this is bad, it may not
154 // * indicate that the whole file is bad; it might just be the current
155 // record.
156 // * Just call {@link CsvToObjectMapper#loadNextRecord()} and try
157 // * {@link CsvToObjectMapper#generateObjectFromCurrentCsvRecord()} again.
158 // *
159 // * @param rawPropertyValue
160 // * The raw property value as it appears in the CSV file.
161 // * @param generatedObject
162 // * The object to which the property will ultimately be stored.
163 // * @param line
164 // * A list of all of the other CSV String values in the same line.
165 // * @return
166 // * @throws ValidationException
167 // * @deprecated use {@link #getObjectValueFromCsvField(String, Object,
168 // List)}
169 // * instead.
170 // */
171
172
173
174
175
176
177
178 /***
179 * This method returns the "adjusted" (post validation and formatting)
180 * property value. If there is a problem with validation or formatting, a
181 * {@link ValidationException} is thrown. While this is bad, it may not
182 * indicate that the whole file is bad; it might just be the current record.
183 * Just call {@link CsvToObjectMapper#loadNextRecord()} and try
184 * {@link CsvToObjectMapper#generateObjectFromCurrentCsvRecord()} again.
185 *
186 * @param rawPropertyValue
187 * The raw property value as it appears in the CSV file.
188 * @param generatedObject
189 * The object to which the property will ultimately be stored.
190 * @param line
191 * A list of all of the other CSV String values in the same line.
192 * @return The value of the Object from the CSV Field.
193 * @throws ValidationException
194 * when the CSV field value cannot be validated.
195 */
196 public final Object getObjectValueFromCsvField(
197 final String rawPropertyValue, final Object generatedObject,
198 final List<String> line) throws ValidationException {
199 Object formattedPropertyValue = rawPropertyValue;
200
201 if (validationCommand != null) {
202 CsvFieldValidationContext csvFieldValidationContext = new CsvFieldValidationContext();
203 csvFieldValidationContext.setValueToValidate(rawPropertyValue);
204 csvFieldValidationContext.setGeneratedObject(generatedObject);
205 csvFieldValidationContext.setCurrentCsvLine(line);
206 try {
207 validationCommand.execute(csvFieldValidationContext);
208 } catch (Exception e) {
209 log.error("Validation failure.", e);
210 throw new ValidationException("The specified value, "
211 + rawPropertyValue
212 + ", is invalid for the given validator, "
213 + csvFieldValidationContext
214 .getCurrentValidationCommandName());
215 }
216 }
217
218 if (formatter != null) {
219 try {
220 formattedPropertyValue = formatter
221 .formatString(rawPropertyValue);
222 } catch (Exception e) {
223 log.error("Conversion failure using "
224 + formatter.getClass().getName() + " on "
225 + rawPropertyValue
226 + " with an expected property name of "
227 + getCsvToObjectExpression()
228 + " and an expected index of " + getColumnIndex());
229 throw new RuntimeException(e);
230 }
231 }
232
233 return formattedPropertyValue;
234 }
235
236 /***
237 * This method returns the "adjusted" (post validation and formatting)
238 * property value. If there is a problem with validation or formatting, a
239 * {@link ValidationException} is thrown. While this is bad, it may not
240 * indicate that the whole file is bad; it might just be the current record.
241 * Just call {@link CsvToObjectMapper#loadNextRecord()} and try
242 * {@link CsvToObjectMapper#generateObjectFromCurrentCsvRecord()} again.
243 *
244 * @param object
245 * The object to convert to CSV field representation.
246 * @return CSV field representation of the given object.
247 * @throws ValidationException
248 * if the object cannot be validated.
249 */
250 public final String getCsvFieldValueFromObject(Object object)
251 throws ValidationException {
252 String stringValue = null;
253
254 if (formatter != null) {
255 try {
256 stringValue = formatter.formatObject(object);
257 } catch (Exception e) {
258 log.error("Conversion failure using "
259 + formatter.getClass().getName() + " on " + object
260 + " with an expected property name of "
261 + getCsvToObjectExpression()
262 + " and an expected index of " + getColumnIndex());
263 throw new RuntimeException(e);
264 }
265 } else if (object != null) {
266 stringValue = object.toString();
267 }
268
269 return stringValue;
270 }
271
272 /***
273 * @param validationCommand
274 * the validators to set
275 */
276 public void setValidationCommand(Command validationCommand) {
277 this.validationCommand = validationCommand;
278 }
279
280 /***
281 * @param beanName
282 * the beanName to set
283 */
284 public final void setBeanName(String beanName) {
285 this.beanName = beanName;
286 }
287
288 /***
289 * @return the beanName
290 */
291 public final String getBeanName() {
292 return beanName;
293 }
294
295 /***
296 // * @deprecated
297 // * @see #complexProperty
298 // * @return
299 // */
300
301
302
303
304 /***
305 // * @deprecated
306 // * @see #complexProperty
307 // */
308
309
310
311
312 /***
313 * @return the csvToObjectExpression
314 */
315 public final String getCsvToObjectExpression() {
316 return csvToObjectExpression;
317 }
318
319 /***
320 * @param csvToObjectExpression
321 * the csvToObjectExpression to set
322 */
323 public final void setCsvToObjectExpression(
324 final String csvToObjectExpression) {
325 this.csvToObjectExpression = csvToObjectExpression;
326 }
327
328 /***
329 * @return the objectToCsvExpression
330 */
331 public final String getObjectToCsvExpression() {
332 return objectToCsvExpression;
333 }
334
335 /***
336 * @param objectToCsvExpression
337 * the objectToCsvExpression to set
338 */
339 public final void setObjectToCsvExpression(
340 final String objectToCsvExpression) {
341 this.objectToCsvExpression = objectToCsvExpression;
342 }
343
344
345
346
347
348
349
350
351
352
353
354 @Override
355 /***
356 *
357 */
358 public final Object clone() {
359 CsvFieldMapping newCsvFieldMapping = new CsvFieldMapping();
360 newCsvFieldMapping.beanName = this.beanName;
361 newCsvFieldMapping.columnIndex = this.columnIndex;
362
363 newCsvFieldMapping.csvToObjectExpression = new String(
364 this.csvToObjectExpression.toCharArray());
365 newCsvFieldMapping.formatter = this.formatter;
366 newCsvFieldMapping.objectToCsvExpression = new String(
367 this.objectToCsvExpression.toCharArray());
368 newCsvFieldMapping.validationCommand = this.validationCommand;
369
370 return newCsvFieldMapping;
371 }
372
373 /***
374 * @return the csvFieldHeader
375 */
376 public final String getCsvFieldHeader() {
377 return csvFieldHeader;
378 }
379
380 /***
381 * @param csvFieldHeader
382 * the csvFieldHeader to set
383 */
384 public final void setCsvFieldHeader(final String csvFieldHeader) {
385 this.csvFieldHeader = csvFieldHeader;
386 }
387 }