001 package org.springframework.richclient.widget.table;
002
003 import java.lang.reflect.InvocationTargetException;
004 import java.lang.reflect.Method;
005
006 /**
007 * This {@link Writer} uses a chaining implementation of getter methods to allow nested properties.
008 *
009 * @author Jan Hoskens
010 * @since 0.5.0
011 */
012 public class NestedWriter implements Writer
013 {
014
015 /** The nested writer to access and write the property. */
016 private final Writer nestedWriter;
017
018 /** The getter to access the first level object. */
019 private final Method getter;
020
021 /**
022 * Convenience constructor. Creates a getter method for the given class and property and reroutes to
023 * {@link NestedWriter#NestedWriter(Method, String)}.
024 *
025 * @param clazz
026 * type with the nested property.
027 * @param propertyName
028 * the first part of the nested property.
029 * @param nestedPropertyName
030 * the nested property, possibly containing more nesting levels. Only the last one in the line
031 * needs the setter method.
032 * @see #NestedWriter(Method, String)
033 */
034 public NestedWriter(Class<?> clazz, String propertyName, String nestedPropertyName)
035 {
036 this(ClassUtils.getReadMethod(clazz, propertyName), nestedPropertyName);
037 }
038
039 /**
040 * Constructor. The given getter should yield the return value on which the nested property exists.
041 *
042 * @param getter
043 * the method providing the entity.
044 * @param nestedPropertyName
045 * the nested property on the entity.
046 */
047 public NestedWriter(Method getter, String nestedPropertyName)
048 {
049 this.getter = getter;
050 this.nestedWriter = ClassUtils.getWriterForProperty(getter.getReturnType(), nestedPropertyName);
051 }
052
053 /**
054 * Set the value on the source entity. If at any point the chaining results in a null value. The chaining
055 * should end.
056 *
057 * @param toEntity
058 * the entity on which the getter should operate.
059 * @param newValue
060 * the value to set.
061 */
062 public void setValue(Object toEntity, Object newValue) throws IllegalAccessException,
063 InvocationTargetException
064 {
065 Object propertyValue = getter.invoke(toEntity);
066 if (propertyValue != null)
067 nestedWriter.setValue(propertyValue, newValue);
068 }
069
070 /**
071 * {@inheritDoc}
072 */
073 public Class<?> getPropertyType()
074 {
075 return nestedWriter.getPropertyType();
076 }
077
078 /**
079 * Get the value from the source entity. If at any point the chaining results in a null value. The
080 * chaining should end and return <code>null</code>.
081 *
082 * @param fromEntity
083 * the entity on which the getter should operate.
084 * @return <code>null</code> if at any point in the chaining a property returned <code>null</code> or
085 * the value of the nested property.
086 */
087 public Object getValue(Object fromEntity) throws IllegalAccessException, InvocationTargetException
088 {
089 Object propertyValue = getter.invoke(fromEntity);
090 return propertyValue == null ? null : nestedWriter.getValue(propertyValue);
091 }
092 }