package org.robobinding.itempresentationmodel; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import org.robobinding.internal.java_beans.PropertyDescriptor; import org.robobinding.property.PropertyUtils; import android.database.AbstractCursor; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** * * @since 1.0 * @version $Revision: 1.0 $ * @author Cheng Wei */ public class BeanCursor<T> extends AbstractCursor implements TypedCursor<T> { private final List<T> beans; private final Map<String, PropertyDescriptor> propertyDescriptorMap; BeanCursor(List<T> beans, Map<String, PropertyDescriptor> propertyDescriptorMap) { this.beans = beans; this.propertyDescriptorMap = propertyDescriptorMap; } @Override public int getCount() { return beans.size(); } private transient volatile String[] propertyNamesCache; @Override public String[] getColumnNames() { if (propertyNamesCache == null) { Set<String> propertyNames = propertyDescriptorMap.keySet(); propertyNamesCache = propertyNames.toArray(new String[0]); } return propertyNamesCache; } @Override public String getString(int column) { return (String) getColumnValue(column); } @Override public short getShort(int column) { return (Short) getColumnValue(column); } @Override public int getInt(int column) { return (Integer) getColumnValue(column); } @Override public long getLong(int column) { return (Long) getColumnValue(column); } @Override public float getFloat(int column) { return (Float) getColumnValue(column); } @Override public double getDouble(int column) { return (Double) getColumnValue(column); } @Override public boolean isNull(int column) { Object value = getColumnValue(column); return value == null; } private Object getColumnValue(int column) { Preconditions.checkArgument(column < getNumColumns(), "column '" + column + "' is out of bound"); PropertyDescriptor descriptor = mapColumnToPropertyDescriptor(column); try { return descriptor.getReadMethod().invoke(getBean(), new Object[0]); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } private PropertyDescriptor mapColumnToPropertyDescriptor(int column) { String propertyName = mapColumnToPropertyName(column); PropertyDescriptor descriptor = propertyDescriptorMap.get(propertyName); return descriptor; } private String mapColumnToPropertyName(int column) { return getColumnName(column); } private int getNumColumns() { return propertyDescriptorMap.size(); } private Object getBean() { return beans.get(getPosition()); } @Override public T getObjectAtPosition(int position) { Preconditions.checkArgument(position < getCount(), "Invalid requested position '" + position + "', as the cursor size is '" + getCount() + "'"); return beans.get(position); } public static <T> BeanCursor<T> create(Collection<T> beans, Class<T> beanClass) { Preconditions.checkNotNull(beans, "beans can not be null"); Preconditions.checkNotNull(beanClass, "beanClass can not be null"); return new BeanCursor<T>(Lists.newArrayList(beans), getPropertyDescriptorMap(beanClass)); } private static Map<String, PropertyDescriptor> getPropertyDescriptorMap(Class<?> beanClass) { Map<String, PropertyDescriptor> propertyDescriptorMap = Maps.newHashMap(); for(PropertyDescriptor descriptor : PropertyUtils.getPropertyDescriptors(beanClass)) { propertyDescriptorMap.put(descriptor.getName(), descriptor); } return propertyDescriptorMap; } }