001: /*
002: * $Id: BeanUtils.java,v 1.44 2007/09/18 08:45:10 agoubard Exp $
003: *
004: * Copyright 2003-2007 Orange Nederland Breedband B.V.
005: * See the COPYRIGHT file for redistribution and use restrictions.
006: */
007: package org.xins.common;
008:
009: import java.lang.reflect.Constructor;
010: import java.lang.reflect.Method;
011: import java.util.AbstractList;
012: import java.util.AbstractSet;
013: import java.util.ArrayList;
014: import java.util.Calendar;
015: import java.util.Collection;
016: import java.util.HashSet;
017: import java.util.Iterator;
018: import java.util.List;
019: import java.util.Map;
020: import java.util.Properties;
021: import java.util.Set;
022:
023: import org.xins.common.collections.ChainedMap;
024: import org.xins.common.collections.PropertyReader;
025: import org.xins.common.collections.PropertyReaderConverter;
026: import org.xins.common.service.Descriptor;
027: import org.xins.common.service.TargetDescriptor;
028: import org.xins.common.text.TextUtils;
029: import org.xins.common.types.EnumItem;
030: import org.xins.common.types.ItemList;
031: import org.xins.common.types.standard.Date;
032: import org.xins.common.types.standard.Timestamp;
033: import org.xins.common.xml.Element;
034:
035: /**
036: * This class contains some utility methods that fills an object with values
037: * from another object.
038: *
039: * @version $Revision: 1.44 $ $Date: 2007/09/18 08:45:10 $
040: * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a>
041: *
042: * @since XINS 1.5.0.
043: */
044: public class BeanUtils {
045:
046: /**
047: * Constant used to identified some methods.
048: */
049: private static final Class[] STRING_CLASS = { String.class };
050:
051: /**
052: * Get the values returned by the get methods of the source object and
053: * call the set method of the destination object for the same property.
054: *
055: * e.g. String getFirstName() value of the source object will be used to
056: * invoke setFirstName(String) of the destination object.
057: *
058: * If the no matching set method exists or the set method parameter is not the
059: * same type as the object returned by the get method, the property is ignored.
060: *
061: * @param source
062: * the source object to get the values from. Cannot be <code>null</code>.
063: * @param destination
064: * the destination object to put the values in. Cannot be <code>null</code>.
065: *
066: * @return
067: * the populated object, never <code>null</code>.
068: *
069: * @throws IllegalArgumentException
070: * if <code>source == null || destination == null</code>.
071: */
072: public static Object populate(Object source, Object destination)
073: throws IllegalArgumentException {
074: return populate(source, destination, null);
075: }
076:
077: /**
078: * Get the values returned by the get methods of the source object and
079: * call the set method of the destination object for the same property.
080: *
081: * e.g. String getFirstName() value of the source object will be used to
082: * invoke setFirstName(String) of the destination object.
083: *
084: * If the no matching set method exists or the set method parameter is not the
085: * same type as the object returned by the get method, the property is ignored.
086: *
087: * @param source
088: * the source object to get the values from. Cannot be <code>null</code>.
089: * @param destination
090: * the destination object to put the values in. Cannot be <code>null</code>.
091: * @param propertiesMapping
092: * the mapping between properties which does not have the same name.
093: *
094: * @return
095: * the populated object, never <code>null</code>.
096: *
097: * @throws IllegalArgumentException
098: * if <code>source == null || destination == null</code>.
099: */
100: public static Object populate(Object source, Object destination,
101: Properties propertiesMapping)
102: throws IllegalArgumentException {
103:
104: MandatoryArgumentChecker.check("source", source, "destination",
105: destination);
106: // Go through all get methods of the source object
107: Method[] sourceMethods = source.getClass().getMethods();
108: for (int i = 0; i < sourceMethods.length; i++) {
109: String getMethodName = sourceMethods[i].getName();
110: Class getMethodReturnType = sourceMethods[i]
111: .getReturnType();
112: if ((getMethodName.startsWith("get")
113: && getMethodName.length() > 3 && !getMethodName
114: .equals("getClass"))
115: || (getMethodName.startsWith("is")
116: && getMethodName.length() > 2 && (getMethodReturnType == Boolean.class || getMethodReturnType == Boolean.TYPE))
117: || (getMethodName.startsWith("has")
118: && getMethodName.length() > 3 && (getMethodReturnType == Boolean.class || getMethodReturnType == Boolean.TYPE))) {
119:
120: // Determine the name of the set method
121: String destProperty = null;
122: if (getMethodName.startsWith("is")) {
123: destProperty = getMethodName.substring(2);
124: } else {
125: destProperty = getMethodName.substring(3);
126: }
127: if (propertiesMapping != null
128: && propertiesMapping.getProperty(destProperty) != null) {
129: destProperty = propertiesMapping
130: .getProperty(destProperty);
131: }
132: String setMethodName = "set" + destProperty;
133:
134: // Invoke the set method with the value returned by the get method
135: try {
136: Object value = sourceMethods[i]
137: .invoke(source, null);
138: if (value != null) {
139: Object setValue = convertObject(value,
140: destination, destProperty);
141: if (setValue != null) {
142: invokeMethod(destination, setMethodName,
143: setValue);
144: }
145: }
146: } catch (Exception nsmex) {
147:
148: // Ignore this property
149: Utils.logIgnoredException(nsmex);
150: }
151: }
152: }
153:
154: // If the source object has a data section, fill the destination with it
155: try {
156: Method dataElementMethod = source.getClass().getMethod(
157: "dataElement", null);
158: Object dataElement = dataElementMethod.invoke(source, null);
159: if ("org.xins.client.DataElement".equals(dataElement
160: .getClass().getName())) {
161: Method toXMLElementMethod = dataElement.getClass()
162: .getMethod("toXMLElement", null);
163: Element element = (Element) toXMLElementMethod.invoke(
164: dataElement, null);
165: xmlToObject(element, destination);
166: }
167: } catch (Exception e) {
168: // Probably no method found
169: }
170: return destination;
171: }
172:
173: /**
174: * Converts the source object to an object of another class.
175: *
176: * @param origValue
177: * the original value of the object to be converted, if needed. Cannot be <code>null</code>.
178: * @param destClass
179: * the destination class in which the object should be converted, cannot be <code>null</code>.
180: *
181: * @return
182: * the converted object or <code>null</code> if the object cannot be converted.
183: *
184: * @since XINS 2.0.
185: */
186: public static Object convert(Object origValue, Class destClass) {
187:
188: if (origValue.getClass() == destClass) {
189: return origValue;
190: }
191: try {
192: // Convert a String or an EnumItem to another EnumItem.
193: if (EnumItem.class.isAssignableFrom(destClass)) {
194: String enumTypeClassName = destClass.getName()
195: .substring(0, destClass.getName().length() - 5);
196: Object enumType = Class.forName(enumTypeClassName)
197: .getDeclaredField("SINGLETON").get(null);
198: Method convertionMethod = enumType.getClass()
199: .getMethod("getItemByValue", STRING_CLASS);
200: Object[] convertParams = { origValue.toString() };
201: Object convertedObj = convertionMethod.invoke(null,
202: convertParams);
203: return convertedObj;
204:
205: // Convert whatever to a String
206: } else if (destClass == String.class) {
207: return origValue.toString();
208:
209: // Convert an Object to a boolean
210: } else if (destClass == Boolean.class
211: || destClass == Boolean.TYPE) {
212: if ("true".equals(origValue)
213: || Boolean.TRUE.equals(origValue)) {
214: return Boolean.TRUE;
215: } else if ("false".equals(origValue)
216: || Boolean.FALSE.equals(origValue)) {
217: return Boolean.FALSE;
218: }
219:
220: // Convert a String to a date
221: } else if (origValue instanceof String
222: && destClass == Date.Value.class) {
223: return Date.SINGLETON.fromString((String) origValue);
224:
225: // Convert a String to a timestamp
226: } else if (origValue instanceof String
227: && destClass == Timestamp.Value.class) {
228: return Timestamp.SINGLETON
229: .fromString((String) origValue);
230:
231: // Convert a Collection (List,Set) to a ListItem
232: } else if (origValue instanceof Collection
233: && ItemList.class.isAssignableFrom(destClass)) {
234: ItemList destValue = (ItemList) destClass.newInstance();
235: destValue.add((Collection) origValue);
236: return destValue;
237:
238: // Convert a ListItem to a collection
239: } else if (origValue instanceof ItemList
240: && Collection.class.isAssignableFrom(destClass)) {
241: Class collectionClass = destClass;
242: if (destClass.isAssignableFrom(AbstractList.class)
243: || destClass == List.class
244: || destClass == Collection.class) {
245: collectionClass = ArrayList.class;
246: } else if (destClass
247: .isAssignableFrom(AbstractSet.class)
248: || destClass == Set.class) {
249: collectionClass = HashSet.class;
250: }
251: Collection destValue = (Collection) collectionClass
252: .newInstance();
253: Collection values = ((ItemList) origValue).get();
254: destValue.addAll(values);
255: return destValue;
256:
257: // Convert a Date or Calendar to a Date.Value or a Timestamp.Value
258: } else if ((origValue instanceof java.util.Date | origValue instanceof Calendar)
259: && (destClass == Date.Value.class || destClass == Timestamp.Value.class)) {
260: Class[] idemClass = { origValue.getClass() };
261: Object[] valueArgs = { origValue };
262: Constructor dateConstructor = destClass
263: .getConstructor(idemClass);
264: return dateConstructor.newInstance(valueArgs);
265:
266: // Convert a Date.Value to a Date
267: } else if (origValue instanceof Date.Value
268: && destClass == java.util.Date.class) {
269: return ((Date.Value) origValue).toDate();
270:
271: // Convert a Timestamp.Value to a Date
272: } else if (origValue instanceof Timestamp.Value
273: && destClass == java.util.Date.class) {
274: return ((Timestamp.Value) origValue).toDate();
275:
276: // Convert a String to whatever is asked
277: } else if (origValue instanceof String) {
278: Method convertionMethod = null;
279: if (destClass.isPrimitive()) {
280: if (destClass == Byte.TYPE) {
281: destClass = Byte.class;
282: } else if (destClass == Short.TYPE) {
283: destClass = Short.class;
284: } else if (destClass == Integer.TYPE) {
285: destClass = Integer.class;
286: } else if (destClass == Long.TYPE) {
287: destClass = Long.class;
288: } else if (destClass == Float.TYPE) {
289: destClass = Float.class;
290: } else if (destClass == Double.TYPE) {
291: destClass = Double.class;
292: }
293: }
294: try {
295: convertionMethod = destClass.getMethod("valueOf",
296: STRING_CLASS);
297: } catch (NoSuchMethodException nsmex) {
298: //Ignore
299: }
300: if (convertionMethod == null) {
301: try {
302: convertionMethod = destClass.getMethod(
303: "fromStringForOptional", STRING_CLASS);
304: } catch (NoSuchMethodException nsmex) {
305: //Ignore
306: }
307: }
308: if (convertionMethod != null) {
309: String[] convertParams = { origValue.toString() };
310: Object convertedObj = convertionMethod.invoke(null,
311: convertParams);
312: return convertedObj;
313: }
314:
315: // Convert a Number to the primitive type
316: } else if (origValue instanceof Number
317: && destClass.isPrimitive()) {
318: return origValue;
319: }
320: } catch (Exception ex) {
321: Log.log_1600(String.valueOf(origValue), origValue
322: .getClass().getName(), destClass.getName(), ex
323: .getClass().getName(), ex.getMessage());
324: }
325: return null;
326: }
327:
328: /**
329: * Converts the value of an object to another object in case that the
330: * set method doesn't accept the same obejct as the get method.
331: *
332: * @param origValue
333: * the original value of the object to be converted, if needed. Cannot be <code>null</code>.
334: * @param destination
335: * the destination class containing the set method, cannot be <code>null</code>.
336: * @param property
337: * the name of the destination property, cannot be <code>null</code>.
338: *
339: * @return
340: * the converted object.
341: *
342: * @throws Exception
343: * if error occurs when using the reflection API.
344: */
345: private static Object convertObject(Object origValue,
346: Object destination, String property) throws Exception {
347: String setMethodName = "set"
348: + TextUtils.firstCharUpper(property);
349:
350: // First test if the method with the same class as source exists
351: try {
352: Class[] idemClass = { origValue.getClass() };
353: destination.getClass().getMethod(setMethodName, idemClass);
354: return origValue;
355: } catch (NoSuchMethodException nsmex) {
356: // Ignore, try to find the other methods
357: }
358:
359: Method[] destMethods = destination.getClass().getMethods();
360: for (int i = 0; i < destMethods.length; i++) {
361: if (destMethods[i].getName().equals(setMethodName)) {
362: Class destClass = destMethods[i].getParameterTypes()[0];
363: Object converted = convert(origValue, destClass);
364: if (converted != null) {
365: return converted;
366: }
367: }
368: }
369:
370: // No method found
371: return null;
372: }
373:
374: /**
375: * Fills the result object with of the content of the XML element object.
376: *
377: * @param element
378: * the XML element object, can be <code>null</code>.
379: * @param result
380: * the object to put the values in, cannot be <code>null</code>.
381: * @param elementMapping
382: * a Map<String, String> that maps the name of the source element
383: * to the name of the destination object, can be <code>null</code>.
384: * @param attributeMapping
385: * a Map<String, String> that maps the attributes of the elements,
386: * can be <code>null</code>.
387: *
388: * @return
389: * the result object filled with the values of the element object, never <code>null</code>.
390: *
391: * @since XINS 2.0.
392: */
393: public static Object xmlToObject(Element element, Object result,
394: Map elementMapping, Map attributeMapping) {
395: return xmlToObject(element, result, elementMapping,
396: attributeMapping, true);
397: }
398:
399: /**
400: * Fills the result object with of the content of the XML element object.
401: *
402: * @param element
403: * the XML element object, can be <code>null</code>.
404: * @param result
405: * the object to put the values in, cannot be <code>null</code>.
406: *
407: * @return
408: * the result object filled with the values of the element object, never <code>null</code>.
409: */
410: public static Object xmlToObject(Element element, Object result) {
411: return xmlToObject(element, result, null, null, true);
412: }
413:
414: /**
415: * Fills the result object with of the content of the XML element object.
416: *
417: * @param element
418: * the XML element object, can be <code>null</code>.
419: * @param result
420: * the object to put the values in, cannot be <code>null</code>.
421: * @param elementMapping
422: * a Map<String, String> that maps the name of the source element
423: * to the name of the destination object, can be <code>null</code>.
424: * @param attributeMapping
425: * a Map<String, String> that maps the attributes of the elements,
426: * can be <code>null</code>.
427: * @param topLevel
428: * <code>true</code> if the element passed is the top element,
429: * <code>false</code> if it is a sub-element.
430: *
431: * @return
432: * the result object filled with the values of the element object, never <code>null</code>.
433: */
434: private static Object xmlToObject(Element element, Object result,
435: Map elementMapping, Map attributeMapping, boolean topLevel) {
436:
437: // Short-circuit if arg is null
438: if (element == null) {
439: return result;
440: }
441: String elementName = element.getLocalName();
442: if (topLevel && elementName.equals("data")) {
443: Iterator itChildren = element.getChildElements().iterator();
444: while (itChildren.hasNext()) {
445: Element nextChild = (Element) itChildren.next();
446: xmlToObject(nextChild, result, elementMapping,
447: attributeMapping, true);
448: }
449: } else {
450: try {
451: String hungarianName = TextUtils
452: .firstCharUpper(elementName);
453: if (elementMapping != null
454: && elementMapping.containsKey(elementName)) {
455: hungarianName = TextUtils
456: .firstCharUpper((String) elementMapping
457: .get(elementName));
458: }
459: Class[] argsClasses = { getElementClass(hungarianName,
460: result) };
461: Method addMethod = result.getClass().getMethod(
462: "add" + hungarianName, argsClasses);
463: Object childElement = elementToObject(element, result,
464: elementMapping, attributeMapping);
465: if (childElement != null) {
466: Object[] addArgs = { childElement };
467: addMethod.invoke(result, addArgs);
468: }
469: } catch (Exception ex) {
470: Utils.logIgnoredException(ex);
471: }
472: }
473:
474: return result;
475: }
476:
477: /**
478: * Gets the class matching the XML element.
479: *
480: * @param hungarianName
481: * the name of the XML element starting with an uppercase, cannot be <code>null</code>.
482: * @param result
483: * the base object to get the class from, cannot be <code>null</code>.
484: *
485: * @return
486: * the class to used to fill the XML values with, never <code>null</code>
487: *
488: * @throws ClassNotFoundException
489: * if the class cannot be found.
490: */
491: private static Class getElementClass(String hungarianName,
492: Object result) throws ClassNotFoundException {
493: String elementClassName = result.getClass().getName();
494: if (elementClassName.indexOf("$") != -1) {
495: elementClassName = elementClassName.substring(0,
496: elementClassName.indexOf("$"));
497: }
498: elementClassName += "$" + hungarianName;
499: Class elementClass = Class.forName(elementClassName);
500: return elementClass;
501: }
502:
503: /**
504: * Fills the result object with of the content of the XML element object.
505: *
506: * @param element
507: * the XML element object, cannot be <code>null</code>.
508: * @param result
509: * the object to put the values in, cannot be <code>null</code>.
510: * @param elementMapping
511: * a Map<String, String> that maps the name of the source element
512: * to the name of the destination object, can be <code>null</code>.
513: * @param attributeMapping
514: * a Map<String, String> that maps the attributes of the elements,
515: * can be <code>null</code>.
516: *
517: * @return
518: * the result object filled with the values of the element object, never <code>null</code>.
519: */
520: private static Object elementToObject(Element element,
521: Object result, Map elementMapping, Map attributeMapping) {
522: String elementName = element.getLocalName();
523: String hungarianName = TextUtils.firstCharUpper(elementName);
524: if (elementMapping != null
525: && elementMapping.containsKey(elementName)) {
526: hungarianName = TextUtils
527: .firstCharUpper((String) elementMapping
528: .get(elementName));
529: }
530: //String newElementClassName = result.getClass().getName() + "." + elementName;
531: Object newElement;
532: try {
533: newElement = getElementClass(hungarianName, result)
534: .newInstance();
535: } catch (Exception ex) {
536: Utils.logIgnoredException(ex);
537: return null;
538: }
539:
540: // Copy the attributes
541: Iterator itAttr = element.getAttributeMap().entrySet()
542: .iterator();
543: while (itAttr.hasNext()) {
544: Map.Entry attr = (Map.Entry) itAttr.next();
545: String name = ((Element.QualifiedName) attr.getKey())
546: .getLocalName();
547: if (attributeMapping != null
548: && attributeMapping.containsKey(name)) {
549: name = (String) attributeMapping.get(name);
550: }
551: String value = (String) attr.getValue();
552: try {
553: Object setArg = convertObject(value, newElement, name);
554: invokeMethod(newElement, "set"
555: + TextUtils.firstCharUpper(name), setArg);
556: } catch (Exception ex) {
557: Utils.logIgnoredException(ex);
558: }
559: }
560:
561: // Copy the character data content
562: String text = element.getText();
563: if (text != null && text.trim().length() > 0) {
564: try {
565: Method pcdataMethod = newElement.getClass().getMethod(
566: "pcdata", STRING_CLASS);
567: Object[] pcdataArgs = { text };
568: pcdataMethod.invoke(newElement, pcdataArgs);
569: } catch (Exception ex) {
570: Utils.logIgnoredException(ex);
571: }
572: }
573:
574: // Copy the children
575: Iterator itChildren = element.getChildElements().iterator();
576: while (itChildren.hasNext()) {
577: Element child = (Element) itChildren.next();
578: xmlToObject(child, newElement, elementMapping,
579: attributeMapping, false);
580: }
581:
582: return newElement;
583: }
584:
585: /**
586: * Gets the values returned by the get methods of the given POJO and put
587: * the values in a <code>Map</code>.
588: * The property names returned start with a lowercase.
589: *
590: * @param source
591: * the object from which the values are extracted and put in the Map, should not be <code>null</code>
592: *
593: * @return
594: * the property values of the source object. The key of the Map is
595: * the name of the property and the value is the value as returned by the get method.
596: * Never <code>null</code>.
597: *
598: * @throws IllegalArgumentException
599: * if <code>source == null</code>.
600: *
601: * @since XINS 2.0.
602: */
603: public static Map getParameters(Object source)
604: throws IllegalArgumentException {
605:
606: MandatoryArgumentChecker.check("source", source);
607:
608: // Go through all get methods of the source object
609: ChainedMap valuesMap = new ChainedMap();
610: Method[] sourceMethods = source.getClass().getMethods();
611: for (int i = 0; i < sourceMethods.length; i++) {
612: String getMethodName = sourceMethods[i].getName();
613: Class getMethodReturnType = sourceMethods[i]
614: .getReturnType();
615: if ((getMethodName.startsWith("get")
616: && getMethodName.length() > 3 && !getMethodName
617: .equals("getClass"))
618: || (getMethodName.startsWith("is")
619: && getMethodName.length() > 2 && (getMethodReturnType == Boolean.class || getMethodReturnType == Boolean.TYPE))
620: || (getMethodName.startsWith("has")
621: && getMethodName.length() > 3 && (getMethodReturnType == Boolean.class || getMethodReturnType == Boolean.TYPE))) {
622:
623: // Determine the name of the property
624: String propertyName = null;
625: if (getMethodName.startsWith("is")) {
626: propertyName = getMethodName.substring(2);
627: } else {
628: propertyName = getMethodName.substring(3);
629: }
630: propertyName = TextUtils.firstCharLower(propertyName);
631: try {
632: Object propertyValue = sourceMethods[i].invoke(
633: source, null);
634: if (propertyValue != null) {
635: valuesMap.put(propertyName, propertyValue);
636: }
637: } catch (Exception ex) {
638: Utils.logIgnoredException(ex);
639: }
640: }
641: }
642: return valuesMap;
643: }
644:
645: /**
646: * Gets the values returned by the get methods of the given POJO,
647: * transform it to a String object and put the values in a <code>Map</code>.
648: * The property names returned start with a lowercase.
649: *
650: * @param source
651: * the object from which the values are extracted and put in the Map, should not be <code>null</code>
652: *
653: * @return
654: * the property values of the source object. The key of the Map is
655: * the name of the property and the value is the String representation of
656: * the value as returned by the get method. Never <code>null</code>.
657: *
658: * @throws IllegalArgumentException
659: * if <code>source == null</code>.
660: *
661: * @since XINS 2.0.
662: */
663: public static Map getParametersAsString(Object source)
664: throws IllegalArgumentException {
665: ChainedMap stringMap = new ChainedMap();
666: Map originalMap = getParameters(source);
667: Iterator itParams = originalMap.entrySet().iterator();
668: while (itParams.hasNext()) {
669: Map.Entry nextParam = (Map.Entry) itParams.next();
670: String paramName = (String) nextParam.getKey();
671: Object paramValue = nextParam.getValue();
672: String stringValue = String.valueOf(paramValue);
673: stringMap.put(paramName, stringValue);
674: }
675: return stringMap;
676: }
677:
678: /**
679: * This method is similar to {@link #getParameters(Object)} except that objects
680: * using classes of org.xins.common.type.* packages will be translated into
681: * standard Java object java.* packages.
682: *
683: * @param source
684: * the object from which the values are extracted and put in the Map, should not be <code>null</code>
685: *
686: * @return
687: * the property values of the source object. The key of the Map is
688: * the name of the property and the value is a standard Java object representation of
689: * the value as returned by the get method. Never <code>null</code>.
690: *
691: * @throws IllegalArgumentException
692: * if <code>source == null</code>.
693: *
694: * @since XINS 2.0.
695: */
696: public static Map getParametersAsObject(Object source)
697: throws IllegalArgumentException {
698: ChainedMap objectMap = new ChainedMap();
699: Map originalMap = getParameters(source);
700: Iterator itParams = originalMap.entrySet().iterator();
701: while (itParams.hasNext()) {
702: Map.Entry nextParam = (Map.Entry) itParams.next();
703: String paramName = (String) nextParam.getKey();
704: Object paramValue = nextParam.getValue();
705:
706: // Convertion of the XINS types.
707: if (paramValue instanceof Date.Value) {
708: paramValue = ((Date.Value) paramValue).toDate();
709: } else if (paramValue instanceof Timestamp.Value) {
710: paramValue = ((Timestamp.Value) paramValue).toDate();
711: } else if (paramValue instanceof PropertyReader) {
712: paramValue = PropertyReaderConverter
713: .toProperties((PropertyReader) paramValue);
714: } else if (paramValue instanceof ItemList) {
715: paramValue = ((ItemList) paramValue).get();
716: } else if (paramValue instanceof EnumItem) {
717: paramValue = ((EnumItem) paramValue).getValue();
718: } else if (paramValue instanceof TargetDescriptor) {
719: paramValue = ((TargetDescriptor) paramValue).getURL();
720: } else if (paramValue instanceof Descriptor) {
721: // TODO: Not supported yet
722: }
723: objectMap.put(paramName, paramValue);
724: }
725: return objectMap;
726: }
727:
728: /**
729: * Puts the values of the <code>Map</code> in the destination object (POJO).
730: * If needed the property value is converted to the type needed for the set method.
731: * The property names can start with an uppercase or a lowercase.
732: *
733: * @param properties
734: * the map containing the values to fill the destination object, cannot be <code>null</code>
735: * The key of the <code>Map</code> should be the property name and will be
736: * used to find the set method of the destination object.
737: *
738: * @param destination
739: * the object which should be filled, cannot be <code>null</code>.
740: *
741: * @return
742: * the destination object filled, never <code>null</code>. This object will
743: * be the same as the input parameter.
744: *
745: * @throws IllegalArgumentException
746: * if <code>properties == null || destination == null</code>.
747: *
748: * @since XINS 2.0.
749: */
750: public static Object setParameters(Map properties,
751: Object destination) throws IllegalArgumentException {
752:
753: MandatoryArgumentChecker.check("properties", properties,
754: "destination", destination);
755:
756: // Go through all properties and find the set method
757: Iterator itProperties = properties.entrySet().iterator();
758: while (itProperties.hasNext()) {
759: Map.Entry nextProp = (Map.Entry) itProperties.next();
760: try {
761: String propertyName = (String) nextProp.getKey();
762: Object propertyValue = nextProp.getValue();
763: String methodName = "set"
764: + TextUtils.firstCharUpper(propertyName);
765: Object methodArg = convertObject(propertyValue,
766: destination, propertyName);
767: invokeMethod(destination, methodName, methodArg);
768: } catch (Exception ex) {
769: Utils.logIgnoredException(ex);
770: }
771: }
772: return destination;
773: }
774:
775: /**
776: * Invokes the given method with the given argument.
777: *
778: * @param destination
779: * the object upon which the method should be invoked, cannnot be <code>null</code>.
780: *
781: * @param methodName
782: * the name of the method to invoke, cannot be <code>null</code>.
783: *
784: * @param argument
785: * the argument for the method, can be <code>null</code>.
786: *
787: * @throws Exception
788: * if the call to the method failed for any reason.
789: */
790: private static void invokeMethod(Object destination,
791: String methodName, Object argument) throws Exception {
792: Class argumentClass = argument.getClass();
793: Class[] argsClasses = { argumentClass };
794: if (argument instanceof Boolean) {
795: try {
796: destination.getClass().getMethod(methodName,
797: argsClasses);
798: } catch (NoSuchMethodException nsmex) {
799: argumentClass = Boolean.TYPE;
800: }
801: } else if (argument instanceof Number) {
802: try {
803: destination.getClass().getMethod(methodName,
804: argsClasses);
805: } catch (NoSuchMethodException nsmex) {
806: argumentClass = (Class) argumentClass.getDeclaredField(
807: "TYPE").get(argument);
808: }
809: }
810: Class[] argsClasses2 = { argumentClass };
811: Object[] args = { argument };
812: Method setMethod = destination.getClass().getMethod(methodName,
813: argsClasses2);
814: setMethod.invoke(destination, args);
815: }
816: }
|