| 1 7 8 package java.beans; 9 10 import java.lang.ref.Reference ; 11 import java.lang.ref.SoftReference ; 12 13 import java.lang.reflect.Method ; 14 import java.lang.reflect.Modifier ; 15 16 import java.security.AccessController ; 17 import java.security.PrivilegedAction ; 18 19 import java.util.Collections ; 20 import java.util.Map ; 21 import java.util.ArrayList ; 22 import java.util.HashMap ; 23 import java.util.Iterator ; 24 import java.util.EventListener ; 25 import java.util.List ; 26 import java.util.WeakHashMap ; 27 import java.util.TreeMap ; 28 import sun.reflect.misc.ReflectUtil; 29 30 83 84 public class Introspector { 85 86 public final static int USE_ALL_BEANINFO = 1; 88 public final static int IGNORE_IMMEDIATE_BEANINFO = 2; 89 public final static int IGNORE_ALL_BEANINFO = 3; 90 91 private static Map declaredMethodCache = 93 Collections.synchronizedMap(new WeakHashMap ()); 94 private static Map beanInfoCache = 95 Collections.synchronizedMap(new WeakHashMap ()); 96 97 private Class beanClass; 98 private BeanInfo explicitBeanInfo; 99 private BeanInfo superBeanInfo; 100 private BeanInfo additionalBeanInfo[]; 101 102 private boolean propertyChangeSource = false; 103 private static Class eventListenerType = EventListener .class; 104 105 private String defaultEventName; 107 private String defaultPropertyName; 108 private int defaultEventIndex = -1; 109 private int defaultPropertyIndex = -1; 110 111 private Map methods; 113 114 private Map properties; 116 117 private Map events; 119 120 private final static String DEFAULT_INFO_PATH = "sun.beans.infos"; 121 122 private static String [] searchPath = { DEFAULT_INFO_PATH }; 123 124 private final static EventSetDescriptor [] EMPTY_EVENTSETDESCRIPTORS = new EventSetDescriptor [0]; 125 126 private static final String ADD_PREFIX = "add"; 127 private static final String REMOVE_PREFIX = "remove"; 128 private static final String GET_PREFIX = "get"; 129 private static final String SET_PREFIX = "set"; 130 private static final String IS_PREFIX = "is"; 131 private static final String BEANINFO_SUFFIX = "BeanInfo"; 132 133 137 151 public static BeanInfo getBeanInfo(Class <?> beanClass) 152 throws IntrospectionException  153 { 154 if (!ReflectUtil.isPackageAccessible(beanClass)) { 155 return (new Introspector (beanClass, null, USE_ALL_BEANINFO)).getBeanInfo(); 156 } 157 BeanInfo bi = (BeanInfo )beanInfoCache.get(beanClass); 158 if (bi == null) { 159 bi = (new Introspector (beanClass, null, USE_ALL_BEANINFO)).getBeanInfo(); 160 beanInfoCache.put(beanClass, bi); 161 } 162 return bi; 163 } 164 165 186 public static BeanInfo getBeanInfo(Class <?> beanClass, int flags) 187 throws IntrospectionException { 188 return getBeanInfo(beanClass, null, flags); 189 } 190 191 206 public static BeanInfo getBeanInfo(Class <?> beanClass, Class <?> stopClass) 207 throws IntrospectionException { 208 return getBeanInfo(beanClass, stopClass, USE_ALL_BEANINFO); 209 } 210 211 215 private static BeanInfo getBeanInfo(Class beanClass, Class stopClass, 216 int flags) throws IntrospectionException { 217 BeanInfo bi; 218 if (stopClass == null && flags == USE_ALL_BEANINFO) { 219 bi = getBeanInfo(beanClass); 221 } else { 222 bi = (new Introspector (beanClass, stopClass, flags)).getBeanInfo(); 223 } 224 return bi; 225 226 } 229 230 231 244 public static String decapitalize(String name) { 245 if (name == null || name.length() == 0) { 246 return name; 247 } 248 if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) && 249 Character.isUpperCase(name.charAt(0))){ 250 return name; 251 } 252 char chars[] = name.toCharArray(); 253 chars[0] = Character.toLowerCase(chars[0]); 254 return new String (chars); 255 } 256 257 266 267 public static synchronized String [] getBeanInfoSearchPath() { 268 String result[] = new String [searchPath.length]; 270 for (int i = 0; i < searchPath.length; i++) { 271 result[i] = searchPath[i]; 272 } 273 return result; 274 } 275 276 291 292 public static synchronized void setBeanInfoSearchPath(String path[]) { 293 SecurityManager sm = System.getSecurityManager(); 294 if (sm != null) { 295 sm.checkPropertiesAccess(); 296 } 297 searchPath = path; 298 } 299 300 301 307 308 public static void flushCaches() { 309 beanInfoCache.clear(); 310 declaredMethodCache.clear(); 311 } 312 313 328 public static void flushFromCaches(Class <?> clz) { 329 if (clz == null) { 330 throw new NullPointerException (); 331 } 332 beanInfoCache.remove(clz); 333 declaredMethodCache.remove(clz); 334 } 335 336 340 private Introspector(Class beanClass, Class stopClass, int flags) 341 throws IntrospectionException { 342 this.beanClass = beanClass; 343 344 if (stopClass != null) { 346 boolean isSuper = false; 347 for (Class c = beanClass.getSuperclass(); c != null; c = c.getSuperclass()) { 348 if (c == stopClass) { 349 isSuper = true; 350 } 351 } 352 if (!isSuper) { 353 throw new IntrospectionException (stopClass.getName() + " not superclass of " + 354 beanClass.getName()); 355 } 356 } 357 358 if (flags == USE_ALL_BEANINFO) { 359 explicitBeanInfo = findExplicitBeanInfo(beanClass); 360 } 361 362 Class superClass = beanClass.getSuperclass(); 363 if (superClass != stopClass) { 364 int newFlags = flags; 365 if (newFlags == IGNORE_IMMEDIATE_BEANINFO) { 366 newFlags = USE_ALL_BEANINFO; 367 } 368 superBeanInfo = getBeanInfo(superClass, stopClass, newFlags); 369 } 370 if (explicitBeanInfo != null) { 371 additionalBeanInfo = explicitBeanInfo.getAdditionalBeanInfo(); 372 } 373 if (additionalBeanInfo == null) { 374 additionalBeanInfo = new BeanInfo [0]; 375 } 376 } 377 378 381 private BeanInfo getBeanInfo() throws IntrospectionException { 382 383 BeanDescriptor bd = getTargetBeanDescriptor(); 387 MethodDescriptor mds[] = getTargetMethodInfo(); 388 EventSetDescriptor esds[] = getTargetEventInfo(); 389 PropertyDescriptor pds[] = getTargetPropertyInfo(); 390 391 int defaultEvent = getTargetDefaultEventIndex(); 392 int defaultProperty = getTargetDefaultPropertyIndex(); 393 394 return new GenericBeanInfo(bd, esds, defaultEvent, pds, 395 defaultProperty, mds, explicitBeanInfo); 396 397 } 398 399 407 private static synchronized BeanInfo findExplicitBeanInfo(Class beanClass) { 408 String name = beanClass.getName() + BEANINFO_SUFFIX; 409 try { 410 return (java.beans.BeanInfo )instantiate(beanClass, name); 411 } catch (Exception ex) { 412 414 } 415 try { 417 if (isSubclass(beanClass, java.beans.BeanInfo .class)) { 418 return (java.beans.BeanInfo )beanClass.newInstance(); 419 } 420 } catch (Exception ex) { 421 } 423 name = name.substring(name.lastIndexOf('.')+1); 425 426 for (int i = 0; i < searchPath.length; i++) { 427 if (!DEFAULT_INFO_PATH.equals(searchPath[i]) || 430 DEFAULT_INFO_PATH.equals(searchPath[i]) && "ComponentBeanInfo".equals(name)) { 431 try { 432 String fullName = searchPath[i] + "." + name; 433 java.beans.BeanInfo bi = (java.beans.BeanInfo )instantiate(beanClass, fullName); 434 435 if (bi.getBeanDescriptor() != null) { 437 if (bi.getBeanDescriptor().getBeanClass() == beanClass) { 438 return bi; 439 } 440 } else if (bi.getPropertyDescriptors() != null) { 441 PropertyDescriptor [] pds = bi.getPropertyDescriptors(); 442 for (int j = 0; j < pds.length; j++) { 443 Method method = pds[j].getReadMethod(); 444 if (method == null) { 445 method = pds[j].getWriteMethod(); 446 } 447 if (method != null && method.getDeclaringClass() == beanClass) { 448 return bi; 449 } 450 } 451 } else if (bi.getMethodDescriptors() != null) { 452 MethodDescriptor [] mds = bi.getMethodDescriptors(); 453 for (int j = 0; j < mds.length; j++) { 454 Method method = mds[j].getMethod(); 455 if (method != null && method.getDeclaringClass() == beanClass) { 456 return bi; 457 } 458 } 459 } 460 } catch (Exception ex) { 461 } 463 } 464 } 465 return null; 466 } 467 468 472 473 private PropertyDescriptor [] getTargetPropertyInfo() { 474 475 PropertyDescriptor [] explicitProperties = null; 478 if (explicitBeanInfo != null) { 479 explicitProperties = explicitBeanInfo.getPropertyDescriptors(); 480 int ix = explicitBeanInfo.getDefaultPropertyIndex(); 481 if (ix >= 0 && ix < explicitProperties.length) { 482 defaultPropertyName = explicitProperties[ix].getName(); 483 } 484 } 485 486 if (explicitProperties == null && superBeanInfo != null) { 487 PropertyDescriptor supers[] = superBeanInfo.getPropertyDescriptors(); 489 for (int i = 0 ; i < supers.length; i++) { 490 addPropertyDescriptor(supers[i]); 491 } 492 int ix = superBeanInfo.getDefaultPropertyIndex(); 493 if (ix >= 0 && ix < supers.length) { 494 defaultPropertyName = supers[ix].getName(); 495 } 496 } 497 498 for (int i = 0; i < additionalBeanInfo.length; i++) { 499 PropertyDescriptor additional[] = additionalBeanInfo[i].getPropertyDescriptors(); 500 if (additional != null) { 501 for (int j = 0 ; j < additional.length; j++) { 502 addPropertyDescriptor(additional[j]); 503 } 504 } 505 } 506 507 if (explicitProperties != null) { 508 for (int i = 0 ; i < explicitProperties.length; i++) { 510 addPropertyDescriptor(explicitProperties[i]); 511 } 512 513 } else { 514 515 517 Method methodList[] = getPublicDeclaredMethods(beanClass); 519 520 for (int i = 0; i < methodList.length; i++) { 522 Method method = methodList[i]; 523 if (method == null) { 524 continue; 525 } 526 int mods = method.getModifiers(); 528 if (Modifier.isStatic(mods)) { 529 continue; 530 } 531 String name = method.getName(); 532 Class argTypes[] = method.getParameterTypes(); 533 Class resultType = method.getReturnType(); 534 int argCount = argTypes.length; 535 PropertyDescriptor pd = null; 536 537 if (name.length() <= 3 && !name.startsWith(IS_PREFIX)) { 538 continue; 540 } 541 542 try { 543 544 if (argCount == 0) { 545 if (name.startsWith(GET_PREFIX)) { 546 pd = new PropertyDescriptor (decapitalize(name.substring(3)), 548 method, null); 549 } else if (resultType == boolean.class && name.startsWith(IS_PREFIX)) { 550 pd = new PropertyDescriptor (decapitalize(name.substring(2)), 552 method, null); 553 } 554 } else if (argCount == 1) { 555 if (argTypes[0] == int.class && name.startsWith(GET_PREFIX)) { 556 pd = new IndexedPropertyDescriptor ( 557 decapitalize(name.substring(3)), 558 null, null, 559 method, null); 560 } else if (resultType == void.class && name.startsWith(SET_PREFIX)) { 561 pd = new PropertyDescriptor (decapitalize(name.substring(3)), 563 null, method); 564 if (throwsException(method, PropertyVetoException .class)) { 565 pd.setConstrained(true); 566 } 567 } 568 } else if (argCount == 2) { 569 if (argTypes[0] == int.class && name.startsWith(SET_PREFIX)) { 570 pd = new IndexedPropertyDescriptor ( 571 decapitalize(name.substring(3)), 572 null, null, 573 null, method); 574 if (throwsException(method, PropertyVetoException .class)) { 575 pd.setConstrained(true); 576 } 577 } 578 } 579 } catch (IntrospectionException ex) { 580 pd = null; 585 } 586 587 if (pd != null) { 588 if (propertyChangeSource) { 591 pd.setBound(true); 592 } 593 addPropertyDescriptor(pd); 594 } 595 } 596 } 597 processPropertyDescriptors(); 598 599 PropertyDescriptor result[] = new PropertyDescriptor [properties.size()]; 601 result = (PropertyDescriptor [])properties.values().toArray(result); 602 603 if (defaultPropertyName != null) { 605 for (int i = 0; i < result.length; i++) { 606 if (defaultPropertyName.equals(result[i].getName())) { 607 defaultPropertyIndex = i; 608 } 609 } 610 } 611 612 return result; 613 } 614 615 private HashMap pdStore = new HashMap (); 616 617 620 private void addPropertyDescriptor(PropertyDescriptor pd) { 621 String propName = pd.getName(); 622 List list = (List )pdStore.get(propName); 623 if (list == null) { 624 list = new ArrayList (); 625 pdStore.put(propName, list); 626 } 627 list.add(pd); 628 } 629 630 634 private void processPropertyDescriptors() { 635 if (properties == null) { 636 properties = new TreeMap (); 637 } 638 639 List list; 640 641 PropertyDescriptor pd, gpd, spd; 642 IndexedPropertyDescriptor ipd, igpd, ispd; 643 644 Iterator it = pdStore.values().iterator(); 645 while (it.hasNext()) { 646 pd = null; gpd = null; spd = null; 647 ipd = null; igpd = null; ispd = null; 648 649 list = (List )it.next(); 650 651 for (int i = 0; i < list.size(); i++) { 654 pd = (PropertyDescriptor )list.get(i); 655 if (pd instanceof IndexedPropertyDescriptor ) { 656 ipd = (IndexedPropertyDescriptor )pd; 657 if (ipd.getIndexedReadMethod() != null) { 658 if (igpd != null) { 659 igpd = new IndexedPropertyDescriptor (igpd, ipd); 660 } else { 661 igpd = ipd; 662 } 663 } 664 } else { 665 if (pd.getReadMethod() != null) { 666 if (gpd != null) { 667 Method method = gpd.getReadMethod(); 670 if (!method.getName().startsWith(IS_PREFIX)) { 671 gpd = new PropertyDescriptor (gpd, pd); 672 } 673 } else { 674 gpd = pd; 675 } 676 } 677 } 678 } 679 680 for (int i = 0; i < list.size(); i++) { 683 pd = (PropertyDescriptor )list.get(i); 684 if (pd instanceof IndexedPropertyDescriptor ) { 685 ipd = (IndexedPropertyDescriptor )pd; 686 if (ipd.getIndexedWriteMethod() != null) { 687 if (igpd != null) { 688 if (igpd.getIndexedPropertyType() 689 == ipd.getIndexedPropertyType()) { 690 if (ispd != null) { 691 ispd = new IndexedPropertyDescriptor (ispd, ipd); 692 } else { 693 ispd = ipd; 694 } 695 } 696 } else { 697 if (ispd != null) { 698 ispd = new IndexedPropertyDescriptor (ispd, ipd); 699 } else { 700 ispd = ipd; 701 } 702 } 703 } 704 } else { 705 if (pd.getWriteMethod() != null) { 706 if (gpd != null) { 707 if (gpd.getPropertyType() == pd.getPropertyType()) { 708 if (spd != null) { 709 spd = new PropertyDescriptor (spd, pd); 710 } else { 711 spd = pd; 712 } 713 } 714 } else { 715 if (spd != null) { 716 spd = new PropertyDescriptor (spd, pd); 717 } else { 718 spd = pd; 719 } 720 } 721 } 722 } 723 } 724 725 pd = null; ipd = null; 730 731 if (igpd != null && ispd != null) { 732 if (gpd != null) { 735 PropertyDescriptor tpd = mergePropertyDescriptor(igpd, gpd); 736 if (tpd instanceof IndexedPropertyDescriptor ) { 737 igpd = (IndexedPropertyDescriptor )tpd; 738 } 739 } 740 if (spd != null) { 741 PropertyDescriptor tpd = mergePropertyDescriptor(ispd, spd); 742 if (tpd instanceof IndexedPropertyDescriptor ) { 743 ispd = (IndexedPropertyDescriptor )tpd; 744 } 745 } 746 if (igpd == ispd) { 747 pd = igpd; 748 } else { 749 pd = mergePropertyDescriptor(igpd, ispd); 750 } 751 } else if (gpd != null && spd != null) { 752 if (gpd == spd) { 754 pd = gpd; 755 } else { 756 pd = mergePropertyDescriptor(gpd, spd); 757 } 758 } else if (ispd != null) { 759 pd = ispd; 761 if (spd != null) { 763 pd = mergePropertyDescriptor(ispd, spd); 764 } 765 if (gpd != null) { 766 pd = mergePropertyDescriptor(ispd, gpd); 767 } 768 } else if (igpd != null) { 769 pd = igpd; 771 if (gpd != null) { 773 pd = mergePropertyDescriptor(igpd, gpd); 774 } 775 if (spd != null) { 776 pd = mergePropertyDescriptor(igpd, spd); 777 } 778 } else if (spd != null) { 779 pd = spd; 781 } else if (gpd != null) { 782 pd = gpd; 784 } 785 786 if (pd instanceof IndexedPropertyDescriptor ) { 791 ipd = (IndexedPropertyDescriptor )pd; 792 if (ipd.getIndexedReadMethod() == null && ipd.getIndexedWriteMethod() == null) { 793 pd = new PropertyDescriptor  |