Refactoring some code

This commit is contained in:
Patrick Gotthard 2013-11-15 23:27:01 +01:00
parent 25aba9758e
commit cb03da8c67
6 changed files with 242 additions and 204 deletions

View file

@ -24,7 +24,6 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -32,8 +31,7 @@ import java.util.Set;
/** /**
* Obtains all property descriptors from a bean (interface or implementation). * Obtains all property descriptors from a bean (interface or implementation).
* <p> * <p>
* The java.beans.Introspector does not process the interfaces hierarchy chain, * The java.beans.Introspector does not process the interfaces hierarchy chain, this one does.
* this one does.
* <p> * <p>
* *
* @author Alejandro Abdelnur * @author Alejandro Abdelnur
@ -42,29 +40,98 @@ import java.util.Set;
public class BeanIntrospector { public class BeanIntrospector {
private static final Map<Class<?>, PropertyDescriptor[]> introspected = new HashMap<Class<?>, PropertyDescriptor[]>(); private static final Map<Class<?>, PropertyDescriptor[]> introspected = new HashMap<Class<?>, PropertyDescriptor[]>();
private static final String SETTER = "set";
private static final String GETTER = "get";
private static final String BOOLEAN_GETTER = "is";
public static synchronized PropertyDescriptor[] getPropertyDescriptors(final Class<?> klass) throws IntrospectionException { /**
PropertyDescriptor[] descriptors = introspected.get(klass); * Extract all {@link PropertyDescriptor}s for properties with getters and setters for the given class.
*
* @param clazz The class to extract the desired {@link PropertyDescriptor}s from
* @return All {@link PropertyDescriptor} for properties with getters and setters for the given class.
* @throws IntrospectionException When the extraction of the desired {@link PropertyDescriptor}s failed
*/
private static synchronized PropertyDescriptor[] getPropertyDescriptors(final Class<?> clazz) throws IntrospectionException {
PropertyDescriptor[] descriptors = introspected.get(clazz);
if (descriptors == null) { if (descriptors == null) {
descriptors = getPDs(klass); descriptors = getPDs(clazz);
introspected.put(klass, descriptors); introspected.put(clazz, descriptors);
} }
return descriptors; return descriptors;
} }
private static PropertyDescriptor[] getPDs(final Class<?> klass) throws IntrospectionException { /**
final Method[] methods = klass.getMethods(); * Extract all {@link PropertyDescriptor}s for properties with a getter that does not come from {@link Object} and does not accept parameters.
final Map<String, PropertyDescriptor> getters = getPDs(methods, false); *
final Map<String, PropertyDescriptor> setters = getPDs(methods, true); * @param clazz The class to extract the desired {@link PropertyDescriptor}s from
final List<PropertyDescriptor> pds = merge(getters, setters); * @return All {@link PropertyDescriptor}s for properties with a getter that does not come from {@link Object} and does not accept parameters.
final PropertyDescriptor[] array = new PropertyDescriptor[pds.size()]; * @throws IntrospectionException When the extraction of the desired {@link PropertyDescriptor}s failed
pds.toArray(array); */
return array; public static List<PropertyDescriptor> getPropertyDescriptorsWithGetters(final Class<?> clazz) throws IntrospectionException {
final List<PropertyDescriptor> relevantDescriptors = new ArrayList<PropertyDescriptor>();
final PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(clazz);
if (propertyDescriptors != null) {
for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
final Method getter = propertyDescriptor.getReadMethod();
final boolean getterExists = getter != null;
if (getterExists) {
final boolean getterFromObject = getter.getDeclaringClass() == Object.class;
final boolean getterWithoutParams = getter.getParameterTypes().length == 0;
if (!getterFromObject && getterWithoutParams) {
relevantDescriptors.add(propertyDescriptor);
}
}
}
}
return relevantDescriptors;
} }
private static final String SETTER = "set"; /**
private static final String GETTER = "get"; * Extract all {@link PropertyDescriptor}s for properties with a getter (that does not come from {@link Object} and does not accept parameters) and a
private static final String BOOLEAN_GETTER = "is"; * setter.
*
* @param clazz The class to extract the desired {@link PropertyDescriptor}s from
* @return All {@link PropertyDescriptor}s for properties with a getter (that does not come from {@link Object} and does not accept parameters) and a
* setter.
* @throws IntrospectionException When the extraction of the desired {@link PropertyDescriptor}s failed
*/
public static List<PropertyDescriptor> getPropertyDescriptorsWithGettersAndSetters(final Class<?> clazz) throws IntrospectionException {
final List<PropertyDescriptor> relevantDescriptors = new ArrayList<PropertyDescriptor>();
final List<PropertyDescriptor> propertyDescriptors = getPropertyDescriptorsWithGetters(clazz);
for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
final Method setter = propertyDescriptor.getWriteMethod();
final boolean setterExists = setter != null;
if (setterExists) {
relevantDescriptors.add(propertyDescriptor);
}
}
return relevantDescriptors;
}
private static PropertyDescriptor[] getPDs(final Class<?> clazz) throws IntrospectionException {
final Method[] methods = clazz.getMethods();
final Map<String, PropertyDescriptor> getters = getPDs(methods, false);
final Map<String, PropertyDescriptor> setters = getPDs(methods, true);
final List<PropertyDescriptor> propertyDescriptors = merge(getters, setters);
return propertyDescriptors.toArray(new PropertyDescriptor[propertyDescriptors.size()]);
}
private static Map<String, PropertyDescriptor> getPDs(final Method[] methods, final boolean setters) throws IntrospectionException { private static Map<String, PropertyDescriptor> getPDs(final Method[] methods, final boolean setters) throws IntrospectionException {
final Map<String, PropertyDescriptor> pds = new HashMap<String, PropertyDescriptor>(); final Map<String, PropertyDescriptor> pds = new HashMap<String, PropertyDescriptor>();
@ -96,29 +163,30 @@ public class BeanIntrospector {
private static List<PropertyDescriptor> merge(final Map<String, PropertyDescriptor> getters, final Map<String, PropertyDescriptor> setters) private static List<PropertyDescriptor> merge(final Map<String, PropertyDescriptor> getters, final Map<String, PropertyDescriptor> setters)
throws IntrospectionException { throws IntrospectionException {
final List<PropertyDescriptor> props = new ArrayList<PropertyDescriptor>(); final List<PropertyDescriptor> props = new ArrayList<PropertyDescriptor>();
final Set<String> processedProps = new HashSet<String>(); final Set<String> processedProps = new HashSet<String>();
final Iterator<String> gs = getters.keySet().iterator();
while (gs.hasNext()) { for (final String propertyName : getters.keySet()) {
final String name = gs.next(); final PropertyDescriptor getter = getters.get(propertyName);
final PropertyDescriptor getter = getters.get(name); final PropertyDescriptor setter = setters.get(propertyName);
final PropertyDescriptor setter = setters.get(name);
if (setter != null) { if (setter != null) {
processedProps.add(name); processedProps.add(propertyName);
final PropertyDescriptor prop = new PropertyDescriptor(name, getter.getReadMethod(), setter.getWriteMethod()); final PropertyDescriptor prop = new PropertyDescriptor(propertyName, getter.getReadMethod(), setter.getWriteMethod());
props.add(prop); props.add(prop);
} else { } else {
props.add(getter); props.add(getter);
} }
} }
final Set<String> writeOnlyProps = new HashSet<String>(setters.keySet());
writeOnlyProps.removeAll(processedProps); final Set<String> writeOnlyProperties = new HashSet<String>();
final Iterator<String> ss = writeOnlyProps.iterator(); writeOnlyProperties.removeAll(processedProps);
while (ss.hasNext()) {
final String name = ss.next(); for (final String propertyName : writeOnlyProperties) {
final PropertyDescriptor setter = setters.get(name); final PropertyDescriptor setter = setters.get(propertyName);
props.add(setter); props.add(setter);
} }
return props; return props;
} }

View file

@ -25,6 +25,7 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
@ -162,34 +163,26 @@ public class CloneableBean implements Serializable, Cloneable {
final Object clonedBean = clazz.newInstance(); final Object clonedBean = clazz.newInstance();
final PropertyDescriptor[] propertyDescriptors = BeanIntrospector.getPropertyDescriptors(clazz); final List<PropertyDescriptor> propertyDescriptors = BeanIntrospector.getPropertyDescriptorsWithGettersAndSetters(clazz);
if (propertyDescriptors != null) { for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
final String propertyName = propertyDescriptor.getName();
final boolean ignoredProperty = ignoreProperties.contains(propertyName);
if (!ignoredProperty) {
final Method getter = propertyDescriptor.getReadMethod(); final Method getter = propertyDescriptor.getReadMethod();
final Method setter = propertyDescriptor.getWriteMethod(); final Method setter = propertyDescriptor.getWriteMethod();
final String propertyName = propertyDescriptor.getName();
final boolean getterExists = getter != null;
final boolean setterExists = setter != null;
final boolean ignoredProperty = ignoreProperties.contains(propertyName);
if (getterExists && setterExists && !ignoredProperty) {
final boolean getterFromObject = getter.getDeclaringClass() == Object.class;
final boolean getterWithoutParams = getter.getParameterTypes().length == 0;
if (!getterFromObject && getterWithoutParams) {
Object value = getter.invoke(obj, NO_PARAMS);
if (value != null) {
value = doClone(value);
setter.invoke(clonedBean, new Object[] { value });
}
}
Object value = getter.invoke(obj, NO_PARAMS);
if (value != null) {
value = doClone(value);
setter.invoke(clonedBean, new Object[] { value });
} }
} }
} }
return clonedBean; return clonedBean;

View file

@ -26,22 +26,43 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.syndication.feed.CopyFrom; import com.sun.syndication.feed.CopyFrom;
/** /**
* @author Alejandro Abdelnur * @author Alejandro Abdelnur
*/ */
public class CopyFromHelper { public class CopyFromHelper {
private static final Logger LOG = LoggerFactory.getLogger(CopyFromHelper.class);
private static final Set<Class<?>> BASIC_TYPES = new HashSet<Class<?>>();
private static final Object[] NO_PARAMS = new Object[0]; private static final Object[] NO_PARAMS = new Object[0];
private final Class<? extends CopyFrom<?>> beanInterfaceClass; private final Class<? extends CopyFrom<?>> beanInterfaceClass;
private final Map<String, Class<?>> baseInterfaceMap; // ENTRIES(propertyName,interface.class) private final Map<String, Class<?>> baseInterfaceMap; // ENTRIES(propertyName,interface.class)
private final Map<Class<? extends CopyFrom<?>>, Class<?>> baseImplMap; // ENTRIES(interface.class,implementation.class) private final Map<Class<? extends CopyFrom<?>>, Class<?>> baseImplMap; // ENTRIES(interface.class,implementation.class)
static {
BASIC_TYPES.add(Boolean.class);
BASIC_TYPES.add(Byte.class);
BASIC_TYPES.add(Character.class);
BASIC_TYPES.add(Double.class);
BASIC_TYPES.add(Float.class);
BASIC_TYPES.add(Integer.class);
BASIC_TYPES.add(Long.class);
BASIC_TYPES.add(Short.class);
BASIC_TYPES.add(String.class);
BASIC_TYPES.add(Date.class);
}
public CopyFromHelper(final Class<? extends CopyFrom<?>> beanInterfaceClass, final Map<String, Class<?>> basePropInterfaceMap, public CopyFromHelper(final Class<? extends CopyFrom<?>> beanInterfaceClass, final Map<String, Class<?>> basePropInterfaceMap,
final Map<Class<? extends CopyFrom<?>>, Class<?>> basePropClassImplMap) { final Map<Class<? extends CopyFrom<?>>, Class<?>> basePropClassImplMap) {
this.beanInterfaceClass = beanInterfaceClass; this.beanInterfaceClass = beanInterfaceClass;
@ -50,47 +71,37 @@ public class CopyFromHelper {
} }
public void copy(final Object target, final Object source) { public void copy(final Object target, final Object source) {
try { try {
final PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(beanInterfaceClass);
if (pds != null) { final List<PropertyDescriptor> propertyDescriptors = BeanIntrospector.getPropertyDescriptorsWithGettersAndSetters(beanInterfaceClass);
for (final PropertyDescriptor pd : pds) { for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
final String propertyName = pd.getName();
final Method pReadMethod = pd.getReadMethod(); final String propertyName = propertyDescriptor.getName();
final Method pWriteMethod = pd.getWriteMethod();
if (pReadMethod != null && pWriteMethod != null && // ensure if (baseInterfaceMap.containsKey(propertyName)) {
// it has
// getter final Method getter = propertyDescriptor.getReadMethod();
// and
// setter // only copies properties defined as copyFrom-able
// methods Object value = getter.invoke(source, NO_PARAMS);
pReadMethod.getDeclaringClass() != Object.class && // filter if (value != null) {
// Object.class
// getter final Method setter = propertyDescriptor.getWriteMethod();
// methods
pReadMethod.getParameterTypes().length == 0 && // filter final Class<?> baseInterface = baseInterfaceMap.get(propertyName);
// getter value = doCopy(value, baseInterface);
// methods setter.invoke(target, new Object[] { value });
// that
// take
// parameters
baseInterfaceMap.containsKey(propertyName)) { // only
// copies
// properties
// defined
// as
// copyFrom-able
Object value = pReadMethod.invoke(source, NO_PARAMS);
if (value != null) {
final Class<?> baseInterface = baseInterfaceMap.get(propertyName);
value = doCopy(value, baseInterface);
pWriteMethod.invoke(target, new Object[] { value });
}
} }
} }
} }
} catch (final Exception ex) {
throw new RuntimeException("Could not do a copyFrom " + ex, ex); } catch (final Exception e) {
LOG.error("Error while copying object", e);
throw new RuntimeException("Could not do a copyFrom " + e, e);
} }
} }
private CopyFrom<?> createInstance(final Class<? extends CopyFrom<?>> interfaceClass) throws Exception { private CopyFrom<?> createInstance(final Class<? extends CopyFrom<?>> interfaceClass) throws Exception {
@ -170,21 +181,6 @@ public class CopyFromHelper {
return newMap; return newMap;
} }
private static final Set<Class<?>> BASIC_TYPES = new HashSet<Class<?>>();
static {
BASIC_TYPES.add(Boolean.class);
BASIC_TYPES.add(Byte.class);
BASIC_TYPES.add(Character.class);
BASIC_TYPES.add(Double.class);
BASIC_TYPES.add(Float.class);
BASIC_TYPES.add(Integer.class);
BASIC_TYPES.add(Long.class);
BASIC_TYPES.add(Short.class);
BASIC_TYPES.add(String.class);
BASIC_TYPES.add(Date.class);
}
private boolean isBasicType(final Class<?> vClass) { private boolean isBasicType(final Class<?> vClass) {
return BASIC_TYPES.contains(vClass); return BASIC_TYPES.contains(vClass);
} }

View file

@ -20,23 +20,22 @@ import java.beans.PropertyDescriptor;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.List;
/** /**
* Provides deep <b>Bean</b> equals() and hashCode() functionality for Java * Provides deep <b>Bean</b> equals() and hashCode() functionality for Java Beans.
* Beans.
* <p> * <p>
* It works on all read/write properties, recursively. It support all primitive * It works on all read/write properties, recursively. It support all primitive types, Strings, Collections, bean-like objects and multi-dimensional arrays of
* types, Strings, Collections, bean-like objects and multi-dimensional arrays * any of them.
* of any of them.
* <p> * <p>
* The hashcode is calculated by getting the hashcode of the Bean String * The hashcode is calculated by getting the hashcode of the Bean String representation.
* representation.
* <p> * <p>
* *
* @author Alejandro Abdelnur * @author Alejandro Abdelnur
* *
*/ */
public class EqualsBean implements Serializable { public class EqualsBean implements Serializable {
private static final long serialVersionUID = 9120107899175152601L; private static final long serialVersionUID = 9120107899175152601L;
private static final Object[] NO_PARAMS = new Object[0]; private static final Object[] NO_PARAMS = new Object[0];
@ -96,12 +95,10 @@ public class EqualsBean implements Serializable {
} }
/** /**
* Indicates whether some other object is "equal to" this object as defined * Indicates whether some other object is "equal to" this object as defined by the Object equals() method.
* by the Object equals() method.
* <p> * <p>
* To be used by classes extending EqualsBean. Although it works also for * To be used by classes extending EqualsBean. Although it works also for classes using EqualsBean in a delegation pattern, for correctness those classes
* classes using EqualsBean in a delegation pattern, for correctness those * should use the
* classes should use the
* *
* @see #beanEquals(Object) beanEquals method. * @see #beanEquals(Object) beanEquals method.
* <p> * <p>
@ -115,58 +112,53 @@ public class EqualsBean implements Serializable {
} }
/** /**
* Indicates whether some other object is "equal to" the object passed in * Indicates whether some other object is "equal to" the object passed in the constructor, as defined by the Object equals() method.
* the constructor, as defined by the Object equals() method.
* <p> * <p>
* To be used by classes using EqualsBean in a delegation pattern, * To be used by classes using EqualsBean in a delegation pattern,
* *
* @see #EqualsBean(Class,Object) constructor. * @see #EqualsBean(Class,Object) constructor.
* <p> * <p>
* @param obj he reference object with which to compare. * @param obj he reference object with which to compare.
* @return <b>true</b> if the object passed in the constructor is equal to * @return <b>true</b> if the object passed in the constructor is equal to the 'obj' object.
* the 'obj' object.
* *
*/ */
public boolean beanEquals(final Object obj) { public boolean beanEquals(final Object obj) {
final Object bean1 = this.obj; final Object bean1 = this.obj;
final Object bean2 = obj; final Object bean2 = obj;
boolean eq; boolean eq;
if (bean1 == null && bean2 == null) {
if (bean1 == null && bean2 == null) { // both are null
eq = true; eq = true;
} else if (bean1 == null || bean2 == null) { } else if (bean1 == null || bean2 == null) { // one of the objects is null
eq = false;
} else if (!beanClass.isInstance(bean2)) { // not of the same type
eq = false; eq = false;
} else { } else {
if (!beanClass.isInstance(bean2)) { eq = true;
eq = false; try {
} else {
eq = true; final List<PropertyDescriptor> propertyDescriptors = BeanIntrospector.getPropertyDescriptorsWithGetters(beanClass);
try { for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
final PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(beanClass);
if (pds != null) { final Method getter = propertyDescriptor.getReadMethod();
for (int i = 0; eq && i < pds.length; i++) {
final Method pReadMethod = pds[i].getReadMethod(); final Object value1 = getter.invoke(bean1, NO_PARAMS);
if (pReadMethod != null && // ensure it has a getter final Object value2 = getter.invoke(bean2, NO_PARAMS);
// method
pReadMethod.getDeclaringClass() != Object.class && // filter eq = doEquals(value1, value2);
// Object.class
// getter if (!eq) {
// methods break;
pReadMethod.getParameterTypes().length == 0) { // filter
// getter
// methods
// that
// take
// parameters
final Object value1 = pReadMethod.invoke(bean1, NO_PARAMS);
final Object value2 = pReadMethod.invoke(bean2, NO_PARAMS);
eq = doEquals(value1, value2);
}
}
} }
} catch (final Exception ex) {
throw new RuntimeException("Could not execute equals()", ex);
} }
} catch (final Exception ex) {
throw new RuntimeException("Could not execute equals()", ex);
} }
} }
return eq; return eq;
} }
@ -176,12 +168,10 @@ public class EqualsBean implements Serializable {
* <p> * <p>
* It follows the contract defined by the Object hashCode() method. * It follows the contract defined by the Object hashCode() method.
* <p> * <p>
* The hashcode is calculated by getting the hashcode of the Bean String * The hashcode is calculated by getting the hashcode of the Bean String representation.
* representation.
* <p> * <p>
* To be used by classes extending EqualsBean. Although it works also for * To be used by classes extending EqualsBean. Although it works also for classes using EqualsBean in a delegation pattern, for correctness those classes
* classes using EqualsBean in a delegation pattern, for correctness those * should use the
* classes should use the
* *
* @see #beanHashCode() beanHashCode method. * @see #beanHashCode() beanHashCode method.
* <p> * <p>
@ -198,8 +188,7 @@ public class EqualsBean implements Serializable {
* <p> * <p>
* It follows the contract defined by the Object hashCode() method. * It follows the contract defined by the Object hashCode() method.
* <p> * <p>
* The hashcode is calculated by getting the hashcode of the Bean String * The hashcode is calculated by getting the hashcode of the Bean String representation.
* representation.
* <p> * <p>
* To be used by classes using EqualsBean in a delegation pattern, * To be used by classes using EqualsBean in a delegation pattern,
* *

View file

@ -20,21 +20,17 @@ import java.io.Serializable;
import java.util.Set; import java.util.Set;
/** /**
* Convenience class providing clone(), toString(), equals() and hashCode() * Convenience class providing clone(), toString(), equals() and hashCode() functionality for Java Beans.
* functionality for Java Beans.
* <p> * <p>
* It works on all read/write properties, recursively. * It works on all read/write properties, recursively.
* <p> * <p>
* It uses the CloneableBean, EqualsBean and ToStringBean classes in a * It uses the CloneableBean, EqualsBean and ToStringBean classes in a delegation pattern.
* delegation pattern.
* <p> * <p>
* <h3>ObjectBean programming conventions</h3> * <h3>ObjectBean programming conventions</h3>
* <P> * <P>
* All ObjectBean subclasses having properties that return collections they * All ObjectBean subclasses having properties that return collections they should never return null if the property has been set to <b>null</b> or if a
* should never return null if the property has been set to <b>null</b> or if a * collection has not been set. They should create and return an empty collection, this empty collection instance should also be set to the corresponding
* collection has not been set. They should create and return an empty * property.
* collection, this empty collection instance should also be set to the
* corresponding property.
* <P> * <P>
* All ObjectBean subclasses properties should be live references. * All ObjectBean subclasses properties should be live references.
* <p> * <p>
@ -43,7 +39,9 @@ import java.util.Set;
* *
*/ */
public class ObjectBean implements Serializable, Cloneable { public class ObjectBean implements Serializable, Cloneable {
private static final long serialVersionUID = -8784981605711980095L; private static final long serialVersionUID = -8784981605711980095L;
private final EqualsBean equalsBean; private final EqualsBean equalsBean;
private final ToStringBean toStringBean; private final ToStringBean toStringBean;
private final CloneableBean cloneableBean; private final CloneableBean cloneableBean;
@ -62,13 +60,9 @@ public class ObjectBean implements Serializable, Cloneable {
/** /**
* Constructor. * Constructor.
* <p> * <p>
* The property names in the ignoreProperties Set will not be copied into * The property names in the ignoreProperties Set will not be copied into the cloned instance. This is useful for cases where the Bean has convenience
* the cloned instance. This is useful for cases where the Bean has * properties (properties that are actually references to other properties or properties of properties). For example SyndFeed and SyndEntry beans have
* convenience properties (properties that are actually references to other * convenience properties, publishedDate, author, copyright and categories all of them mapped to properties in the DC Module.
* properties or properties of properties). For example SyndFeed and
* SyndEntry beans have convenience properties, publishedDate, author,
* copyright and categories all of them mapped to properties in the DC
* Module.
* <p> * <p>
* *
* @param beanClass the class/interface to be used for property scanning. * @param beanClass the class/interface to be used for property scanning.
@ -86,8 +80,7 @@ public class ObjectBean implements Serializable, Cloneable {
* <p> * <p>
* *
* @return a clone of the object. * @return a clone of the object.
* @throws CloneNotSupportedException thrown if an element of the object * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned.
* cannot be cloned.
* *
*/ */
@Override @Override
@ -96,8 +89,7 @@ public class ObjectBean implements Serializable, Cloneable {
} }
/** /**
* Indicates whether some other object is "equal to" this one as defined by * Indicates whether some other object is "equal to" this one as defined by the Object equals() method.
* the Object equals() method.
* <p> * <p>
* *
* @param other he reference object with which to compare. * @param other he reference object with which to compare.

View file

@ -22,15 +22,18 @@ import java.lang.reflect.Array;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Stack; import java.util.Stack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Provides deep <b>Bean</b> toString support. * Provides deep <b>Bean</b> toString support.
* <p> * <p>
* It works on all read/write properties, recursively. It support all primitive * It works on all read/write properties, recursively. It support all primitive types, Strings, Collections, ToString objects and multi-dimensional arrays of
* types, Strings, Collections, ToString objects and multi-dimensional arrays of
* any of them. * any of them.
* <p> * <p>
* *
@ -38,7 +41,9 @@ import java.util.Stack;
* *
*/ */
public class ToStringBean implements Serializable { public class ToStringBean implements Serializable {
private static final long serialVersionUID = -5850496718959612854L; private static final long serialVersionUID = -5850496718959612854L;
private static final Logger LOG = LoggerFactory.getLogger(ToStringBean.class);
private static final ThreadLocal<Stack<String[]>> PREFIX_TL = new ThreadLocal<Stack<String[]>>() { private static final ThreadLocal<Stack<String[]>> PREFIX_TL = new ThreadLocal<Stack<String[]>>() {
@Override @Override
@ -63,8 +68,7 @@ public class ToStringBean implements Serializable {
* To be used by classes extending ToStringBean only. * To be used by classes extending ToStringBean only.
* <p> * <p>
* *
* @param beanClass indicates the class to scan for properties, normally an * @param beanClass indicates the class to scan for properties, normally an interface class.
* interface class.
* *
*/ */
protected ToStringBean(final Class<?> beanClass) { protected ToStringBean(final Class<?> beanClass) {
@ -93,8 +97,7 @@ public class ToStringBean implements Serializable {
* </code> * </code>
* <p> * <p>
* *
* @param beanClass indicates the class to scan for properties, normally an * @param beanClass indicates the class to scan for properties, normally an interface class.
* interface class.
* @param obj object bean to create String representation. * @param obj object bean to create String representation.
* *
*/ */
@ -141,32 +144,29 @@ public class ToStringBean implements Serializable {
* *
*/ */
private String toString(final String prefix) { private String toString(final String prefix) {
final StringBuffer sb = new StringBuffer(128); final StringBuffer sb = new StringBuffer(128);
try { try {
final PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(beanClass);
if (pds != null) { final List<PropertyDescriptor> propertyDescriptors = BeanIntrospector.getPropertyDescriptorsWithGetters(beanClass);
for (final PropertyDescriptor pd : pds) { for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
final String pName = pd.getName();
final Method pReadMethod = pd.getReadMethod(); final String propertyName = propertyDescriptor.getName();
if (pReadMethod != null && // ensure it has a getter method final Method getter = propertyDescriptor.getReadMethod();
pReadMethod.getDeclaringClass() != Object.class && // filter
// Object.class final Object value = getter.invoke(obj, NO_PARAMS);
// getter printProperty(sb, prefix + "." + propertyName, value);
// methods
pReadMethod.getParameterTypes().length == 0) { // filter
// getter
// methods
// that
// take
// parameters
final Object value = pReadMethod.invoke(obj, NO_PARAMS);
printProperty(sb, prefix + "." + pName, value);
}
}
} }
} catch (final Exception ex) {
sb.append("\n\nEXCEPTION: Could not complete " + obj.getClass() + ".toString(): " + ex.getMessage() + "\n"); } catch (final Exception e) {
LOG.error("Error while generating toString", e);
final Class<? extends Object> clazz = obj.getClass();
final String errorMessage = e.getMessage();
sb.append(String.format("\n\nEXCEPTION: Could not complete %s.toString(): %s\n", clazz, errorMessage));
} }
return sb.toString(); return sb.toString();
} }