/******************************************************************************* * Copyright (c) 2011-2016 Medevit OG, Medelexis AG * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Marco Descher, initial API and implementaion * Lucia Amman, bug fixes and improvements * Sponsors: M. + P. Richter *******************************************************************************/ package at.medevit.elexis.gdt.ui.table.util; import java.beans.PropertyDescriptor; import java.util.ArrayList; import java.util.List; import org.eclipse.core.internal.databinding.beans.BeanPropertyHelper; /** * PropertyValue: Resolves nested property Strings like "company.country.name". * * Use like this: * * <pre> * PropertyValue prop = new PropertyValue("country.name"); * Object countryName = prop.getValue(someObject); * </pre> * * This class allows to use JFace Data Binding property support to get and set nested property * values without observing them. * * Please note that this class is not prepared for a case where the classes of the objects change on * the path to the property. For example, if you use "country.name" on a "Company" object once, it * expects a "Company" object you use it the next time. * * WARNING: This uses internal data binding classes. This enhancement described in * https://bugs.eclipse.org/bugs/show_bug.cgi?id=285307 would allow to use official API instead of * this class. * * @author Ralf Ebert <info@ralfebert.de> */ @SuppressWarnings("restriction") public class PropertyValue implements IValue { private final Object[] properties; /** * Creates a PropertyValue to access the bean property referred by propertyName. */ public PropertyValue(String propertyName){ properties = split(propertyName); } private static Object[] split(String propertyName){ if (propertyName.indexOf('.') == -1) return new Object[] { propertyName }; List<String> propertyNames = new ArrayList<String>(); int index; while ((index = propertyName.indexOf('.')) != -1) { propertyNames.add(propertyName.substring(0, index)); propertyName = propertyName.substring(index + 1); } propertyNames.add(propertyName); return propertyNames.toArray(new Object[propertyNames.size()]); } /** * Returns the property value referred by object."propertyName" */ public Object getValue(Object object){ Object currentObject = object; for (int i = 0; i < properties.length; i++) { if (currentObject == null) return null; if (properties[i] instanceof String) { properties[i] = BeanPropertyHelper.getPropertyDescriptor(currentObject.getClass(), (String) properties[i]); } if (properties[i] instanceof PropertyDescriptor) { currentObject = BeanPropertyHelper.readProperty(currentObject, (PropertyDescriptor) properties[i]); } else { throw new RuntimeException("Invalid property: " + properties[i]); } } return currentObject; } /** * Sets the property value referred by object."propertyName" to value */ public void setValue(Object object, Object value){ Object currentObject = object; for (int i = 0; i < properties.length; i++) { if (currentObject == null) throw new RuntimeException( "Value cannot be set because of null value in nested property!"); if (properties[i] instanceof String) { properties[i] = BeanPropertyHelper.getPropertyDescriptor(currentObject.getClass(), (String) properties[i]); } if (properties[i] instanceof PropertyDescriptor) { boolean lastProperty = (i == properties.length - 1); if (lastProperty) BeanPropertyHelper.writeProperty(currentObject, (PropertyDescriptor) properties[i], value); else currentObject = BeanPropertyHelper.readProperty(currentObject, (PropertyDescriptor) properties[i]); } else { throw new RuntimeException("Invalid property: " + properties[i]); } } } }