1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.beans;
18
19 import java.beans.BeanInfo;
20 import java.beans.IndexedPropertyDescriptor;
21 import java.beans.IntrospectionException;
22 import java.beans.Introspector;
23 import java.beans.PropertyDescriptor;
24 import java.math.BigDecimal;
25
26 import org.junit.Test;
27
28 import org.springframework.core.JdkVersion;
29 import org.springframework.tests.sample.beans.TestBean;
30
31 import static org.hamcrest.CoreMatchers.equalTo;
32 import static org.hamcrest.CoreMatchers.is;
33 import static org.hamcrest.Matchers.*;
34 import static org.junit.Assert.*;
35
36
37
38
39
40 public class ExtendedBeanInfoTests {
41
42 @Test
43 public void standardReadMethodOnly() throws IntrospectionException {
44 @SuppressWarnings("unused") class C {
45 public String getFoo() { return null; }
46 }
47
48 BeanInfo bi = Introspector.getBeanInfo(C.class);
49 ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
50
51 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
52 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
53
54 assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
55 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(false));
56 }
57
58 @Test
59 public void standardWriteMethodOnly() throws IntrospectionException {
60 @SuppressWarnings("unused") class C {
61 public void setFoo(String f) { }
62 }
63
64 BeanInfo bi = Introspector.getBeanInfo(C.class);
65 ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
66
67 assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
68 assertThat(hasWriteMethodForProperty(bi, "foo"), is(true));
69
70 assertThat(hasReadMethodForProperty(ebi, "foo"), is(false));
71 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
72 }
73
74 @Test
75 public void standardReadAndWriteMethods() throws IntrospectionException {
76 @SuppressWarnings("unused") class C {
77 public void setFoo(String f) { }
78 public String getFoo() { return null; }
79 }
80
81 BeanInfo bi = Introspector.getBeanInfo(C.class);
82 ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
83
84 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
85 assertThat(hasWriteMethodForProperty(bi, "foo"), is(true));
86
87 assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
88 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
89 }
90
91 @Test
92 public void nonStandardWriteMethodOnly() throws IntrospectionException {
93 @SuppressWarnings("unused") class C {
94 public C setFoo(String foo) { return this; }
95 }
96
97 BeanInfo bi = Introspector.getBeanInfo(C.class);
98 ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
99
100 assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
101 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
102
103 assertThat(hasReadMethodForProperty(ebi, "foo"), is(false));
104 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
105 }
106
107 @Test
108 public void standardReadAndNonStandardWriteMethods() throws IntrospectionException {
109 @SuppressWarnings("unused") class C {
110 public String getFoo() { return null; }
111 public C setFoo(String foo) { return this; }
112 }
113
114 BeanInfo bi = Introspector.getBeanInfo(C.class);
115
116 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
117 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
118
119 ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
120
121 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
122 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
123
124 assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
125 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
126 }
127
128 @Test
129 public void standardReadAndNonStandardIndexedWriteMethod() throws IntrospectionException {
130 @SuppressWarnings("unused") class C {
131 public String[] getFoo() { return null; }
132 public C setFoo(int i, String foo) { return this; }
133 }
134
135 BeanInfo bi = Introspector.getBeanInfo(C.class);
136
137 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
138 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
139 assertThat(hasIndexedWriteMethodForProperty(bi, "foo"), is(trueUntilJdk17()));
140
141 BeanInfo ebi = new ExtendedBeanInfo(bi);
142
143 assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
144 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(false));
145 assertThat(hasIndexedWriteMethodForProperty(ebi, "foo"), is(true));
146 }
147
148 @Test
149 public void standardReadMethodsAndOverloadedNonStandardWriteMethods() throws Exception {
150 @SuppressWarnings("unused") class C {
151 public String getFoo() { return null; }
152 public C setFoo(String foo) { return this; }
153 public C setFoo(Number foo) { return this; }
154 }
155
156 BeanInfo bi = Introspector.getBeanInfo(C.class);
157
158 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
159 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
160
161 ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
162
163 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
164 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
165
166 assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
167 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
168
169 for (PropertyDescriptor pd : ebi.getPropertyDescriptors()) {
170 if (pd.getName().equals("foo")) {
171 assertThat(pd.getWriteMethod(), is(C.class.getMethod("setFoo", String.class)));
172 return;
173 }
174 }
175 fail("never matched write method");
176 }
177
178 @Test
179 public void cornerSpr9414() throws IntrospectionException {
180 @SuppressWarnings("unused") class Parent {
181 public Number getProperty1() {
182 return 1;
183 }
184 }
185 class Child extends Parent {
186 @Override
187 public Integer getProperty1() {
188 return 2;
189 }
190 }
191 {
192 ExtendedBeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(Parent.class));
193 assertThat(hasReadMethodForProperty(bi, "property1"), is(true));
194 }
195 {
196 ExtendedBeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(Child.class));
197 assertThat(hasReadMethodForProperty(bi, "property1"), is(true));
198 }
199 }
200
201 @Test
202 public void cornerSpr9453() throws IntrospectionException {
203 final class Bean implements Spr9453<Class<?>> {
204 @Override
205 public Class<?> getProp() {
206 return null;
207 }
208 }
209 {
210 BeanInfo info = Introspector.getBeanInfo(Bean.class);
211 assertThat(info.getPropertyDescriptors().length, equalTo(2));
212 }
213 {
214 BeanInfo info = new ExtendedBeanInfo(Introspector.getBeanInfo(Bean.class));
215 assertThat(info.getPropertyDescriptors().length, equalTo(2));
216 }
217 }
218
219 @Test
220 public void standardReadMethodInSuperclassAndNonStandardWriteMethodInSubclass() throws Exception {
221 @SuppressWarnings("unused") class B {
222 public String getFoo() { return null; }
223 }
224 @SuppressWarnings("unused") class C extends B {
225 public C setFoo(String foo) { return this; }
226 }
227
228 BeanInfo bi = Introspector.getBeanInfo(C.class);
229
230 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
231 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
232
233 ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
234
235 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
236 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
237
238 assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
239 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
240 }
241
242 @Test
243 public void standardReadMethodInSuperAndSubclassesAndGenericBuilderStyleNonStandardWriteMethodInSuperAndSubclasses() throws Exception {
244 abstract class B<This extends B<This>> {
245 @SuppressWarnings("unchecked")
246 protected final This instance = (This) this;
247 private String foo;
248 public String getFoo() { return foo; }
249 public This setFoo(String foo) {
250 this.foo = foo;
251 return this.instance;
252 }
253 }
254
255 class C extends B<C> {
256 private int bar = -1;
257 public int getBar() { return bar; }
258 public C setBar(int bar) {
259 this.bar = bar;
260 return this.instance;
261 }
262 }
263
264 C c = new C()
265 .setFoo("blue")
266 .setBar(42);
267
268 assertThat(c.getFoo(), is("blue"));
269 assertThat(c.getBar(), is(42));
270
271 BeanInfo bi = Introspector.getBeanInfo(C.class);
272
273 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
274 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
275
276 assertThat(hasReadMethodForProperty(bi, "bar"), is(true));
277 assertThat(hasWriteMethodForProperty(bi, "bar"), is(false));
278
279 BeanInfo ebi = new ExtendedBeanInfo(bi);
280
281 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
282 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
283
284 assertThat(hasReadMethodForProperty(bi, "bar"), is(true));
285 assertThat(hasWriteMethodForProperty(bi, "bar"), is(false));
286
287 assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
288 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
289
290 assertThat(hasReadMethodForProperty(ebi, "bar"), is(true));
291 assertThat(hasWriteMethodForProperty(ebi, "bar"), is(true));
292 }
293
294 @Test
295 public void nonPublicStandardReadAndWriteMethods() throws Exception {
296 @SuppressWarnings("unused") class C {
297 String getFoo() { return null; }
298 C setFoo(String foo) { return this; }
299 }
300
301 BeanInfo bi = Introspector.getBeanInfo(C.class);
302 BeanInfo ebi = new ExtendedBeanInfo(bi);
303
304 assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
305 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
306
307 assertThat(hasReadMethodForProperty(ebi, "foo"), is(false));
308 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(false));
309 }
310
311
312
313
314
315 @Test
316 public void readMethodReturnsSupertypeOfWriteMethodParameter() throws IntrospectionException {
317 @SuppressWarnings("unused") class C {
318 public Number getFoo() { return null; }
319 public void setFoo(Integer foo) { }
320 }
321
322 BeanInfo bi = Introspector.getBeanInfo(C.class);
323 BeanInfo ebi = new ExtendedBeanInfo(bi);
324
325 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
326 assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
327 assertEquals(hasWriteMethodForProperty(bi, "foo"), hasWriteMethodForProperty(ebi, "foo"));
328 }
329
330 @Test
331 public void indexedReadMethodReturnsSupertypeOfIndexedWriteMethodParameter() throws IntrospectionException {
332 @SuppressWarnings("unused") class C {
333 public Number getFoos(int index) { return null; }
334 public void setFoos(int index, Integer foo) { }
335 }
336
337 BeanInfo bi = Introspector.getBeanInfo(C.class);
338 BeanInfo ebi = new ExtendedBeanInfo(bi);
339
340 assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
341 assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
342 assertEquals(hasIndexedWriteMethodForProperty(bi, "foos"), hasIndexedWriteMethodForProperty(ebi, "foos"));
343 }
344
345
346
347
348
349 @Test
350 public void readMethodReturnsSubtypeOfWriteMethodParameter() throws IntrospectionException {
351 @SuppressWarnings("unused") class C {
352 public Integer getFoo() { return null; }
353 public void setFoo(Number foo) { }
354 }
355
356 BeanInfo bi = Introspector.getBeanInfo(C.class);
357 BeanInfo ebi = new ExtendedBeanInfo(bi);
358
359 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
360 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
361
362 assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
363 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(false));
364 }
365
366 @Test
367 public void indexedReadMethodReturnsSubtypeOfIndexedWriteMethodParameter() throws IntrospectionException {
368 @SuppressWarnings("unused") class C {
369 public Integer getFoos(int index) { return null; }
370 public void setFoo(int index, Number foo) { }
371 }
372
373 BeanInfo bi = Introspector.getBeanInfo(C.class);
374 BeanInfo ebi = new ExtendedBeanInfo(bi);
375
376 assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
377 assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(false));
378
379 assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
380 assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(false));
381 }
382
383 @Test
384 public void indexedReadMethodOnly() throws IntrospectionException {
385 @SuppressWarnings("unused")
386 class C {
387
388 public String getFoos(int i) { return null; }
389 }
390
391 BeanInfo bi = Introspector.getBeanInfo(C.class);
392 BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
393
394 assertThat(hasReadMethodForProperty(bi, "foos"), is(false));
395 assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
396
397 assertThat(hasReadMethodForProperty(ebi, "foos"), is(false));
398 assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
399 }
400
401 @Test
402 public void indexedWriteMethodOnly() throws IntrospectionException {
403 @SuppressWarnings("unused")
404 class C {
405
406 public void setFoos(int i, String foo) { }
407 }
408
409 BeanInfo bi = Introspector.getBeanInfo(C.class);
410 BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
411
412 assertThat(hasWriteMethodForProperty(bi, "foos"), is(false));
413 assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
414
415 assertThat(hasWriteMethodForProperty(ebi, "foos"), is(false));
416 assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(true));
417 }
418
419 @Test
420 public void indexedReadAndIndexedWriteMethods() throws IntrospectionException {
421 @SuppressWarnings("unused")
422 class C {
423
424 public String getFoos(int i) { return null; }
425
426 public void setFoos(int i, String foo) { }
427 }
428
429 BeanInfo bi = Introspector.getBeanInfo(C.class);
430 BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
431
432 assertThat(hasReadMethodForProperty(bi, "foos"), is(false));
433 assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
434 assertThat(hasWriteMethodForProperty(bi, "foos"), is(false));
435 assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
436
437 assertThat(hasReadMethodForProperty(ebi, "foos"), is(false));
438 assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
439 assertThat(hasWriteMethodForProperty(ebi, "foos"), is(false));
440 assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(true));
441 }
442
443 @Test
444 public void readAndWriteAndIndexedReadAndIndexedWriteMethods() throws IntrospectionException {
445 @SuppressWarnings("unused")
446 class C {
447
448 public String[] getFoos() { return null; }
449
450 public String getFoos(int i) { return null; }
451
452 public void setFoos(String[] foos) { }
453
454 public void setFoos(int i, String foo) { }
455 }
456
457 BeanInfo bi = Introspector.getBeanInfo(C.class);
458 BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
459
460 assertThat(hasReadMethodForProperty(bi, "foos"), is(true));
461 assertThat(hasWriteMethodForProperty(bi, "foos"), is(true));
462 assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
463 assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
464
465 assertThat(hasReadMethodForProperty(ebi, "foos"), is(true));
466 assertThat(hasWriteMethodForProperty(ebi, "foos"), is(true));
467 assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
468 assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(true));
469 }
470
471 @Test
472 public void indexedReadAndNonStandardIndexedWrite() throws IntrospectionException {
473 @SuppressWarnings("unused")
474 class C {
475
476 public String getFoos(int i) { return null; }
477
478 public C setFoos(int i, String foo) { return this; }
479 }
480
481 BeanInfo bi = Introspector.getBeanInfo(C.class);
482
483 assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
484
485 assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(trueUntilJdk17()));
486
487 BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
488
489 assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
490 assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(true));
491 }
492
493 @Test
494 public void indexedReadAndNonStandardWriteAndNonStandardIndexedWrite() throws IntrospectionException {
495 @SuppressWarnings("unused")
496 class C {
497
498 public C setFoos(String[] foos) { return this; }
499
500 public String getFoos(int i) { return null; }
501
502 public C setFoos(int i, String foo) { return this; }
503 }
504
505 BeanInfo bi = Introspector.getBeanInfo(C.class);
506
507 assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
508 assertThat(hasWriteMethodForProperty(bi, "foos"), is(false));
509
510 assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(trueUntilJdk17()));
511
512 BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
513
514 assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
515 assertThat(hasWriteMethodForProperty(bi, "foos"), is(false));
516 assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(trueUntilJdk17()));
517
518 assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
519 assertThat(hasWriteMethodForProperty(ebi, "foos"), is(true));
520 assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(true));
521 }
522
523 @Test
524 public void cornerSpr9702() throws IntrospectionException {
525 {
526 @SuppressWarnings("unused")
527 class C {
528
529 public void setFoos(String[] foos) { }
530
531 public String getFoos(int i) { return null; }
532 }
533
534 BeanInfo bi = Introspector.getBeanInfo(C.class);
535 assertThat(hasReadMethodForProperty(bi, "foos"), is(false));
536 assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
537 assertThat(hasWriteMethodForProperty(bi, "foos"), is(true));
538 assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(false));
539
540 BeanInfo ebi = Introspector.getBeanInfo(C.class);
541 assertThat(hasReadMethodForProperty(ebi, "foos"), is(false));
542 assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
543 assertThat(hasWriteMethodForProperty(ebi, "foos"), is(true));
544 assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(false));
545 }
546 {
547 @SuppressWarnings("unused")
548 class C {
549
550 public C setFoos(String[] foos) { return this; }
551
552 public String getFoos(int i) { return null; }
553 }
554
555 BeanInfo bi = Introspector.getBeanInfo(C.class);
556 assertThat(hasReadMethodForProperty(bi, "foos"), is(false));
557 assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
558 assertThat(hasWriteMethodForProperty(bi, "foos"), is(false));
559 assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(false));
560
561 BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
562 assertThat(hasReadMethodForProperty(ebi, "foos"), is(false));
563 assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
564 assertThat(hasWriteMethodForProperty(ebi, "foos"), is(true));
565 assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(false));
566 }
567 }
568
569
570
571
572
573
574
575
576
577 @Test
578 public void cornerSpr10111() throws Exception {
579 new ExtendedBeanInfo(Introspector.getBeanInfo(BigDecimal.class));
580 }
581
582 @Test
583 public void subclassWriteMethodWithCovariantReturnType() throws IntrospectionException {
584 @SuppressWarnings("unused") class B {
585 public String getFoo() { return null; }
586 public Number setFoo(String foo) { return null; }
587 }
588 class C extends B {
589 @Override
590 public String getFoo() { return null; }
591 @Override
592 public Integer setFoo(String foo) { return null; }
593 }
594
595 BeanInfo bi = Introspector.getBeanInfo(C.class);
596
597 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
598 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
599
600 BeanInfo ebi = new ExtendedBeanInfo(bi);
601
602 assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
603 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
604
605 assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
606 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
607
608 assertThat(ebi.getPropertyDescriptors().length, equalTo(bi.getPropertyDescriptors().length));
609 }
610
611 @Test
612 public void nonStandardReadMethodAndStandardWriteMethod() throws IntrospectionException {
613 @SuppressWarnings("unused") class C {
614 public void getFoo() { }
615 public void setFoo(String foo) { }
616 }
617
618 BeanInfo bi = Introspector.getBeanInfo(C.class);
619 BeanInfo ebi = new ExtendedBeanInfo(bi);
620
621 assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
622 assertThat(hasWriteMethodForProperty(bi, "foo"), is(true));
623
624 assertThat(hasReadMethodForProperty(ebi, "foo"), is(false));
625 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
626 }
627
628
629
630
631
632 @Test
633 public void emptyPropertiesIgnored() throws IntrospectionException {
634 @SuppressWarnings("unused") class C {
635 public Object set(Object o) { return null; }
636 public Object set(int i, Object o) { return null; }
637 }
638
639 BeanInfo bi = Introspector.getBeanInfo(C.class);
640 BeanInfo ebi = new ExtendedBeanInfo(bi);
641
642 assertThat(ebi.getPropertyDescriptors(), equalTo(bi.getPropertyDescriptors()));
643 }
644
645 @Test
646 public void overloadedNonStandardWriteMethodsOnly_orderA() throws IntrospectionException, SecurityException, NoSuchMethodException {
647 @SuppressWarnings("unused") class C {
648 public Object setFoo(String p) { return new Object(); }
649 public Object setFoo(int p) { return new Object(); }
650 }
651 BeanInfo bi = Introspector.getBeanInfo(C.class);
652
653 assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
654 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
655
656 BeanInfo ebi = new ExtendedBeanInfo(bi);
657
658 assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
659 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
660
661 assertThat(hasReadMethodForProperty(ebi, "foo"), is(false));
662 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
663
664 for (PropertyDescriptor pd : ebi.getPropertyDescriptors()) {
665 if (pd.getName().equals("foo")) {
666 assertThat(pd.getWriteMethod(), is(C.class.getMethod("setFoo", String.class)));
667 return;
668 }
669 }
670 fail("never matched write method");
671 }
672
673 @Test
674 public void overloadedNonStandardWriteMethodsOnly_orderB() throws IntrospectionException, SecurityException, NoSuchMethodException {
675 @SuppressWarnings("unused") class C {
676 public Object setFoo(int p) { return new Object(); }
677 public Object setFoo(String p) { return new Object(); }
678 }
679 BeanInfo bi = Introspector.getBeanInfo(C.class);
680
681 assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
682 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
683
684 BeanInfo ebi = new ExtendedBeanInfo(bi);
685
686 assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
687 assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
688
689 assertThat(hasReadMethodForProperty(ebi, "foo"), is(false));
690 assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
691
692 for (PropertyDescriptor pd : ebi.getPropertyDescriptors()) {
693 if (pd.getName().equals("foo")) {
694 assertThat(pd.getWriteMethod(), is(C.class.getMethod("setFoo", String.class)));
695 return;
696 }
697 }
698 fail("never matched write method");
699 }
700
701
702
703
704
705
706
707
708 @Test
709 public void reproSpr8522() throws IntrospectionException {
710 @SuppressWarnings("unused") class C {
711 public Object setDateFormat(String pattern) { return new Object(); }
712 public Object setDateFormat(int style) { return new Object(); }
713 public Object setDateFormat(int dateStyle, int timeStyle) { return new Object(); }
714 }
715 BeanInfo bi = Introspector.getBeanInfo(C.class);
716
717 assertThat(hasReadMethodForProperty(bi, "dateFormat"), is(false));
718 assertThat(hasWriteMethodForProperty(bi, "dateFormat"), is(false));
719 assertThat(hasIndexedReadMethodForProperty(bi, "dateFormat"), is(false));
720 assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(trueUntilJdk17()));
721
722 BeanInfo ebi = new ExtendedBeanInfo(bi);
723
724 assertThat(hasReadMethodForProperty(bi, "dateFormat"), is(false));
725 assertThat(hasWriteMethodForProperty(bi, "dateFormat"), is(false));
726 assertThat(hasIndexedReadMethodForProperty(bi, "dateFormat"), is(false));
727 assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(trueUntilJdk17()));
728
729 assertThat(hasReadMethodForProperty(ebi, "dateFormat"), is(false));
730 assertThat(hasWriteMethodForProperty(ebi, "dateFormat"), is(true));
731 assertThat(hasIndexedReadMethodForProperty(ebi, "dateFormat"), is(false));
732 assertThat(hasIndexedWriteMethodForProperty(ebi, "dateFormat"), is(trueUntilJdk17()));
733 }
734
735 @Test
736 public void propertyCountsMatch() throws IntrospectionException {
737 BeanInfo bi = Introspector.getBeanInfo(TestBean.class);
738 BeanInfo ebi = new ExtendedBeanInfo(bi);
739
740 assertThat(ebi.getPropertyDescriptors().length, equalTo(bi.getPropertyDescriptors().length));
741 }
742
743 @Test
744 public void propertyCountsWithNonStandardWriteMethod() throws IntrospectionException {
745 class ExtendedTestBean extends TestBean {
746 @SuppressWarnings("unused")
747 public ExtendedTestBean setFoo(String s) { return this; }
748 }
749 BeanInfo bi = Introspector.getBeanInfo(ExtendedTestBean.class);
750 BeanInfo ebi = new ExtendedBeanInfo(bi);
751
752 boolean found = false;
753 for (PropertyDescriptor pd : ebi.getPropertyDescriptors()) {
754 if (pd.getName().equals("foo")) {
755 found = true;
756 }
757 }
758 assertThat(found, is(true));
759 assertThat(ebi.getPropertyDescriptors().length, equalTo(bi.getPropertyDescriptors().length+1));
760 }
761
762
763
764
765
766 @Test
767 public void propertyDescriptorOrderIsEqual() throws IntrospectionException {
768 BeanInfo bi = Introspector.getBeanInfo(TestBean.class);
769 BeanInfo ebi = new ExtendedBeanInfo(bi);
770
771 for (int i = 0; i < bi.getPropertyDescriptors().length; i++) {
772 assertThat("element " + i + " in BeanInfo and ExtendedBeanInfo propertyDescriptor arrays do not match",
773 ebi.getPropertyDescriptors()[i].getName(), equalTo(bi.getPropertyDescriptors()[i].getName()));
774 }
775 }
776
777 @Test
778 public void propertyDescriptorComparator() throws IntrospectionException {
779 ExtendedBeanInfo.PropertyDescriptorComparator c = new ExtendedBeanInfo.PropertyDescriptorComparator();
780
781 assertThat(c.compare(new PropertyDescriptor("a", null, null), new PropertyDescriptor("a", null, null)), equalTo(0));
782 assertThat(c.compare(new PropertyDescriptor("abc", null, null), new PropertyDescriptor("abc", null, null)), equalTo(0));
783 assertThat(c.compare(new PropertyDescriptor("a", null, null), new PropertyDescriptor("b", null, null)), lessThan(0));
784 assertThat(c.compare(new PropertyDescriptor("b", null, null), new PropertyDescriptor("a", null, null)), greaterThan(0));
785 assertThat(c.compare(new PropertyDescriptor("abc", null, null), new PropertyDescriptor("abd", null, null)), lessThan(0));
786 assertThat(c.compare(new PropertyDescriptor("xyz", null, null), new PropertyDescriptor("123", null, null)), greaterThan(0));
787 assertThat(c.compare(new PropertyDescriptor("a", null, null), new PropertyDescriptor("abc", null, null)), lessThan(0));
788 assertThat(c.compare(new PropertyDescriptor("abc", null, null), new PropertyDescriptor("a", null, null)), greaterThan(0));
789 assertThat(c.compare(new PropertyDescriptor("abc", null, null), new PropertyDescriptor("b", null, null)), lessThan(0));
790
791 assertThat(c.compare(new PropertyDescriptor(" ", null, null), new PropertyDescriptor("a", null, null)), lessThan(0));
792 assertThat(c.compare(new PropertyDescriptor("1", null, null), new PropertyDescriptor("a", null, null)), lessThan(0));
793 assertThat(c.compare(new PropertyDescriptor("a", null, null), new PropertyDescriptor("A", null, null)), greaterThan(0));
794 }
795
796 @Test
797 public void reproSpr8806() throws IntrospectionException {
798
799 Introspector.getBeanInfo(LawLibrary.class);
800
801
802 new ExtendedBeanInfo(Introspector.getBeanInfo(LawLibrary.class));
803 }
804
805 @Test
806 public void cornerSpr8949() throws IntrospectionException {
807 class A {
808 @SuppressWarnings("unused")
809 public boolean isTargetMethod() {
810 return false;
811 }
812 }
813
814 class B extends A {
815 @Override
816 public boolean isTargetMethod() {
817 return false;
818 }
819 }
820
821 BeanInfo bi = Introspector.getBeanInfo(B.class);
822
823
824
825
826
827 BeanInfo ebi = new ExtendedBeanInfo(bi);
828
829 assertThat(hasReadMethodForProperty(bi, "targetMethod"), is(true));
830 assertThat(hasWriteMethodForProperty(bi, "targetMethod"), is(false));
831
832 assertThat(hasReadMethodForProperty(ebi, "targetMethod"), is(true));
833 assertThat(hasWriteMethodForProperty(ebi, "targetMethod"), is(false));
834 }
835
836 @Test
837 public void cornerSpr8937() throws IntrospectionException {
838 @SuppressWarnings("unused") class A {
839 public void setAddress(String addr){ }
840 public void setAddress(int index, String addr) { }
841 public String getAddress(int index){ return null; }
842 }
843
844
845 boolean hasReadMethod;
846 boolean hasWriteMethod;
847 boolean hasIndexedReadMethod;
848 boolean hasIndexedWriteMethod;
849 {
850 BeanInfo bi = Introspector.getBeanInfo(A.class);
851 hasReadMethod = hasReadMethodForProperty(bi, "address");
852 hasWriteMethod = hasWriteMethodForProperty(bi, "address");
853 hasIndexedReadMethod = hasIndexedReadMethodForProperty(bi, "address");
854 hasIndexedWriteMethod = hasIndexedWriteMethodForProperty(bi, "address");
855 }
856 {
857 BeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(A.class));
858 assertEquals(hasReadMethodForProperty(bi, "address"), hasReadMethod);
859 assertEquals(hasWriteMethodForProperty(bi, "address"), hasWriteMethod);
860 assertEquals(hasIndexedReadMethodForProperty(bi, "address"), hasIndexedReadMethod);
861 assertEquals(hasIndexedWriteMethodForProperty(bi, "address"), hasIndexedWriteMethod);
862 }
863 }
864
865 @Test
866 public void shouldSupportStaticWriteMethod() throws IntrospectionException {
867 {
868 BeanInfo bi = Introspector.getBeanInfo(WithStaticWriteMethod.class);
869 assertThat(hasReadMethodForProperty(bi, "prop1"), is(false));
870 assertThat(hasWriteMethodForProperty(bi, "prop1"), is(false));
871 assertThat(hasIndexedReadMethodForProperty(bi, "prop1"), is(false));
872 assertThat(hasIndexedWriteMethodForProperty(bi, "prop1"), is(false));
873 }
874 {
875 BeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(WithStaticWriteMethod.class));
876 assertThat(hasReadMethodForProperty(bi, "prop1"), is(false));
877 assertThat(hasWriteMethodForProperty(bi, "prop1"), is(true));
878 assertThat(hasIndexedReadMethodForProperty(bi, "prop1"), is(false));
879 assertThat(hasIndexedWriteMethodForProperty(bi, "prop1"), is(false));
880 }
881 }
882
883 @Test
884 public void shouldDetectValidPropertiesAndIgnoreInvalidProperties() throws IntrospectionException {
885 BeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(java.awt.Window.class));
886 assertThat(hasReadMethodForProperty(bi, "locationByPlatform"), is(true));
887 assertThat(hasWriteMethodForProperty(bi, "locationByPlatform"), is(true));
888 assertThat(hasIndexedReadMethodForProperty(bi, "locationByPlatform"), is(false));
889 assertThat(hasIndexedWriteMethodForProperty(bi, "locationByPlatform"), is(false));
890 }
891
892
893 private boolean hasWriteMethodForProperty(BeanInfo beanInfo, String propertyName) {
894 for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
895 if (pd.getName().equals(propertyName)) {
896 return pd.getWriteMethod() != null;
897 }
898 }
899 return false;
900 }
901
902 private boolean hasReadMethodForProperty(BeanInfo beanInfo, String propertyName) {
903 for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
904 if (pd.getName().equals(propertyName)) {
905 return pd.getReadMethod() != null;
906 }
907 }
908 return false;
909 }
910
911 private boolean hasIndexedWriteMethodForProperty(BeanInfo beanInfo, String propertyName) {
912 for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
913 if (pd.getName().equals(propertyName)) {
914 if (!(pd instanceof IndexedPropertyDescriptor)) {
915 return false;
916 }
917 return ((IndexedPropertyDescriptor)pd).getIndexedWriteMethod() != null;
918 }
919 }
920 return false;
921 }
922
923 private boolean hasIndexedReadMethodForProperty(BeanInfo beanInfo, String propertyName) {
924 for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
925 if (pd.getName().equals(propertyName)) {
926 if (!(pd instanceof IndexedPropertyDescriptor)) {
927 return false;
928 }
929 return ((IndexedPropertyDescriptor)pd).getIndexedReadMethod() != null;
930 }
931 }
932 return false;
933 }
934
935 private boolean trueUntilJdk17() {
936 return JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_17;
937 }
938
939
940 interface Spr9453<T> {
941
942 T getProp();
943 }
944
945
946 interface Book {
947 }
948
949
950 interface TextBook extends Book {
951 }
952
953
954 interface LawBook extends TextBook {
955 }
956
957
958 interface BookOperations {
959
960 Book getBook();
961
962 void setBook(Book book);
963 }
964
965
966 interface TextBookOperations extends BookOperations {
967
968 @Override
969 TextBook getBook();
970 }
971
972
973 abstract class Library {
974
975 public Book getBook() {
976 return null;
977 }
978
979 public void setBook(Book book) {
980 }
981 }
982
983
984 class LawLibrary extends Library implements TextBookOperations {
985
986 @Override
987 public LawBook getBook() {
988 return null;
989 }
990 }
991
992
993 static class WithStaticWriteMethod {
994
995 public static void setProp1(String prop1) {
996 }
997 }
998
999 }