Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/java/beans/PropertyDescriptor.java
41152 views
1
/*
2
* Copyright (c) 1996, 2015, 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
package java.beans;
26
27
import java.lang.ref.Reference;
28
import java.lang.reflect.Method;
29
import java.lang.reflect.Constructor;
30
import java.util.Map.Entry;
31
32
import com.sun.beans.introspect.PropertyInfo;
33
import sun.reflect.misc.ReflectUtil;
34
35
/**
36
* A PropertyDescriptor describes one property that a Java Bean
37
* exports via a pair of accessor methods.
38
* @since 1.1
39
*/
40
public class PropertyDescriptor extends FeatureDescriptor {
41
42
private Reference<? extends Class<?>> propertyTypeRef;
43
private final MethodRef readMethodRef = new MethodRef();
44
private final MethodRef writeMethodRef = new MethodRef();
45
private Reference<? extends Class<?>> propertyEditorClassRef;
46
47
private boolean bound;
48
private boolean constrained;
49
50
// The base name of the method name which will be prefixed with the
51
// read and write method. If name == "foo" then the baseName is "Foo"
52
private String baseName;
53
54
private String writeMethodName;
55
private String readMethodName;
56
57
/**
58
* Constructs a PropertyDescriptor for a property that follows
59
* the standard Java convention by having getFoo and setFoo
60
* accessor methods. Thus if the argument name is "fred", it will
61
* assume that the writer method is "setFred" and the reader method
62
* is "getFred" (or "isFred" for a boolean property). Note that the
63
* property name should start with a lower case character, which will
64
* be capitalized in the method names.
65
*
66
* @param propertyName The programmatic name of the property.
67
* @param beanClass The Class object for the target bean. For
68
* example sun.beans.OurButton.class.
69
* @exception IntrospectionException if an exception occurs during
70
* introspection.
71
*/
72
public PropertyDescriptor(String propertyName, Class<?> beanClass)
73
throws IntrospectionException {
74
this(propertyName, beanClass,
75
Introspector.IS_PREFIX + NameGenerator.capitalize(propertyName),
76
Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName));
77
}
78
79
/**
80
* This constructor takes the name of a simple property, and method
81
* names for reading and writing the property.
82
*
83
* @param propertyName The programmatic name of the property.
84
* @param beanClass The Class object for the target bean. For
85
* example sun.beans.OurButton.class.
86
* @param readMethodName The name of the method used for reading the property
87
* value. May be null if the property is write-only.
88
* @param writeMethodName The name of the method used for writing the property
89
* value. May be null if the property is read-only.
90
* @exception IntrospectionException if an exception occurs during
91
* introspection.
92
*/
93
public PropertyDescriptor(String propertyName, Class<?> beanClass,
94
String readMethodName, String writeMethodName)
95
throws IntrospectionException {
96
if (beanClass == null) {
97
throw new IntrospectionException("Target Bean class is null");
98
}
99
if (propertyName == null || propertyName.length() == 0) {
100
throw new IntrospectionException("bad property name");
101
}
102
if ("".equals(readMethodName) || "".equals(writeMethodName)) {
103
throw new IntrospectionException("read or write method name should not be the empty string");
104
}
105
setName(propertyName);
106
setClass0(beanClass);
107
108
this.readMethodName = readMethodName;
109
if (readMethodName != null && getReadMethod() == null) {
110
throw new IntrospectionException("Method not found: " + readMethodName);
111
}
112
this.writeMethodName = writeMethodName;
113
if (writeMethodName != null && getWriteMethod() == null) {
114
throw new IntrospectionException("Method not found: " + writeMethodName);
115
}
116
// If this class or one of its base classes allow PropertyChangeListener,
117
// then we assume that any properties we discover are "bound".
118
// See Introspector.getTargetPropertyInfo() method.
119
Class<?>[] args = { PropertyChangeListener.class };
120
this.bound = null != Introspector.findMethod(beanClass, "addPropertyChangeListener", args.length, args);
121
}
122
123
/**
124
* This constructor takes the name of a simple property, and Method
125
* objects for reading and writing the property.
126
*
127
* @param propertyName The programmatic name of the property.
128
* @param readMethod The method used for reading the property value.
129
* May be null if the property is write-only.
130
* @param writeMethod The method used for writing the property value.
131
* May be null if the property is read-only.
132
* @exception IntrospectionException if an exception occurs during
133
* introspection.
134
*/
135
public PropertyDescriptor(String propertyName, Method readMethod, Method writeMethod)
136
throws IntrospectionException {
137
if (propertyName == null || propertyName.length() == 0) {
138
throw new IntrospectionException("bad property name");
139
}
140
setName(propertyName);
141
setReadMethod(readMethod);
142
setWriteMethod(writeMethod);
143
}
144
145
/**
146
* Creates {@code PropertyDescriptor} from the specified property info.
147
*
148
* @param entry the pair of values,
149
* where the {@code key} is the base name of the property (the rest of the method name)
150
* and the {@code value} is the automatically generated property info
151
* @param bound the flag indicating whether it is possible to treat this property as a bound property
152
*
153
* @since 9
154
*/
155
PropertyDescriptor(Entry<String,PropertyInfo> entry, boolean bound) {
156
String base = entry.getKey();
157
PropertyInfo info = entry.getValue();
158
setName(Introspector.decapitalize(base));
159
setReadMethod0(info.getReadMethod());
160
setWriteMethod0(info.getWriteMethod());
161
setPropertyType(info.getPropertyType());
162
setConstrained(info.isConstrained());
163
setBound(bound && info.is(PropertyInfo.Name.bound));
164
165
boolean isExpert = info.is(PropertyInfo.Name.expert);
166
setValue(PropertyInfo.Name.expert.name(), isExpert); // compatibility
167
setExpert(isExpert);
168
169
boolean isHidden = info.is(PropertyInfo.Name.hidden);
170
setValue(PropertyInfo.Name.hidden.name(), isHidden); // compatibility
171
setHidden(isHidden);
172
173
setPreferred(info.is(PropertyInfo.Name.preferred));
174
175
boolean isRequired = info.is(PropertyInfo.Name.required);
176
setValue(PropertyInfo.Name.required.name(), isRequired);
177
178
boolean visual = info.is(PropertyInfo.Name.visualUpdate);
179
setValue(PropertyInfo.Name.visualUpdate.name(), visual);
180
181
Object description = info.get(PropertyInfo.Name.description);
182
if (description != null) {
183
setShortDescription(description.toString());
184
}
185
Object values = info.get(PropertyInfo.Name.enumerationValues);
186
if (values == null) {
187
values = new Object[0];
188
}
189
setValue(PropertyInfo.Name.enumerationValues.name(), values);
190
this.baseName = base;
191
}
192
193
/**
194
* Returns the Java type info for the property.
195
* Note that the {@code Class} object may describe
196
* primitive Java types such as {@code int}.
197
* This type is returned by the read method
198
* or is used as the parameter type of the write method.
199
* Returns {@code null} if the type is an indexed property
200
* that does not support non-indexed access.
201
*
202
* @return the {@code Class} object that represents the Java type info,
203
* or {@code null} if the type cannot be determined
204
*/
205
public synchronized Class<?> getPropertyType() {
206
Class<?> type = getPropertyType0();
207
if (type == null) {
208
try {
209
type = findPropertyType(getReadMethod(), getWriteMethod());
210
setPropertyType(type);
211
} catch (IntrospectionException ex) {
212
// Fall
213
}
214
}
215
return type;
216
}
217
218
private void setPropertyType(Class<?> type) {
219
this.propertyTypeRef = getWeakReference(type);
220
}
221
222
private Class<?> getPropertyType0() {
223
return (this.propertyTypeRef != null)
224
? this.propertyTypeRef.get()
225
: null;
226
}
227
228
/**
229
* Gets the method that should be used to read the property value.
230
*
231
* @return The method that should be used to read the property value.
232
* May return null if the property can't be read.
233
*/
234
public synchronized Method getReadMethod() {
235
Method readMethod = this.readMethodRef.get();
236
if (readMethod == null) {
237
Class<?> cls = getClass0();
238
if (cls == null || (readMethodName == null && !this.readMethodRef.isSet())) {
239
// The read method was explicitly set to null.
240
return null;
241
}
242
String nextMethodName = Introspector.GET_PREFIX + getBaseName();
243
if (readMethodName == null) {
244
Class<?> type = getPropertyType0();
245
if (type == boolean.class || type == null) {
246
readMethodName = Introspector.IS_PREFIX + getBaseName();
247
} else {
248
readMethodName = nextMethodName;
249
}
250
}
251
252
// Since there can be multiple write methods but only one getter
253
// method, find the getter method first so that you know what the
254
// property type is. For booleans, there can be "is" and "get"
255
// methods. If an "is" method exists, this is the official
256
// reader method so look for this one first.
257
readMethod = Introspector.findMethod(cls, readMethodName, 0);
258
if ((readMethod == null) && !readMethodName.equals(nextMethodName)) {
259
readMethodName = nextMethodName;
260
readMethod = Introspector.findMethod(cls, readMethodName, 0);
261
}
262
try {
263
setReadMethod(readMethod);
264
} catch (IntrospectionException ex) {
265
// fall
266
}
267
}
268
return readMethod;
269
}
270
271
/**
272
* Sets the method that should be used to read the property value.
273
*
274
* @param readMethod The new read method.
275
* @throws IntrospectionException if the read method is invalid
276
* @since 1.2
277
*/
278
public synchronized void setReadMethod(Method readMethod)
279
throws IntrospectionException {
280
// The property type is determined by the read method.
281
setPropertyType(findPropertyType(readMethod, this.writeMethodRef.get()));
282
setReadMethod0(readMethod);
283
}
284
285
private void setReadMethod0(Method readMethod) {
286
this.readMethodRef.set(readMethod);
287
if (readMethod == null) {
288
readMethodName = null;
289
return;
290
}
291
setClass0(readMethod.getDeclaringClass());
292
293
readMethodName = readMethod.getName();
294
setTransient(readMethod.getAnnotation(Transient.class));
295
}
296
297
/**
298
* Gets the method that should be used to write the property value.
299
*
300
* @return The method that should be used to write the property value.
301
* May return null if the property can't be written.
302
*/
303
public synchronized Method getWriteMethod() {
304
Method writeMethod = this.writeMethodRef.get();
305
if (writeMethod == null) {
306
Class<?> cls = getClass0();
307
if (cls == null || (writeMethodName == null && !this.writeMethodRef.isSet())) {
308
// The write method was explicitly set to null.
309
return null;
310
}
311
312
// We need the type to fetch the correct method.
313
Class<?> type = getPropertyType0();
314
if (type == null) {
315
try {
316
// Can't use getPropertyType since it will lead to recursive loop.
317
type = findPropertyType(getReadMethod(), null);
318
setPropertyType(type);
319
} catch (IntrospectionException ex) {
320
// Without the correct property type we can't be guaranteed
321
// to find the correct method.
322
return null;
323
}
324
}
325
326
if (writeMethodName == null) {
327
writeMethodName = Introspector.SET_PREFIX + getBaseName();
328
}
329
330
Class<?>[] args = (type == null) ? null : new Class<?>[] { type };
331
writeMethod = Introspector.findMethod(cls, writeMethodName, 1, args);
332
if (writeMethod != null) {
333
if (!writeMethod.getReturnType().equals(void.class)) {
334
writeMethod = null;
335
}
336
}
337
try {
338
setWriteMethod(writeMethod);
339
} catch (IntrospectionException ex) {
340
// fall through
341
}
342
}
343
return writeMethod;
344
}
345
346
/**
347
* Sets the method that should be used to write the property value.
348
*
349
* @param writeMethod The new write method.
350
* @throws IntrospectionException if the write method is invalid
351
* @since 1.2
352
*/
353
public synchronized void setWriteMethod(Method writeMethod)
354
throws IntrospectionException {
355
// Set the property type - which validates the method
356
setPropertyType(findPropertyType(getReadMethod(), writeMethod));
357
setWriteMethod0(writeMethod);
358
}
359
360
private void setWriteMethod0(Method writeMethod) {
361
this.writeMethodRef.set(writeMethod);
362
if (writeMethod == null) {
363
writeMethodName = null;
364
return;
365
}
366
setClass0(writeMethod.getDeclaringClass());
367
368
writeMethodName = writeMethod.getName();
369
setTransient(writeMethod.getAnnotation(Transient.class));
370
}
371
372
/**
373
* Overridden to ensure that a super class doesn't take precedent
374
*/
375
void setClass0(Class<?> clz) {
376
if (getClass0() != null && clz.isAssignableFrom(getClass0())) {
377
// don't replace a subclass with a superclass
378
return;
379
}
380
super.setClass0(clz);
381
}
382
383
/**
384
* Updates to "bound" properties will cause a "PropertyChange" event to
385
* get fired when the property is changed.
386
*
387
* @return True if this is a bound property.
388
*/
389
public boolean isBound() {
390
return bound;
391
}
392
393
/**
394
* Updates to "bound" properties will cause a "PropertyChange" event to
395
* get fired when the property is changed.
396
*
397
* @param bound True if this is a bound property.
398
*/
399
public void setBound(boolean bound) {
400
this.bound = bound;
401
}
402
403
/**
404
* Attempted updates to "Constrained" properties will cause a "VetoableChange"
405
* event to get fired when the property is changed.
406
*
407
* @return True if this is a constrained property.
408
*/
409
public boolean isConstrained() {
410
return constrained;
411
}
412
413
/**
414
* Attempted updates to "Constrained" properties will cause a "VetoableChange"
415
* event to get fired when the property is changed.
416
*
417
* @param constrained True if this is a constrained property.
418
*/
419
public void setConstrained(boolean constrained) {
420
this.constrained = constrained;
421
}
422
423
424
/**
425
* Normally PropertyEditors will be found using the PropertyEditorManager.
426
* However if for some reason you want to associate a particular
427
* PropertyEditor with a given property, then you can do it with
428
* this method.
429
*
430
* @param propertyEditorClass The Class for the desired PropertyEditor.
431
*/
432
public void setPropertyEditorClass(Class<?> propertyEditorClass) {
433
this.propertyEditorClassRef = getWeakReference(propertyEditorClass);
434
}
435
436
/**
437
* Gets any explicit PropertyEditor Class that has been registered
438
* for this property.
439
*
440
* @return Any explicit PropertyEditor Class that has been registered
441
* for this property. Normally this will return "null",
442
* indicating that no special editor has been registered,
443
* so the PropertyEditorManager should be used to locate
444
* a suitable PropertyEditor.
445
*/
446
public Class<?> getPropertyEditorClass() {
447
return (this.propertyEditorClassRef != null)
448
? this.propertyEditorClassRef.get()
449
: null;
450
}
451
452
/**
453
* Constructs an instance of a property editor using the current
454
* property editor class.
455
* <p>
456
* If the property editor class has a public constructor that takes an
457
* Object argument then it will be invoked using the bean parameter
458
* as the argument. Otherwise, the default constructor will be invoked.
459
*
460
* @param bean the source object
461
* @return a property editor instance or null if a property editor has
462
* not been defined or cannot be created
463
* @since 1.5
464
*/
465
@SuppressWarnings("deprecation")
466
public PropertyEditor createPropertyEditor(Object bean) {
467
Object editor = null;
468
469
final Class<?> cls = getPropertyEditorClass();
470
if (cls != null && PropertyEditor.class.isAssignableFrom(cls)
471
&& ReflectUtil.isPackageAccessible(cls)) {
472
Constructor<?> ctor = null;
473
if (bean != null) {
474
try {
475
ctor = cls.getConstructor(new Class<?>[] { Object.class });
476
} catch (Exception ex) {
477
// Fall through
478
}
479
}
480
try {
481
if (ctor == null) {
482
editor = cls.newInstance();
483
} else {
484
editor = ctor.newInstance(new Object[] { bean });
485
}
486
} catch (Exception ex) {
487
// Fall through
488
}
489
}
490
return (PropertyEditor)editor;
491
}
492
493
494
/**
495
* Compares this {@code PropertyDescriptor} against the specified object.
496
* Returns true if the objects are the same. Two {@code PropertyDescriptor}s
497
* are the same if the read, write, property types, property editor and
498
* flags are equivalent.
499
*
500
* @since 1.4
501
*/
502
public boolean equals(Object obj) {
503
if (this == obj) {
504
return true;
505
}
506
if (obj != null && obj instanceof PropertyDescriptor) {
507
PropertyDescriptor other = (PropertyDescriptor)obj;
508
Method otherReadMethod = other.getReadMethod();
509
Method otherWriteMethod = other.getWriteMethod();
510
511
if (!compareMethods(getReadMethod(), otherReadMethod)) {
512
return false;
513
}
514
515
if (!compareMethods(getWriteMethod(), otherWriteMethod)) {
516
return false;
517
}
518
519
if (getPropertyType() == other.getPropertyType() &&
520
getPropertyEditorClass() == other.getPropertyEditorClass() &&
521
bound == other.isBound() && constrained == other.isConstrained() &&
522
writeMethodName == other.writeMethodName &&
523
readMethodName == other.readMethodName) {
524
return true;
525
}
526
}
527
return false;
528
}
529
530
/**
531
* Package private helper method for Descriptor .equals methods.
532
*
533
* @param a first method to compare
534
* @param b second method to compare
535
* @return boolean to indicate that the methods are equivalent
536
*/
537
boolean compareMethods(Method a, Method b) {
538
// Note: perhaps this should be a protected method in FeatureDescriptor
539
if ((a == null) != (b == null)) {
540
return false;
541
}
542
543
if (a != null && b != null) {
544
if (!a.equals(b)) {
545
return false;
546
}
547
}
548
return true;
549
}
550
551
/**
552
* Package-private constructor.
553
* Merge two property descriptors. Where they conflict, give the
554
* second argument (y) priority over the first argument (x).
555
*
556
* @param x The first (lower priority) PropertyDescriptor
557
* @param y The second (higher priority) PropertyDescriptor
558
*/
559
PropertyDescriptor(PropertyDescriptor x, PropertyDescriptor y) {
560
super(x,y);
561
562
if (y.baseName != null) {
563
baseName = y.baseName;
564
} else {
565
baseName = x.baseName;
566
}
567
568
if (y.readMethodName != null) {
569
readMethodName = y.readMethodName;
570
} else {
571
readMethodName = x.readMethodName;
572
}
573
574
if (y.writeMethodName != null) {
575
writeMethodName = y.writeMethodName;
576
} else {
577
writeMethodName = x.writeMethodName;
578
}
579
580
if (y.propertyTypeRef != null) {
581
propertyTypeRef = y.propertyTypeRef;
582
} else {
583
propertyTypeRef = x.propertyTypeRef;
584
}
585
586
// Figure out the merged read method.
587
Method xr = x.getReadMethod();
588
Method yr = y.getReadMethod();
589
590
// Normally give priority to y's readMethod.
591
try {
592
if (isAssignable(xr, yr)) {
593
setReadMethod(yr);
594
} else {
595
setReadMethod(xr);
596
}
597
} catch (IntrospectionException ex) {
598
// fall through
599
}
600
601
// However, if both x and y reference read methods in the same class,
602
// give priority to a boolean "is" method over a boolean "get" method.
603
if (xr != null && yr != null &&
604
xr.getDeclaringClass() == yr.getDeclaringClass() &&
605
getReturnType(getClass0(), xr) == boolean.class &&
606
getReturnType(getClass0(), yr) == boolean.class &&
607
xr.getName().indexOf(Introspector.IS_PREFIX) == 0 &&
608
yr.getName().indexOf(Introspector.GET_PREFIX) == 0) {
609
try {
610
setReadMethod(xr);
611
} catch (IntrospectionException ex) {
612
// fall through
613
}
614
}
615
616
Method xw = x.getWriteMethod();
617
Method yw = y.getWriteMethod();
618
619
try {
620
if (yw != null) {
621
setWriteMethod(yw);
622
} else {
623
setWriteMethod(xw);
624
}
625
} catch (IntrospectionException ex) {
626
// Fall through
627
}
628
629
if (y.getPropertyEditorClass() != null) {
630
setPropertyEditorClass(y.getPropertyEditorClass());
631
} else {
632
setPropertyEditorClass(x.getPropertyEditorClass());
633
}
634
635
636
bound = x.bound | y.bound;
637
constrained = x.constrained | y.constrained;
638
}
639
640
/*
641
* Package-private dup constructor.
642
* This must isolate the new object from any changes to the old object.
643
*/
644
PropertyDescriptor(PropertyDescriptor old) {
645
super(old);
646
propertyTypeRef = old.propertyTypeRef;
647
this.readMethodRef.set(old.readMethodRef.get());
648
this.writeMethodRef.set(old.writeMethodRef.get());
649
propertyEditorClassRef = old.propertyEditorClassRef;
650
651
writeMethodName = old.writeMethodName;
652
readMethodName = old.readMethodName;
653
baseName = old.baseName;
654
655
bound = old.bound;
656
constrained = old.constrained;
657
}
658
659
void updateGenericsFor(Class<?> type) {
660
setClass0(type);
661
try {
662
setPropertyType(findPropertyType(this.readMethodRef.get(), this.writeMethodRef.get()));
663
}
664
catch (IntrospectionException exception) {
665
setPropertyType(null);
666
}
667
}
668
669
/**
670
* Returns the property type that corresponds to the read and write method.
671
* The type precedence is given to the readMethod.
672
*
673
* @return the type of the property descriptor or null if both
674
* read and write methods are null.
675
* @throws IntrospectionException if the read or write method is invalid
676
*/
677
private Class<?> findPropertyType(Method readMethod, Method writeMethod)
678
throws IntrospectionException {
679
Class<?> propertyType = null;
680
try {
681
if (readMethod != null) {
682
Class<?>[] params = getParameterTypes(getClass0(), readMethod);
683
if (params.length != 0) {
684
throw new IntrospectionException("bad read method arg count: "
685
+ readMethod);
686
}
687
propertyType = getReturnType(getClass0(), readMethod);
688
if (propertyType == Void.TYPE) {
689
throw new IntrospectionException("read method " +
690
readMethod.getName() + " returns void");
691
}
692
}
693
if (writeMethod != null) {
694
Class<?>[] params = getParameterTypes(getClass0(), writeMethod);
695
if (params.length != 1) {
696
throw new IntrospectionException("bad write method arg count: "
697
+ writeMethod);
698
}
699
if (propertyType != null && !params[0].isAssignableFrom(propertyType)) {
700
throw new IntrospectionException("type mismatch between read and write methods");
701
}
702
propertyType = params[0];
703
}
704
} catch (IntrospectionException ex) {
705
throw ex;
706
}
707
return propertyType;
708
}
709
710
711
/**
712
* Returns a hash code value for the object.
713
* See {@link java.lang.Object#hashCode} for a complete description.
714
*
715
* @return a hash code value for this object.
716
* @since 1.5
717
*/
718
public int hashCode() {
719
int result = 7;
720
721
result = 37 * result + ((getPropertyType() == null) ? 0 :
722
getPropertyType().hashCode());
723
result = 37 * result + ((getReadMethod() == null) ? 0 :
724
getReadMethod().hashCode());
725
result = 37 * result + ((getWriteMethod() == null) ? 0 :
726
getWriteMethod().hashCode());
727
result = 37 * result + ((getPropertyEditorClass() == null) ? 0 :
728
getPropertyEditorClass().hashCode());
729
result = 37 * result + ((writeMethodName == null) ? 0 :
730
writeMethodName.hashCode());
731
result = 37 * result + ((readMethodName == null) ? 0 :
732
readMethodName.hashCode());
733
result = 37 * result + getName().hashCode();
734
result = 37 * result + ((bound == false) ? 0 : 1);
735
result = 37 * result + ((constrained == false) ? 0 : 1);
736
737
return result;
738
}
739
740
// Calculate once since capitalize() is expensive.
741
String getBaseName() {
742
if (baseName == null) {
743
baseName = NameGenerator.capitalize(getName());
744
}
745
return baseName;
746
}
747
748
void appendTo(StringBuilder sb) {
749
appendTo(sb, "bound", this.bound);
750
appendTo(sb, "constrained", this.constrained);
751
appendTo(sb, "propertyEditorClass", this.propertyEditorClassRef);
752
appendTo(sb, "propertyType", this.propertyTypeRef);
753
appendTo(sb, "readMethod", this.readMethodRef.get());
754
appendTo(sb, "writeMethod", this.writeMethodRef.get());
755
}
756
757
boolean isAssignable(Method m1, Method m2) {
758
if (m1 == null) {
759
return true; // choose second method
760
}
761
if (m2 == null) {
762
return false; // choose first method
763
}
764
if (!m1.getName().equals(m2.getName())) {
765
return true; // choose second method by default
766
}
767
Class<?> type1 = m1.getDeclaringClass();
768
Class<?> type2 = m2.getDeclaringClass();
769
if (!type1.isAssignableFrom(type2)) {
770
return false; // choose first method: it declared later
771
}
772
type1 = getReturnType(getClass0(), m1);
773
type2 = getReturnType(getClass0(), m2);
774
if (!type1.isAssignableFrom(type2)) {
775
return false; // choose first method: it overrides return type
776
}
777
Class<?>[] args1 = getParameterTypes(getClass0(), m1);
778
Class<?>[] args2 = getParameterTypes(getClass0(), m2);
779
if (args1.length != args2.length) {
780
return true; // choose second method by default
781
}
782
for (int i = 0; i < args1.length; i++) {
783
if (!args1[i].isAssignableFrom(args2[i])) {
784
return false; // choose first method: it overrides parameter
785
}
786
}
787
return true; // choose second method
788
}
789
}
790
791