/** * Copyright (C) 2015 Valkyrie RCP * * 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 org.valkyriercp.widget.table; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * This {@link Writer} uses a chaining implementation of getter methods to allow nested properties. * * @author Jan Hoskens * @since 0.5.0 */ public class NestedWriter implements Writer { /** The nested writer to access and write the property. */ private final Writer nestedWriter; /** The getter to access the first level object. */ private final Method getter; /** * Convenience constructor. Creates a getter method for the given class and property and reroutes to * {@link NestedWriter#NestedWriter(Method, String)}. * * @param clazz * type with the nested property. * @param propertyName * the first part of the nested property. * @param nestedPropertyName * the nested property, possibly containing more nesting levels. Only the last one in the line * needs the setter method. * @see #NestedWriter(Method, String) */ public NestedWriter(Class<?> clazz, String propertyName, String nestedPropertyName) { this(ClassUtils.getReadMethod(clazz, propertyName), nestedPropertyName); } /** * Constructor. The given getter should yield the return value on which the nested property exists. * * @param getter * the method providing the entity. * @param nestedPropertyName * the nested property on the entity. */ public NestedWriter(Method getter, String nestedPropertyName) { this.getter = getter; this.nestedWriter = ClassUtils.getWriterForProperty(getter.getReturnType(), nestedPropertyName); } /** * Set the value on the source entity. If at any point the chaining results in a null value. The chaining * should end. * * @param toEntity * the entity on which the getter should operate. * @param newValue * the value to set. */ public void setValue(Object toEntity, Object newValue) throws IllegalAccessException, InvocationTargetException { Object propertyValue = getter.invoke(toEntity); if (propertyValue != null) nestedWriter.setValue(propertyValue, newValue); } /** * {@inheritDoc} */ public Class<?> getPropertyType() { return nestedWriter.getPropertyType(); } /** * Get the value from the source entity. If at any point the chaining results in a null value. The * chaining should end and return <code>null</code>. * * @param fromEntity * the entity on which the getter should operate. * @return <code>null</code> if at any point in the chaining a property returned <code>null</code> or * the value of the nested property. */ public Object getValue(Object fromEntity) throws IllegalAccessException, InvocationTargetException { Object propertyValue = getter.invoke(fromEntity); return propertyValue == null ? null : nestedWriter.getValue(propertyValue); } }