blob: f8cbc82baeba48bd17cd0e8f82ae9a0dd2265804 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2012, 2021 Original NatTable authors and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0.
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# Original NatTable authors and others - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.ecommons.waltable.data;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.statet.internal.ecommons.waltable.WaLTablePlugin;
/**
* Convenience class which uses java reflection to get/set property names
* from the row bean. It looks for getter methods for reading and setter
* methods for writing according to the Java conventions.
*
* @param <R> type of the row object/bean
*/
public class ReflectiveColumnPropertyAccessor<R> implements IColumnPropertyAccessor<R> {
private final List<String> propertyNames;
private Map<String, PropertyDescriptor> propertyDescriptorMap;
/**
* @param propertyNames of the members of the row bean
*/
public ReflectiveColumnPropertyAccessor(final String[] propertyNames) {
this.propertyNames= Arrays.asList(propertyNames);
}
@Override
public long getColumnCount() {
return this.propertyNames.size();
}
@Override
public Object getDataValue(final R rowObj, final long columnIndex) {
try {
final PropertyDescriptor propertyDesc= getPropertyDescriptor(rowObj, columnIndex);
final Method readMethod= propertyDesc.getReadMethod();
return readMethod.invoke(rowObj);
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void setDataValue(final R rowObj, final long columnIndex, final Object newValue) {
try {
final PropertyDescriptor propertyDesc= getPropertyDescriptor(rowObj, columnIndex);
final Method writeMethod= propertyDesc.getWriteMethod();
if (writeMethod == null) {
throw new RuntimeException("Setter method not found in backing bean for value at column index: " + columnIndex); //$NON-NLS-1$
}
writeMethod.invoke(rowObj, newValue);
} catch (final IllegalArgumentException ex) {
WaLTablePlugin.log(new Status(IStatus.WARNING, WaLTablePlugin.BUNDLE_ID,
"Data type being set does not match the data type of the setter method in the backing bean", ex )); //$NON-NLS-1$
} catch (final Exception e) {
WaLTablePlugin.log(new Status(IStatus.ERROR, WaLTablePlugin.BUNDLE_ID,
"Error while setting data value", e )); //$NON-NLS-1$
throw new RuntimeException("Error while setting data value"); //$NON-NLS-1$
}
}
@Override
public String getColumnProperty(final long columnIndex) {
if (columnIndex >= Integer.MAX_VALUE) {
throw new IndexOutOfBoundsException();
}
return this.propertyNames.get((int) columnIndex);
}
@Override
public long getColumnIndex(final String propertyName) {
return this.propertyNames.indexOf(propertyName);
}
private PropertyDescriptor getPropertyDescriptor(final R rowObj, final long columnIndex) throws IntrospectionException {
if (columnIndex >= Integer.MAX_VALUE) {
throw new IndexOutOfBoundsException();
}
if (this.propertyDescriptorMap == null) {
this.propertyDescriptorMap= new HashMap<>();
final PropertyDescriptor[] propertyDescriptors= Introspector.getBeanInfo(rowObj.getClass()).getPropertyDescriptors();
for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
this.propertyDescriptorMap.put(propertyDescriptor.getName(), propertyDescriptor);
}
}
final String propertyName= this.propertyNames.get((int) columnIndex);
return this.propertyDescriptorMap.get(propertyName);
}
}