1 package com.thoughtworks.xstream.converters.javabean; 2 3 import java.beans.Introspector ; 4 import java.lang.reflect.Method ; 5 import java.lang.reflect.Modifier ; 6 import java.util.ArrayList ; 7 import java.util.Collection ; 8 import java.util.Collections ; 9 import java.util.Comparator ; 10 import java.util.HashMap ; 11 import java.util.Iterator ; 12 import java.util.List ; 13 import java.util.Map ; 14 15 import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; 16 17 20 public class PropertyDictionary { 21 22 private final Map keyedByPropertyNameCache = Collections.synchronizedMap(new HashMap ()); 23 24 public Iterator serializablePropertiesFor(Class cls) { 25 return buildMap(cls).values().iterator(); 26 } 27 28 36 public BeanProperty property(Class cls, String name) { 37 Map properties = buildMap(cls); 38 BeanProperty property = (BeanProperty) properties.get(name); 39 if (property == null) { 40 throw new ObjectAccessException("No such property " + cls.getName() + "." + name); 41 } else { 42 return property; 43 } 44 } 45 46 53 private Map buildMap(Class cls) { 54 final String clsName = cls.getName(); 55 if (!keyedByPropertyNameCache.containsKey(clsName)) { 56 synchronized (keyedByPropertyNameCache) { 57 if (!keyedByPropertyNameCache.containsKey(clsName)) { final Map propertyMap = new HashMap (); 63 Method [] methods = cls.getMethods(); 64 65 for (int i = 0; i < methods.length; i++) { 66 if (!Modifier.isPublic(methods[i].getModifiers()) 67 || Modifier.isStatic(methods[i].getModifiers())) 68 continue; 69 70 String methodName = methods[i].getName(); 71 Class [] parameters = methods[i].getParameterTypes(); 72 Class returnType = methods[i].getReturnType(); 73 String propertyName = null; 74 if ((methodName.startsWith("get") || methodName.startsWith("is")) 75 && parameters.length == 0 && returnType != null) { 76 if (methodName.startsWith("get")) 77 propertyName = Introspector.decapitalize(methodName.substring(3)); 78 else 79 propertyName = Introspector.decapitalize(methodName.substring(2)); 80 BeanProperty property = getBeanProperty(propertyMap, cls, propertyName, 81 returnType); 82 property.setGetterMethod(methods[i]); 83 } else if (methodName.startsWith("set") && parameters.length == 1 84 && returnType.equals(void.class)) { 85 propertyName = Introspector.decapitalize(methodName.substring(3)); 86 BeanProperty property = getBeanProperty(propertyMap, cls, propertyName, 87 parameters[0]); 88 property.setSetterMethod(methods[i]); 89 } 90 } 91 92 List serializableProperties = new ArrayList (); 95 for (Iterator it = propertyMap.values().iterator(); it.hasNext();) { 96 BeanProperty property = (BeanProperty) it.next(); 97 if (property.isReadable() && property.isWritable()) { 98 serializableProperties.add(property); 99 } 100 } 101 Collections.sort(serializableProperties, new BeanPropertyComparator()); 102 103 final Map keyedByFieldName = new OrderRetainingMap(); 105 for (Iterator it = serializableProperties.iterator(); it.hasNext();) { 106 BeanProperty property = (BeanProperty) it.next(); 107 keyedByFieldName.put(property.getName(), property); 108 } 109 110 keyedByPropertyNameCache.put(clsName, keyedByFieldName); 111 } 112 } 113 } 114 return (Map ) keyedByPropertyNameCache.get(clsName); 115 } 116 117 private BeanProperty getBeanProperty(Map propertyMap, Class cls, String propertyName, Class type) { 118 PropertyKey key = new PropertyKey(propertyName, type); 119 BeanProperty property = (BeanProperty) propertyMap.get(key); 120 if (property == null) { 121 property = new BeanProperty(cls, propertyName, type); 122 propertyMap.put(key, property); 123 } 124 return property; 125 } 126 127 131 private static class PropertyKey { 132 private String propertyName; 133 134 private Class propertyType; 135 136 public PropertyKey(String propertyName, Class propertyType) { 137 this.propertyName = propertyName; 138 this.propertyType = propertyType; 139 } 140 141 public boolean equals(Object o) { 142 if (this == o) 143 return true; 144 if (!(o instanceof PropertyKey)) 145 return false; 146 147 final PropertyKey propertyKey = (PropertyKey) o; 148 149 if (propertyName != null ? !propertyName.equals(propertyKey.propertyName) 150 : propertyKey.propertyName != null) 151 return false; 152 if (propertyType != null ? !propertyType.equals(propertyKey.propertyType) 153 : propertyKey.propertyType != null) 154 return false; 155 156 return true; 157 } 158 159 public int hashCode() { 160 int result; 161 result = (propertyName != null ? propertyName.hashCode() : 0); 162 result = 29 * result + (propertyType != null ? propertyType.hashCode() : 0); 163 return result; 164 } 165 166 public String toString() { 167 return "PropertyKey{propertyName='" + propertyName + "'" + ", propertyType=" 168 + propertyType + "}"; 169 } 170 171 } 172 173 176 private static class BeanPropertyComparator implements Comparator { 177 178 public int compare(Object o1, Object o2) { 179 return ((BeanProperty) o1).getName().compareTo(((BeanProperty) o2).getName()); 180 } 181 182 } 183 184 private static class OrderRetainingMap extends HashMap { 185 186 private List valueOrder = new ArrayList (); 187 188 public Object put(Object key, Object value) { 189 valueOrder.add(value); 190 return super.put(key, value); 191 } 192 193 public Collection values() { 194 return Collections.unmodifiableList(valueOrder); 195 } 196 } 197 198 } | Popular Tags |