1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 package com.ivata.mask.field;
70 import java.beans.PropertyDescriptor;
71 import java.io.Serializable;
72 import java.lang.reflect.Constructor;
73 import java.lang.reflect.InvocationTargetException;
74 import java.util.Arrays;
75
76 import org.apache.commons.beanutils.PropertyUtils;
77 import org.apache.log4j.Logger;
78
79 import com.ivata.mask.util.StringHandling;
80 import com.ivata.mask.util.SystemException;
81 import com.ivata.mask.validation.ValidationError;
82 import com.ivata.mask.validation.ValidationErrors;
83 /***
84 * <p>
85 * Retrieve the value from a value object for a given field.
86 * </p>
87 *
88 * @since ivata masks 0.1 (2004-05-14)
89 * @author Colin MacLeod
90 * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
91 * @version $Revision: 1.7 $
92 */
93 public class FieldValueConvertor implements Serializable {
94 /***
95 * <p>
96 * Wraps any error encountered when trying retrieve a field value via
97 * reflection.
98 * </p>
99 *
100 * @since ivata masks 0.1 (2004-05-14)
101 * @author Colin MacLeod
102 * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
103 * @version $Revision: 1.7 $
104 */
105 public static class FieldValueException extends RuntimeException {
106 /***
107 * <p>
108 * Construct a field value exception from another throwable.
109 * </p>
110 *
111 * @param throwable
112 * cause of the exception.
113 */
114 public FieldValueException(final Throwable throwable) {
115 super("ERROR (" + throwable.getClass().getName() + "): "
116 + throwable.getMessage());
117 }
118 /***
119 * <p>
120 * Construct a field value exception from another throwable.
121 * </p>
122 *
123 * @param throwable
124 * cause of the exception.
125 * @param location
126 * brief text describing where the error ocurred
127 */
128 public FieldValueException(final Throwable throwable,
129 final String location) {
130 super("ERROR (" + throwable.getClass().getName() + ") " + location
131 + ": " + throwable.getMessage());
132 }
133 }
134 /***
135 * <p>
136 * This log provides tracing and debugging information.
137 * </p>
138 */
139 private Logger log = Logger.getLogger(FieldValueConvertor.class);
140 /***
141 * <p>
142 * Convert a value from a string. Override this method to choose how your
143 * class converts string values to your object class values.
144 * </p>
145 *
146 * <p>
147 * This implementation attempts to instantiate an object of the desired
148 * class by locating a constructor which takes a single string as an
149 * argument.
150 * </p>
151 *
152 * @param propertyClassParam
153 * exact class to be converted to.
154 * @param stringValue
155 * value to be converted.
156 * @return valid object value converted from a string.
157 */
158 public Object convertFromString(final Class propertyClassParam,
159 final String stringValue) {
160 if (StringHandling.isNullOrEmpty(stringValue)) {
161 return null;
162 }
163 Constructor stringConstructor;
164 Class propertyClass;
165 if (propertyClassParam.isPrimitive()) {
166 try {
167 propertyClass = DefaultFieldValueConvertorFactory
168 .convertPrimitiveType(propertyClassParam);
169 } catch (SystemException e) {
170 throw new RuntimeException(e);
171 }
172 } else {
173 propertyClass = propertyClassParam;
174 }
175 try {
176 stringConstructor = propertyClass
177 .getConstructor(new Class[] {
178 String.class
179 });
180 } catch (SecurityException e) {
181 throw new FieldValueException(e, "constructing '"
182 + propertyClass.getName() + "' from string value '"
183 + stringValue + "'");
184 } catch (NoSuchMethodException e) {
185 throw new FieldValueException(e, "constructing '"
186 + propertyClass.getName() + "' from string value '"
187 + stringValue + "'");
188 }
189 Object value;
190 try {
191 value = stringConstructor.newInstance(new Object[] {
192 stringValue
193 });
194 } catch (IllegalArgumentException e) {
195 throw new FieldValueException(e, "constructing '"
196 + propertyClass.getName() + "' from string value '"
197 + stringValue + "'");
198 } catch (InstantiationException e) {
199 throw new FieldValueException(e, "constructing '"
200 + propertyClass.getName() + "' from string value '"
201 + stringValue + "'");
202 } catch (IllegalAccessException e) {
203 throw new FieldValueException(e, "constructing '"
204 + propertyClass.getName() + "' from string value '"
205 + stringValue + "'");
206 } catch (InvocationTargetException e) {
207 throw new FieldValueException(e, "constructing '"
208 + propertyClass.getName() + "' from string value '"
209 + stringValue + "'");
210 }
211 return value;
212 }
213 /***
214 * <p>
215 * Get the value of a named property within an object.
216 * </p>
217 *
218 * @param object
219 * POJO for which to return the field value.
220 * @param propertyName
221 * name of the property/field to return the value for.
222 * @param defaultValue
223 * value to use if none is set.
224 * @return the value of the named property.
225 */
226 protected final Object getObjectValue(final Object object,
227 final String propertyName, final Object defaultValue) {
228 Object objectValue;
229 try {
230 objectValue = PropertyUtils.getProperty(object, propertyName);
231 } catch (IllegalAccessException e) {
232 throw new FieldValueException(e);
233 } catch (InvocationTargetException e) {
234 throw new FieldValueException(e);
235 } catch (NoSuchMethodException e) {
236
237 objectValue = null;
238 }
239 if (objectValue == null) {
240 objectValue = defaultValue;
241 }
242 return objectValue;
243 }
244 /***
245 * <p>
246 * Get the value of the field provided, in the value object supplied, and
247 * return the string equivalent.
248 * </p>
249 *
250 * @param object
251 * POJO for which to return the field value.
252 * @param propertyName
253 * name of the property/field to return the value for.
254 * @param defaultValue
255 * value to use if none is set.
256 * @return the value of the named property, as a string.
257 */
258 public final String getStringValue(final Object object,
259 final String propertyName, final String defaultValue) {
260 Object objectValue = getObjectValue(object, propertyName, defaultValue);
261 return toString(objectValue);
262 }
263 /***
264 * <p>
265 * Set the value of the field provided, in the value object supplied.
266 * </p>
267 *
268 * <p>
269 * This implementation attempts to instantiate an object of the desired
270 * class by locating a constructor which takes a single string as an
271 * argument.
272 * </p>
273 *
274 * @param object
275 * POJO for which to set the field value.
276 * @param field
277 * field to be set.
278 * @param stringValue
279 * new string equivalent value of this field.
280 * @return errors, if there are any errors with the field values, otherwise
281 * an empty collection.
282 */
283 public final ValidationErrors setStringValue(final Object object,
284 final Field field, final String stringValue) {
285 ValidationErrors validationErrors = new ValidationErrors();
286 PropertyDescriptor descriptor;
287 try {
288 descriptor = PropertyUtils.getPropertyDescriptor(object, field
289 .getName());
290 } catch (IllegalAccessException e) {
291 throw new FieldValueException(e);
292 } catch (InvocationTargetException e) {
293 throw new FieldValueException(e);
294 } catch (NoSuchMethodException e) {
295 throw new FieldValueException(e);
296 }
297
298 if (descriptor == null) {
299 return validationErrors;
300 }
301 Class propertyClass = descriptor.getPropertyType();
302 Object value;
303 try {
304
305 if ("int".equals(propertyClass.getName())) {
306 propertyClass = Integer.class;
307 } else if ("short".equals(propertyClass.getName())) {
308 propertyClass = Short.class;
309 } else if ("long".equals(propertyClass.getName())) {
310 propertyClass = Long.class;
311 } else if ("float".equals(propertyClass.getName())) {
312 propertyClass = Float.class;
313 } else if ("double".equals(propertyClass.getName())) {
314 propertyClass = Double.class;
315 }
316 value = convertFromString(propertyClass, stringValue);
317 } catch (FieldValueException e) {
318 validationErrors.add(new ValidationError(
319 "errors.field.invalidValue",
320 Arrays.asList(new Object[] {
321 stringValue, field })));
322 return validationErrors;
323 }
324 if (validationErrors.isEmpty()) {
325 try {
326 PropertyUtils.setProperty(object, field.getName(), value);
327 } catch (IllegalAccessException e) {
328 throw new FieldValueException(e);
329 } catch (InvocationTargetException e) {
330 throw new FieldValueException(e);
331 } catch (NoSuchMethodException e) {
332
333 if (!("idString".equals(field.getName()) || "class".equals(field
334 .getName()))) {
335 log.warn("Warning (" + e.getClass().getName()
336 + ": setting value '" + value + "' to field '"
337 + field + " on object " + object + ": "
338 + e.getMessage());
339 }
340 }
341 }
342 return validationErrors;
343 }
344 /***
345 * <p>
346 * Convert a field object value into a string. Override this method to
347 * convert for a specific type.
348 * </p>
349 *
350 * @param objectValue
351 * object to be converted.
352 * @return string equivalent.
353 */
354 protected String toString(final Object objectValue) {
355
356 if (objectValue == null) {
357 return "";
358 } else {
359 return objectValue.toString();
360 }
361 }
362 }