Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/java/beans/Introspector.java
41152 views
1
/*
2
* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package java.beans;
27
28
import java.awt.Component;
29
import java.lang.ref.Reference;
30
import java.lang.ref.SoftReference;
31
import java.lang.reflect.Constructor;
32
import java.lang.reflect.InvocationTargetException;
33
import java.lang.reflect.Method;
34
import java.lang.reflect.Type;
35
import java.util.ArrayList;
36
import java.util.EventObject;
37
import java.util.HashMap;
38
import java.util.Iterator;
39
import java.util.List;
40
import java.util.Map;
41
import java.util.TreeMap;
42
43
import com.sun.beans.TypeResolver;
44
import com.sun.beans.finder.ClassFinder;
45
import com.sun.beans.introspect.ClassInfo;
46
import com.sun.beans.introspect.EventSetInfo;
47
import com.sun.beans.introspect.PropertyInfo;
48
import jdk.internal.access.JavaBeansAccess;
49
import jdk.internal.access.SharedSecrets;
50
import sun.reflect.misc.ReflectUtil;
51
52
/**
53
* The Introspector class provides a standard way for tools to learn about
54
* the properties, events, and methods supported by a target Java Bean.
55
* <p>
56
* For each of those three kinds of information, the Introspector will
57
* separately analyze the bean's class and superclasses looking for
58
* either explicit or implicit information and use that information to
59
* build a BeanInfo object that comprehensively describes the target bean.
60
* <p>
61
* For each class "Foo", explicit information may be available if there exists
62
* a corresponding "FooBeanInfo" class that provides a non-null value when
63
* queried for the information. We first look for the BeanInfo class by
64
* taking the full package-qualified name of the target bean class and
65
* appending "BeanInfo" to form a new class name. If this fails, then
66
* we take the final classname component of this name, and look for that
67
* class in each of the packages specified in the BeanInfo package search
68
* path.
69
* <p>
70
* Thus for a class such as "sun.xyz.OurButton" we would first look for a
71
* BeanInfo class called "sun.xyz.OurButtonBeanInfo" and if that failed we'd
72
* look in each package in the BeanInfo search path for an OurButtonBeanInfo
73
* class. With the default search path, this would mean looking for
74
* "sun.beans.infos.OurButtonBeanInfo".
75
* <p>
76
* If a class provides explicit BeanInfo about itself then we add that to
77
* the BeanInfo information we obtained from analyzing any derived classes,
78
* but we regard the explicit information as being definitive for the current
79
* class and its base classes, and do not proceed any further up the superclass
80
* chain.
81
* <p>
82
* If we don't find explicit BeanInfo on a class, we use low-level
83
* reflection to study the methods of the class and apply standard design
84
* patterns to identify property accessors, event sources, or public
85
* methods. We then proceed to analyze the class's superclass and add
86
* in the information from it (and possibly on up the superclass chain).
87
* <p>
88
* For more information about introspection and design patterns, please
89
* consult the
90
* <a href="http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html">JavaBeans specification</a>.
91
*
92
* @since 1.1
93
*/
94
95
public class Introspector {
96
97
// Flags that can be used to control getBeanInfo:
98
/**
99
* Flag to indicate to use of all beaninfo.
100
* @since 1.2
101
*/
102
public static final int USE_ALL_BEANINFO = 1;
103
/**
104
* Flag to indicate to ignore immediate beaninfo.
105
* @since 1.2
106
*/
107
public static final int IGNORE_IMMEDIATE_BEANINFO = 2;
108
/**
109
* Flag to indicate to ignore all beaninfo.
110
* @since 1.2
111
*/
112
public static final int IGNORE_ALL_BEANINFO = 3;
113
114
private Class<?> beanClass;
115
private BeanInfo explicitBeanInfo;
116
private BeanInfo superBeanInfo;
117
private BeanInfo[] additionalBeanInfo;
118
119
private boolean propertyChangeSource = false;
120
121
// These should be removed.
122
private String defaultEventName;
123
private String defaultPropertyName;
124
private int defaultEventIndex = -1;
125
private int defaultPropertyIndex = -1;
126
127
// Methods maps from Method names to MethodDescriptors
128
private Map<String, MethodDescriptor> methods;
129
130
// properties maps from String names to PropertyDescriptors
131
private Map<String, PropertyDescriptor> properties;
132
133
// events maps from String names to EventSetDescriptors
134
private Map<String, EventSetDescriptor> events;
135
136
private static final EventSetDescriptor[] EMPTY_EVENTSETDESCRIPTORS = new EventSetDescriptor[0];
137
138
static final String ADD_PREFIX = "add";
139
static final String REMOVE_PREFIX = "remove";
140
static final String GET_PREFIX = "get";
141
static final String SET_PREFIX = "set";
142
static final String IS_PREFIX = "is";
143
144
// register with SharedSecrets for JMX usage
145
static {
146
SharedSecrets.setJavaBeansAccess(new JavaBeansAccess() {
147
@Override
148
public Method getReadMethod(Class<?> clazz, String property) throws Exception {
149
BeanInfo bi = Introspector.getBeanInfo(clazz);
150
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
151
for (PropertyDescriptor pd: pds) {
152
if (pd.getName().equals(property)) {
153
return pd.getReadMethod();
154
}
155
}
156
return null;
157
}
158
159
@Override
160
public String[] getConstructorPropertiesValue(Constructor<?> ctr) {
161
ConstructorProperties cp = ctr.getAnnotation(ConstructorProperties.class);
162
String [] ret = cp != null ? cp.value() : null;
163
return ret;
164
}
165
});
166
}
167
168
//======================================================================
169
// Public methods
170
//======================================================================
171
172
/**
173
* Introspect on a Java Bean and learn about all its properties, exposed
174
* methods, and events.
175
* <p>
176
* If the BeanInfo class for a Java Bean has been previously Introspected
177
* then the BeanInfo class is retrieved from the BeanInfo cache.
178
*
179
* @param beanClass The bean class to be analyzed.
180
* @return A BeanInfo object describing the target bean.
181
* @exception IntrospectionException if an exception occurs during
182
* introspection.
183
* @see #flushCaches
184
* @see #flushFromCaches
185
*/
186
public static BeanInfo getBeanInfo(Class<?> beanClass)
187
throws IntrospectionException
188
{
189
if (!ReflectUtil.isPackageAccessible(beanClass)) {
190
return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
191
}
192
ThreadGroupContext context = ThreadGroupContext.getContext();
193
BeanInfo beanInfo = context.getBeanInfo(beanClass);
194
if (beanInfo == null) {
195
beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();
196
context.putBeanInfo(beanClass, beanInfo);
197
}
198
return beanInfo;
199
}
200
201
/**
202
* Introspect on a Java bean and learn about all its properties, exposed
203
* methods, and events, subject to some control flags.
204
* <p>
205
* If the BeanInfo class for a Java Bean has been previously Introspected
206
* based on the same arguments then the BeanInfo class is retrieved
207
* from the BeanInfo cache.
208
*
209
* @param beanClass The bean class to be analyzed.
210
* @param flags Flags to control the introspection.
211
* If flags == USE_ALL_BEANINFO then we use all of the BeanInfo
212
* classes we can discover.
213
* If flags == IGNORE_IMMEDIATE_BEANINFO then we ignore any
214
* BeanInfo associated with the specified beanClass.
215
* If flags == IGNORE_ALL_BEANINFO then we ignore all BeanInfo
216
* associated with the specified beanClass or any of its
217
* parent classes.
218
* @return A BeanInfo object describing the target bean.
219
* @exception IntrospectionException if an exception occurs during
220
* introspection.
221
* @since 1.2
222
*/
223
public static BeanInfo getBeanInfo(Class<?> beanClass, int flags)
224
throws IntrospectionException {
225
return getBeanInfo(beanClass, null, flags);
226
}
227
228
/**
229
* Introspect on a Java bean and learn all about its properties, exposed
230
* methods, below a given "stop" point.
231
* <p>
232
* If the BeanInfo class for a Java Bean has been previously Introspected
233
* based on the same arguments, then the BeanInfo class is retrieved
234
* from the BeanInfo cache.
235
* @return the BeanInfo for the bean
236
* @param beanClass The bean class to be analyzed.
237
* @param stopClass The baseclass at which to stop the analysis. Any
238
* methods/properties/events in the stopClass or in its baseclasses
239
* will be ignored in the analysis.
240
* @exception IntrospectionException if an exception occurs during
241
* introspection.
242
*/
243
public static BeanInfo getBeanInfo(Class<?> beanClass, Class<?> stopClass)
244
throws IntrospectionException {
245
return getBeanInfo(beanClass, stopClass, USE_ALL_BEANINFO);
246
}
247
248
/**
249
* Introspect on a Java Bean and learn about all its properties,
250
* exposed methods and events, below a given {@code stopClass} point
251
* subject to some control {@code flags}.
252
* <dl>
253
* <dt>USE_ALL_BEANINFO</dt>
254
* <dd>Any BeanInfo that can be discovered will be used.</dd>
255
* <dt>IGNORE_IMMEDIATE_BEANINFO</dt>
256
* <dd>Any BeanInfo associated with the specified {@code beanClass} will be ignored.</dd>
257
* <dt>IGNORE_ALL_BEANINFO</dt>
258
* <dd>Any BeanInfo associated with the specified {@code beanClass}
259
* or any of its parent classes will be ignored.</dd>
260
* </dl>
261
* Any methods/properties/events in the {@code stopClass}
262
* or in its parent classes will be ignored in the analysis.
263
* <p>
264
* If the BeanInfo class for a Java Bean has been
265
* previously introspected based on the same arguments then
266
* the BeanInfo class is retrieved from the BeanInfo cache.
267
*
268
* @param beanClass the bean class to be analyzed
269
* @param stopClass the parent class at which to stop the analysis
270
* @param flags flags to control the introspection
271
* @return a BeanInfo object describing the target bean
272
* @exception IntrospectionException if an exception occurs during introspection
273
*
274
* @since 1.7
275
*/
276
public static BeanInfo getBeanInfo(Class<?> beanClass, Class<?> stopClass,
277
int flags) throws IntrospectionException {
278
BeanInfo bi;
279
if (stopClass == null && flags == USE_ALL_BEANINFO) {
280
// Same parameters to take advantage of caching.
281
bi = getBeanInfo(beanClass);
282
} else {
283
bi = (new Introspector(beanClass, stopClass, flags)).getBeanInfo();
284
}
285
return bi;
286
287
// Old behaviour: Make an independent copy of the BeanInfo.
288
//return new GenericBeanInfo(bi);
289
}
290
291
292
/**
293
* Utility method to take a string and convert it to normal Java variable
294
* name capitalization. This normally means converting the first
295
* character from upper case to lower case, but in the (unusual) special
296
* case when there is more than one character and both the first and
297
* second characters are upper case, we leave it alone.
298
* <p>
299
* Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
300
* as "URL".
301
*
302
* @param name The string to be decapitalized.
303
* @return The decapitalized version of the string.
304
*/
305
public static String decapitalize(String name) {
306
if (name == null || name.length() == 0) {
307
return name;
308
}
309
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
310
Character.isUpperCase(name.charAt(0))){
311
return name;
312
}
313
char[] chars = name.toCharArray();
314
chars[0] = Character.toLowerCase(chars[0]);
315
return new String(chars);
316
}
317
318
/**
319
* Gets the list of package names that will be used for
320
* finding BeanInfo classes.
321
*
322
* @return The array of package names that will be searched in
323
* order to find BeanInfo classes. The default value
324
* for this array is implementation-dependent; e.g.
325
* Sun implementation initially sets to {"sun.beans.infos"}.
326
*/
327
328
public static String[] getBeanInfoSearchPath() {
329
return ThreadGroupContext.getContext().getBeanInfoFinder().getPackages();
330
}
331
332
/**
333
* Change the list of package names that will be used for
334
* finding BeanInfo classes. The behaviour of
335
* this method is undefined if parameter path
336
* is null.
337
*
338
* <p>First, if there is a security manager, its {@code checkPropertiesAccess}
339
* method is called. This could result in a SecurityException.
340
*
341
* @param path Array of package names.
342
* @exception SecurityException if a security manager exists and its
343
* {@code checkPropertiesAccess} method doesn't allow setting
344
* of system properties.
345
* @see SecurityManager#checkPropertiesAccess
346
*/
347
348
public static void setBeanInfoSearchPath(String[] path) {
349
@SuppressWarnings("removal")
350
SecurityManager sm = System.getSecurityManager();
351
if (sm != null) {
352
sm.checkPropertiesAccess();
353
}
354
ThreadGroupContext.getContext().getBeanInfoFinder().setPackages(path);
355
}
356
357
358
/**
359
* Flush all of the Introspector's internal caches. This method is
360
* not normally required. It is normally only needed by advanced
361
* tools that update existing "Class" objects in-place and need
362
* to make the Introspector re-analyze existing Class objects.
363
*
364
* @since 1.2
365
*/
366
public static void flushCaches() {
367
ThreadGroupContext.getContext().clearBeanInfoCache();
368
ClassInfo.clear();
369
}
370
371
/**
372
* Flush the Introspector's internal cached information for a given class.
373
* This method is not normally required. It is normally only needed
374
* by advanced tools that update existing "Class" objects in-place
375
* and need to make the Introspector re-analyze an existing Class object.
376
*
377
* Note that only the direct state associated with the target Class
378
* object is flushed. We do not flush state for other Class objects
379
* with the same name, nor do we flush state for any related Class
380
* objects (such as subclasses), even though their state may include
381
* information indirectly obtained from the target Class object.
382
*
383
* @param clz Class object to be flushed.
384
* @throws NullPointerException If the Class object is null.
385
* @since 1.2
386
*/
387
public static void flushFromCaches(Class<?> clz) {
388
if (clz == null) {
389
throw new NullPointerException();
390
}
391
ThreadGroupContext.getContext().removeBeanInfo(clz);
392
ClassInfo.remove(clz);
393
}
394
395
//======================================================================
396
// Private implementation methods
397
//======================================================================
398
399
private Introspector(Class<?> beanClass, Class<?> stopClass, int flags)
400
throws IntrospectionException {
401
this.beanClass = beanClass;
402
403
// Check stopClass is a superClass of startClass.
404
if (stopClass != null) {
405
boolean isSuper = false;
406
for (Class<?> c = beanClass.getSuperclass(); c != null; c = c.getSuperclass()) {
407
if (c == stopClass) {
408
isSuper = true;
409
}
410
}
411
if (!isSuper) {
412
throw new IntrospectionException(stopClass.getName() + " not superclass of " +
413
beanClass.getName());
414
}
415
}
416
417
if (flags == USE_ALL_BEANINFO) {
418
explicitBeanInfo = findExplicitBeanInfo(beanClass);
419
}
420
421
Class<?> superClass = beanClass.getSuperclass();
422
if (superClass != stopClass) {
423
int newFlags = flags;
424
if (newFlags == IGNORE_IMMEDIATE_BEANINFO) {
425
newFlags = USE_ALL_BEANINFO;
426
}
427
superBeanInfo = getBeanInfo(superClass, stopClass, newFlags);
428
}
429
if (explicitBeanInfo != null) {
430
additionalBeanInfo = explicitBeanInfo.getAdditionalBeanInfo();
431
}
432
if (additionalBeanInfo == null) {
433
additionalBeanInfo = new BeanInfo[0];
434
}
435
}
436
437
/**
438
* Constructs a GenericBeanInfo class from the state of the Introspector
439
*/
440
private BeanInfo getBeanInfo() throws IntrospectionException {
441
442
// the evaluation order here is import, as we evaluate the
443
// event sets and locate PropertyChangeListeners before we
444
// look for properties.
445
BeanDescriptor bd = getTargetBeanDescriptor();
446
MethodDescriptor[] mds = getTargetMethodInfo();
447
EventSetDescriptor[] esds = getTargetEventInfo();
448
PropertyDescriptor[] pds = getTargetPropertyInfo();
449
450
int defaultEvent = getTargetDefaultEventIndex();
451
int defaultProperty = getTargetDefaultPropertyIndex();
452
453
return new GenericBeanInfo(bd, esds, defaultEvent, pds,
454
defaultProperty, mds, explicitBeanInfo);
455
456
}
457
458
/**
459
* Looks for an explicit BeanInfo class that corresponds to the Class.
460
* First it looks in the existing package that the Class is defined in,
461
* then it checks to see if the class is its own BeanInfo. Finally,
462
* the BeanInfo search path is prepended to the class and searched.
463
*
464
* @param beanClass the class type of the bean
465
* @return Instance of an explicit BeanInfo class or null if one isn't found.
466
*/
467
private static BeanInfo findExplicitBeanInfo(Class<?> beanClass) {
468
return ThreadGroupContext.getContext().getBeanInfoFinder().find(beanClass);
469
}
470
471
/**
472
* @return An array of PropertyDescriptors describing the editable
473
* properties supported by the target bean.
474
*/
475
476
private PropertyDescriptor[] getTargetPropertyInfo() {
477
478
// Check if the bean has its own BeanInfo that will provide
479
// explicit information.
480
PropertyDescriptor[] explicitProperties = null;
481
if (explicitBeanInfo != null) {
482
explicitProperties = getPropertyDescriptors(this.explicitBeanInfo);
483
}
484
485
if (explicitProperties == null && superBeanInfo != null) {
486
// We have no explicit BeanInfo properties. Check with our parent.
487
addPropertyDescriptors(getPropertyDescriptors(this.superBeanInfo));
488
}
489
490
for (int i = 0; i < additionalBeanInfo.length; i++) {
491
addPropertyDescriptors(additionalBeanInfo[i].getPropertyDescriptors());
492
}
493
494
if (explicitProperties != null) {
495
// Add the explicit BeanInfo data to our results.
496
addPropertyDescriptors(explicitProperties);
497
498
} else {
499
// Apply some reflection to the current class.
500
for (Map.Entry<String,PropertyInfo> entry : ClassInfo.get(this.beanClass).getProperties().entrySet()) {
501
addPropertyDescriptor(null != entry.getValue().getIndexed()
502
? new IndexedPropertyDescriptor(entry, this.propertyChangeSource)
503
: new PropertyDescriptor(entry, this.propertyChangeSource));
504
}
505
JavaBean annotation = this.beanClass.getAnnotation(JavaBean.class);
506
if ((annotation != null) && !annotation.defaultProperty().isEmpty()) {
507
this.defaultPropertyName = annotation.defaultProperty();
508
}
509
}
510
processPropertyDescriptors();
511
512
// Allocate and populate the result array.
513
PropertyDescriptor[] result =
514
properties.values().toArray(new PropertyDescriptor[properties.size()]);
515
516
// Set the default index.
517
if (defaultPropertyName != null) {
518
for (int i = 0; i < result.length; i++) {
519
if (defaultPropertyName.equals(result[i].getName())) {
520
defaultPropertyIndex = i;
521
}
522
}
523
}
524
return result;
525
}
526
527
private HashMap<String, List<PropertyDescriptor>> pdStore = new HashMap<>();
528
529
/**
530
* Adds the property descriptor to the list store.
531
*/
532
private void addPropertyDescriptor(PropertyDescriptor pd) {
533
String propName = pd.getName();
534
List<PropertyDescriptor> list = pdStore.get(propName);
535
if (list == null) {
536
list = new ArrayList<>();
537
pdStore.put(propName, list);
538
}
539
if (this.beanClass != pd.getClass0()) {
540
// replace existing property descriptor
541
// only if we have types to resolve
542
// in the context of this.beanClass
543
Method read = pd.getReadMethod();
544
Method write = pd.getWriteMethod();
545
boolean cls = true;
546
if (read != null) cls = cls && read.getGenericReturnType() instanceof Class;
547
if (write != null) cls = cls && write.getGenericParameterTypes()[0] instanceof Class;
548
if (pd instanceof IndexedPropertyDescriptor) {
549
IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
550
Method readI = ipd.getIndexedReadMethod();
551
Method writeI = ipd.getIndexedWriteMethod();
552
if (readI != null) cls = cls && readI.getGenericReturnType() instanceof Class;
553
if (writeI != null) cls = cls && writeI.getGenericParameterTypes()[1] instanceof Class;
554
if (!cls) {
555
pd = new IndexedPropertyDescriptor(ipd);
556
pd.updateGenericsFor(this.beanClass);
557
}
558
}
559
else if (!cls) {
560
pd = new PropertyDescriptor(pd);
561
pd.updateGenericsFor(this.beanClass);
562
}
563
}
564
list.add(pd);
565
}
566
567
private void addPropertyDescriptors(PropertyDescriptor[] descriptors) {
568
if (descriptors != null) {
569
for (PropertyDescriptor descriptor : descriptors) {
570
addPropertyDescriptor(descriptor);
571
}
572
}
573
}
574
575
private PropertyDescriptor[] getPropertyDescriptors(BeanInfo info) {
576
PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
577
int index = info.getDefaultPropertyIndex();
578
if ((0 <= index) && (index < descriptors.length)) {
579
this.defaultPropertyName = descriptors[index].getName();
580
}
581
return descriptors;
582
}
583
584
/**
585
* Populates the property descriptor table by merging the
586
* lists of Property descriptors.
587
*/
588
private void processPropertyDescriptors() {
589
if (properties == null) {
590
properties = new TreeMap<>();
591
}
592
593
List<PropertyDescriptor> list;
594
595
PropertyDescriptor pd, gpd, spd;
596
IndexedPropertyDescriptor ipd, igpd, ispd;
597
598
for (List<PropertyDescriptor> propertyDescriptors : pdStore.values()) {
599
pd = null; gpd = null; spd = null;
600
ipd = null; igpd = null; ispd = null;
601
602
list = propertyDescriptors;
603
604
// First pass. Find the latest getter method. Merge properties
605
// of previous getter methods.
606
for (int i = 0; i < list.size(); i++) {
607
pd = list.get(i);
608
if (pd instanceof IndexedPropertyDescriptor) {
609
ipd = (IndexedPropertyDescriptor)pd;
610
if (ipd.getIndexedReadMethod() != null) {
611
if (igpd != null) {
612
igpd = new IndexedPropertyDescriptor(igpd, ipd);
613
} else {
614
igpd = ipd;
615
}
616
}
617
} else {
618
if (pd.getReadMethod() != null) {
619
String pdName = pd.getReadMethod().getName();
620
if (gpd != null) {
621
// Don't replace the existing read
622
// method if it starts with "is"
623
String gpdName = gpd.getReadMethod().getName();
624
if (gpdName.equals(pdName) || !gpdName.startsWith(IS_PREFIX)) {
625
gpd = new PropertyDescriptor(gpd, pd);
626
}
627
} else {
628
gpd = pd;
629
}
630
}
631
}
632
}
633
634
// Second pass. Find the latest setter method which
635
// has the same type as the getter method.
636
for (int i = 0; i < list.size(); i++) {
637
pd = list.get(i);
638
if (pd instanceof IndexedPropertyDescriptor) {
639
ipd = (IndexedPropertyDescriptor)pd;
640
if (ipd.getIndexedWriteMethod() != null) {
641
if (igpd != null) {
642
if (isAssignable(igpd.getIndexedPropertyType(), ipd.getIndexedPropertyType())) {
643
if (ispd != null) {
644
ispd = new IndexedPropertyDescriptor(ispd, ipd);
645
} else {
646
ispd = ipd;
647
}
648
}
649
} else {
650
if (ispd != null) {
651
ispd = new IndexedPropertyDescriptor(ispd, ipd);
652
} else {
653
ispd = ipd;
654
}
655
}
656
}
657
} else {
658
if (pd.getWriteMethod() != null) {
659
if (gpd != null) {
660
if (isAssignable(gpd.getPropertyType(), pd.getPropertyType())) {
661
if (spd != null) {
662
spd = new PropertyDescriptor(spd, pd);
663
} else {
664
spd = pd;
665
}
666
}
667
} else {
668
if (spd != null) {
669
spd = new PropertyDescriptor(spd, pd);
670
} else {
671
spd = pd;
672
}
673
}
674
}
675
}
676
}
677
678
// At this stage we should have either PDs or IPDs for the
679
// representative getters and setters. The order at which the
680
// property descriptors are determined represent the
681
// precedence of the property ordering.
682
pd = null; ipd = null;
683
684
if (igpd != null && ispd != null) {
685
// Complete indexed properties set
686
// Merge any classic property descriptors
687
if ((gpd == spd) || (gpd == null)) {
688
pd = spd;
689
} else if (spd == null) {
690
pd = gpd;
691
} else if (spd instanceof IndexedPropertyDescriptor) {
692
pd = mergePropertyWithIndexedProperty(gpd, (IndexedPropertyDescriptor) spd);
693
} else if (gpd instanceof IndexedPropertyDescriptor) {
694
pd = mergePropertyWithIndexedProperty(spd, (IndexedPropertyDescriptor) gpd);
695
} else {
696
pd = mergePropertyDescriptor(gpd, spd);
697
}
698
if (igpd == ispd) {
699
ipd = igpd;
700
} else {
701
ipd = mergePropertyDescriptor(igpd, ispd);
702
}
703
if (pd == null) {
704
pd = ipd;
705
} else {
706
Class<?> propType = pd.getPropertyType();
707
Class<?> ipropType = ipd.getIndexedPropertyType();
708
if (propType.isArray() && propType.getComponentType() == ipropType) {
709
pd = pd.getClass0().isAssignableFrom(ipd.getClass0())
710
? new IndexedPropertyDescriptor(pd, ipd)
711
: new IndexedPropertyDescriptor(ipd, pd);
712
} else if (pd.getClass0().isAssignableFrom(ipd.getClass0())) {
713
pd = pd.getClass0().isAssignableFrom(ipd.getClass0())
714
? new PropertyDescriptor(pd, ipd)
715
: new PropertyDescriptor(ipd, pd);
716
} else {
717
pd = ipd;
718
}
719
}
720
} else if (gpd != null && spd != null) {
721
if (igpd != null) {
722
gpd = mergePropertyWithIndexedProperty(gpd, igpd);
723
}
724
if (ispd != null) {
725
spd = mergePropertyWithIndexedProperty(spd, ispd);
726
}
727
// Complete simple properties set
728
if (gpd == spd) {
729
pd = gpd;
730
} else if (spd instanceof IndexedPropertyDescriptor) {
731
pd = mergePropertyWithIndexedProperty(gpd, (IndexedPropertyDescriptor) spd);
732
} else if (gpd instanceof IndexedPropertyDescriptor) {
733
pd = mergePropertyWithIndexedProperty(spd, (IndexedPropertyDescriptor) gpd);
734
} else {
735
pd = mergePropertyDescriptor(gpd, spd);
736
}
737
} else if (ispd != null) {
738
// indexed setter
739
pd = ispd;
740
// Merge any classic property descriptors
741
if (spd != null) {
742
pd = mergePropertyDescriptor(ispd, spd);
743
}
744
if (gpd != null) {
745
pd = mergePropertyDescriptor(ispd, gpd);
746
}
747
} else if (igpd != null) {
748
// indexed getter
749
pd = igpd;
750
// Merge any classic property descriptors
751
if (gpd != null) {
752
pd = mergePropertyDescriptor(igpd, gpd);
753
}
754
if (spd != null) {
755
pd = mergePropertyDescriptor(igpd, spd);
756
}
757
} else if (spd != null) {
758
// simple setter
759
pd = spd;
760
} else if (gpd != null) {
761
// simple getter
762
pd = gpd;
763
}
764
765
// Very special case to ensure that an IndexedPropertyDescriptor
766
// doesn't contain less information than the enclosed
767
// PropertyDescriptor. If it does, then recreate as a
768
// PropertyDescriptor. See 4168833
769
if (pd instanceof IndexedPropertyDescriptor) {
770
ipd = (IndexedPropertyDescriptor)pd;
771
if (ipd.getIndexedReadMethod() == null && ipd.getIndexedWriteMethod() == null) {
772
pd = new PropertyDescriptor(ipd);
773
}
774
}
775
776
// Find the first property descriptor
777
// which does not have getter and setter methods.
778
// See regression bug 4984912.
779
if ( (pd == null) && (list.size() > 0) ) {
780
pd = list.get(0);
781
}
782
783
if (pd != null) {
784
properties.put(pd.getName(), pd);
785
}
786
}
787
}
788
789
private static boolean isAssignable(Class<?> current, Class<?> candidate) {
790
return ((current == null) || (candidate == null)) ? current == candidate : current.isAssignableFrom(candidate);
791
}
792
793
private PropertyDescriptor mergePropertyWithIndexedProperty(PropertyDescriptor pd, IndexedPropertyDescriptor ipd) {
794
Class<?> type = pd.getPropertyType();
795
if (type.isArray() && (type.getComponentType() == ipd.getIndexedPropertyType())) {
796
return pd.getClass0().isAssignableFrom(ipd.getClass0())
797
? new IndexedPropertyDescriptor(pd, ipd)
798
: new IndexedPropertyDescriptor(ipd, pd);
799
}
800
return pd;
801
}
802
803
/**
804
* Adds the property descriptor to the indexedproperty descriptor only if the
805
* types are the same.
806
*
807
* The most specific property descriptor will take precedence.
808
*/
809
private PropertyDescriptor mergePropertyDescriptor(IndexedPropertyDescriptor ipd,
810
PropertyDescriptor pd) {
811
PropertyDescriptor result = null;
812
813
Class<?> propType = pd.getPropertyType();
814
Class<?> ipropType = ipd.getIndexedPropertyType();
815
816
if (propType.isArray() && propType.getComponentType() == ipropType) {
817
if (pd.getClass0().isAssignableFrom(ipd.getClass0())) {
818
result = new IndexedPropertyDescriptor(pd, ipd);
819
} else {
820
result = new IndexedPropertyDescriptor(ipd, pd);
821
}
822
} else if ((ipd.getReadMethod() == null) && (ipd.getWriteMethod() == null)) {
823
if (pd.getClass0().isAssignableFrom(ipd.getClass0())) {
824
result = new PropertyDescriptor(pd, ipd);
825
} else {
826
result = new PropertyDescriptor(ipd, pd);
827
}
828
} else {
829
// Cannot merge the pd because of type mismatch
830
// Return the most specific pd
831
if (pd.getClass0().isAssignableFrom(ipd.getClass0())) {
832
result = ipd;
833
} else {
834
result = pd;
835
// Try to add methods which may have been lost in the type change
836
// See 4168833
837
Method write = result.getWriteMethod();
838
Method read = result.getReadMethod();
839
840
if (read == null && write != null) {
841
read = findMethod(result.getClass0(),
842
GET_PREFIX + NameGenerator.capitalize(result.getName()), 0);
843
if (read != null) {
844
try {
845
result.setReadMethod(read);
846
} catch (IntrospectionException ex) {
847
// no consequences for failure.
848
}
849
}
850
}
851
if (write == null && read != null) {
852
write = findMethod(result.getClass0(),
853
SET_PREFIX + NameGenerator.capitalize(result.getName()), 1,
854
new Class<?>[] { FeatureDescriptor.getReturnType(result.getClass0(), read) });
855
if (write != null) {
856
try {
857
result.setWriteMethod(write);
858
} catch (IntrospectionException ex) {
859
// no consequences for failure.
860
}
861
}
862
}
863
}
864
}
865
return result;
866
}
867
868
// Handle regular pd merge
869
private PropertyDescriptor mergePropertyDescriptor(PropertyDescriptor pd1,
870
PropertyDescriptor pd2) {
871
if (pd1.getClass0().isAssignableFrom(pd2.getClass0())) {
872
return new PropertyDescriptor(pd1, pd2);
873
} else {
874
return new PropertyDescriptor(pd2, pd1);
875
}
876
}
877
878
// Handle regular ipd merge
879
private IndexedPropertyDescriptor mergePropertyDescriptor(IndexedPropertyDescriptor ipd1,
880
IndexedPropertyDescriptor ipd2) {
881
if (ipd1.getClass0().isAssignableFrom(ipd2.getClass0())) {
882
return new IndexedPropertyDescriptor(ipd1, ipd2);
883
} else {
884
return new IndexedPropertyDescriptor(ipd2, ipd1);
885
}
886
}
887
888
/**
889
* @return An array of EventSetDescriptors describing the kinds of
890
* events fired by the target bean.
891
*/
892
private EventSetDescriptor[] getTargetEventInfo() throws IntrospectionException {
893
if (events == null) {
894
events = new HashMap<>();
895
}
896
897
// Check if the bean has its own BeanInfo that will provide
898
// explicit information.
899
EventSetDescriptor[] explicitEvents = null;
900
if (explicitBeanInfo != null) {
901
explicitEvents = explicitBeanInfo.getEventSetDescriptors();
902
int ix = explicitBeanInfo.getDefaultEventIndex();
903
if (ix >= 0 && ix < explicitEvents.length) {
904
defaultEventName = explicitEvents[ix].getName();
905
}
906
}
907
908
if (explicitEvents == null && superBeanInfo != null) {
909
// We have no explicit BeanInfo events. Check with our parent.
910
EventSetDescriptor[] supers = superBeanInfo.getEventSetDescriptors();
911
for (int i = 0 ; i < supers.length; i++) {
912
addEvent(supers[i]);
913
}
914
int ix = superBeanInfo.getDefaultEventIndex();
915
if (ix >= 0 && ix < supers.length) {
916
defaultEventName = supers[ix].getName();
917
}
918
}
919
920
for (int i = 0; i < additionalBeanInfo.length; i++) {
921
EventSetDescriptor[] additional = additionalBeanInfo[i].getEventSetDescriptors();
922
if (additional != null) {
923
for (int j = 0 ; j < additional.length; j++) {
924
addEvent(additional[j]);
925
}
926
}
927
}
928
929
if (explicitEvents != null) {
930
// Add the explicit explicitBeanInfo data to our results.
931
for (int i = 0 ; i < explicitEvents.length; i++) {
932
addEvent(explicitEvents[i]);
933
}
934
935
} else {
936
// Apply some reflection to the current class.
937
for (Map.Entry<String,EventSetInfo> entry : ClassInfo.get(this.beanClass).getEventSets().entrySet()) {
938
// generate a list of Method objects for each of the target methods:
939
List<Method> methods = new ArrayList<>();
940
for (Method method : ClassInfo.get(entry.getValue().getListenerType()).getMethods()) {
941
if (isEventHandler(method)) {
942
methods.add(method);
943
}
944
}
945
addEvent(new EventSetDescriptor(
946
entry.getKey(),
947
entry.getValue(),
948
methods.toArray(new Method[methods.size()])));
949
}
950
JavaBean annotation = this.beanClass.getAnnotation(JavaBean.class);
951
if ((annotation != null) && !annotation.defaultEventSet().isEmpty()) {
952
this.defaultEventName = annotation.defaultEventSet();
953
}
954
}
955
EventSetDescriptor[] result;
956
if (events.size() == 0) {
957
result = EMPTY_EVENTSETDESCRIPTORS;
958
} else {
959
// Allocate and populate the result array.
960
result = new EventSetDescriptor[events.size()];
961
result = events.values().toArray(result);
962
// Set the default index.
963
if (defaultEventName != null) {
964
for (int i = 0; i < result.length; i++) {
965
if (defaultEventName.equals(result[i].getName())) {
966
defaultEventIndex = i;
967
}
968
}
969
}
970
}
971
return result;
972
}
973
974
private void addEvent(EventSetDescriptor esd) {
975
String key = esd.getName();
976
if (esd.getName().equals("propertyChange")) {
977
propertyChangeSource = true;
978
}
979
EventSetDescriptor old = events.get(key);
980
if (old == null) {
981
events.put(key, esd);
982
return;
983
}
984
EventSetDescriptor composite = new EventSetDescriptor(old, esd);
985
events.put(key, composite);
986
}
987
988
/**
989
* @return An array of MethodDescriptors describing the private
990
* methods supported by the target bean.
991
*/
992
private MethodDescriptor[] getTargetMethodInfo() {
993
if (methods == null) {
994
methods = new HashMap<>(100);
995
}
996
997
// Check if the bean has its own BeanInfo that will provide
998
// explicit information.
999
MethodDescriptor[] explicitMethods = null;
1000
if (explicitBeanInfo != null) {
1001
explicitMethods = explicitBeanInfo.getMethodDescriptors();
1002
}
1003
1004
if (explicitMethods == null && superBeanInfo != null) {
1005
// We have no explicit BeanInfo methods. Check with our parent.
1006
MethodDescriptor[] supers = superBeanInfo.getMethodDescriptors();
1007
for (int i = 0 ; i < supers.length; i++) {
1008
addMethod(supers[i]);
1009
}
1010
}
1011
1012
for (int i = 0; i < additionalBeanInfo.length; i++) {
1013
MethodDescriptor[] additional = additionalBeanInfo[i].getMethodDescriptors();
1014
if (additional != null) {
1015
for (int j = 0 ; j < additional.length; j++) {
1016
addMethod(additional[j]);
1017
}
1018
}
1019
}
1020
1021
if (explicitMethods != null) {
1022
// Add the explicit explicitBeanInfo data to our results.
1023
for (int i = 0 ; i < explicitMethods.length; i++) {
1024
addMethod(explicitMethods[i]);
1025
}
1026
1027
} else {
1028
// Apply some reflection to the current class.
1029
for (Method method : ClassInfo.get(this.beanClass).getMethods()) {
1030
addMethod(new MethodDescriptor(method));
1031
}
1032
}
1033
1034
// Allocate and populate the result array.
1035
MethodDescriptor[] result = new MethodDescriptor[methods.size()];
1036
result = methods.values().toArray(result);
1037
1038
return result;
1039
}
1040
1041
private void addMethod(MethodDescriptor md) {
1042
// We have to be careful here to distinguish method by both name
1043
// and argument lists.
1044
// This method gets called a *lot, so we try to be efficient.
1045
String name = md.getName();
1046
1047
MethodDescriptor old = methods.get(name);
1048
if (old == null) {
1049
// This is the common case.
1050
methods.put(name, md);
1051
return;
1052
}
1053
1054
// We have a collision on method names. This is rare.
1055
1056
// Check if old and md have the same type.
1057
String[] p1 = md.getParamNames();
1058
String[] p2 = old.getParamNames();
1059
1060
boolean match = false;
1061
if (p1.length == p2.length) {
1062
match = true;
1063
for (int i = 0; i < p1.length; i++) {
1064
if (p1[i] != p2[i]) {
1065
match = false;
1066
break;
1067
}
1068
}
1069
}
1070
if (match) {
1071
MethodDescriptor composite = new MethodDescriptor(old, md);
1072
methods.put(name, composite);
1073
return;
1074
}
1075
1076
// We have a collision on method names with different type signatures.
1077
// This is very rare.
1078
1079
String longKey = makeQualifiedMethodName(name, p1);
1080
old = methods.get(longKey);
1081
if (old == null) {
1082
methods.put(longKey, md);
1083
return;
1084
}
1085
MethodDescriptor composite = new MethodDescriptor(old, md);
1086
methods.put(longKey, composite);
1087
}
1088
1089
/**
1090
* Creates a key for a method in a method cache.
1091
*/
1092
private static String makeQualifiedMethodName(String name, String[] params) {
1093
StringBuilder sb = new StringBuilder(name);
1094
sb.append('=');
1095
for (int i = 0; i < params.length; i++) {
1096
sb.append(':');
1097
sb.append(params[i]);
1098
}
1099
return sb.toString();
1100
}
1101
1102
private int getTargetDefaultEventIndex() {
1103
return defaultEventIndex;
1104
}
1105
1106
private int getTargetDefaultPropertyIndex() {
1107
return defaultPropertyIndex;
1108
}
1109
1110
private BeanDescriptor getTargetBeanDescriptor() {
1111
// Use explicit info, if available,
1112
if (explicitBeanInfo != null) {
1113
BeanDescriptor bd = explicitBeanInfo.getBeanDescriptor();
1114
if (bd != null) {
1115
return (bd);
1116
}
1117
}
1118
// OK, fabricate a default BeanDescriptor.
1119
return new BeanDescriptor(this.beanClass, findCustomizerClass(this.beanClass));
1120
}
1121
1122
private static Class<?> findCustomizerClass(Class<?> type) {
1123
String name = type.getName() + "Customizer";
1124
try {
1125
type = ClassFinder.findClass(name, type.getClassLoader());
1126
// Each customizer should inherit java.awt.Component and implement java.beans.Customizer
1127
// according to the section 9.3 of JavaBeans specification
1128
if (Component.class.isAssignableFrom(type) && Customizer.class.isAssignableFrom(type)) {
1129
return type;
1130
}
1131
}
1132
catch (Exception exception) {
1133
// ignore any exceptions
1134
}
1135
return null;
1136
}
1137
1138
private boolean isEventHandler(Method m) {
1139
// We assume that a method is an event handler if it has a single
1140
// argument, whose type inherit from java.util.Event.
1141
Type[] argTypes = m.getGenericParameterTypes();
1142
if (argTypes.length != 1) {
1143
return false;
1144
}
1145
return isSubclass(TypeResolver.erase(TypeResolver.resolveInClass(beanClass, argTypes[0])), EventObject.class);
1146
}
1147
1148
//======================================================================
1149
// Package private support methods.
1150
//======================================================================
1151
1152
/**
1153
* Internal support for finding a target methodName with a given
1154
* parameter list on a given class.
1155
*/
1156
private static Method internalFindMethod(Class<?> start, String methodName,
1157
int argCount, Class<?>[] args) {
1158
// For overriden methods we need to find the most derived version.
1159
// So we start with the given class and walk up the superclass chain.
1160
for (Class<?> cl = start; cl != null; cl = cl.getSuperclass()) {
1161
for (Method method : ClassInfo.get(cl).getMethods()) {
1162
// make sure method signature matches.
1163
if (method.getName().equals(methodName)) {
1164
Type[] params = method.getGenericParameterTypes();
1165
if (params.length == argCount) {
1166
if (args != null) {
1167
boolean different = false;
1168
if (argCount > 0) {
1169
for (int j = 0; j < argCount; j++) {
1170
if (TypeResolver.erase(TypeResolver.resolveInClass(start, params[j])) != args[j]) {
1171
different = true;
1172
continue;
1173
}
1174
}
1175
if (different) {
1176
continue;
1177
}
1178
}
1179
}
1180
return method;
1181
}
1182
}
1183
}
1184
}
1185
// Now check any inherited interfaces. This is necessary both when
1186
// the argument class is itself an interface, and when the argument
1187
// class is an abstract class.
1188
Class<?>[] ifcs = start.getInterfaces();
1189
for (int i = 0 ; i < ifcs.length; i++) {
1190
// Note: The original implementation had both methods calling
1191
// the 3 arg method. This is preserved but perhaps it should
1192
// pass the args array instead of null.
1193
Method method = internalFindMethod(ifcs[i], methodName, argCount, null);
1194
if (method != null) {
1195
return method;
1196
}
1197
}
1198
return null;
1199
}
1200
1201
/**
1202
* Find a target methodName on a given class.
1203
*/
1204
static Method findMethod(Class<?> cls, String methodName, int argCount) {
1205
return findMethod(cls, methodName, argCount, null);
1206
}
1207
1208
/**
1209
* Find a target methodName with specific parameter list on a given class.
1210
* <p>
1211
* Used in the contructors of the EventSetDescriptor,
1212
* PropertyDescriptor and the IndexedPropertyDescriptor.
1213
* <p>
1214
* @param cls The Class object on which to retrieve the method.
1215
* @param methodName Name of the method.
1216
* @param argCount Number of arguments for the desired method.
1217
* @param args Array of argument types for the method.
1218
* @return the method or null if not found
1219
*/
1220
static Method findMethod(Class<?> cls, String methodName, int argCount,
1221
Class<?>[] args) {
1222
if (methodName == null) {
1223
return null;
1224
}
1225
return internalFindMethod(cls, methodName, argCount, args);
1226
}
1227
1228
/**
1229
* Return true if class a is either equivalent to class b, or
1230
* if class a is a subclass of class b, i.e. if a either "extends"
1231
* or "implements" b.
1232
* Note tht either or both "Class" objects may represent interfaces.
1233
*/
1234
static boolean isSubclass(Class<?> a, Class<?> b) {
1235
// We rely on the fact that for any given java class or
1236
// primtitive type there is a unqiue Class object, so
1237
// we can use object equivalence in the comparisons.
1238
if (a == b) {
1239
return true;
1240
}
1241
if (a == null || b == null) {
1242
return false;
1243
}
1244
for (Class<?> x = a; x != null; x = x.getSuperclass()) {
1245
if (x == b) {
1246
return true;
1247
}
1248
if (b.isInterface()) {
1249
Class<?>[] interfaces = x.getInterfaces();
1250
for (int i = 0; i < interfaces.length; i++) {
1251
if (isSubclass(interfaces[i], b)) {
1252
return true;
1253
}
1254
}
1255
}
1256
}
1257
return false;
1258
}
1259
1260
/**
1261
* Try to create an instance of a named class.
1262
* First try the classloader of "sibling", then try the system
1263
* classloader then the class loader of the current Thread.
1264
*/
1265
@SuppressWarnings("deprecation")
1266
static Object instantiate(Class<?> sibling, String className)
1267
throws InstantiationException, IllegalAccessException,
1268
NoSuchMethodException, InvocationTargetException,
1269
ClassNotFoundException {
1270
// First check with sibling's classloader (if any).
1271
ClassLoader cl = sibling.getClassLoader();
1272
Class<?> cls = ClassFinder.findClass(className, cl);
1273
return cls.newInstance();
1274
}
1275
1276
} // end class Introspector
1277
1278
//===========================================================================
1279
1280
/**
1281
* Package private implementation support class for Introspector's
1282
* internal use.
1283
* <p>
1284
* Mostly this is used as a placeholder for the descriptors.
1285
*/
1286
1287
class GenericBeanInfo extends SimpleBeanInfo {
1288
1289
private BeanDescriptor beanDescriptor;
1290
private EventSetDescriptor[] events;
1291
private int defaultEvent;
1292
private PropertyDescriptor[] properties;
1293
private int defaultProperty;
1294
private MethodDescriptor[] methods;
1295
private Reference<BeanInfo> targetBeanInfoRef;
1296
1297
public GenericBeanInfo(BeanDescriptor beanDescriptor,
1298
EventSetDescriptor[] events, int defaultEvent,
1299
PropertyDescriptor[] properties, int defaultProperty,
1300
MethodDescriptor[] methods, BeanInfo targetBeanInfo) {
1301
this.beanDescriptor = beanDescriptor;
1302
this.events = events;
1303
this.defaultEvent = defaultEvent;
1304
this.properties = properties;
1305
this.defaultProperty = defaultProperty;
1306
this.methods = methods;
1307
this.targetBeanInfoRef = (targetBeanInfo != null)
1308
? new SoftReference<>(targetBeanInfo)
1309
: null;
1310
}
1311
1312
/**
1313
* Package-private dup constructor
1314
* This must isolate the new object from any changes to the old object.
1315
*/
1316
GenericBeanInfo(GenericBeanInfo old) {
1317
1318
beanDescriptor = new BeanDescriptor(old.beanDescriptor);
1319
if (old.events != null) {
1320
int len = old.events.length;
1321
events = new EventSetDescriptor[len];
1322
for (int i = 0; i < len; i++) {
1323
events[i] = new EventSetDescriptor(old.events[i]);
1324
}
1325
}
1326
defaultEvent = old.defaultEvent;
1327
if (old.properties != null) {
1328
int len = old.properties.length;
1329
properties = new PropertyDescriptor[len];
1330
for (int i = 0; i < len; i++) {
1331
PropertyDescriptor oldp = old.properties[i];
1332
if (oldp instanceof IndexedPropertyDescriptor) {
1333
properties[i] = new IndexedPropertyDescriptor(
1334
(IndexedPropertyDescriptor) oldp);
1335
} else {
1336
properties[i] = new PropertyDescriptor(oldp);
1337
}
1338
}
1339
}
1340
defaultProperty = old.defaultProperty;
1341
if (old.methods != null) {
1342
int len = old.methods.length;
1343
methods = new MethodDescriptor[len];
1344
for (int i = 0; i < len; i++) {
1345
methods[i] = new MethodDescriptor(old.methods[i]);
1346
}
1347
}
1348
this.targetBeanInfoRef = old.targetBeanInfoRef;
1349
}
1350
1351
public PropertyDescriptor[] getPropertyDescriptors() {
1352
return properties;
1353
}
1354
1355
public int getDefaultPropertyIndex() {
1356
return defaultProperty;
1357
}
1358
1359
public EventSetDescriptor[] getEventSetDescriptors() {
1360
return events;
1361
}
1362
1363
public int getDefaultEventIndex() {
1364
return defaultEvent;
1365
}
1366
1367
public MethodDescriptor[] getMethodDescriptors() {
1368
return methods;
1369
}
1370
1371
public BeanDescriptor getBeanDescriptor() {
1372
return beanDescriptor;
1373
}
1374
1375
public java.awt.Image getIcon(int iconKind) {
1376
BeanInfo targetBeanInfo = getTargetBeanInfo();
1377
if (targetBeanInfo != null) {
1378
return targetBeanInfo.getIcon(iconKind);
1379
}
1380
return super.getIcon(iconKind);
1381
}
1382
1383
private BeanInfo getTargetBeanInfo() {
1384
if (this.targetBeanInfoRef == null) {
1385
return null;
1386
}
1387
BeanInfo targetBeanInfo = this.targetBeanInfoRef.get();
1388
if (targetBeanInfo == null) {
1389
targetBeanInfo = ThreadGroupContext.getContext().getBeanInfoFinder()
1390
.find(this.beanDescriptor.getBeanClass());
1391
if (targetBeanInfo != null) {
1392
this.targetBeanInfoRef = new SoftReference<>(targetBeanInfo);
1393
}
1394
}
1395
return targetBeanInfo;
1396
}
1397
}
1398
1399