| 1 16 17 package org.cojen.util; 18 19 import java.lang.ref.SoftReference ; 20 import java.lang.reflect.Method ; 21 import java.lang.reflect.Modifier ; 22 import java.util.Collections ; 23 import java.util.HashMap ; 24 import java.util.Map ; 25 26 33 public class BeanIntrospector { 34 private static Map cPropertiesCache = new WeakIdentityMap(); 36 37 public static void main(String [] args) throws Exception { 38 System.out.println(getAllProperties(Class.forName(args[0]))); 39 } 40 41 49 public static Map getAllProperties(Class clazz) { 50 synchronized (cPropertiesCache) { 51 Map properties; 52 SoftReference ref = (SoftReference ) cPropertiesCache.get(clazz); 53 if (ref != null) { 54 properties = (Map ) ref.get(); 55 if (properties != null) { 56 return properties; 57 } 58 } 59 properties = createProperties(clazz); 60 cPropertiesCache.put(clazz, new SoftReference (properties)); 61 return properties; 62 } 63 } 64 65 private static Map createProperties(Class clazz) { 66 if (clazz == null || clazz.isPrimitive()) { 67 return Collections.EMPTY_MAP; 68 } 69 70 Map properties = new HashMap (); 71 fillInProperties(clazz, properties); 72 73 if (clazz.isInterface()) { 75 fillInProperties(Object .class, properties); 76 } 77 78 Class [] interfaces = clazz.getInterfaces(); 80 for (int i=0; i<interfaces.length; i++) { 81 fillInProperties(interfaces[i], properties); 82 } 83 84 return Collections.unmodifiableMap(properties); 85 } 86 87 91 private static void fillInProperties(Class clazz, Map properties) { 92 Method [] methods = clazz.getMethods(); 93 94 Method method; 95 String name; 96 Class type; 97 Class [] params; 98 SimpleProperty property; 99 IndexedProperty indexedProperty; 100 101 for (int i=0; i<methods.length; i++) { 103 method = methods[i]; 104 if (Modifier.isStatic(method.getModifiers()) || 105 (type = method.getReturnType()) == void.class || 106 method.getParameterTypes().length > 0 || 107 (name = extractPropertyName(method, "get")) == null) { 108 continue; 109 } 110 if (properties.containsKey(name)) { 111 property = (SimpleProperty) properties.get(name); 112 if (type != property.getType() || property.getReadMethod() != null) { 113 continue; 114 } 115 } else { 116 property = new SimpleProperty(name, type); 117 properties.put(name, property); 118 } 119 property.setReadMethod(method); 120 } 121 122 for (int i=0; i<methods.length; i++) { 124 method = methods[i]; 125 if (Modifier.isStatic(method.getModifiers()) || 126 (type = method.getReturnType()) != boolean.class || 127 method.getParameterTypes().length > 0 || 128 (name = extractPropertyName(method, "is")) == null) { 129 continue; 130 } 131 if (properties.containsKey(name)) { 132 property = (SimpleProperty) properties.get(name); 133 if (type != property.getType() || property.getReadMethod() != null) { 134 continue; 135 } 136 } else { 137 property = new SimpleProperty(name, type); 138 properties.put(name, property); 139 } 140 property.setReadMethod(method); 141 } 142 143 for (int i=0; i<methods.length; i++) { 145 method = methods[i]; 146 if (Modifier.isStatic(method.getModifiers()) || 147 method.getReturnType() != void.class || 148 (params = method.getParameterTypes()).length != 1 || 149 (name = extractPropertyName(method, "set")) == null) { 150 continue; 151 } 152 type = params[0]; 153 if (properties.containsKey(name)) { 154 property = (SimpleProperty) properties.get(name); 155 if (type != property.getType() || property.getWriteMethod() != null) { 156 continue; 157 } 158 } else { 159 property = new SimpleProperty(name, type); 160 properties.put(name, property); 161 } 162 property.setWriteMethod(method); 163 } 164 165 for (int i=0; i<methods.length; i++) { 167 method = methods[i]; 168 if (Modifier.isStatic(method.getModifiers()) || 169 (type = method.getReturnType()) == void.class || 170 (params = method.getParameterTypes()).length != 1 || 171 (name = extractPropertyName(method, "get")) == null) { 172 continue; 173 } 174 if (properties.containsKey(name)) { 175 property = (SimpleProperty) properties.get(name); 176 if (type != property.getType()) { 177 continue; 178 } 179 if (property instanceof IndexedProperty) { 180 indexedProperty = (IndexedProperty) property; 181 } else { 182 indexedProperty = new IndexedProperty(property); 183 properties.put(name, indexedProperty); 184 } 185 } else { 186 indexedProperty = new IndexedProperty(name, type); 187 properties.put(name, indexedProperty); 188 } 189 indexedProperty.addIndexedReadMethod(method); 190 } 191 192 for (int i=0; i<methods.length; i++) { 194 method = methods[i]; 195 if (Modifier.isStatic(method.getModifiers()) || 196 method.getReturnType() != void.class || 197 (params = method.getParameterTypes()).length != 2 || 198 (name = extractPropertyName(method, "set")) == null) { 199 continue; 200 } 201 type = params[1]; 202 if (properties.containsKey(name)) { 203 property = (SimpleProperty) properties.get(name); 204 if (type != property.getType()) { 205 continue; 206 } 207 if (property instanceof IndexedProperty) { 208 indexedProperty = (IndexedProperty) property; 209 } else { 210 indexedProperty = new IndexedProperty(property); 211 properties.put(name, indexedProperty); 212 } 213 } else { 214 indexedProperty = new IndexedProperty(name, type); 215 properties.put(name, indexedProperty); 216 } 217 indexedProperty.addIndexedWriteMethod(method); 218 } 219 } 220 221 224 private static String extractPropertyName(Method method, String prefix) { 225 String name = method.getName(); 226 if (!name.startsWith(prefix)) { 227 return null; 228 } 229 if (name.length() == prefix.length()) { 230 return ""; 231 } 232 name = name.substring(prefix.length()); 233 if (!Character.isUpperCase(name.charAt(0)) || name.indexOf('$') >= 0) { 234 return null; 235 } 236 237 240 if (name.length() == 1 || !Character.isUpperCase(name.charAt(1))) { 241 char chars[] = name.toCharArray(); 242 chars[0] = Character.toLowerCase(chars[0]); 243 name = new String (chars); 244 } 245 246 return name.intern(); 247 } 248 249 private static class SimpleProperty implements BeanProperty { 250 private final String mName; 251 private final Class mType; 252 253 private Method mReadMethod; 254 private Method mWriteMethod; 255 256 SimpleProperty(String name, Class type) { 257 mName = name; 258 mType = type; 259 } 260 261 public String getName() { 262 return mName; 263 } 264 265 public Class getType() { 266 return mType; 267 } 268 269 public Method getReadMethod() { 270 return mReadMethod; 271 } 272 273 public Method getWriteMethod() { 274 return mWriteMethod; 275 } 276 277 public int getIndexTypesCount() { 278 return 0; 279 } 280 281 public Class getIndexType(int index) { 282 throw new IndexOutOfBoundsException (); 283 } 284 285 public Method getIndexedReadMethod(int index) { 286 throw new IndexOutOfBoundsException (); 287 } 288 289 public Method getIndexedWriteMethod(int index) { 290 throw new IndexOutOfBoundsException (); 291 } 292 293 public String toString() { 294 return "BeanProperty[name=" + getName() + 295 ", type=" + getType().getName() + ']'; 296 } 297 298 void setReadMethod(Method method) { 299 mReadMethod = method; 300 } 301 302 void setWriteMethod(Method method) { 303 mWriteMethod = method; 304 } 305 } 306 307 private static class IndexedProperty extends SimpleProperty { 308 private Method [] mIndexedReadMethods; 309 private Method [] mIndexedWriteMethods; 310 311 IndexedProperty(String name, Class type) { 312 super(name, type); 313 } 314 315 IndexedProperty(BeanProperty property) { 316 super(property.getName(), property.getType()); 317 setReadMethod(property.getReadMethod()); 318 setWriteMethod(property.getWriteMethod()); 319 } 320 321 public int getIndexTypesCount() { 322 Method [] methods = mIndexedReadMethods; 323 if (methods != null) { 324 return methods.length; 325 } 326 methods = mIndexedWriteMethods; 327 return methods == null ? 0 : methods.length; 328 } 329 330 public Class getIndexType(int index) { 331 Method [] methods = mIndexedReadMethods; 332 if (methods != null) { 333 Method method = methods[0]; 334 if (method != null) { 335 return method.getParameterTypes()[0]; 336 } 337 } 338 methods = mIndexedWriteMethods; 339 if (methods != null) { 340 Method method = methods[index]; 341 if (method != null) { 342 return method.getParameterTypes()[0]; 343 } 344 } 345 if (index >= getIndexTypesCount()) { 346 throw new IndexOutOfBoundsException (); 347 } 348 return null; 349 } 350 351 public Method getIndexedReadMethod(int index) { 352 return mIndexedReadMethods[index]; 353 } 354 355 public Method getIndexedWriteMethod(int index) { 356 return mIndexedWriteMethods[index]; 357 } 358 359 public String toString() { 360 StringBuffer buf = new StringBuffer (); 361 buf.append("BeanProperty[name="); 362 buf.append(getName()); 363 buf.append(", type="); 364 buf.append(getType().getName()); 365 buf.append(", "); 366 int count = getIndexTypesCount(); 367 for (int i=0; i<count; i++) { 368 if (i > 0) { 369 buf.append(", "); 370 } 371 buf.append("indexType["); 372 buf.append(i); 373 buf.append("]="); 374 buf.append(getIndexType(0)); 375 } 376 buf.append(']'); 377 return buf.toString(); 378 } 379 380 void addIndexedReadMethod(Method method) { 381 Class indexType = method.getParameterTypes()[0]; 382 int count = getIndexTypesCount(); 383 int i; 384 for (i=0; i<count; i++) { 385 if (getIndexType(i) == indexType) { 386 break; 387 } 388 } 389 if (i >= count) { 390 expandCapactity(); 391 } 392 if (mIndexedReadMethods[i] == null) { 393 mIndexedReadMethods[i] = method; 394 } 395 } 396 397 void addIndexedWriteMethod(Method method) { 398 Class indexType = method.getParameterTypes()[0]; 399 int count = getIndexTypesCount(); 400 int i; 401 for (i=0; i<count; i++) { 402 if (getIndexType(i) == indexType) { 403 break; 404 } 405 } 406 if (i >= count) { 407 expandCapactity(); 408 } 409 if (mIndexedWriteMethods[i] == null) { 410 mIndexedWriteMethods[i] = method; 411 } 412 } 413 414 private void expandCapactity() { 415 int count = getIndexTypesCount(); 416 Method [] methods = new Method [count + 1]; 417 if (mIndexedReadMethods != null) { 418 System.arraycopy(mIndexedReadMethods, 0, methods, 0, count); 419 } 420 mIndexedReadMethods = methods; 421 methods = new Method [count + 1]; 422 if (mIndexedWriteMethods != null) { 423 System.arraycopy(mIndexedWriteMethods, 0, methods, 0, count); 424 } 425 mIndexedWriteMethods = methods; 426 } 427 } 428 } 429 | Popular Tags |