package com.onaro.sanscreen.client.view.tabular.columns; import java.beans.PropertyDescriptor; import java.text.MessageFormat; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.eclipse.core.runtime.IAdaptable; import com.onaro.client.leekui.runtime.OnaroAdapterUtils; import com.onaro.commons.beans.BeanUtils; /** * Column value retriever class that will use Java reflection to read a value from a bean * using a property path. Property paths support using dot (.) notation to do multi-property * lookup. See BeanUtils for details. * * @param the type of the bean objects to retrieve the property value from * @param the type of the property value */ public class PropertyColumnValueRetriever extends AbstractColumnValueRetriever { protected final Class beanClass; protected final Class valueClass; protected final List propertyDescriptors; public PropertyColumnValueRetriever(Class beanClass, String propertyPath) { if (StringUtils.isBlank(propertyPath) || !BeanUtils.hasPropertyPath(beanClass, propertyPath)) { throw new IllegalArgumentException( MessageFormat.format("Property path ''{0}'' not valid for class ''{1}''", //$NON-NLS-1$ propertyPath, beanClass.getName())); } this.beanClass = beanClass; this.propertyDescriptors = BeanUtils.getPropertyDescriptorsByPath(beanClass, propertyPath); @SuppressWarnings("unchecked") Class valueType = (Class)getValueType(propertyDescriptors); this.valueClass = valueType; } /** * Helper method to verify that the value of the property is assignable from the value class specified * in the constructor. * @throws IllegalStateException if the types are not compatible */ private static Class getValueType(List propertyDescriptors) { PropertyDescriptor lastPd = propertyDescriptors.get(propertyDescriptors.size() - 1); Class valueType = lastPd.getPropertyType(); if (valueType.isPrimitive()) { valueType = BeanUtils.getObjectClassForPrimitive(valueType); } return valueType; } /** * Retrieve the bean instance to retrieve the property value from. The default implementation * adapts the row object to the bean class. Subclasses may override to provide alternate means * to arrive at the bean. * * @param rowObj the row to retrieve the bean for * @return the bean object, may be null */ protected B getBean(IAdaptable rowObj) { B bean = OnaroAdapterUtils.getAdapter(rowObj, beanClass); return bean; } /** * Retrieve the property value from the given bean instance. * @param bean the bean to retrieve the property value from * @return the property value, may be null */ protected V getPropertyValue(B bean) { Object propertyObj = BeanUtils.getPropertyValueByPath(propertyDescriptors, bean); return valueClass.cast(propertyObj); } @Override public final Class getValueType() { return valueClass; } @Override public V getValue(IAdaptable rowObj) { B bean = getBean(rowObj); if (bean == null) { return null; } V value = getPropertyValue(bean); return value; } }