001: /*
002: * ====================================================================
003: * JAFFA - Java Application Framework For All
004: *
005: * Copyright (C) 2002 JAFFA Development Group
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: * Redistribution and use of this software and associated documentation ("Software"),
022: * with or without modification, are permitted provided that the following conditions are met:
023: * 1. Redistributions of source code must retain copyright statements and notices.
024: * Redistributions must also contain a copy of this document.
025: * 2. Redistributions in binary form must reproduce the above copyright notice,
026: * this list of conditions and the following disclaimer in the documentation
027: * and/or other materials provided with the distribution.
028: * 3. The name "JAFFA" must not be used to endorse or promote products derived from
029: * this Software without prior written permission. For written permission,
030: * please contact mail to: jaffagroup@yahoo.com.
031: * 4. Products derived from this Software may not be called "JAFFA" nor may "JAFFA"
032: * appear in their names without prior written permission.
033: * 5. Due credit should be given to the JAFFA Project (http://jaffa.sourceforge.net).
034: *
035: * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: */
049:
050: package org.jaffa.util;
051:
052: import org.apache.log4j.Logger;
053: import java.lang.reflect.Method;
054: import java.beans.BeanInfo;
055: import java.beans.Introspector;
056: import java.beans.PropertyDescriptor;
057: import java.beans.IntrospectionException;
058: import java.lang.reflect.InvocationTargetException;
059: import org.jaffa.datatypes.DateOnly;
060: import org.jaffa.datatypes.DateTime;
061: import org.jaffa.datatypes.Currency;
062: import org.jaffa.datatypes.Parser;
063: import org.jaffa.datatypes.exceptions.*;
064:
065: /** This has convenience methods for dealing with Java Beans.
066: */
067: public class BeanHelper {
068: private static Logger log = Logger.getLogger(BeanHelper.class);
069:
070: /** This will inspect the specified java bean, and extract an Object from the beans
071: * getXxx() method, where 'xxx' is the field name passed in.
072: * A null will be returned in case there is any error in invoking the getter.
073: * @param bean The Java Bean.
074: * @param field The field.
075: * @throws NoSuchMethodException if there is no getter for the input field.
076: * @return the output of the getter for the field.
077: */
078: public static Object getField(Object bean, String field)
079: throws NoSuchMethodException {
080: java.lang.reflect.Method method = null;
081: try {
082: // Get the Java Bean Info
083: java.beans.BeanInfo info = java.beans.Introspector
084: .getBeanInfo(bean.getClass());
085: if (info != null) {
086: // Get all the properties
087: java.beans.PropertyDescriptor pd[] = info
088: .getPropertyDescriptors();
089: // Loop for a matching method
090: for (int i = 0; i < pd.length; i++) {
091: if (StringHelper.getLower1(pd[i].getName()).equals(
092: StringHelper.getLower1(field))) {
093: // Match found....
094: method = pd[i].getReadMethod();
095: break;
096: }
097: }
098: }
099: if (method != null) {
100: return method.invoke(bean, new Object[] {});
101: }
102: } catch (Exception ex) {
103: log.error("Introspection of Property " + field
104: + " on Bean " + bean + " failed. Reason : "
105: + ex.getMessage(), ex);
106: return null;
107: }
108:
109: // If we reach here, the method was not found
110: throw new NoSuchMethodException("Field Name = " + field);
111: }
112:
113: /** Get the name of the reader method for the specified string.
114: * For example 'hello' will return 'getHello'
115: * @param field The field.
116: * @return the name of the reader/getter method for the specified string.
117: */
118: public static String getReaderName(String field) {
119: if (field == null)
120: return null;
121: return "get" + field.substring(0, 1).toUpperCase()
122: + field.substring(1);
123: }
124:
125: /** This method will introspect the bean & get the setter method for the input propertyName.
126: * It will then try & convert the propertyValue to the appropriate datatype.
127: * Finally it will invoke the setter.
128: * @return A true indicates, the property was succesfully set to the passed value. A false indicates the property doesn't exist or the propertyValue passed is not compatible with the setter.
129: * @param bean The bean class to be introspected.
130: * @param propertyName The Property being searched for.
131: * @param propertyValue The value to be set.
132: * @throws IntrospectionException if an exception occurs during introspection.
133: * @throws IllegalAccessException if the underlying method is inaccessible.
134: * @throws InvocationTargetException if the underlying method throws an exception.
135: */
136: public static boolean setField(Object bean, String propertyName,
137: String propertyValue) throws IntrospectionException,
138: IllegalAccessException, InvocationTargetException {
139: boolean result = false;
140: BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
141: if (beanInfo != null) {
142: PropertyDescriptor[] pds = beanInfo
143: .getPropertyDescriptors();
144: if (pds != null) {
145: for (int i = 0; i < pds.length; i++) {
146: PropertyDescriptor pd = pds[i];
147: if (StringHelper.getLower1(pd.getName()).equals(
148: StringHelper.getLower1(propertyName))) {
149: Method m = pd.getWriteMethod();
150: Object convertedPropertyValue = null;
151: try {
152: convertedPropertyValue = convertDataType(
153: bean.getClass(), propertyName,
154: propertyValue);
155: } catch (Exception e) {
156: // do nothing
157: break;
158: }
159: m
160: .invoke(
161: bean,
162: new Object[] { convertedPropertyValue });
163: result = true;
164: break;
165: }
166: }
167: }
168: }
169: return result;
170: }
171:
172: /** This method will introspect the beanClass & get the getter method for the input propertyName.
173: * It will then try & convert the propertyValue to the appropriate datatype.
174: * @param beanClass The bean class to be introspected.
175: * @param propertyName The Property being searched for.
176: * @param propertyValue The value to be converted.
177: * @throws IntrospectionException if an exception occurs during introspection.
178: * @throws IllegalArgumentException if the propertyValue cannot be converted to the appropriate datatype.
179: * @return a converted propertyValue compatible with the getter.
180: */
181: public static Object convertDataType(Class beanClass,
182: String propertyName, String propertyValue)
183: throws IntrospectionException, IllegalArgumentException {
184: boolean foundProperty = false;
185: Object convertedPropertyValue = null;
186: BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
187: if (beanInfo != null) {
188: PropertyDescriptor[] pds = beanInfo
189: .getPropertyDescriptors();
190: if (pds != null) {
191: for (int i = 0; i < pds.length; i++) {
192: PropertyDescriptor pd = pds[i];
193: if (StringHelper.getLower1(pd.getName()).equals(
194: StringHelper.getLower1(propertyName))) {
195: // get the property type
196: Class clazz = pd.getPropertyType();
197: if (clazz == String.class) {
198: if (propertyValue == null
199: || propertyValue.length() == 0)
200: convertedPropertyValue = null;
201: else
202: convertedPropertyValue = propertyValue;
203: } else if (clazz == Boolean.TYPE
204: || clazz == Boolean.class) {
205: convertedPropertyValue = Parser
206: .parseBoolean(propertyValue);
207: } else if (clazz == Integer.TYPE
208: || clazz == Integer.class) {
209: try {
210: convertedPropertyValue = new Integer(
211: propertyValue);
212: } catch (NumberFormatException e) {
213: throw new IllegalArgumentException(
214: "Exception raised while trying to convert the input String to an Integer: "
215: + beanClass.getName()
216: + '.' + propertyName
217: + '=' + propertyValue);
218: }
219: } else if (clazz == Long.TYPE
220: || clazz == Long.class) {
221: try {
222: convertedPropertyValue = new Long(
223: propertyValue);
224: } catch (NumberFormatException e) {
225: throw new IllegalArgumentException(
226: "Exception raised while trying to convert the input String to a Long: "
227: + beanClass.getName()
228: + '.' + propertyName
229: + '=' + propertyValue);
230: }
231: } else if (clazz == Float.TYPE
232: || clazz == Float.class) {
233: try {
234: convertedPropertyValue = new Float(
235: propertyValue);
236: } catch (NumberFormatException e) {
237: throw new IllegalArgumentException(
238: "Exception raised while trying to convert the input String to a Float: "
239: + beanClass.getName()
240: + '.' + propertyName
241: + '=' + propertyValue);
242: }
243: } else if (clazz == Double.TYPE
244: || clazz == Double.class) {
245: try {
246: convertedPropertyValue = new Double(
247: propertyValue);
248: } catch (NumberFormatException e) {
249: throw new IllegalArgumentException(
250: "Exception raised while trying to convert the input String to a Double: "
251: + beanClass.getName()
252: + '.' + propertyName
253: + '=' + propertyValue);
254: }
255: } else if (clazz == Byte.TYPE
256: || clazz == Byte.class) {
257: try {
258: convertedPropertyValue = new Byte(
259: propertyValue);
260: } catch (NumberFormatException e) {
261: throw new IllegalArgumentException(
262: "Exception raised while trying to convert the input String to a Byte: "
263: + beanClass.getName()
264: + '.' + propertyName
265: + '=' + propertyValue);
266: }
267: } else if (clazz == Short.TYPE
268: || clazz == Short.class) {
269: try {
270: convertedPropertyValue = new Short(
271: propertyValue);
272: } catch (NumberFormatException e) {
273: throw new IllegalArgumentException(
274: "Exception raised while trying to convert the input String to a Short: "
275: + beanClass.getName()
276: + '.' + propertyName
277: + '=' + propertyValue);
278: }
279: } else if (clazz == Character.TYPE
280: || clazz == Character.class) {
281: if (propertyValue == null
282: || propertyValue.length() == 0)
283: convertedPropertyValue = new Character(
284: ' ');
285: else if (propertyValue.length() == 1)
286: convertedPropertyValue = new Character(
287: propertyValue.charAt(0));
288: else
289: throw new IllegalArgumentException(
290: "Cannot convert the input String to a Character: "
291: + beanClass.getName()
292: + '.' + propertyName
293: + '=' + propertyValue);
294: } else if (clazz == DateOnly.class) {
295: try {
296: convertedPropertyValue = Parser
297: .parseDateOnly(propertyValue);
298: } catch (FormatDateOnlyException e) {
299: throw new IllegalArgumentException(
300: "Exception raised while trying to convert the input String to a DateOnly: "
301: + beanClass.getName()
302: + '.' + propertyName
303: + '=' + propertyValue);
304: }
305: } else if (clazz == DateTime.class) {
306: try {
307: convertedPropertyValue = Parser
308: .parseDateTime(propertyValue);
309: } catch (FormatDateTimeException e) {
310: throw new IllegalArgumentException(
311: "Exception raised while trying to convert the input String to a DateTime: "
312: + beanClass.getName()
313: + '.' + propertyName
314: + '=' + propertyValue);
315: }
316: } else if (clazz == Currency.class) {
317: try {
318: convertedPropertyValue = Parser
319: .parseCurrency(propertyValue);
320: } catch (FormatCurrencyException e) {
321: throw new IllegalArgumentException(
322: "Exception raised while trying to convert the input String to a Currency: "
323: + beanClass.getName()
324: + '.' + propertyName
325: + '=' + propertyValue);
326: }
327: } else {
328: // Unknown or unsupported type.. do nothing !!!
329: throw new IllegalArgumentException(
330: "Unknown/Unsupported datatype "
331: + clazz.getName()
332: + " for the property: "
333: + beanClass.getName() + '.'
334: + propertyName);
335: }
336: foundProperty = true;
337: }
338: }
339: }
340: }
341: if (!foundProperty)
342: throw new IllegalArgumentException(
343: "Could not find the the property: "
344: + beanClass.getName() + '.' + propertyName);
345: return convertedPropertyValue;
346: }
347: }
|