View Javadoc

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      // private boolean complexProperty;
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     // public String getPropertyName() {
113     // return getCsvToObjectExpression();
114     // }
115 
116     // /***
117     // * @param csvToObjectExpression
118     // * the csvToObjectExpression to set
119     // * @deprecated use {@link #setCsvToObjectExpression(String)} instead.
120     // */
121     // public void setPropertyName(String propertyName) {
122     // setCsvToObjectExpression(propertyName);
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     // public Object getPropertyValue(String rawPropertyValue,
172     // Object generatedObject, List<String> line)
173     // throws ValidationException {
174     // return getObjectValueFromCsvField(rawPropertyValue, generatedObject,
175     // line);
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     // public boolean isComplexProperty() {
301     // return complexProperty;
302     // }
303 
304     // /***
305     // * @deprecated
306     // * @see #complexProperty
307     // */
308     // public void setComplexProperty(boolean complexProperty) {
309     // this.complexProperty = complexProperty;
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      * (non-Javadoc)
346      * 
347      * @see java.lang.Object#clone()
348      */
349     /*
350      * (non-Javadoc)
351      * 
352      * @see java.lang.Object#clone()
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 	// newCsvFieldMapping.complexProperty = this.complexProperty;
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 }