001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.utils; 022 023import java.beans.BeanInfo; 024import java.beans.IntrospectionException; 025import java.beans.Introspector; 026import java.beans.PropertyDescriptor; 027import java.lang.reflect.InvocationTargetException; 028import java.util.AbstractMap; 029import java.util.AbstractSet; 030import java.util.HashMap; 031import java.util.Iterator; 032import java.util.Map; 033import java.util.Set; 034 035/** 036 * @author Matthew Pocock 037 */ 038public class BeanAsMap 039 extends 040 AbstractMap 041{ 042 // fixme: does this class work at all? 043 044 private static Map beanInfoCache; 045 private static Object[] NO_PARAMS; 046 047 static { 048 beanInfoCache = new HashMap(); 049 NO_PARAMS = new Object[] {}; 050 } 051 052 private static BeanInfo getBeanInfo(Class clazz) 053 throws IntrospectionException { 054 BeanInfo bi = (BeanInfo) beanInfoCache.get(clazz); 055 056 if(bi == null) { 057 beanInfoCache.put(clazz, bi = Introspector.getBeanInfo(clazz)); 058 } 059 060 return bi; 061 } 062 063 private final BeanInfo beanInfo; 064 private final Object bean; 065 private final PropertyDescriptor[] descriptors; 066 private final Set entrySet; 067 068 public BeanAsMap(Object bean) 069 throws IntrospectionException { 070 this.beanInfo = getBeanInfo(bean.getClass()); 071 this.bean = bean; 072 this.descriptors = this.beanInfo.getPropertyDescriptors(); 073 this.entrySet = new PropertySet(); 074 } 075 076 public int size() { 077 return entrySet.size(); 078 } 079 080 public Set entrySet() { 081 return entrySet; 082 } 083 084 public Object put(Object key, Object value) { 085 for(Iterator i = entrySet.iterator(); i.hasNext(); ) { 086 PropertyEntry pe = (PropertyEntry) i.next(); 087 if(pe.getKey().equals(key)) { 088 return pe.setValue(value); 089 } 090 } 091 throw new IllegalArgumentException("BeanAsMap does not support key: " + key); 092 } 093 094 private class PropertySet 095 extends 096 AbstractSet 097 { 098 private PropertyEntry[] entries; 099 100 public PropertySet() { 101 entries = new PropertyEntry[descriptors.length]; 102 for(int i = 0; i < entries.length; i++) { 103 entries[i] = new PropertyEntry(descriptors[i]); 104 } 105 } 106 107 public int size() { 108 return entries.length; 109 } 110 111 public Iterator iterator() { 112 return new Iterator() { 113 int i = 0; 114 115 public boolean hasNext() { 116 return i < entries.length; 117 } 118 119 public Object next() { 120 return entries[i++]; 121 } 122 123 public void remove() { 124 throw new UnsupportedOperationException(); 125 } 126 }; 127 } 128 } 129 130 private class PropertyEntry implements Map.Entry { 131 private final PropertyDescriptor pd; 132 133 public PropertyEntry(PropertyDescriptor pd) { 134 this.pd = pd; 135 } 136 137 public Object getKey() { 138 return pd.getName(); 139 } 140 141 public Object getValue() { 142 try { 143 return pd.getReadMethod().invoke(bean, NO_PARAMS); 144 } catch (IllegalAccessException iae) { 145 throw new AssertionFailure("Could not set property", iae); 146 } catch (InvocationTargetException ite) { 147 throw new AssertionFailure("Could not invoke property", ite); 148 } 149 } 150 151 public Object setValue(Object value) { 152 try { 153 Object old = getValue(); 154 pd.getWriteMethod().invoke(bean, new Object[] { value }); 155 156 return old; 157 } catch (IllegalAccessException iae) { 158 throw new AssertionFailure("Could not access property", iae); 159 } catch (InvocationTargetException ite) { 160 throw new AssertionFailure("Could not invoke property", ite); 161 } 162 } 163 } 164}