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