/* * Copyright 2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License") * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.sf.beanlib; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; /** * Bean Getter. * * @author Joe D. Velopar */ public class BeanGetter { /** Singleton instance. */ // private static final boolean debug = false; private final Logger log = Logger.getLogger(this.getClass()); /** Returns the string value of the given property of the specified java bean class. */ public final String getPropertyAsString(Object bean, PropertyDescriptor pd) { Method m = pd.getReadMethod(); Object ret; try { ret = m.invoke(bean); } catch (IllegalAccessException e) { log.error("", e); throw new BeanlibException(e); } catch (InvocationTargetException e) { log.error("", e.getTargetException()); throw new BeanlibException(e.getTargetException()); } return ret == null ? (String) ret : ret.toString(); } /** Returns the property name to descriptor map for the given bean class. */ public final Map<String, PropertyDescriptor> getPropertyName2DescriptorMap(Class<?> beanClass) { Map<String, PropertyDescriptor> map = new HashMap<String, PropertyDescriptor>(); BeanInfo bi; try { bi = Introspector.getBeanInfo(beanClass); } catch (IntrospectionException e) { log.error("", e); throw new BeanlibException(e); } PropertyDescriptor[] pda = bi.getPropertyDescriptors(); for (int i = pda.length - 1; i > -1; i--) { PropertyDescriptor pd = pda[i]; map.put(pd.getName(), pd); } return Collections.unmodifiableMap(map); } /** * Returns a hash code modified from the input hash code with the value returned from a JavaBean reader method using * the algorithm suggested in Item 8 of Effective Java by Joshua Bloch. * * @param hashCode starting hash code * @param m a JavaBean reader method * @param bean JavaNean object */ private int beanReaderHash(int hashCode, Method m, Object bean) throws IllegalAccessException, InvocationTargetException { int result = hashCode == 0 ? 17 : hashCode; Object v = m.invoke(bean); if (v == null) return result; Class<?> c = m.getReturnType(); return hashReturnValue(result, c, v); } /** * @param hashCode hash code value before invoking this method * @param c class of value returned from a JavaBean reader method * @param v value returned from a JavaBean reader method * @return the hash code by taking into account the give value returned from a JavaBean reader method */ private int hashReturnValue(int hashCode, Class<?> c, Object v) { if (v == null) return hashCode; if (c == Boolean.class) { boolean b = ((Boolean) v).booleanValue(); return b ? hashCode : addBeanHashCode(hashCode, 1); } if (c == Byte.class) { Byte b = (Byte) v; return addBeanHashCode(hashCode, b.byteValue()); } if (c == Character.class) { Character ch = (Character) v; return addBeanHashCode(hashCode, ch.charValue()); } if (c == Short.class) { Short s = (Short) v; return addBeanHashCode(hashCode, s.shortValue()); } if (c == Integer.class) { Integer i = (Integer) v; return addBeanHashCode(hashCode, i.intValue()); } if (c == Long.class) { Long L = (Long) v; long l = L.longValue(); return addBeanHashCode(hashCode, (int) (l ^ (l >>> 32))); } if (c == Float.class) { Float F = (Float) v; return addBeanHashCode(hashCode, Float.floatToIntBits(F.floatValue())); } if (c == Array.class) { Object[] a = (Object[]) v; for (int i = a.length - 1; i > -1; i--) { Object o = a[i]; hashCode = addBeanHashCode(hashCode, hashReturnValue(hashCode, o.getClass(), o)); } return hashCode; } // Object reference return addBeanHashCode(hashCode, v.hashCode()); } /** * @param hashCode hash code to add to * @param delta value to be added to the hash code * @return resultant hash code added with the given delta value. */ private int addBeanHashCode(int hashCode, int delta) { return 37 * hashCode + delta; } /** * Returns a hash code for the given JavaBean object for all the reader methods using the algorithm suggested in * Item 8 of Effective Java by Joshua Bloch. * * @param bean java bean for which the hash code is to be calculated. * @return the hash code for the given java bean. */ public int getBeanHashCode(Object bean) { Class<?> beanClass = bean.getClass(); BeanInfo bi; try { bi = Introspector.getBeanInfo(beanClass); } catch (IntrospectionException e) { log.error("", e); throw new BeanlibException(e); } int hashCode = 0; PropertyDescriptor[] pda = bi.getPropertyDescriptors(); try { for (int i = pda.length - 1; i > -1; i--) { PropertyDescriptor pd = pda[i]; Method m = pd.getReadMethod(); hashCode = beanReaderHash(hashCode, m, bean); } } catch (IllegalAccessException e) { log.error("", e); throw new BeanlibException(e); } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); log.error("", t); throw new BeanlibException(t); } return hashCode; } }