blob: 001181a6eca6ea6d482ddcc33a12c463cfcec8ca [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 Matthew Hall and others.
* 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:
* Matthew Hall - initial API and implementation (bug 194734)
* Martin Frey <martin.frey@logica.com> - bug 256150
* Matthew Hall - bug 264307
******************************************************************************/
package org.eclipse.core.internal.databinding.beans;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.util.Policy;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
/**
* @since 1.2
*
*/
public class BeanPropertyHelper {
/**
* Sets the contents of the given property on the given source object to the
* given value.
*
* @param source
* the source object which has the property being updated
* @param propertyDescriptor
* the property being changed
* @param value
* the new value of the property
*/
public static void writeProperty(Object source,
PropertyDescriptor propertyDescriptor, Object value) {
try {
Method writeMethod = propertyDescriptor.getWriteMethod();
if (!writeMethod.isAccessible()) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(source, new Object[] { value });
} catch (InvocationTargetException e) {
/*
* InvocationTargetException wraps any exception thrown by the
* invoked method.
*/
throw new RuntimeException(e.getCause());
} catch (Exception e) {
if (BeansObservables.DEBUG) {
Policy
.getLog()
.log(
new Status(
IStatus.WARNING,
Policy.JFACE_DATABINDING,
IStatus.OK,
"Could not change value of " + source + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
/**
* Returns the contents of the given property for the given bean.
*
* @param source
* the source bean
* @param propertyDescriptor
* the property to retrieve
* @return the contents of the given property for the given bean.
*/
public static Object readProperty(Object source,
PropertyDescriptor propertyDescriptor) {
try {
Method readMethod = propertyDescriptor.getReadMethod();
if (readMethod == null) {
throw new IllegalArgumentException(propertyDescriptor.getName()
+ " property does not have a read method."); //$NON-NLS-1$
}
if (!readMethod.isAccessible()) {
readMethod.setAccessible(true);
}
return readMethod.invoke(source, null);
} catch (InvocationTargetException e) {
/*
* InvocationTargetException wraps any exception thrown by the
* invoked method.
*/
throw new RuntimeException(e.getCause());
} catch (Exception e) {
if (BeansObservables.DEBUG) {
Policy
.getLog()
.log(
new Status(
IStatus.WARNING,
Policy.JFACE_DATABINDING,
IStatus.OK,
"Could not read value of " + source + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$
}
return null;
}
}
/**
* Returns the element type of the given collection-typed property for the
* given bean.
*
* @param descriptor
* the property being inspected
* @return the element type of the given collection-typed property if it is
* an array property, or Object.class otherwise.
*/
public static Class getCollectionPropertyElementType(
PropertyDescriptor descriptor) {
Class propertyType = descriptor.getPropertyType();
return propertyType.isArray() ? propertyType.getComponentType()
: Object.class;
}
/**
* @param beanClass
* @param propertyName
* @return the PropertyDescriptor for the named property on the given bean
* class
*/
public static PropertyDescriptor getPropertyDescriptor(Class beanClass,
String propertyName) {
if (!beanClass.isInterface()) {
BeanInfo beanInfo;
try {
beanInfo = Introspector.getBeanInfo(beanClass);
} catch (IntrospectionException e) {
// cannot introspect, give up
return null;
}
PropertyDescriptor[] propertyDescriptors = beanInfo
.getPropertyDescriptors();
for (int i = 0; i < propertyDescriptors.length; i++) {
PropertyDescriptor descriptor = propertyDescriptors[i];
if (descriptor.getName().equals(propertyName)) {
return descriptor;
}
}
} else {
try {
PropertyDescriptor propertyDescriptors[];
List pds = new ArrayList();
getInterfacePropertyDescriptors(pds, beanClass);
if (pds.size() > 0) {
propertyDescriptors = (PropertyDescriptor[]) pds
.toArray(new PropertyDescriptor[pds.size()]);
PropertyDescriptor descriptor;
for (int i = 0; i < propertyDescriptors.length; i++) {
descriptor = propertyDescriptors[i];
if (descriptor.getName().equals(propertyName))
return descriptor;
}
}
} catch (IntrospectionException e) {
// cannot introspect, give up
return null;
}
}
throw new IllegalArgumentException(
"Could not find property with name " + propertyName + " in class " + beanClass); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Goes recursively into the interface and gets all defined
* propertyDescriptors
*
* @param propertyDescriptors
* The result list of all PropertyDescriptors the given interface
* defines (hierarchical)
* @param iface
* The interface to fetch the PropertyDescriptors
* @throws IntrospectionException
*/
private static void getInterfacePropertyDescriptors(
List propertyDescriptors, Class iface)
throws IntrospectionException {
BeanInfo beanInfo = Introspector.getBeanInfo(iface);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (int i = 0; i < pds.length; i++) {
PropertyDescriptor pd = pds[i];
propertyDescriptors.add(pd);
}
Class[] subIntfs = iface.getInterfaces();
for (int j = 0; j < subIntfs.length; j++) {
getInterfacePropertyDescriptors(propertyDescriptors, subIntfs[j]);
}
}
/**
* @param observable
* @param propertyName
* @return property descriptor or <code>null</code>
*/
/* package */public static PropertyDescriptor getValueTypePropertyDescriptor(
IObservableValue observable, String propertyName) {
if (observable.getValueType() != null)
return getPropertyDescriptor((Class) observable.getValueType(),
propertyName);
return null;
}
/**
* @param propertyDescriptor
* @return String description of property descriptor
*/
public static String propertyName(PropertyDescriptor propertyDescriptor) {
Class beanClass = propertyDescriptor.getReadMethod()
.getDeclaringClass();
return shortClassName(beanClass)
+ "." + propertyDescriptor.getName() + ""; //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* @param beanClass
* @return class name excluding package
*/
public static String shortClassName(Class beanClass) {
if (beanClass == null)
return "?"; //$NON-NLS-1$
String className = beanClass.getName();
int lastDot = className.lastIndexOf('.');
if (lastDot != -1)
className = className.substring(lastDot + 1);
return className;
}
}