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 }