jdk/src/share/classes/java/beans/Introspector.java
changeset 11140 f93045767e5d
parent 11086 09b1d6383d0b
parent 11120 f8576c769572
child 11668 138b661e3841
equal deleted inserted replaced
11104:457cc3968455 11140:f93045767e5d
    95     public final static int IGNORE_ALL_BEANINFO        = 3;
    95     public final static int IGNORE_ALL_BEANINFO        = 3;
    96 
    96 
    97     // Static Caches to speed up introspection.
    97     // Static Caches to speed up introspection.
    98     private static final WeakCache<Class<?>, Method[]> declaredMethodCache = new WeakCache<>();
    98     private static final WeakCache<Class<?>, Method[]> declaredMethodCache = new WeakCache<>();
    99 
    99 
   100     private Class beanClass;
   100     private Class<?> beanClass;
   101     private BeanInfo explicitBeanInfo;
   101     private BeanInfo explicitBeanInfo;
   102     private BeanInfo superBeanInfo;
   102     private BeanInfo superBeanInfo;
   103     private BeanInfo additionalBeanInfo[];
   103     private BeanInfo additionalBeanInfo[];
   104 
   104 
   105     private boolean propertyChangeSource = false;
   105     private boolean propertyChangeSource = false;
   106     private static Class eventListenerType = EventListener.class;
   106     private static Class<EventListener> eventListenerType = EventListener.class;
   107 
   107 
   108     // These should be removed.
   108     // These should be removed.
   109     private String defaultEventName;
   109     private String defaultEventName;
   110     private String defaultPropertyName;
   110     private String defaultPropertyName;
   111     private int defaultEventIndex = -1;
   111     private int defaultEventIndex = -1;
   112     private int defaultPropertyIndex = -1;
   112     private int defaultPropertyIndex = -1;
   113 
   113 
   114     // Methods maps from Method objects to MethodDescriptors
   114     // Methods maps from Method names to MethodDescriptors
   115     private Map methods;
   115     private Map<String, MethodDescriptor> methods;
   116 
   116 
   117     // properties maps from String names to PropertyDescriptors
   117     // properties maps from String names to PropertyDescriptors
   118     private Map properties;
   118     private Map<String, PropertyDescriptor> properties;
   119 
   119 
   120     // events maps from String names to EventSetDescriptors
   120     // events maps from String names to EventSetDescriptors
   121     private Map events;
   121     private Map<String, EventSetDescriptor> events;
   122 
   122 
   123     private final static EventSetDescriptor[] EMPTY_EVENTSETDESCRIPTORS = new EventSetDescriptor[0];
   123     private final static EventSetDescriptor[] EMPTY_EVENTSETDESCRIPTORS = new EventSetDescriptor[0];
   124 
   124 
   125     static final String ADD_PREFIX = "add";
   125     static final String ADD_PREFIX = "add";
   126     static final String REMOVE_PREFIX = "remove";
   126     static final String REMOVE_PREFIX = "remove";
   362 
   362 
   363     //======================================================================
   363     //======================================================================
   364     //                  Private implementation methods
   364     //                  Private implementation methods
   365     //======================================================================
   365     //======================================================================
   366 
   366 
   367     private Introspector(Class beanClass, Class stopClass, int flags)
   367     private Introspector(Class<?> beanClass, Class<?> stopClass, int flags)
   368                                             throws IntrospectionException {
   368                                             throws IntrospectionException {
   369         this.beanClass = beanClass;
   369         this.beanClass = beanClass;
   370 
   370 
   371         // Check stopClass is a superClass of startClass.
   371         // Check stopClass is a superClass of startClass.
   372         if (stopClass != null) {
   372         if (stopClass != null) {
   373             boolean isSuper = false;
   373             boolean isSuper = false;
   374             for (Class c = beanClass.getSuperclass(); c != null; c = c.getSuperclass()) {
   374             for (Class<?> c = beanClass.getSuperclass(); c != null; c = c.getSuperclass()) {
   375                 if (c == stopClass) {
   375                 if (c == stopClass) {
   376                     isSuper = true;
   376                     isSuper = true;
   377                 }
   377                 }
   378             }
   378             }
   379             if (!isSuper) {
   379             if (!isSuper) {
   384 
   384 
   385         if (flags == USE_ALL_BEANINFO) {
   385         if (flags == USE_ALL_BEANINFO) {
   386             explicitBeanInfo = findExplicitBeanInfo(beanClass);
   386             explicitBeanInfo = findExplicitBeanInfo(beanClass);
   387         }
   387         }
   388 
   388 
   389         Class superClass = beanClass.getSuperclass();
   389         Class<?> superClass = beanClass.getSuperclass();
   390         if (superClass != stopClass) {
   390         if (superClass != stopClass) {
   391             int newFlags = flags;
   391             int newFlags = flags;
   392             if (newFlags == IGNORE_IMMEDIATE_BEANINFO) {
   392             if (newFlags == IGNORE_IMMEDIATE_BEANINFO) {
   393                 newFlags = USE_ALL_BEANINFO;
   393                 newFlags = USE_ALL_BEANINFO;
   394             }
   394             }
   430      * the BeanInfo search path is prepended to the class and searched.
   430      * the BeanInfo search path is prepended to the class and searched.
   431      *
   431      *
   432      * @param beanClass  the class type of the bean
   432      * @param beanClass  the class type of the bean
   433      * @return Instance of an explicit BeanInfo class or null if one isn't found.
   433      * @return Instance of an explicit BeanInfo class or null if one isn't found.
   434      */
   434      */
   435     private static BeanInfo findExplicitBeanInfo(Class beanClass) {
   435     private static BeanInfo findExplicitBeanInfo(Class<?> beanClass) {
   436         return ThreadGroupContext.getContext().getBeanInfoFinder().find(beanClass);
   436         return ThreadGroupContext.getContext().getBeanInfoFinder().find(beanClass);
   437     }
   437     }
   438 
   438 
   439     /**
   439     /**
   440      * @return An array of PropertyDescriptors describing the editable
   440      * @return An array of PropertyDescriptors describing the editable
   480                 int mods = method.getModifiers();
   480                 int mods = method.getModifiers();
   481                 if (Modifier.isStatic(mods)) {
   481                 if (Modifier.isStatic(mods)) {
   482                     continue;
   482                     continue;
   483                 }
   483                 }
   484                 String name = method.getName();
   484                 String name = method.getName();
   485                 Class argTypes[] = method.getParameterTypes();
   485                 Class<?>[] argTypes = method.getParameterTypes();
   486                 Class resultType = method.getReturnType();
   486                 Class<?> resultType = method.getReturnType();
   487                 int argCount = argTypes.length;
   487                 int argCount = argTypes.length;
   488                 PropertyDescriptor pd = null;
   488                 PropertyDescriptor pd = null;
   489 
   489 
   490                 if (name.length() <= 3 && !name.startsWith(IS_PREFIX)) {
   490                 if (name.length() <= 3 && !name.startsWith(IS_PREFIX)) {
   491                     // Optimization. Don't bother with invalid propertyNames.
   491                     // Optimization. Don't bother with invalid propertyNames.
   539             }
   539             }
   540         }
   540         }
   541         processPropertyDescriptors();
   541         processPropertyDescriptors();
   542 
   542 
   543         // Allocate and populate the result array.
   543         // Allocate and populate the result array.
   544         PropertyDescriptor result[] = new PropertyDescriptor[properties.size()];
   544         PropertyDescriptor result[] =
   545         result = (PropertyDescriptor[])properties.values().toArray(result);
   545                 properties.values().toArray(new PropertyDescriptor[properties.size()]);
   546 
   546 
   547         // Set the default index.
   547         // Set the default index.
   548         if (defaultPropertyName != null) {
   548         if (defaultPropertyName != null) {
   549             for (int i = 0; i < result.length; i++) {
   549             for (int i = 0; i < result.length; i++) {
   550                 if (defaultPropertyName.equals(result[i].getName())) {
   550                 if (defaultPropertyName.equals(result[i].getName())) {
   554         }
   554         }
   555 
   555 
   556         return result;
   556         return result;
   557     }
   557     }
   558 
   558 
   559     private HashMap pdStore = new HashMap();
   559     private HashMap<String, List<PropertyDescriptor>> pdStore = new HashMap<>();
   560 
   560 
   561     /**
   561     /**
   562      * Adds the property descriptor to the list store.
   562      * Adds the property descriptor to the list store.
   563      */
   563      */
   564     private void addPropertyDescriptor(PropertyDescriptor pd) {
   564     private void addPropertyDescriptor(PropertyDescriptor pd) {
   565         String propName = pd.getName();
   565         String propName = pd.getName();
   566         List list = (List)pdStore.get(propName);
   566         List<PropertyDescriptor> list = pdStore.get(propName);
   567         if (list == null) {
   567         if (list == null) {
   568             list = new ArrayList();
   568             list = new ArrayList<>();
   569             pdStore.put(propName, list);
   569             pdStore.put(propName, list);
   570         }
   570         }
   571         if (this.beanClass != pd.getClass0()) {
   571         if (this.beanClass != pd.getClass0()) {
   572             // replace existing property descriptor
   572             // replace existing property descriptor
   573             // only if we have types to resolve
   573             // only if we have types to resolve
   618      * Populates the property descriptor table by merging the
   618      * Populates the property descriptor table by merging the
   619      * lists of Property descriptors.
   619      * lists of Property descriptors.
   620      */
   620      */
   621     private void processPropertyDescriptors() {
   621     private void processPropertyDescriptors() {
   622         if (properties == null) {
   622         if (properties == null) {
   623             properties = new TreeMap();
   623             properties = new TreeMap<>();
   624         }
   624         }
   625 
   625 
   626         List list;
   626         List<PropertyDescriptor> list;
   627 
   627 
   628         PropertyDescriptor pd, gpd, spd;
   628         PropertyDescriptor pd, gpd, spd;
   629         IndexedPropertyDescriptor ipd, igpd, ispd;
   629         IndexedPropertyDescriptor ipd, igpd, ispd;
   630 
   630 
   631         Iterator it = pdStore.values().iterator();
   631         Iterator<List<PropertyDescriptor>> it = pdStore.values().iterator();
   632         while (it.hasNext()) {
   632         while (it.hasNext()) {
   633             pd = null; gpd = null; spd = null;
   633             pd = null; gpd = null; spd = null;
   634             ipd = null; igpd = null; ispd = null;
   634             ipd = null; igpd = null; ispd = null;
   635 
   635 
   636             list = (List)it.next();
   636             list = it.next();
   637 
   637 
   638             // First pass. Find the latest getter method. Merge properties
   638             // First pass. Find the latest getter method. Merge properties
   639             // of previous getter methods.
   639             // of previous getter methods.
   640             for (int i = 0; i < list.size(); i++) {
   640             for (int i = 0; i < list.size(); i++) {
   641                 pd = (PropertyDescriptor)list.get(i);
   641                 pd = list.get(i);
   642                 if (pd instanceof IndexedPropertyDescriptor) {
   642                 if (pd instanceof IndexedPropertyDescriptor) {
   643                     ipd = (IndexedPropertyDescriptor)pd;
   643                     ipd = (IndexedPropertyDescriptor)pd;
   644                     if (ipd.getIndexedReadMethod() != null) {
   644                     if (ipd.getIndexedReadMethod() != null) {
   645                         if (igpd != null) {
   645                         if (igpd != null) {
   646                             igpd = new IndexedPropertyDescriptor(igpd, ipd);
   646                             igpd = new IndexedPropertyDescriptor(igpd, ipd);
   665             }
   665             }
   666 
   666 
   667             // Second pass. Find the latest setter method which
   667             // Second pass. Find the latest setter method which
   668             // has the same type as the getter method.
   668             // has the same type as the getter method.
   669             for (int i = 0; i < list.size(); i++) {
   669             for (int i = 0; i < list.size(); i++) {
   670                 pd = (PropertyDescriptor)list.get(i);
   670                 pd = list.get(i);
   671                 if (pd instanceof IndexedPropertyDescriptor) {
   671                 if (pd instanceof IndexedPropertyDescriptor) {
   672                     ipd = (IndexedPropertyDescriptor)pd;
   672                     ipd = (IndexedPropertyDescriptor)pd;
   673                     if (ipd.getIndexedWriteMethod() != null) {
   673                     if (ipd.getIndexedWriteMethod() != null) {
   674                         if (igpd != null) {
   674                         if (igpd != null) {
   675                             if (igpd.getIndexedPropertyType()
   675                             if (igpd.getIndexedPropertyType()
   783 
   783 
   784             // Find the first property descriptor
   784             // Find the first property descriptor
   785             // which does not have getter and setter methods.
   785             // which does not have getter and setter methods.
   786             // See regression bug 4984912.
   786             // See regression bug 4984912.
   787             if ( (pd == null) && (list.size() > 0) ) {
   787             if ( (pd == null) && (list.size() > 0) ) {
   788                 pd = (PropertyDescriptor) list.get(0);
   788                 pd = list.get(0);
   789             }
   789             }
   790 
   790 
   791             if (pd != null) {
   791             if (pd != null) {
   792                 properties.put(pd.getName(), pd);
   792                 properties.put(pd.getName(), pd);
   793             }
   793             }
   802      */
   802      */
   803     private PropertyDescriptor mergePropertyDescriptor(IndexedPropertyDescriptor ipd,
   803     private PropertyDescriptor mergePropertyDescriptor(IndexedPropertyDescriptor ipd,
   804                                                        PropertyDescriptor pd) {
   804                                                        PropertyDescriptor pd) {
   805         PropertyDescriptor result = null;
   805         PropertyDescriptor result = null;
   806 
   806 
   807         Class propType = pd.getPropertyType();
   807         Class<?> propType = pd.getPropertyType();
   808         Class ipropType = ipd.getIndexedPropertyType();
   808         Class<?> ipropType = ipd.getIndexedPropertyType();
   809 
   809 
   810         if (propType.isArray() && propType.getComponentType() == ipropType) {
   810         if (propType.isArray() && propType.getComponentType() == ipropType) {
   811             if (pd.getClass0().isAssignableFrom(ipd.getClass0())) {
   811             if (pd.getClass0().isAssignableFrom(ipd.getClass0())) {
   812                 result = new IndexedPropertyDescriptor(pd, ipd);
   812                 result = new IndexedPropertyDescriptor(pd, ipd);
   813             } else {
   813             } else {
   837                     }
   837                     }
   838                 }
   838                 }
   839                 if (write == null && read != null) {
   839                 if (write == null && read != null) {
   840                     write = findMethod(result.getClass0(),
   840                     write = findMethod(result.getClass0(),
   841                                        SET_PREFIX + NameGenerator.capitalize(result.getName()), 1,
   841                                        SET_PREFIX + NameGenerator.capitalize(result.getName()), 1,
   842                                        new Class[] { FeatureDescriptor.getReturnType(result.getClass0(), read) });
   842                                        new Class<?>[] { FeatureDescriptor.getReturnType(result.getClass0(), read) });
   843                     if (write != null) {
   843                     if (write != null) {
   844                         try {
   844                         try {
   845                             result.setWriteMethod(write);
   845                             result.setWriteMethod(write);
   846                         } catch (IntrospectionException ex) {
   846                         } catch (IntrospectionException ex) {
   847                             // no consequences for failure.
   847                             // no consequences for failure.
   877      * @return An array of EventSetDescriptors describing the kinds of
   877      * @return An array of EventSetDescriptors describing the kinds of
   878      * events fired by the target bean.
   878      * events fired by the target bean.
   879      */
   879      */
   880     private EventSetDescriptor[] getTargetEventInfo() throws IntrospectionException {
   880     private EventSetDescriptor[] getTargetEventInfo() throws IntrospectionException {
   881         if (events == null) {
   881         if (events == null) {
   882             events = new HashMap();
   882             events = new HashMap<>();
   883         }
   883         }
   884 
   884 
   885         // Check if the bean has its own BeanInfo that will provide
   885         // Check if the bean has its own BeanInfo that will provide
   886         // explicit information.
   886         // explicit information.
   887         EventSetDescriptor[] explicitEvents = null;
   887         EventSetDescriptor[] explicitEvents = null;
   928             Method methodList[] = getPublicDeclaredMethods(beanClass);
   928             Method methodList[] = getPublicDeclaredMethods(beanClass);
   929 
   929 
   930             // Find all suitable "add", "remove" and "get" Listener methods
   930             // Find all suitable "add", "remove" and "get" Listener methods
   931             // The name of the listener type is the key for these hashtables
   931             // The name of the listener type is the key for these hashtables
   932             // i.e, ActionListener
   932             // i.e, ActionListener
   933             Map adds = null;
   933             Map<String, Method> adds = null;
   934             Map removes = null;
   934             Map<String, Method> removes = null;
   935             Map gets = null;
   935             Map<String, Method> gets = null;
   936 
   936 
   937             for (int i = 0; i < methodList.length; i++) {
   937             for (int i = 0; i < methodList.length; i++) {
   938                 Method method = methodList[i];
   938                 Method method = methodList[i];
   939                 if (method == null) {
   939                 if (method == null) {
   940                     continue;
   940                     continue;
   949                 if (!name.startsWith(ADD_PREFIX) && !name.startsWith(REMOVE_PREFIX)
   949                 if (!name.startsWith(ADD_PREFIX) && !name.startsWith(REMOVE_PREFIX)
   950                     && !name.startsWith(GET_PREFIX)) {
   950                     && !name.startsWith(GET_PREFIX)) {
   951                     continue;
   951                     continue;
   952                 }
   952                 }
   953 
   953 
   954                 Class argTypes[] = FeatureDescriptor.getParameterTypes(beanClass, method);
   954                 Class<?>[] argTypes = FeatureDescriptor.getParameterTypes(beanClass, method);
   955                 Class resultType = FeatureDescriptor.getReturnType(beanClass, method);
   955                 Class<?> resultType = FeatureDescriptor.getReturnType(beanClass, method);
   956 
   956 
   957                 if (name.startsWith(ADD_PREFIX) && argTypes.length == 1 &&
   957                 if (name.startsWith(ADD_PREFIX) && argTypes.length == 1 &&
   958                     resultType == Void.TYPE &&
   958                     resultType == Void.TYPE &&
   959                     Introspector.isSubclass(argTypes[0], eventListenerType)) {
   959                     Introspector.isSubclass(argTypes[0], eventListenerType)) {
   960                     String listenerName = name.substring(3);
   960                     String listenerName = name.substring(3);
   961                     if (listenerName.length() > 0 &&
   961                     if (listenerName.length() > 0 &&
   962                         argTypes[0].getName().endsWith(listenerName)) {
   962                         argTypes[0].getName().endsWith(listenerName)) {
   963                         if (adds == null) {
   963                         if (adds == null) {
   964                             adds = new HashMap();
   964                             adds = new HashMap<>();
   965                         }
   965                         }
   966                         adds.put(listenerName, method);
   966                         adds.put(listenerName, method);
   967                     }
   967                     }
   968                 }
   968                 }
   969                 else if (name.startsWith(REMOVE_PREFIX) && argTypes.length == 1 &&
   969                 else if (name.startsWith(REMOVE_PREFIX) && argTypes.length == 1 &&
   971                          Introspector.isSubclass(argTypes[0], eventListenerType)) {
   971                          Introspector.isSubclass(argTypes[0], eventListenerType)) {
   972                     String listenerName = name.substring(6);
   972                     String listenerName = name.substring(6);
   973                     if (listenerName.length() > 0 &&
   973                     if (listenerName.length() > 0 &&
   974                         argTypes[0].getName().endsWith(listenerName)) {
   974                         argTypes[0].getName().endsWith(listenerName)) {
   975                         if (removes == null) {
   975                         if (removes == null) {
   976                             removes = new HashMap();
   976                             removes = new HashMap<>();
   977                         }
   977                         }
   978                         removes.put(listenerName, method);
   978                         removes.put(listenerName, method);
   979                     }
   979                     }
   980                 }
   980                 }
   981                 else if (name.startsWith(GET_PREFIX) && argTypes.length == 0 &&
   981                 else if (name.startsWith(GET_PREFIX) && argTypes.length == 0 &&
   984                                                  eventListenerType)) {
   984                                                  eventListenerType)) {
   985                     String listenerName  = name.substring(3, name.length() - 1);
   985                     String listenerName  = name.substring(3, name.length() - 1);
   986                     if (listenerName.length() > 0 &&
   986                     if (listenerName.length() > 0 &&
   987                         resultType.getComponentType().getName().endsWith(listenerName)) {
   987                         resultType.getComponentType().getName().endsWith(listenerName)) {
   988                         if (gets == null) {
   988                         if (gets == null) {
   989                             gets = new HashMap();
   989                             gets = new HashMap<>();
   990                         }
   990                         }
   991                         gets.put(listenerName, method);
   991                         gets.put(listenerName, method);
   992                     }
   992                     }
   993                 }
   993                 }
   994             }
   994             }
   995 
   995 
   996             if (adds != null && removes != null) {
   996             if (adds != null && removes != null) {
   997                 // Now look for matching addFooListener+removeFooListener pairs.
   997                 // Now look for matching addFooListener+removeFooListener pairs.
   998                 // Bonus if there is a matching getFooListeners method as well.
   998                 // Bonus if there is a matching getFooListeners method as well.
   999                 Iterator keys = adds.keySet().iterator();
   999                 Iterator<String> keys = adds.keySet().iterator();
  1000                 while (keys.hasNext()) {
  1000                 while (keys.hasNext()) {
  1001                     String listenerName = (String) keys.next();
  1001                     String listenerName = keys.next();
  1002                     // Skip any "add" which doesn't have a matching "remove" or
  1002                     // Skip any "add" which doesn't have a matching "remove" or
  1003                     // a listener name that doesn't end with Listener
  1003                     // a listener name that doesn't end with Listener
  1004                     if (removes.get(listenerName) == null || !listenerName.endsWith("Listener")) {
  1004                     if (removes.get(listenerName) == null || !listenerName.endsWith("Listener")) {
  1005                         continue;
  1005                         continue;
  1006                     }
  1006                     }
  1007                     String eventName = decapitalize(listenerName.substring(0, listenerName.length()-8));
  1007                     String eventName = decapitalize(listenerName.substring(0, listenerName.length()-8));
  1008                     Method addMethod = (Method)adds.get(listenerName);
  1008                     Method addMethod = adds.get(listenerName);
  1009                     Method removeMethod = (Method)removes.get(listenerName);
  1009                     Method removeMethod = removes.get(listenerName);
  1010                     Method getMethod = null;
  1010                     Method getMethod = null;
  1011                     if (gets != null) {
  1011                     if (gets != null) {
  1012                         getMethod = (Method)gets.get(listenerName);
  1012                         getMethod = gets.get(listenerName);
  1013                     }
  1013                     }
  1014                     Class argType = FeatureDescriptor.getParameterTypes(beanClass, addMethod)[0];
  1014                     Class<?> argType = FeatureDescriptor.getParameterTypes(beanClass, addMethod)[0];
  1015 
  1015 
  1016                     // generate a list of Method objects for each of the target methods:
  1016                     // generate a list of Method objects for each of the target methods:
  1017                     Method allMethods[] = getPublicDeclaredMethods(argType);
  1017                     Method allMethods[] = getPublicDeclaredMethods(argType);
  1018                     List validMethods = new ArrayList(allMethods.length);
  1018                     List<Method> validMethods = new ArrayList<>(allMethods.length);
  1019                     for (int i = 0; i < allMethods.length; i++) {
  1019                     for (int i = 0; i < allMethods.length; i++) {
  1020                         if (allMethods[i] == null) {
  1020                         if (allMethods[i] == null) {
  1021                             continue;
  1021                             continue;
  1022                         }
  1022                         }
  1023 
  1023 
  1024                         if (isEventHandler(allMethods[i])) {
  1024                         if (isEventHandler(allMethods[i])) {
  1025                             validMethods.add(allMethods[i]);
  1025                             validMethods.add(allMethods[i]);
  1026                         }
  1026                         }
  1027                     }
  1027                     }
  1028                     Method[] methods = (Method[])validMethods.toArray(new Method[validMethods.size()]);
  1028                     Method[] methods = validMethods.toArray(new Method[validMethods.size()]);
  1029 
  1029 
  1030                     EventSetDescriptor esd = new EventSetDescriptor(eventName, argType,
  1030                     EventSetDescriptor esd = new EventSetDescriptor(eventName, argType,
  1031                                                                     methods, addMethod,
  1031                                                                     methods, addMethod,
  1032                                                                     removeMethod,
  1032                                                                     removeMethod,
  1033                                                                     getMethod);
  1033                                                                     getMethod);
  1046         if (events.size() == 0) {
  1046         if (events.size() == 0) {
  1047             result = EMPTY_EVENTSETDESCRIPTORS;
  1047             result = EMPTY_EVENTSETDESCRIPTORS;
  1048         } else {
  1048         } else {
  1049             // Allocate and populate the result array.
  1049             // Allocate and populate the result array.
  1050             result = new EventSetDescriptor[events.size()];
  1050             result = new EventSetDescriptor[events.size()];
  1051             result = (EventSetDescriptor[])events.values().toArray(result);
  1051             result = events.values().toArray(result);
  1052 
  1052 
  1053             // Set the default index.
  1053             // Set the default index.
  1054             if (defaultEventName != null) {
  1054             if (defaultEventName != null) {
  1055                 for (int i = 0; i < result.length; i++) {
  1055                 for (int i = 0; i < result.length; i++) {
  1056                     if (defaultEventName.equals(result[i].getName())) {
  1056                     if (defaultEventName.equals(result[i].getName())) {
  1065     private void addEvent(EventSetDescriptor esd) {
  1065     private void addEvent(EventSetDescriptor esd) {
  1066         String key = esd.getName();
  1066         String key = esd.getName();
  1067         if (esd.getName().equals("propertyChange")) {
  1067         if (esd.getName().equals("propertyChange")) {
  1068             propertyChangeSource = true;
  1068             propertyChangeSource = true;
  1069         }
  1069         }
  1070         EventSetDescriptor old = (EventSetDescriptor)events.get(key);
  1070         EventSetDescriptor old = events.get(key);
  1071         if (old == null) {
  1071         if (old == null) {
  1072             events.put(key, esd);
  1072             events.put(key, esd);
  1073             return;
  1073             return;
  1074         }
  1074         }
  1075         EventSetDescriptor composite = new EventSetDescriptor(old, esd);
  1075         EventSetDescriptor composite = new EventSetDescriptor(old, esd);
  1080      * @return An array of MethodDescriptors describing the private
  1080      * @return An array of MethodDescriptors describing the private
  1081      * methods supported by the target bean.
  1081      * methods supported by the target bean.
  1082      */
  1082      */
  1083     private MethodDescriptor[] getTargetMethodInfo() {
  1083     private MethodDescriptor[] getTargetMethodInfo() {
  1084         if (methods == null) {
  1084         if (methods == null) {
  1085             methods = new HashMap(100);
  1085             methods = new HashMap<>(100);
  1086         }
  1086         }
  1087 
  1087 
  1088         // Check if the bean has its own BeanInfo that will provide
  1088         // Check if the bean has its own BeanInfo that will provide
  1089         // explicit information.
  1089         // explicit information.
  1090         MethodDescriptor[] explicitMethods = null;
  1090         MethodDescriptor[] explicitMethods = null;
  1133             }
  1133             }
  1134         }
  1134         }
  1135 
  1135 
  1136         // Allocate and populate the result array.
  1136         // Allocate and populate the result array.
  1137         MethodDescriptor result[] = new MethodDescriptor[methods.size()];
  1137         MethodDescriptor result[] = new MethodDescriptor[methods.size()];
  1138         result = (MethodDescriptor[])methods.values().toArray(result);
  1138         result = methods.values().toArray(result);
  1139 
  1139 
  1140         return result;
  1140         return result;
  1141     }
  1141     }
  1142 
  1142 
  1143     private void addMethod(MethodDescriptor md) {
  1143     private void addMethod(MethodDescriptor md) {
  1144         // We have to be careful here to distinguish method by both name
  1144         // We have to be careful here to distinguish method by both name
  1145         // and argument lists.
  1145         // and argument lists.
  1146         // This method gets called a *lot, so we try to be efficient.
  1146         // This method gets called a *lot, so we try to be efficient.
  1147         String name = md.getName();
  1147         String name = md.getName();
  1148 
  1148 
  1149         MethodDescriptor old = (MethodDescriptor)methods.get(name);
  1149         MethodDescriptor old = methods.get(name);
  1150         if (old == null) {
  1150         if (old == null) {
  1151             // This is the common case.
  1151             // This is the common case.
  1152             methods.put(name, md);
  1152             methods.put(name, md);
  1153             return;
  1153             return;
  1154         }
  1154         }
  1177 
  1177 
  1178         // We have a collision on method names with different type signatures.
  1178         // We have a collision on method names with different type signatures.
  1179         // This is very rare.
  1179         // This is very rare.
  1180 
  1180 
  1181         String longKey = makeQualifiedMethodName(name, p1);
  1181         String longKey = makeQualifiedMethodName(name, p1);
  1182         old = (MethodDescriptor)methods.get(longKey);
  1182         old = methods.get(longKey);
  1183         if (old == null) {
  1183         if (old == null) {
  1184             methods.put(longKey, md);
  1184             methods.put(longKey, md);
  1185             return;
  1185             return;
  1186         }
  1186         }
  1187         MethodDescriptor composite = new MethodDescriptor(old, md);
  1187         MethodDescriptor composite = new MethodDescriptor(old, md);
  1248     }
  1248     }
  1249 
  1249 
  1250     /*
  1250     /*
  1251      * Internal method to return *public* methods within a class.
  1251      * Internal method to return *public* methods within a class.
  1252      */
  1252      */
  1253     private static Method[] getPublicDeclaredMethods(Class clz) {
  1253     private static Method[] getPublicDeclaredMethods(Class<?> clz) {
  1254         // Looking up Class.getDeclaredMethods is relatively expensive,
  1254         // Looking up Class.getDeclaredMethods is relatively expensive,
  1255         // so we cache the results.
  1255         // so we cache the results.
  1256         if (!ReflectUtil.isPackageAccessible(clz)) {
  1256         if (!ReflectUtil.isPackageAccessible(clz)) {
  1257             return new Method[0];
  1257             return new Method[0];
  1258         }
  1258         }
  1278 
  1278 
  1279     /**
  1279     /**
  1280      * Internal support for finding a target methodName with a given
  1280      * Internal support for finding a target methodName with a given
  1281      * parameter list on a given class.
  1281      * parameter list on a given class.
  1282      */
  1282      */
  1283     private static Method internalFindMethod(Class start, String methodName,
  1283     private static Method internalFindMethod(Class<?> start, String methodName,
  1284                                                  int argCount, Class args[]) {
  1284                                                  int argCount, Class args[]) {
  1285         // For overriden methods we need to find the most derived version.
  1285         // For overriden methods we need to find the most derived version.
  1286         // So we start with the given class and walk up the superclass chain.
  1286         // So we start with the given class and walk up the superclass chain.
  1287 
  1287 
  1288         Method method = null;
  1288         Method method = null;
  1289 
  1289 
  1290         for (Class cl = start; cl != null; cl = cl.getSuperclass()) {
  1290         for (Class<?> cl = start; cl != null; cl = cl.getSuperclass()) {
  1291             Method methods[] = getPublicDeclaredMethods(cl);
  1291             Method methods[] = getPublicDeclaredMethods(cl);
  1292             for (int i = 0; i < methods.length; i++) {
  1292             for (int i = 0; i < methods.length; i++) {
  1293                 method = methods[i];
  1293                 method = methods[i];
  1294                 if (method == null) {
  1294                 if (method == null) {
  1295                     continue;
  1295                     continue;
  1336     }
  1336     }
  1337 
  1337 
  1338     /**
  1338     /**
  1339      * Find a target methodName on a given class.
  1339      * Find a target methodName on a given class.
  1340      */
  1340      */
  1341     static Method findMethod(Class cls, String methodName, int argCount) {
  1341     static Method findMethod(Class<?> cls, String methodName, int argCount) {
  1342         return findMethod(cls, methodName, argCount, null);
  1342         return findMethod(cls, methodName, argCount, null);
  1343     }
  1343     }
  1344 
  1344 
  1345     /**
  1345     /**
  1346      * Find a target methodName with specific parameter list on a given class.
  1346      * Find a target methodName with specific parameter list on a given class.
  1352      * @param methodName Name of the method.
  1352      * @param methodName Name of the method.
  1353      * @param argCount Number of arguments for the desired method.
  1353      * @param argCount Number of arguments for the desired method.
  1354      * @param args Array of argument types for the method.
  1354      * @param args Array of argument types for the method.
  1355      * @return the method or null if not found
  1355      * @return the method or null if not found
  1356      */
  1356      */
  1357     static Method findMethod(Class cls, String methodName, int argCount,
  1357     static Method findMethod(Class<?> cls, String methodName, int argCount,
  1358                              Class args[]) {
  1358                              Class args[]) {
  1359         if (methodName == null) {
  1359         if (methodName == null) {
  1360             return null;
  1360             return null;
  1361         }
  1361         }
  1362         return internalFindMethod(cls, methodName, argCount, args);
  1362         return internalFindMethod(cls, methodName, argCount, args);
  1366      * Return true if class a is either equivalent to class b, or
  1366      * Return true if class a is either equivalent to class b, or
  1367      * if class a is a subclass of class b, i.e. if a either "extends"
  1367      * if class a is a subclass of class b, i.e. if a either "extends"
  1368      * or "implements" b.
  1368      * or "implements" b.
  1369      * Note tht either or both "Class" objects may represent interfaces.
  1369      * Note tht either or both "Class" objects may represent interfaces.
  1370      */
  1370      */
  1371     static  boolean isSubclass(Class a, Class b) {
  1371     static  boolean isSubclass(Class<?> a, Class<?> b) {
  1372         // We rely on the fact that for any given java class or
  1372         // We rely on the fact that for any given java class or
  1373         // primtitive type there is a unqiue Class object, so
  1373         // primtitive type there is a unqiue Class object, so
  1374         // we can use object equivalence in the comparisons.
  1374         // we can use object equivalence in the comparisons.
  1375         if (a == b) {
  1375         if (a == b) {
  1376             return true;
  1376             return true;
  1377         }
  1377         }
  1378         if (a == null || b == null) {
  1378         if (a == null || b == null) {
  1379             return false;
  1379             return false;
  1380         }
  1380         }
  1381         for (Class x = a; x != null; x = x.getSuperclass()) {
  1381         for (Class<?> x = a; x != null; x = x.getSuperclass()) {
  1382             if (x == b) {
  1382             if (x == b) {
  1383                 return true;
  1383                 return true;
  1384             }
  1384             }
  1385             if (b.isInterface()) {
  1385             if (b.isInterface()) {
  1386                 Class interfaces[] = x.getInterfaces();
  1386                 Class<?>[] interfaces = x.getInterfaces();
  1387                 for (int i = 0; i < interfaces.length; i++) {
  1387                 for (int i = 0; i < interfaces.length; i++) {
  1388                     if (isSubclass(interfaces[i], b)) {
  1388                     if (isSubclass(interfaces[i], b)) {
  1389                         return true;
  1389                         return true;
  1390                     }
  1390                     }
  1391                 }
  1391                 }
  1395     }
  1395     }
  1396 
  1396 
  1397     /**
  1397     /**
  1398      * Return true iff the given method throws the given exception.
  1398      * Return true iff the given method throws the given exception.
  1399      */
  1399      */
  1400     private boolean throwsException(Method method, Class exception) {
  1400     private boolean throwsException(Method method, Class<?> exception) {
  1401         Class exs[] = method.getExceptionTypes();
  1401         Class exs[] = method.getExceptionTypes();
  1402         for (int i = 0; i < exs.length; i++) {
  1402         for (int i = 0; i < exs.length; i++) {
  1403             if (exs[i] == exception) {
  1403             if (exs[i] == exception) {
  1404                 return true;
  1404                 return true;
  1405             }
  1405             }
  1410     /**
  1410     /**
  1411      * Try to create an instance of a named class.
  1411      * Try to create an instance of a named class.
  1412      * First try the classloader of "sibling", then try the system
  1412      * First try the classloader of "sibling", then try the system
  1413      * classloader then the class loader of the current Thread.
  1413      * classloader then the class loader of the current Thread.
  1414      */
  1414      */
  1415     static Object instantiate(Class sibling, String className)
  1415     static Object instantiate(Class<?> sibling, String className)
  1416                  throws InstantiationException, IllegalAccessException,
  1416                  throws InstantiationException, IllegalAccessException,
  1417                                                 ClassNotFoundException {
  1417                                                 ClassNotFoundException {
  1418         // First check with sibling's classloader (if any).
  1418         // First check with sibling's classloader (if any).
  1419         ClassLoader cl = sibling.getClassLoader();
  1419         ClassLoader cl = sibling.getClassLoader();
  1420         Class cls = ClassFinder.findClass(className, cl);
  1420         Class<?> cls = ClassFinder.findClass(className, cl);
  1421         return cls.newInstance();
  1421         return cls.newInstance();
  1422     }
  1422     }
  1423 
  1423 
  1424 } // end class Introspector
  1424 } // end class Introspector
  1425 
  1425 
  1450         this.events = events;
  1450         this.events = events;
  1451         this.defaultEvent = defaultEvent;
  1451         this.defaultEvent = defaultEvent;
  1452         this.properties = properties;
  1452         this.properties = properties;
  1453         this.defaultProperty = defaultProperty;
  1453         this.defaultProperty = defaultProperty;
  1454         this.methods = methods;
  1454         this.methods = methods;
  1455         this.targetBeanInfoRef = new SoftReference<BeanInfo>(targetBeanInfo);
  1455         this.targetBeanInfoRef = new SoftReference<>(targetBeanInfo);
  1456     }
  1456     }
  1457 
  1457 
  1458     /**
  1458     /**
  1459      * Package-private dup constructor
  1459      * Package-private dup constructor
  1460      * This must isolate the new object from any changes to the old object.
  1460      * This must isolate the new object from any changes to the old object.