mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-18 09:59:03 +00:00
Compare commits
536
Commits
v5.3.0-RC2
...
v5.3.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9a9686b45 | ||
|
|
efc335e198 | ||
|
|
1e57e572dd | ||
|
|
829000d511 | ||
|
|
a315abfd32 | ||
|
|
36d133ce53 | ||
|
|
9417975f66 | ||
|
|
ed9ec58caa | ||
|
|
f48c3d9b67 | ||
|
|
6b705443a6 | ||
|
|
c26087e848 | ||
|
|
7225238ad5 | ||
|
|
ff43731347 | ||
|
|
29fb3f27be | ||
|
|
63db250ebe | ||
|
|
b00c7075a5 | ||
|
|
3718c8d0e0 | ||
|
|
ca8261cbf8 | ||
|
|
8de10e9199 | ||
|
|
7536b7f42a | ||
|
|
bc71cc1a76 | ||
|
|
582559dd9e | ||
|
|
d4c609f2f0 | ||
|
|
3524401bf1 | ||
|
|
86423c91f7 | ||
|
|
8807f94ad8 | ||
|
|
da3ff29e88 | ||
|
|
9c6b1b645d | ||
|
|
0fc8bf654b | ||
|
|
729535d36c | ||
|
|
634c7710f9 | ||
|
|
2fbfd8a5db | ||
|
|
42c15be8d3 | ||
|
|
3baa44c5ef | ||
|
|
4b86a1a755 | ||
|
|
df977a2fd2 | ||
|
|
99a1388bbd | ||
|
|
809813dd52 | ||
|
|
d5e5dcb7e1 | ||
|
|
defc2466b0 | ||
|
|
a991c23db5 | ||
|
|
b928ed8f37 | ||
|
|
5d70aaacef | ||
|
|
566ff54782 | ||
|
|
77b7e49fb2 | ||
|
|
1c6bab23ea | ||
|
|
3e502d4739 | ||
|
|
667256adf9 | ||
|
|
8791928f61 | ||
|
|
c9147c4281 | ||
|
|
d6f363c634 | ||
|
|
87c0e9b48a | ||
|
|
9a4164c4a8 | ||
|
|
c36b80bd75 | ||
|
|
bc90512309 | ||
|
|
edd15646af | ||
|
|
53cafe728c | ||
|
|
58e9b187fe | ||
|
|
9b0c2cca95 | ||
|
|
26000ee29f | ||
|
|
0c2c66b38b | ||
|
|
bd8e682c51 | ||
|
|
f7c952cb3e | ||
|
|
6bc7e12bcd | ||
|
|
ab94c7c016 | ||
|
|
8fb9796d1d | ||
|
|
a264013d7a | ||
|
|
cd80b6b4ac | ||
|
|
164b48e25f | ||
|
|
eb7b206142 | ||
|
|
42061d27bd | ||
|
|
0d16c9100a | ||
|
|
7cdaaa22bd | ||
|
|
f4c9f6b860 | ||
|
|
1721b0b8d7 | ||
|
|
836976d732 | ||
|
|
59818ceca9 | ||
|
|
08ce6baedf | ||
|
|
c52526ad42 | ||
|
|
7a329eba5b | ||
|
|
91d542e406 | ||
|
|
6fde28be98 | ||
|
|
1e481cd14c | ||
|
|
df4ba742cb | ||
|
|
996c86f448 | ||
|
|
0575e6637c | ||
|
|
ad8775ef95 | ||
|
|
8589804012 | ||
|
|
c649b74235 | ||
|
|
bef5d59e43 | ||
|
|
99bd8115dd | ||
|
|
1a3ff83157 | ||
|
|
c19b2851f1 | ||
|
|
3b4a3431d4 | ||
|
|
c82a445094 | ||
|
|
95752ef1c9 | ||
|
|
0ff50d6d9e | ||
|
|
30cdeb23fe | ||
|
|
ecf5113e0e | ||
|
|
80c4e6bb95 | ||
|
|
5e5d8e4a23 | ||
|
|
d7e05aa48f | ||
|
|
cf52246319 | ||
|
|
c5284009a1 | ||
|
|
2d29fcd0bb | ||
|
|
5e56162394 | ||
|
|
45650f2b27 | ||
|
|
3e1b1638ef | ||
|
|
e80a23d6ad | ||
|
|
8aeae49f40 | ||
|
|
f22e2ac578 | ||
|
|
355aca7665 | ||
|
|
ec5f99f981 | ||
|
|
03f1b65084 | ||
|
|
0de2833894 | ||
|
|
cd9d562129 | ||
|
|
080ba5d448 | ||
|
|
d96448fde9 | ||
|
|
84eed00260 | ||
|
|
cee51b248a | ||
|
|
5a640bb635 | ||
|
|
5c1cbb769c | ||
|
|
4a7a2258f9 | ||
|
|
bad8954e65 | ||
|
|
e4566c11b8 | ||
|
|
9d8910d869 | ||
|
|
aa7584d252 | ||
|
|
e537844a09 | ||
|
|
daa5465003 | ||
|
|
5a4a677fbd | ||
|
|
584dabbb39 | ||
|
|
4779323d33 | ||
|
|
67112b211a | ||
|
|
799885fd6d | ||
|
|
3c959d3515 | ||
|
|
cfae40afb4 | ||
|
|
1b1ae33efe | ||
|
|
d80b08084e | ||
|
|
d1a7fed16c | ||
|
|
469eb8146e | ||
|
|
35225e5794 | ||
|
|
a7413ea76b | ||
|
|
c3c36ab498 | ||
|
|
ea4fe7eaf7 | ||
|
|
3112dc5f81 | ||
|
|
b07a6b3283 | ||
|
|
6b9d5698ce | ||
|
|
72a9d0ff4b | ||
|
|
872255a591 | ||
|
|
671270dae2 | ||
|
|
6ea39fd122 | ||
|
|
dadef9f5bc | ||
|
|
fceceb480f | ||
|
|
e5ab67bd71 | ||
|
|
2d53570f4c | ||
|
|
be5eb7037f | ||
|
|
fff2291f2a | ||
|
|
917f3ad101 | ||
|
|
2fd6e6e87c | ||
|
|
570bdbd253 | ||
|
|
b587a16d46 | ||
|
|
dd8ea89bea | ||
|
|
b0dea4d3f6 | ||
|
|
4ac27e4dab | ||
|
|
b0abdee012 | ||
|
|
e4dc863ad0 | ||
|
|
689b5566bf | ||
|
|
234b4719c6 | ||
|
|
ce1ae2f1b2 | ||
|
|
69ce7d33b9 | ||
|
|
e36d4162c2 | ||
|
|
d387d9ae1e | ||
|
|
138f6bfd84 | ||
|
|
a1cf6bbc37 | ||
|
|
fb040479eb | ||
|
|
d50375da8e | ||
|
|
fb2e53276c | ||
|
|
c040cd7b05 | ||
|
|
dcc8dcdff8 | ||
|
|
efa360cff7 | ||
|
|
5804db6479 | ||
|
|
faa749934b | ||
|
|
e1385090e4 | ||
|
|
3113917c55 | ||
|
|
994a35d691 | ||
|
|
8095ba4cd2 | ||
|
|
bd2edf26df | ||
|
|
4f6d26b25c | ||
|
|
6d85a8a0cc | ||
|
|
44b29b6ecf | ||
|
|
91a6254187 | ||
|
|
c8ad762b40 | ||
|
|
5c1176786c | ||
|
|
eab61f692f | ||
|
|
ee41ebc1ab | ||
|
|
885f6dbab9 | ||
|
|
b0f404722e | ||
|
|
cd7b0b11f3 | ||
|
|
1565f4b83e | ||
|
|
65a395ef0e | ||
|
|
947255e377 | ||
|
|
499be70a71 | ||
|
|
0cf5005a3d | ||
|
|
f07fc76cf3 | ||
|
|
d3e1c54354 | ||
|
|
a109b4c31a | ||
|
|
00b56c026a | ||
|
|
fbd2ffdd23 | ||
|
|
b3a47c76f8 | ||
|
|
1292947f78 | ||
|
|
ef6a582c78 | ||
|
|
a11d1c8510 | ||
|
|
83c19cd60e | ||
|
|
bcfbde9848 | ||
|
|
17e6cf1cc1 | ||
|
|
ec33b4241a | ||
|
|
657641ebaa | ||
|
|
4597e9b547 | ||
|
|
721dacca5a | ||
|
|
9d124fffcb | ||
|
|
2a47751fcd | ||
|
|
06e352822a | ||
|
|
25101fb034 | ||
|
|
cb44ae62e9 | ||
|
|
01fb4dbeba | ||
|
|
07fadae27d | ||
|
|
2b77c08e09 | ||
|
|
cb2b141d31 | ||
|
|
3b92d45984 | ||
|
|
1195b3a0b0 | ||
|
|
56721669d1 | ||
|
|
e87e03c539 | ||
|
|
194cebd730 | ||
|
|
7418c4b7b7 | ||
|
|
ad42010785 | ||
|
|
10f6a22315 | ||
|
|
c970c318f4 | ||
|
|
834032df1f | ||
|
|
5efa4ad442 | ||
|
|
7ef3257b03 | ||
|
|
0172424635 | ||
|
|
994ec708fc | ||
|
|
da15fe4c94 | ||
|
|
a1d134b086 | ||
|
|
3c85c263d2 | ||
|
|
7b3f53de50 | ||
|
|
ec7425c1f4 | ||
|
|
ef05eb3729 | ||
|
|
8ac39a50fe | ||
|
|
d82cb15439 | ||
|
|
8c1d06e0c4 | ||
|
|
01892c6524 | ||
|
|
9776929a9d | ||
|
|
4337d8465c | ||
|
|
8f0ad73bfd | ||
|
|
3714d0e401 | ||
|
|
227d85a6b4 | ||
|
|
a1320cd450 | ||
|
|
c7f2f50c15 | ||
|
|
396fb0cd51 | ||
|
|
5328184f3a | ||
|
|
1e19e51c9c | ||
|
|
69aed83504 | ||
|
|
0978cc629a | ||
|
|
0c825621b8 | ||
|
|
e7b0b65244 | ||
|
|
e9caee1b6e | ||
|
|
622d0831a3 | ||
|
|
56dbe06d9b | ||
|
|
11f6c4e7ab | ||
|
|
d46091565b | ||
|
|
42216b77df | ||
|
|
43faa439ab | ||
|
|
1f701d9bad | ||
|
|
73e1f24ac1 | ||
|
|
86f9716fef | ||
|
|
80701082cd | ||
|
|
3612990344 | ||
|
|
dea2029e94 | ||
|
|
77d6f8bc00 | ||
|
|
23006d417b | ||
|
|
d8dafbc49d | ||
|
|
cc4a1af091 | ||
|
|
fd70a9e95d | ||
|
|
298cb22bfe | ||
|
|
4ed645e710 | ||
|
|
7c47f554c0 | ||
|
|
642d47ef8d | ||
|
|
42e492ef2a | ||
|
|
4fb5d59c64 | ||
|
|
e6324bd578 | ||
|
|
45a9227047 | ||
|
|
f1af8a6ae9 | ||
|
|
c4d7e6ff46 | ||
|
|
922d5d271a | ||
|
|
05e3f271b6 | ||
|
|
a7cce64e5d | ||
|
|
a0544e78ea | ||
|
|
c92dccea1b | ||
|
|
9ec96f6141 | ||
|
|
135682e073 | ||
|
|
6a0377b1a2 | ||
|
|
8c3a05bbcf | ||
|
|
684e695b08 | ||
|
|
8130bf505f | ||
|
|
9beca06404 | ||
|
|
ae75db2657 | ||
|
|
4cc831238c | ||
|
|
41835ba5a4 | ||
|
|
de0b5bc5a1 | ||
|
|
b29723623b | ||
|
|
2ee231dee2 | ||
|
|
b56dbd2aa8 | ||
|
|
c9b27af64f | ||
|
|
9139cb85bd | ||
|
|
367fbbb981 | ||
|
|
1b1ba47912 | ||
|
|
041bff4e56 | ||
|
|
bc5a10c70d | ||
|
|
3d31750acc | ||
|
|
c22a483c3d | ||
|
|
238354a081 | ||
|
|
51b1306d70 | ||
|
|
7206a23d33 | ||
|
|
83996b12cc | ||
|
|
0fd6c100a6 | ||
|
|
0819a9fcc9 | ||
|
|
0b580d194d | ||
|
|
500b54b86f | ||
|
|
942400ae47 | ||
|
|
b92d249f45 | ||
|
|
204a7fe91f | ||
|
|
42d3bc47c9 | ||
|
|
94fcb37d30 | ||
|
|
ba9325446c | ||
|
|
5338d8b5e9 | ||
|
|
1b0be5862d | ||
|
|
48af36c6fa | ||
|
|
bd4e915abf | ||
|
|
c419ea7ba7 | ||
|
|
66292cd7a1 | ||
|
|
6eec1acdac | ||
|
|
bc32d513d9 | ||
|
|
3851b291da | ||
|
|
2b1f229998 | ||
|
|
fc5e3c335f | ||
|
|
daf9a82e8c | ||
|
|
b019f30a15 | ||
|
|
d5b5e894c9 | ||
|
|
2899652d8e | ||
|
|
560a504a83 | ||
|
|
79f79e9306 | ||
|
|
bd2640a9d6 | ||
|
|
6825287360 | ||
|
|
737d77a739 | ||
|
|
1f13516528 | ||
|
|
6bb3ad793e | ||
|
|
c73cff8bad | ||
|
|
e592634290 | ||
|
|
b25637e8ad | ||
|
|
0c347769a2 | ||
|
|
2497d4285f | ||
|
|
32238cc996 | ||
|
|
d80dd50c9d | ||
|
|
bdf120f1ef | ||
|
|
e781d21097 | ||
|
|
8cef13cc30 | ||
|
|
2214ff8ce0 | ||
|
|
411539ffef | ||
|
|
11aa901634 | ||
|
|
6e51370490 | ||
|
|
bcd2b9a8a7 | ||
|
|
17dd7785f6 | ||
|
|
21f9d05bd9 | ||
|
|
19911af30a | ||
|
|
6acb091c4e | ||
|
|
99ed01e3f7 | ||
|
|
2657757566 | ||
|
|
e1f51b4bf8 | ||
|
|
f2f84bfa7a | ||
|
|
6d67bdf04f | ||
|
|
97c8628bd6 | ||
|
|
990a9c74b9 | ||
|
|
b815accca9 | ||
|
|
4e8d6bea4d | ||
|
|
079ca80854 | ||
|
|
412aa06d86 | ||
|
|
d5b3e65718 | ||
|
|
a4679b87b9 | ||
|
|
fbf8e37f94 | ||
|
|
8c3cab7ead | ||
|
|
0015fd6734 | ||
|
|
b077e4cd85 | ||
|
|
0a0299693b | ||
|
|
41bdde5d6b | ||
|
|
2e2d662158 | ||
|
|
68934f1b79 | ||
|
|
f781c459b4 | ||
|
|
5628c8cd63 | ||
|
|
0f6038af70 | ||
|
|
3eb2c5e22f | ||
|
|
3f722a9c7f | ||
|
|
acbbf61be8 | ||
|
|
154f0c71c9 | ||
|
|
7be7e5beb4 | ||
|
|
37504e75e9 | ||
|
|
b89b37729c | ||
|
|
141c79bc8f | ||
|
|
885a5048c1 | ||
|
|
e981bf34b3 | ||
|
|
44239b2d7b | ||
|
|
a00c483927 | ||
|
|
96ffa14141 | ||
|
|
9f632cf0c1 | ||
|
|
a9dec6a4af | ||
|
|
9c2fd0bd05 | ||
|
|
6e936a4081 | ||
|
|
b2d337c527 | ||
|
|
24cef14683 | ||
|
|
bb4e802af5 | ||
|
|
b01adadf60 | ||
|
|
9c11887fe8 | ||
|
|
4503260282 | ||
|
|
d91b66a04c | ||
|
|
d1e6883d5d | ||
|
|
5170f3f594 | ||
|
|
a4d546a9d6 | ||
|
|
fc9650a9a6 | ||
|
|
82fa3f3fc1 | ||
|
|
1fb33fbd3c | ||
|
|
b6dae6acba | ||
|
|
a3cd8e11b0 | ||
|
|
f50c2caf59 | ||
|
|
0aa3205e38 | ||
|
|
5b910a87c3 | ||
|
|
9ebd3ee1fe | ||
|
|
3f01af6f7c | ||
|
|
f329748657 | ||
|
|
d12996a6a8 | ||
|
|
d04c5f8b2c | ||
|
|
41247d49ba | ||
|
|
16c8676e5b | ||
|
|
d7f1813cd7 | ||
|
|
ada255d584 | ||
|
|
7aef0c78a0 | ||
|
|
188a5a086b | ||
|
|
705cf09ad7 | ||
|
|
449377908f | ||
|
|
b1fef925af | ||
|
|
9287c15583 | ||
|
|
9a4a593c7f | ||
|
|
c840ba9989 | ||
|
|
3924947773 | ||
|
|
9d70d2023c | ||
|
|
82835b99ec | ||
|
|
a3f3a136c4 | ||
|
|
a2ff03074f | ||
|
|
a3fcfc5d2a | ||
|
|
1247e4a0e8 | ||
|
|
1676470729 | ||
|
|
4726663f81 | ||
|
|
86af93a504 | ||
|
|
efe933ad83 | ||
|
|
5429c7afeb | ||
|
|
73eefeac5f | ||
|
|
1a50732daa | ||
|
|
1c82ba425b | ||
|
|
946e5c9bbf | ||
|
|
af4d68b1a5 | ||
|
|
a40cc8bbe0 | ||
|
|
6e640c806f | ||
|
|
e66e34766e | ||
|
|
5644a7aebb | ||
|
|
7af726480f | ||
|
|
51fb49be34 | ||
|
|
c524849774 | ||
|
|
f2eb67373a | ||
|
|
cf988f81b5 | ||
|
|
417e7e03d4 | ||
|
|
8d86d61f9f | ||
|
|
fb4363e4e0 | ||
|
|
1ec6843913 | ||
|
|
cff57ca1fe | ||
|
|
784d72cc56 | ||
|
|
4480269432 | ||
|
|
9a1323aad5 | ||
|
|
eec6ec8f44 | ||
|
|
6946fe2f74 | ||
|
|
db9e0b0ccb | ||
|
|
aaa2d21058 | ||
|
|
b8b854db8c | ||
|
|
95110d8257 | ||
|
|
cfc3522641 | ||
|
|
621295dbd8 | ||
|
|
07769ddcc6 | ||
|
|
c748870853 | ||
|
|
f7ec92c647 | ||
|
|
bd91dc70d5 | ||
|
|
7bee3d1574 | ||
|
|
dff9924a0c | ||
|
|
bfb2ce6e2a | ||
|
|
76eb5e6e2c | ||
|
|
43f595f80e | ||
|
|
6f131ba1c4 | ||
|
|
d18fbab7a8 | ||
|
|
a4d0af802a | ||
|
|
db3d537e72 | ||
|
|
a0727191e1 | ||
|
|
702a05e926 | ||
|
|
0df6d60fea | ||
|
|
5ab1097b43 | ||
|
|
d77ecb26a9 | ||
|
|
6d4b286b1a | ||
|
|
970afbc614 | ||
|
|
f13c43bafe | ||
|
|
23211c784e | ||
|
|
a2ff139edd | ||
|
|
424e28bc35 | ||
|
|
4952336419 | ||
|
|
babcbd0d2b | ||
|
|
c45b106d95 | ||
|
|
b7d1bbb991 | ||
|
|
603a1dd319 | ||
|
|
6b978cb5dc | ||
|
|
b79548d12e | ||
|
|
f9e11593a6 | ||
|
|
57ac32b808 | ||
|
|
2eee56d0e2 | ||
|
|
a271a0a2bf | ||
|
|
69af56c4e9 | ||
|
|
a924677b49 | ||
|
|
7e647ab1d8 | ||
|
|
abd79d43af | ||
|
|
431ec906c4 | ||
|
|
1d96f6a266 | ||
|
|
e5ae2cb0fe |
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
!!! For Security Vulnerabilities, please go to https://pivotal.io/security !!!
|
||||
!!! For Security Vulnerabilities, please go to https://spring.io/security-policy !!!
|
||||
-->
|
||||
**Affects:** \<Spring Framework version>
|
||||
|
||||
@@ -14,4 +14,4 @@ Thanks for taking the time to create an issue. Please read the following:
|
||||
Issue or Pull Request? Create only one, not both. GitHub treats them as the same.
|
||||
If unsure, start with an issue, and if you submit a pull request later, the
|
||||
issue will be closed as superseded.
|
||||
-->
|
||||
-->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# <img src="src/docs/spring-framework.png" width="80" height="80"> Spring Framework [](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.3.x?groups=Build")
|
||||
# <img src="src/docs/spring-framework.png" width="80" height="80"> Spring Framework [](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.3.x?groups=Build") [](https://ge.spring.io/scans?search.rootProjectNames=spring)
|
||||
|
||||
This is the home of the Spring Framework: the foundation for all [Spring projects](https://spring.io/projects). Collectively the Spring Framework and the family of Spring projects are often referred to simply as "Spring".
|
||||
|
||||
|
||||
+46
-45
@@ -1,15 +1,16 @@
|
||||
plugins {
|
||||
id 'io.spring.dependency-management' version '1.0.9.RELEASE' apply false
|
||||
id 'io.spring.nohttp' version '0.0.5.RELEASE'
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.4.10' apply false
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.4.30' apply false
|
||||
id 'org.jetbrains.dokka' version '0.10.1' apply false
|
||||
id 'org.asciidoctor.jvm.convert' version '3.1.0'
|
||||
id 'org.asciidoctor.jvm.pdf' version '3.1.0'
|
||||
id 'de.undercouch.download' version '4.1.1'
|
||||
id "io.freefair.aspectj" version '5.1.1' apply false
|
||||
id "com.github.ben-manes.versions" version '0.28.0'
|
||||
id "me.champeau.gradle.jmh" version "0.5.0" apply false
|
||||
id "org.jetbrains.kotlin.plugin.serialization" version "1.4.10" apply false
|
||||
id "com.github.johnrengelman.shadow" version "6.1.0" apply false
|
||||
id "me.champeau.gradle.jmh" version "0.5.2" apply false
|
||||
id "org.jetbrains.kotlin.plugin.serialization" version "1.4.30" apply false
|
||||
}
|
||||
|
||||
ext {
|
||||
@@ -25,22 +26,22 @@ configure(allprojects) { project ->
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.11.3"
|
||||
mavenBom "io.netty:netty-bom:4.1.52.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.0-RC2"
|
||||
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR7"
|
||||
mavenBom "io.rsocket:rsocket-bom:1.1.0-RC1"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.32.v20200930"
|
||||
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.4.10"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.4.0-M1"
|
||||
mavenBom "org.junit:junit-bom:5.7.0"
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.1"
|
||||
mavenBom "io.netty:netty-bom:4.1.59.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.4"
|
||||
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR8"
|
||||
mavenBom "io.rsocket:rsocket-bom:1.1.0"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.36.v20210114"
|
||||
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.4.30"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.4.2"
|
||||
mavenBom "org.junit:junit-bom:5.7.1"
|
||||
}
|
||||
dependencies {
|
||||
dependencySet(group: 'org.apache.logging.log4j', version: '2.13.3') {
|
||||
dependencySet(group: 'org.apache.logging.log4j', version: '2.14.0') {
|
||||
entry 'log4j-api'
|
||||
entry 'log4j-core'
|
||||
entry 'log4j-slf4j-impl'
|
||||
entry 'log4j-jul'
|
||||
entry 'log4j-slf4j-impl'
|
||||
}
|
||||
dependency "org.slf4j:slf4j-api:1.7.30"
|
||||
dependency("com.google.code.findbugs:findbugs:3.0.1") {
|
||||
@@ -53,7 +54,7 @@ configure(allprojects) { project ->
|
||||
entry 'aspectjtools'
|
||||
entry 'aspectjweaver'
|
||||
}
|
||||
dependencySet(group: 'org.codehaus.groovy', version: '3.0.6') {
|
||||
dependencySet(group: 'org.codehaus.groovy', version: '3.0.7') {
|
||||
entry 'groovy'
|
||||
entry 'groovy-jsr223'
|
||||
entry 'groovy-templates' // requires findbugs for warning-free compilation
|
||||
@@ -63,23 +64,23 @@ configure(allprojects) { project ->
|
||||
|
||||
dependency "io.reactivex:rxjava:1.3.8"
|
||||
dependency "io.reactivex:rxjava-reactive-streams:1.2.1"
|
||||
dependency "io.reactivex.rxjava2:rxjava:2.2.19"
|
||||
dependency "io.reactivex.rxjava3:rxjava:3.0.7"
|
||||
dependency "io.projectreactor.tools:blockhound:1.0.2.RELEASE"
|
||||
dependency "io.reactivex.rxjava2:rxjava:2.2.21"
|
||||
dependency "io.reactivex.rxjava3:rxjava:3.0.10"
|
||||
dependency "io.projectreactor.tools:blockhound:1.0.4.RELEASE"
|
||||
|
||||
dependency "com.caucho:hessian:4.0.63"
|
||||
dependency "com.fasterxml:aalto-xml:1.2.2"
|
||||
dependency("com.fasterxml.woodstox:woodstox-core:6.2.1") {
|
||||
dependency("com.fasterxml.woodstox:woodstox-core:6.2.3") {
|
||||
exclude group: "stax", name: "stax-api"
|
||||
}
|
||||
dependency "com.google.code.gson:gson:2.8.6"
|
||||
dependency "com.google.protobuf:protobuf-java-util:3.13.0"
|
||||
dependency "com.google.protobuf:protobuf-java-util:3.14.0"
|
||||
dependency "com.googlecode.protobuf-java-format:protobuf-java-format:1.4"
|
||||
dependency("com.thoughtworks.xstream:xstream:1.4.13") {
|
||||
dependency("com.thoughtworks.xstream:xstream:1.4.15") {
|
||||
exclude group: "xpp3", name: "xpp3_min"
|
||||
exclude group: "xmlpull", name: "xmlpull"
|
||||
}
|
||||
dependency "org.apache.johnzon:johnzon-jsonb:1.2.8"
|
||||
dependency "org.apache.johnzon:johnzon-jsonb:1.2.10"
|
||||
dependency("org.codehaus.jettison:jettison:1.3.8") {
|
||||
exclude group: "stax", name: "stax-api"
|
||||
}
|
||||
@@ -88,15 +89,15 @@ configure(allprojects) { project ->
|
||||
entry 'jibx-run'
|
||||
}
|
||||
dependency "org.ogce:xpp3:1.1.6"
|
||||
dependency "org.yaml:snakeyaml:1.26"
|
||||
dependency "org.yaml:snakeyaml:1.27"
|
||||
dependencySet(group: 'org.jetbrains.kotlinx', version: '1.0.0') {
|
||||
entry 'kotlinx-serialization-core'
|
||||
entry 'kotlinx-serialization-json'
|
||||
}
|
||||
|
||||
dependency "com.h2database:h2:1.4.200"
|
||||
dependency "com.github.ben-manes.caffeine:caffeine:2.8.6"
|
||||
dependency "com.github.librepdf:openpdf:1.3.22"
|
||||
dependency "com.github.ben-manes.caffeine:caffeine:2.8.8"
|
||||
dependency "com.github.librepdf:openpdf:1.3.25"
|
||||
dependency "com.rometools:rome:1.15.0"
|
||||
dependency "commons-io:commons-io:2.5"
|
||||
dependency "io.vavr:vavr:0.10.3"
|
||||
@@ -123,23 +124,23 @@ configure(allprojects) { project ->
|
||||
dependency "net.sf.ehcache:ehcache:2.10.6"
|
||||
dependency "org.ehcache:jcache:1.0.1"
|
||||
dependency "org.ehcache:ehcache:3.4.0"
|
||||
dependency "org.hibernate:hibernate-core:5.4.22.Final"
|
||||
dependency "org.hibernate:hibernate-validator:6.1.6.Final"
|
||||
dependency "org.hibernate:hibernate-core:5.4.28.Final"
|
||||
dependency "org.hibernate:hibernate-validator:6.2.0.Final"
|
||||
dependency "org.webjars:webjars-locator-core:0.46"
|
||||
dependency "org.webjars:underscorejs:1.8.3"
|
||||
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.38') {
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.43') {
|
||||
entry 'tomcat-util'
|
||||
entry('tomcat-websocket') {
|
||||
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
|
||||
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
|
||||
}
|
||||
}
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.38') {
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.43') {
|
||||
entry 'tomcat-embed-core'
|
||||
entry 'tomcat-embed-websocket'
|
||||
}
|
||||
dependencySet(group: 'io.undertow', version: '2.2.2.Final') {
|
||||
dependencySet(group: 'io.undertow', version: '2.2.4.Final') {
|
||||
entry 'undertow-core'
|
||||
entry('undertow-websockets-jsr') {
|
||||
exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec"
|
||||
@@ -154,7 +155,7 @@ configure(allprojects) { project ->
|
||||
entry 'okhttp'
|
||||
entry 'mockwebserver'
|
||||
}
|
||||
dependency("org.apache.httpcomponents:httpclient:4.5.12") {
|
||||
dependency("org.apache.httpcomponents:httpclient:4.5.13") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.apache.httpcomponents:httpasyncclient:4.1.4") {
|
||||
@@ -162,7 +163,7 @@ configure(allprojects) { project ->
|
||||
}
|
||||
dependency 'org.apache.httpcomponents.client5:httpclient5:5.0.3'
|
||||
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.0.3'
|
||||
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.4"
|
||||
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.5"
|
||||
|
||||
dependency "org.jruby:jruby:9.2.13.0"
|
||||
dependency "org.python:jython-standalone:2.7.1"
|
||||
@@ -181,7 +182,7 @@ configure(allprojects) { project ->
|
||||
exclude group: "dom4j", name: "dom4j"
|
||||
}
|
||||
|
||||
dependency("junit:junit:4.13.1") {
|
||||
dependency("junit:junit:4.13.2") {
|
||||
exclude group: "org.hamcrest", name: "hamcrest-core"
|
||||
}
|
||||
dependency("de.bechte.junit:junit-hierarchicalcontextrunner:4.12.1") {
|
||||
@@ -190,25 +191,25 @@ configure(allprojects) { project ->
|
||||
dependency "org.testng:testng:7.3.0"
|
||||
dependency "org.hamcrest:hamcrest:2.1"
|
||||
dependency "org.awaitility:awaitility:3.1.6"
|
||||
dependency "org.assertj:assertj-core:3.17.2"
|
||||
dependencySet(group: 'org.xmlunit', version: '2.6.2') {
|
||||
dependency "org.assertj:assertj-core:3.19.0"
|
||||
dependencySet(group: 'org.xmlunit', version: '2.8.2') {
|
||||
entry 'xmlunit-assertj'
|
||||
entry('xmlunit-matchers') {
|
||||
exclude group: "org.hamcrest", name: "hamcrest-core"
|
||||
}
|
||||
}
|
||||
dependencySet(group: 'org.mockito', version: '3.5.13') {
|
||||
dependencySet(group: 'org.mockito', version: '3.7.7') {
|
||||
entry('mockito-core') {
|
||||
exclude group: "org.hamcrest", name: "hamcrest-core"
|
||||
}
|
||||
entry 'mockito-junit-jupiter'
|
||||
}
|
||||
dependency "io.mockk:mockk:1.10.0"
|
||||
dependency "io.mockk:mockk:1.10.2"
|
||||
|
||||
dependency("net.sourceforge.htmlunit:htmlunit:2.44.0") {
|
||||
dependency("net.sourceforge.htmlunit:htmlunit:2.47.1") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.seleniumhq.selenium:htmlunit-driver:2.44.0") {
|
||||
dependency("org.seleniumhq.selenium:htmlunit-driver:2.47.1") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
|
||||
@@ -236,8 +237,8 @@ configure(allprojects) { project ->
|
||||
|
||||
dependency "com.ibm.websphere:uow:6.0.2.17"
|
||||
dependency "com.jamonapi:jamon:2.82"
|
||||
dependency "joda-time:joda-time:2.10.6"
|
||||
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.7"
|
||||
dependency "joda-time:joda-time:2.10.10"
|
||||
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.8"
|
||||
dependency "org.javamoney:moneta:1.3"
|
||||
|
||||
dependency "com.sun.activation:javax.activation:1.2.0"
|
||||
@@ -291,7 +292,6 @@ configure(allprojects) { project ->
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "https://repo.spring.io/libs-spring-framework-build" }
|
||||
maven { url "https://repo.spring.io/milestone" } // Reactor
|
||||
}
|
||||
}
|
||||
configurations.all {
|
||||
@@ -340,7 +340,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "8.36.2"
|
||||
toolVersion = "8.39"
|
||||
configDirectory.set(rootProject.file("src/checkstyle"))
|
||||
}
|
||||
|
||||
@@ -380,8 +380,9 @@ configure([rootProject] + javaProjects) { project ->
|
||||
"https://fasterxml.github.io/jackson-databind/javadoc/2.10/",
|
||||
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/",
|
||||
"https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/",
|
||||
"https://junit.org/junit4/javadoc/4.13.1/",
|
||||
"https://junit.org/junit5/docs/5.7.0/api/"
|
||||
"https://projectreactor.io/docs/test/release/api/",
|
||||
"https://junit.org/junit4/javadoc/4.13.2/",
|
||||
"https://junit.org/junit5/docs/5.7.1/api/"
|
||||
] as String[]
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
changelog:
|
||||
repository: spring-projects/spring-framework
|
||||
sections:
|
||||
- title: ":star: New Features"
|
||||
labels:
|
||||
- "type: enhancement"
|
||||
- title: ":beetle: Bug Fixes"
|
||||
labels:
|
||||
- "type: bug"
|
||||
- "type: regression"
|
||||
- title: ":notebook_with_decorative_cover: Documentation"
|
||||
labels:
|
||||
- "type: documentation"
|
||||
- title: ":hammer: Dependency Upgrades"
|
||||
sort: "title"
|
||||
labels:
|
||||
- "type: dependency-upgrade"
|
||||
@@ -0,0 +1,9 @@
|
||||
logging:
|
||||
level:
|
||||
io.spring.concourse: DEBUG
|
||||
distribute:
|
||||
optional-deployments:
|
||||
- '.*\.zip'
|
||||
spring:
|
||||
main:
|
||||
banner-mode: off
|
||||
@@ -3,16 +3,13 @@ set -e
|
||||
|
||||
case "$1" in
|
||||
java8)
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u265-b01/OpenJDK8U-jdk_x64_linux_hotspot_8u265b01.tar.gz"
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u282-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u282b08.tar.gz"
|
||||
;;
|
||||
java11)
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_linux_hotspot_11.0.8_10.tar.gz"
|
||||
;;
|
||||
java14)
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.2%2B12/OpenJDK14U-jdk_x64_linux_hotspot_14.0.2_12.tar.gz"
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_linux_hotspot_11.0.10_9.tar.gz"
|
||||
;;
|
||||
java15)
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_linux_hotspot_15_36.tar.gz"
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.2%2B7/OpenJDK15U-jdk_x64_linux_hotspot_15.0.2_7.tar.gz"
|
||||
;;
|
||||
*)
|
||||
echo $"Unknown java version"
|
||||
|
||||
+5
-2
@@ -5,13 +5,16 @@ set -ex
|
||||
# UTILS
|
||||
###########################################################
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install --no-install-recommends -y ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq fontconfig
|
||||
apt-get install --no-install-recommends -y tzdata ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq fontconfig
|
||||
ln -fs /usr/share/zoneinfo/UTC /etc/localtime
|
||||
dpkg-reconfigure --frontend noninteractive tzdata
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.3/concourse-java.sh > /opt/concourse-java.sh
|
||||
|
||||
curl --output /opt/concourse-release-scripts.jar https://repo.spring.io/release/io/spring/concourse/releasescripts/concourse-release-scripts/0.2.0/concourse-release-scripts-0.2.0.jar
|
||||
curl --output /opt/concourse-release-scripts.jar https://repo.spring.io/release/io/spring/concourse/releasescripts/concourse-release-scripts/0.2.1/concourse-release-scripts-0.2.1.jar
|
||||
|
||||
###########################################################
|
||||
# JAVA
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:bionic-20200713
|
||||
FROM ubuntu:focal-20210119
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:bionic-20200713
|
||||
FROM ubuntu:focal-20210119
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
FROM ubuntu:bionic-20200713
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
RUN ./setup.sh java14
|
||||
|
||||
ENV JAVA_HOME /opt/openjdk
|
||||
ENV PATH $JAVA_HOME/bin:$PATH
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:bionic-20200713
|
||||
FROM ubuntu:focal-20210119
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
|
||||
+160
-127
@@ -1,28 +1,61 @@
|
||||
anchors:
|
||||
artifactory-task-params: &artifactory-task-params
|
||||
ARTIFACTORY_SERVER: ((artifactory-server))
|
||||
ARTIFACTORY_USERNAME: ((artifactory-username))
|
||||
ARTIFACTORY_PASSWORD: ((artifactory-password))
|
||||
bintray-task-params: &bintray-task-params
|
||||
BINTRAY_SUBJECT: ((bintray-subject))
|
||||
BINTRAY_REPO: ((bintray-repo))
|
||||
BINTRAY_USERNAME: ((bintray-username))
|
||||
BINTRAY_API_KEY: ((bintray-api-key))
|
||||
docker-resource-source: &docker-resource-source
|
||||
username: ((docker-hub-username))
|
||||
password: ((docker-hub-password))
|
||||
tag: 5.3.x
|
||||
gradle-enterprise-task-params: &gradle-enterprise-task-params
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
|
||||
slack-fail-params: &slack-fail-params
|
||||
text: >
|
||||
:concourse-failed: <https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!>
|
||||
[$TEXT_FILE_CONTENT]
|
||||
text_file: git-repo/build/build-scan-uri.txt
|
||||
silent: true
|
||||
icon_emoji: ":concourse:"
|
||||
username: concourse-ci
|
||||
sonatype-task-params: &sonatype-task-params
|
||||
SONATYPE_USER_TOKEN: ((sonatype-user-token))
|
||||
SONATYPE_PASSWORD_TOKEN: ((sonatype-user-token-password))
|
||||
changelog-task-params: &changelog-task-params
|
||||
name: generated-changelog/tag
|
||||
tag: generated-changelog/tag
|
||||
body: generated-changelog/changelog.md
|
||||
github-task-params: &github-task-params
|
||||
GITHUB_USERNAME: ((github-username))
|
||||
GITHUB_TOKEN: ((github-ci-release-token))
|
||||
|
||||
resource_types:
|
||||
- name: artifactory-resource
|
||||
type: docker-image
|
||||
type: registry-image
|
||||
source:
|
||||
repository: springio/artifactory-resource
|
||||
tag: 0.0.12-SNAPSHOT
|
||||
tag: 0.0.12
|
||||
- name: github-status-resource
|
||||
type: docker-image
|
||||
type: registry-image
|
||||
source:
|
||||
repository: dpb587/github-status-resource
|
||||
tag: master
|
||||
- name: email
|
||||
type: docker-image
|
||||
source:
|
||||
repository: pcfseceng/email-resource
|
||||
tag: 1.0.19
|
||||
- name: slack-notification
|
||||
type: docker-image
|
||||
type: registry-image
|
||||
source:
|
||||
repository: cfcommunity/slack-notification-resource
|
||||
tag: latest
|
||||
|
||||
resources:
|
||||
- name: git-repo
|
||||
type: git
|
||||
icon: github-circle
|
||||
icon: github
|
||||
source:
|
||||
uri: ((github-repo))
|
||||
username: ((github-username))
|
||||
@@ -37,7 +70,7 @@ resources:
|
||||
location: Europe/Vienna
|
||||
- name: ci-images-git-repo
|
||||
type: git
|
||||
icon: github-circle
|
||||
icon: github
|
||||
source:
|
||||
uri: ((github-repo))
|
||||
branch: ((branch))
|
||||
@@ -46,34 +79,20 @@ resources:
|
||||
type: docker-image
|
||||
icon: docker
|
||||
source:
|
||||
<<: *docker-resource-source
|
||||
repository: ((docker-hub-organization))/spring-framework-ci-image
|
||||
username: ((docker-hub-username))
|
||||
password: ((docker-hub-password))
|
||||
tag: 5.3.x
|
||||
- name: spring-framework-jdk11-ci-image
|
||||
type: docker-image
|
||||
icon: docker
|
||||
source:
|
||||
<<: *docker-resource-source
|
||||
repository: ((docker-hub-organization))/spring-framework-jdk11-ci-image
|
||||
username: ((docker-hub-username))
|
||||
password: ((docker-hub-password))
|
||||
tag: 5.3.x
|
||||
- name: spring-framework-jdk14-ci-image
|
||||
type: docker-image
|
||||
icon: docker
|
||||
source:
|
||||
repository: ((docker-hub-organization))/spring-framework-jdk14-ci-image
|
||||
username: ((docker-hub-username))
|
||||
password: ((docker-hub-password))
|
||||
tag: 5.3.x
|
||||
- name: spring-framework-jdk15-ci-image
|
||||
type: docker-image
|
||||
icon: docker
|
||||
source:
|
||||
<<: *docker-resource-source
|
||||
repository: ((docker-hub-organization))/spring-framework-jdk15-ci-image
|
||||
username: ((docker-hub-username))
|
||||
password: ((docker-hub-password))
|
||||
tag: 5.3.x
|
||||
- name: artifactory-repo
|
||||
type: artifactory-resource
|
||||
icon: package-variant
|
||||
@@ -98,14 +117,6 @@ resources:
|
||||
access_token: ((github-ci-status-token))
|
||||
branch: ((branch))
|
||||
context: jdk11-build
|
||||
- name: repo-status-jdk14-build
|
||||
type: github-status-resource
|
||||
icon: eye-check-outline
|
||||
source:
|
||||
repository: ((github-repo-name))
|
||||
access_token: ((github-ci-status-token))
|
||||
branch: ((branch))
|
||||
context: jdk14-build
|
||||
- name: repo-status-jdk15-build
|
||||
type: github-status-resource
|
||||
icon: eye-check-outline
|
||||
@@ -119,6 +130,24 @@ resources:
|
||||
icon: slack
|
||||
source:
|
||||
url: ((slack-webhook-url))
|
||||
- name: github-pre-release
|
||||
type: github-release
|
||||
icon: briefcase-download-outline
|
||||
source:
|
||||
owner: spring-projects
|
||||
repository: spring-framework
|
||||
access_token: ((github-ci-release-token))
|
||||
pre_release: true
|
||||
release: false
|
||||
- name: github-release
|
||||
type: github-release
|
||||
icon: briefcase-download
|
||||
source:
|
||||
owner: spring-projects
|
||||
repository: spring-framework
|
||||
access_token: ((github-ci-release-token))
|
||||
pre_release: false
|
||||
|
||||
jobs:
|
||||
- name: build-spring-framework-ci-images
|
||||
plan:
|
||||
@@ -133,10 +162,6 @@ jobs:
|
||||
params:
|
||||
build: ci-images-git-repo/ci/images
|
||||
dockerfile: ci-images-git-repo/ci/images/spring-framework-jdk11-ci-image/Dockerfile
|
||||
- put: spring-framework-jdk14-ci-image
|
||||
params:
|
||||
build: ci-images-git-repo/ci/images
|
||||
dockerfile: ci-images-git-repo/ci/images/spring-framework-jdk14-ci-image/Dockerfile
|
||||
- put: spring-framework-jdk15-ci-image
|
||||
params:
|
||||
build: ci-images-git-repo/ci/images
|
||||
@@ -158,23 +183,14 @@ jobs:
|
||||
file: git-repo/ci/tasks/build-project.yml
|
||||
params:
|
||||
BRANCH: ((branch))
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
|
||||
<<: *gradle-enterprise-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-build
|
||||
params: { state: "failure", commit: "git-repo" }
|
||||
- put: slack-alert
|
||||
params:
|
||||
text: >
|
||||
:concourse-failed: ${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!
|
||||
[<https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|build log>]
|
||||
[<$TEXT_FILE_CONTENT|build scan>]
|
||||
text_file: git-repo/build/build-scan-uri.txt
|
||||
silent: true
|
||||
icon_emoji: ":concourse:"
|
||||
username: concourse-ci
|
||||
<<: *slack-fail-params
|
||||
- put: repo-status-build
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- put: artifactory-repo
|
||||
@@ -224,62 +240,16 @@ jobs:
|
||||
file: git-repo/ci/tasks/check-project.yml
|
||||
params:
|
||||
BRANCH: ((branch))
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
|
||||
<<: *gradle-enterprise-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-jdk11-build
|
||||
params: { state: "failure", commit: "git-repo" }
|
||||
- put: slack-alert
|
||||
params:
|
||||
text: >
|
||||
:concourse-failed: ${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!
|
||||
[<https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|build log>]
|
||||
[<$TEXT_FILE_CONTENT|build scan>]
|
||||
text_file: git-repo/build/build-scan-uri.txt
|
||||
silent: true
|
||||
icon_emoji: ":concourse:"
|
||||
username: concourse-ci
|
||||
<<: *slack-fail-params
|
||||
- put: repo-status-jdk11-build
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- name: jdk14-build
|
||||
serial: true
|
||||
public: true
|
||||
plan:
|
||||
- get: spring-framework-jdk14-ci-image
|
||||
- get: git-repo
|
||||
- get: every-morning
|
||||
trigger: true
|
||||
- put: repo-status-jdk14-build
|
||||
params: { state: "pending", commit: "git-repo" }
|
||||
- do:
|
||||
- task: check-project
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
image: spring-framework-jdk14-ci-image
|
||||
file: git-repo/ci/tasks/check-project.yml
|
||||
params:
|
||||
BRANCH: ((branch))
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-jdk14-build
|
||||
params: { state: "failure", commit: "git-repo" }
|
||||
- put: slack-alert
|
||||
params:
|
||||
text: >
|
||||
:concourse-failed: ${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!
|
||||
[<https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|build log>]
|
||||
[<$TEXT_FILE_CONTENT|build scan>]
|
||||
text_file: git-repo/build/build-scan-uri.txt
|
||||
silent: true
|
||||
icon_emoji: ":concourse:"
|
||||
username: concourse-ci
|
||||
- put: repo-status-jdk14-build
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- name: jdk15-build
|
||||
serial: true
|
||||
public: true
|
||||
@@ -298,23 +268,14 @@ jobs:
|
||||
file: git-repo/ci/tasks/check-project.yml
|
||||
params:
|
||||
BRANCH: ((branch))
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
|
||||
<<: *gradle-enterprise-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-jdk15-build
|
||||
params: { state: "failure", commit: "git-repo" }
|
||||
- put: slack-alert
|
||||
params:
|
||||
text: >
|
||||
:concourse-failed: ${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!
|
||||
[<https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|build log>]
|
||||
[<$TEXT_FILE_CONTENT|build scan>]
|
||||
text_file: git-repo/build/build-scan-uri.txt
|
||||
silent: true
|
||||
icon_emoji: ":concourse:"
|
||||
username: concourse-ci
|
||||
<<: *slack-fail-params
|
||||
- put: repo-status-jdk15-build
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- name: stage-milestone
|
||||
@@ -328,9 +289,7 @@ jobs:
|
||||
file: git-repo/ci/tasks/stage-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: M
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
|
||||
<<: *gradle-enterprise-task-params
|
||||
- put: artifactory-repo
|
||||
params:
|
||||
<<: *artifactory-params
|
||||
@@ -355,9 +314,15 @@ jobs:
|
||||
file: git-repo/ci/tasks/promote-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: M
|
||||
ARTIFACTORY_SERVER: ((artifactory-server))
|
||||
ARTIFACTORY_USERNAME: ((artifactory-username))
|
||||
ARTIFACTORY_PASSWORD: ((artifactory-password))
|
||||
<<: *artifactory-task-params
|
||||
- task: generate-changelog
|
||||
file: git-repo/ci/tasks/generate-changelog.yml
|
||||
params:
|
||||
RELEASE_TYPE: M
|
||||
<<: *github-task-params
|
||||
- put: github-pre-release
|
||||
params:
|
||||
<<: *changelog-task-params
|
||||
- name: stage-rc
|
||||
serial: true
|
||||
plan:
|
||||
@@ -369,9 +334,7 @@ jobs:
|
||||
file: git-repo/ci/tasks/stage-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: RC
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
|
||||
<<: *gradle-enterprise-task-params
|
||||
- put: artifactory-repo
|
||||
params:
|
||||
<<: *artifactory-params
|
||||
@@ -396,13 +359,83 @@ jobs:
|
||||
file: git-repo/ci/tasks/promote-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: RC
|
||||
ARTIFACTORY_SERVER: ((artifactory-server))
|
||||
ARTIFACTORY_USERNAME: ((artifactory-username))
|
||||
ARTIFACTORY_PASSWORD: ((artifactory-password))
|
||||
<<: *artifactory-task-params
|
||||
- task: generate-changelog
|
||||
file: git-repo/ci/tasks/generate-changelog.yml
|
||||
params:
|
||||
RELEASE_TYPE: RC
|
||||
<<: *github-task-params
|
||||
- put: github-pre-release
|
||||
params:
|
||||
<<: *changelog-task-params
|
||||
- name: stage-release
|
||||
serial: true
|
||||
plan:
|
||||
- get: spring-framework-ci-image
|
||||
- get: git-repo
|
||||
trigger: false
|
||||
- task: stage
|
||||
image: spring-framework-ci-image
|
||||
file: git-repo/ci/tasks/stage-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: RELEASE
|
||||
<<: *gradle-enterprise-task-params
|
||||
- put: artifactory-repo
|
||||
params:
|
||||
<<: *artifactory-params
|
||||
repo: libs-staging-local
|
||||
- put: git-repo
|
||||
params:
|
||||
repository: stage-git-repo
|
||||
- name: promote-release
|
||||
serial: true
|
||||
plan:
|
||||
- get: spring-framework-ci-image
|
||||
- get: git-repo
|
||||
trigger: false
|
||||
- get: artifactory-repo
|
||||
trigger: false
|
||||
passed: [stage-release]
|
||||
params:
|
||||
download_artifacts: false
|
||||
save_build_info: true
|
||||
- task: promote
|
||||
image: spring-framework-ci-image
|
||||
file: git-repo/ci/tasks/promote-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: RELEASE
|
||||
<<: *artifactory-task-params
|
||||
<<: *bintray-task-params
|
||||
- name: sync-to-maven-central
|
||||
serial: true
|
||||
plan:
|
||||
- get: spring-framework-ci-image
|
||||
- get: git-repo
|
||||
- get: artifactory-repo
|
||||
trigger: true
|
||||
passed: [promote-release]
|
||||
params:
|
||||
download_artifacts: false
|
||||
save_build_info: true
|
||||
- task: sync-to-maven-central
|
||||
image: spring-framework-ci-image
|
||||
file: git-repo/ci/tasks/sync-to-maven-central.yml
|
||||
params:
|
||||
<<: *bintray-task-params
|
||||
<<: *sonatype-task-params
|
||||
- task: generate-changelog
|
||||
file: git-repo/ci/tasks/generate-changelog.yml
|
||||
params:
|
||||
RELEASE_TYPE: RELEASE
|
||||
<<: *github-task-params
|
||||
- put: github-release
|
||||
params:
|
||||
<<: *changelog-task-params
|
||||
|
||||
groups:
|
||||
- name: "Build"
|
||||
jobs: ["build", "jdk11-build", "jdk14-build", "jdk15-build"]
|
||||
- name: "Release"
|
||||
jobs: ["stage-milestone","stage-rc", "promote-milestone","promote-rc"]
|
||||
- name: "CI Images"
|
||||
- name: "builds"
|
||||
jobs: ["build", "jdk11-build", "jdk15-build"]
|
||||
- name: "releases"
|
||||
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone","promote-rc", "promote-release", "sync-to-maven-central"]
|
||||
- name: "ci-images"
|
||||
jobs: ["build-spring-framework-ci-images"]
|
||||
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
CONFIG_DIR=git-repo/ci/config
|
||||
version=$( cat version/version )
|
||||
|
||||
java -jar /github-changelog-generator.jar \
|
||||
--spring.config.location=${CONFIG_DIR}/changelog-generator.yml \
|
||||
${version} generated-changelog/changelog.md
|
||||
|
||||
echo ${version} > generated-changelog/version
|
||||
echo v${version} > generated-changelog/tag
|
||||
@@ -1,13 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
source $(dirname $0)/common.sh
|
||||
CONFIG_DIR=git-repo/ci/config
|
||||
|
||||
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
|
||||
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
|
||||
|
||||
java -jar /opt/concourse-release-scripts.jar promote $RELEASE_TYPE $BUILD_INFO_LOCATION > /dev/null || { exit 1; }
|
||||
java -jar /opt/concourse-release-scripts.jar promote $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; }
|
||||
|
||||
java -jar /opt/concourse-release-scripts.jar distribute $RELEASE_TYPE $BUILD_INFO_LOCATION > /dev/null || { exit 1; }
|
||||
java -jar /opt/concourse-release-scripts.jar \
|
||||
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
|
||||
distribute $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; }
|
||||
|
||||
echo "Promotion complete"
|
||||
echo $version > version/version
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
|
||||
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
|
||||
java -jar /opt/concourse-release-scripts.jar syncToCentral "RELEASE" $BUILD_INFO_LOCATION || { exit 1; }
|
||||
|
||||
echo "Sync complete"
|
||||
echo $version > version/version
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
---
|
||||
platform: linux
|
||||
image_resource:
|
||||
type: docker-image
|
||||
source:
|
||||
repository: springio/github-changelog-generator
|
||||
tag: '0.0.4'
|
||||
inputs:
|
||||
- name: git-repo
|
||||
- name: version
|
||||
outputs:
|
||||
- name: generated-changelog
|
||||
params:
|
||||
GITHUB_ORGANIZATION:
|
||||
GITHUB_REPO:
|
||||
GITHUB_USERNAME:
|
||||
GITHUB_TOKEN:
|
||||
RELEASE_TYPE:
|
||||
run:
|
||||
path: git-repo/ci/scripts/generate-changelog.sh
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
platform: linux
|
||||
inputs:
|
||||
- name: git-repo
|
||||
- name: artifactory-repo
|
||||
outputs:
|
||||
- name: version
|
||||
params:
|
||||
BINTRAY_REPO:
|
||||
BINTRAY_SUBJECT:
|
||||
BINTRAY_USERNAME:
|
||||
BINTRAY_API_KEY:
|
||||
SONATYPE_USER_TOKEN:
|
||||
SONATYPE_PASSWORD_TOKEN:
|
||||
run:
|
||||
path: git-repo/ci/scripts/sync-to-maven-central.sh
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=5.3.0-SNAPSHOT
|
||||
version=5.3.4
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
+5
-2
@@ -3,7 +3,7 @@ configurations {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.4.3.RELEASE")
|
||||
asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.5.0")
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -106,11 +106,14 @@ dokka {
|
||||
externalDocumentationLink {
|
||||
url = new URL("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/")
|
||||
}
|
||||
externalDocumentationLink {
|
||||
url = new URL("https://r2dbc.io/spec/0.8.3.RELEASE/api/")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task downloadResources(type: Download) {
|
||||
def version = "0.2.2.RELEASE"
|
||||
def version = "0.2.5"
|
||||
src "https://repo.spring.io/release/io/spring/docresources/" +
|
||||
"spring-doc-resources/$version/spring-doc-resources-${version}.zip"
|
||||
dest project.file("$buildDir/docs/spring-doc-resources.zip")
|
||||
|
||||
+10
-2
@@ -29,12 +29,11 @@ eclipse.classpath.file.whenMerged { classpath ->
|
||||
classpath.entries.removeAll { entry -> (entry.path =~ /(?!.*?repack.*\.jar).*?\/([^\/]+)\/build\/libs\/[^\/]+\.jar/) }
|
||||
}
|
||||
|
||||
|
||||
// Use separate main/test outputs (prevents WTP from packaging test classes)
|
||||
eclipse.classpath.defaultOutputDir = file(project.name+"/bin/eclipse")
|
||||
eclipse.classpath.file.beforeMerged { classpath ->
|
||||
classpath.entries.findAll{ it instanceof SourceFolder }.each {
|
||||
if(it.output.startsWith("bin/")) {
|
||||
if (it.output.startsWith("bin/")) {
|
||||
it.output = null
|
||||
}
|
||||
}
|
||||
@@ -56,6 +55,15 @@ eclipse.classpath.file.whenMerged { classpath ->
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that JMH sources and resources are treated as test classpath entries
|
||||
// so that they can see test fixtures.
|
||||
// https://github.com/melix/jmh-gradle-plugin/issues/157
|
||||
eclipse.classpath.file.whenMerged {
|
||||
entries.findAll { it.path =~ /src\/jmh\/(java|resources)/ }.each {
|
||||
it.entryAttributes['test'] = 'true'
|
||||
}
|
||||
}
|
||||
|
||||
// Allow projects to be used as WTP modules
|
||||
eclipse.project.natures "org.eclipse.wst.common.project.facet.core.nature"
|
||||
|
||||
|
||||
@@ -1,17 +1,37 @@
|
||||
apply plugin: 'org.springframework.build.compile'
|
||||
apply plugin: 'org.springframework.build.optional-dependencies'
|
||||
// Uncomment the following for Shadow support in the jmhJar block.
|
||||
// Currently commented out due to ZipException: archive is not a ZIP archive
|
||||
// apply plugin: 'com.github.johnrengelman.shadow'
|
||||
apply plugin: 'me.champeau.gradle.jmh'
|
||||
apply from: "$rootDir/gradle/publications.gradle"
|
||||
|
||||
dependencies {
|
||||
jmh 'org.openjdk.jmh:jmh-core:1.23'
|
||||
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.23'
|
||||
jmh 'org.openjdk.jmh:jmh-core:1.25'
|
||||
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.25'
|
||||
jmh 'net.sf.jopt-simple:jopt-simple:4.6'
|
||||
}
|
||||
|
||||
jmh {
|
||||
duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
|
||||
jmhJar {
|
||||
// Uncomment the following for Shadow's Transformer support.
|
||||
// mergeServiceFiles()
|
||||
// append('META-INF/spring.handlers')
|
||||
// append('META-INF/spring.schemas')
|
||||
// append('META-INF/spring.tooling')
|
||||
exclude 'LICENSE'
|
||||
exclude 'THIRD-PARTY'
|
||||
exclude 'META-INF/license.txt'
|
||||
exclude 'META-INF/notice.txt'
|
||||
exclude 'META-INF/DEPENDENCIES'
|
||||
exclude 'META-INF/LICENSE*'
|
||||
exclude 'META-INF/NOTICE'
|
||||
exclude 'META-INF/THIRD-PARTY'
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest.attributes["Implementation-Title"] = project.name
|
||||
manifest.attributes["Implementation-Version"] = project.version
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "com.gradle.enterprise" version "3.2"
|
||||
id "io.spring.gradle-enterprise-conventions" version "0.0.2"
|
||||
id "com.gradle.enterprise" version "3.5.1"
|
||||
id "io.spring.ge.conventions" version "0.0.7"
|
||||
}
|
||||
|
||||
include "spring-aop"
|
||||
|
||||
+3
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -350,17 +350,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
return this.discoveredThrowingType;
|
||||
}
|
||||
|
||||
private boolean isVariableName(String name) {
|
||||
char[] chars = name.toCharArray();
|
||||
if (!Character.isJavaIdentifierStart(chars[0])) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 1; i < chars.length; i++) {
|
||||
if (!Character.isJavaIdentifierPart(chars[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
private static boolean isVariableName(String name) {
|
||||
return AspectJProxyUtils.isVariableName(name);
|
||||
}
|
||||
|
||||
|
||||
@@ -640,7 +631,6 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
}
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
|
||||
// TODO AopUtils.invokeJoinpointUsingReflection
|
||||
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
|
||||
+2
-14
@@ -470,22 +470,10 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
*/
|
||||
@Nullable
|
||||
private String maybeExtractVariableName(@Nullable String candidateToken) {
|
||||
if (!StringUtils.hasLength(candidateToken)) {
|
||||
return null;
|
||||
}
|
||||
if (Character.isJavaIdentifierStart(candidateToken.charAt(0)) &&
|
||||
Character.isLowerCase(candidateToken.charAt(0))) {
|
||||
char[] tokenChars = candidateToken.toCharArray();
|
||||
for (char tokenChar : tokenChars) {
|
||||
if (!Character.isJavaIdentifierPart(tokenChar)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (AspectJProxyUtils.isVariableName(candidateToken)) {
|
||||
return candidateToken;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,8 @@ import java.util.List;
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.PointcutAdvisor;
|
||||
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Utility methods for working with AspectJ proxies.
|
||||
@@ -73,4 +75,19 @@ public abstract class AspectJProxyUtils {
|
||||
((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
|
||||
}
|
||||
|
||||
static boolean isVariableName(@Nullable String name) {
|
||||
if (!StringUtils.hasLength(name)) {
|
||||
return false;
|
||||
}
|
||||
if (!Character.isJavaIdentifierStart(name.charAt(0))) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 1; i < name.length(); i++) {
|
||||
if (!Character.isJavaIdentifierPart(name.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-3
@@ -221,10 +221,12 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
|
||||
@Override
|
||||
@Nullable
|
||||
public String[] getParameterNames() {
|
||||
if (this.parameterNames == null) {
|
||||
this.parameterNames = parameterNameDiscoverer.getParameterNames(getMethod());
|
||||
String[] parameterNames = this.parameterNames;
|
||||
if (parameterNames == null) {
|
||||
parameterNames = parameterNameDiscoverer.getParameterNames(getMethod());
|
||||
this.parameterNames = parameterNames;
|
||||
}
|
||||
return this.parameterNames;
|
||||
return parameterNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -160,23 +160,12 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton aspect instance for the supplied aspect type. An instance
|
||||
* is created if one cannot be found in the instance cache.
|
||||
* Get the singleton aspect instance for the supplied aspect type.
|
||||
* An instance is created if one cannot be found in the instance cache.
|
||||
*/
|
||||
private Object getSingletonAspectInstance(Class<?> aspectClass) {
|
||||
// Quick check without a lock...
|
||||
Object instance = aspectCache.get(aspectClass);
|
||||
if (instance == null) {
|
||||
synchronized (aspectCache) {
|
||||
// To be safe, check within full lock now...
|
||||
instance = aspectCache.get(aspectClass);
|
||||
if (instance == null) {
|
||||
instance = new SimpleAspectInstanceFactory(aspectClass).getAspectInstance();
|
||||
aspectCache.put(aspectClass, instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
return aspectCache.computeIfAbsent(aspectClass,
|
||||
clazz -> new SimpleAspectInstanceFactory(clazz).getAspectInstance());
|
||||
}
|
||||
|
||||
|
||||
|
||||
+10
-10
@@ -51,6 +51,7 @@ import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.ConvertingComparator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.comparator.InstanceComparator;
|
||||
|
||||
@@ -70,7 +71,11 @@ import org.springframework.util.comparator.InstanceComparator;
|
||||
@SuppressWarnings("serial")
|
||||
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
|
||||
|
||||
private static final Comparator<Method> METHOD_COMPARATOR;
|
||||
// Exclude @Pointcut methods
|
||||
private static final MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS
|
||||
.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));
|
||||
|
||||
private static final Comparator<Method> adviceMethodComparator;
|
||||
|
||||
static {
|
||||
// Note: although @After is ordered before @AfterReturning and @AfterThrowing,
|
||||
@@ -86,7 +91,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
return (ann != null ? ann.getAnnotation() : null);
|
||||
});
|
||||
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
|
||||
METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
|
||||
adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
|
||||
}
|
||||
|
||||
|
||||
@@ -160,15 +165,10 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
}
|
||||
|
||||
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
|
||||
final List<Method> methods = new ArrayList<>();
|
||||
ReflectionUtils.doWithMethods(aspectClass, method -> {
|
||||
// Exclude pointcuts
|
||||
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
|
||||
methods.add(method);
|
||||
}
|
||||
}, ReflectionUtils.USER_DECLARED_METHODS);
|
||||
List<Method> methods = new ArrayList<>();
|
||||
ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
|
||||
if (methods.size() > 1) {
|
||||
methods.sort(METHOD_COMPARATOR);
|
||||
methods.sort(adviceMethodComparator);
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -114,6 +114,15 @@ public interface Advised extends TargetClassAware {
|
||||
*/
|
||||
Advisor[] getAdvisors();
|
||||
|
||||
/**
|
||||
* Return the number of advisors applying to this proxy.
|
||||
* <p>The default implementation delegates to {@code getAdvisors().length}.
|
||||
* @since 5.3.1
|
||||
*/
|
||||
default int getAdvisorCount() {
|
||||
return getAdvisors().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an advisor at the end of the advisor chain.
|
||||
* <p>The Advisor may be an {@link org.springframework.aop.IntroductionAdvisor},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -95,12 +95,6 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
*/
|
||||
private List<Advisor> advisors = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Array updated on changes to the advisors list, which is easier
|
||||
* to manipulate internally.
|
||||
*/
|
||||
private Advisor[] advisorArray = new Advisor[0];
|
||||
|
||||
|
||||
/**
|
||||
* No-arg constructor for use as a JavaBean.
|
||||
@@ -244,7 +238,12 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
|
||||
@Override
|
||||
public final Advisor[] getAdvisors() {
|
||||
return this.advisorArray;
|
||||
return this.advisors.toArray(new Advisor[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAdvisorCount() {
|
||||
return this.advisors.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -292,7 +291,6 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
}
|
||||
}
|
||||
|
||||
updateAdvisorArray();
|
||||
adviceChanged();
|
||||
}
|
||||
|
||||
@@ -339,7 +337,6 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
Assert.notNull(advisor, "Advisor must not be null");
|
||||
this.advisors.add(advisor);
|
||||
}
|
||||
updateAdvisorArray();
|
||||
adviceChanged();
|
||||
}
|
||||
}
|
||||
@@ -363,27 +360,18 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
"Illegal position " + pos + " in advisor list with size " + this.advisors.size());
|
||||
}
|
||||
this.advisors.add(pos, advisor);
|
||||
updateAdvisorArray();
|
||||
adviceChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bring the array up to date with the list.
|
||||
*/
|
||||
protected final void updateAdvisorArray() {
|
||||
this.advisorArray = this.advisors.toArray(new Advisor[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows uncontrolled access to the {@link List} of {@link Advisor Advisors}.
|
||||
* <p>Use with care, and remember to {@link #updateAdvisorArray() refresh the advisor array}
|
||||
* and {@link #adviceChanged() fire advice changed events} when making any modifications.
|
||||
* <p>Use with care, and remember to {@link #adviceChanged() fire advice changed events}
|
||||
* when making any modifications.
|
||||
*/
|
||||
protected final List<Advisor> getAdvisorsInternal() {
|
||||
return this.advisors;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addAdvice(Advice advice) throws AopConfigException {
|
||||
int pos = this.advisors.size();
|
||||
@@ -521,7 +509,6 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
Assert.notNull(advisor, "Advisor must not be null");
|
||||
this.advisors.add(advisor);
|
||||
}
|
||||
updateAdvisorArray();
|
||||
adviceChanged();
|
||||
}
|
||||
|
||||
@@ -536,7 +523,6 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
copy.advisorChainFactory = this.advisorChainFactory;
|
||||
copy.interfaces = this.interfaces;
|
||||
copy.advisors = this.advisors;
|
||||
copy.updateAdvisorArray();
|
||||
return copy;
|
||||
}
|
||||
|
||||
@@ -553,7 +539,6 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
this.methodCache = new ConcurrentHashMap<>(32);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toProxyConfigString() {
|
||||
return toString();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -206,7 +206,7 @@ public abstract class AopProxyUtils {
|
||||
* Check equality of the advisors behind the given AdvisedSupport objects.
|
||||
*/
|
||||
public static boolean equalsAdvisors(AdvisedSupport a, AdvisedSupport b) {
|
||||
return Arrays.equals(a.getAdvisors(), b.getAdvisors());
|
||||
return a.getAdvisorCount() == b.getAdvisorCount() && Arrays.equals(a.getAdvisors(), b.getAdvisors());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodInterceptor;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.cglib.proxy.NoOp;
|
||||
import org.springframework.core.KotlinDetector;
|
||||
import org.springframework.core.SmartClassLoader;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -125,7 +126,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
*/
|
||||
public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
|
||||
Assert.notNull(config, "AdvisedSupport must not be null");
|
||||
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
|
||||
if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
|
||||
throw new AopConfigException("No advisors and no TargetSource specified");
|
||||
}
|
||||
this.advised = config;
|
||||
@@ -752,10 +753,17 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
|
||||
if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) ||
|
||||
KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) {
|
||||
// Propagate original exception if declared on the target method
|
||||
// (with callers expecting it). Always propagate it for Kotlin code
|
||||
// since checked exceptions do not have to be explicitly declared there.
|
||||
throw ex;
|
||||
}
|
||||
else {
|
||||
// Checked exception thrown in the interceptor but not declared on the
|
||||
// target method signature -> apply an UndeclaredThrowableException,
|
||||
// aligned with standard JDK dynamic proxy behavior.
|
||||
throw new UndeclaredThrowableException(ex);
|
||||
}
|
||||
}
|
||||
@@ -942,11 +950,11 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
}
|
||||
// Advice instance identity is unimportant to the proxy class:
|
||||
// All that matters is type and ordering.
|
||||
Advisor[] thisAdvisors = this.advised.getAdvisors();
|
||||
Advisor[] thatAdvisors = otherAdvised.getAdvisors();
|
||||
if (thisAdvisors.length != thatAdvisors.length) {
|
||||
if (this.advised.getAdvisorCount() != otherAdvised.getAdvisorCount()) {
|
||||
return false;
|
||||
}
|
||||
Advisor[] thisAdvisors = this.advised.getAdvisors();
|
||||
Advisor[] thatAdvisors = otherAdvised.getAdvisors();
|
||||
for (int i = 0; i < thisAdvisors.length; i++) {
|
||||
Advisor thisAdvisor = thisAdvisors[i];
|
||||
Advisor thatAdvisor = thatAdvisors[i];
|
||||
|
||||
+3
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,6 +20,7 @@ import java.io.Serializable;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.springframework.aop.SpringProxy;
|
||||
import org.springframework.core.NativeDetector;
|
||||
|
||||
/**
|
||||
* Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy
|
||||
@@ -47,17 +48,10 @@ import org.springframework.aop.SpringProxy;
|
||||
@SuppressWarnings("serial")
|
||||
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
|
||||
|
||||
/**
|
||||
* Whether this environment lives within a native image.
|
||||
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
|
||||
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
|
||||
*/
|
||||
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
|
||||
|
||||
|
||||
@Override
|
||||
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
|
||||
if (!IN_NATIVE_IMAGE &&
|
||||
if (!NativeDetector.inNativeImage() &&
|
||||
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
|
||||
Class<?> targetClass = config.getTargetClass();
|
||||
if (targetClass == null) {
|
||||
|
||||
@@ -104,7 +104,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
|
||||
*/
|
||||
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
|
||||
Assert.notNull(config, "AdvisedSupport must not be null");
|
||||
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
|
||||
if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
|
||||
throw new AopConfigException("No advisors and no TargetSource specified");
|
||||
}
|
||||
this.advised = config;
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -116,7 +116,7 @@ public abstract class AbstractPoolingTargetSource extends AbstractPrototypeBased
|
||||
|
||||
|
||||
/**
|
||||
* Return an IntroductionAdvisor that providing a mixin
|
||||
* Return an IntroductionAdvisor that provides a mixin
|
||||
* exposing statistics about the pool maintained by this object.
|
||||
*/
|
||||
public DefaultIntroductionAdvisor getPoolingConfigMixin() {
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,7 +59,8 @@ public abstract aspect AbstractTransactionAspect extends TransactionAspectSuppor
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
clearTransactionManagerCache(); // An aspect is basically a singleton
|
||||
// An aspect is basically a singleton -> cleanup on destruction
|
||||
clearTransactionManagerCache();
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
|
||||
@@ -25,6 +25,7 @@ sourceSets {
|
||||
compileGroovy {
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
options.compilerArgs += "-Werror"
|
||||
}
|
||||
|
||||
// This module also builds Kotlin code and the compileKotlin task naturally depends on
|
||||
|
||||
+4
-5
@@ -1,14 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="bean1" class="org.springframework.beans.factory.ConcurrentBeanFactoryTests$ConcurrentBean"
|
||||
<bean id="bean1" class="org.springframework.beans.factory.ConcurrentBeanFactoryBenchmark$ConcurrentBean"
|
||||
scope="prototype">
|
||||
<property name="date" value="2004/08/08"/>
|
||||
</bean>
|
||||
|
||||
<bean id="bean2" class="org.springframework.beans.factory.ConcurrentBeanFactoryTests$ConcurrentBean"
|
||||
<bean id="bean2" class="org.springframework.beans.factory.ConcurrentBeanFactoryBenchmark$ConcurrentBean"
|
||||
scope="prototype">
|
||||
<property name="date" value="2000/02/02"/>
|
||||
</bean>
|
||||
|
||||
+6
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -422,9 +422,12 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw createNotWritablePropertyException(tokens.canonicalName);
|
||||
if (this.suppressNotWritablePropertyException) {
|
||||
// Optimization for common ignoreUnknown=true scenario since the
|
||||
// exception would be caught and swallowed higher up anyway...
|
||||
return;
|
||||
}
|
||||
throw createNotWritablePropertyException(tokens.canonicalName);
|
||||
}
|
||||
|
||||
Object oldValue = null;
|
||||
|
||||
+33
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,6 +40,8 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
|
||||
|
||||
private boolean autoGrowNestedPaths = false;
|
||||
|
||||
boolean suppressNotWritablePropertyException = false;
|
||||
|
||||
|
||||
@Override
|
||||
public void setExtractOldValueForEditor(boolean extractOldValueForEditor) {
|
||||
@@ -89,30 +91,41 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
|
||||
List<PropertyAccessException> propertyAccessExceptions = null;
|
||||
List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
|
||||
((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
|
||||
for (PropertyValue pv : propertyValues) {
|
||||
try {
|
||||
// This method may throw any BeansException, which won't be caught
|
||||
|
||||
if (ignoreUnknown) {
|
||||
this.suppressNotWritablePropertyException = true;
|
||||
}
|
||||
try {
|
||||
for (PropertyValue pv : propertyValues) {
|
||||
// setPropertyValue may throw any BeansException, which won't be caught
|
||||
// here, if there is a critical failure such as no matching field.
|
||||
// We can attempt to deal only with less serious exceptions.
|
||||
setPropertyValue(pv);
|
||||
}
|
||||
catch (NotWritablePropertyException ex) {
|
||||
if (!ignoreUnknown) {
|
||||
throw ex;
|
||||
try {
|
||||
setPropertyValue(pv);
|
||||
}
|
||||
// Otherwise, just ignore it and continue...
|
||||
}
|
||||
catch (NullValueInNestedPathException ex) {
|
||||
if (!ignoreInvalid) {
|
||||
throw ex;
|
||||
catch (NotWritablePropertyException ex) {
|
||||
if (!ignoreUnknown) {
|
||||
throw ex;
|
||||
}
|
||||
// Otherwise, just ignore it and continue...
|
||||
}
|
||||
// Otherwise, just ignore it and continue...
|
||||
}
|
||||
catch (PropertyAccessException ex) {
|
||||
if (propertyAccessExceptions == null) {
|
||||
propertyAccessExceptions = new ArrayList<>();
|
||||
catch (NullValueInNestedPathException ex) {
|
||||
if (!ignoreInvalid) {
|
||||
throw ex;
|
||||
}
|
||||
// Otherwise, just ignore it and continue...
|
||||
}
|
||||
propertyAccessExceptions.add(ex);
|
||||
catch (PropertyAccessException ex) {
|
||||
if (propertyAccessExceptions == null) {
|
||||
propertyAccessExceptions = new ArrayList<>();
|
||||
}
|
||||
propertyAccessExceptions.add(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (ignoreUnknown) {
|
||||
this.suppressNotWritablePropertyException = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -268,10 +268,7 @@ public abstract class BeanUtils {
|
||||
public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(clazz)) {
|
||||
Constructor<T> kotlinPrimaryConstructor = KotlinDelegate.findPrimaryConstructor(clazz);
|
||||
if (kotlinPrimaryConstructor != null) {
|
||||
return kotlinPrimaryConstructor;
|
||||
}
|
||||
return KotlinDelegate.findPrimaryConstructor(clazz);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -543,6 +540,7 @@ public abstract class BeanUtils {
|
||||
if (targetType == null || targetType.isArray() || unknownEditorTypes.contains(targetType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClassLoader cl = targetType.getClassLoader();
|
||||
if (cl == null) {
|
||||
try {
|
||||
@@ -559,28 +557,34 @@ public abstract class BeanUtils {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String targetTypeName = targetType.getName();
|
||||
String editorName = targetTypeName + "Editor";
|
||||
try {
|
||||
Class<?> editorClass = cl.loadClass(editorName);
|
||||
if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Editor class [" + editorName +
|
||||
"] does not implement [java.beans.PropertyEditor] interface");
|
||||
if (editorClass != null) {
|
||||
if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Editor class [" + editorName +
|
||||
"] does not implement [java.beans.PropertyEditor] interface");
|
||||
}
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
}
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
return (PropertyEditor) instantiateClass(editorClass);
|
||||
}
|
||||
return (PropertyEditor) instantiateClass(editorClass);
|
||||
// Misbehaving ClassLoader returned null instead of ClassNotFoundException
|
||||
// - fall back to unknown editor type registration below
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("No property editor [" + editorName + "] found for type " +
|
||||
targetTypeName + " according to 'Editor' suffix convention");
|
||||
}
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
// Ignore - fall back to unknown editor type registration below
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("No property editor [" + editorName + "] found for type " +
|
||||
targetTypeName + " according to 'Editor' suffix convention");
|
||||
}
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -772,7 +776,14 @@ public abstract class BeanUtils {
|
||||
if (readMethod != null) {
|
||||
ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod);
|
||||
ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0);
|
||||
if (targetResolvableType.isAssignableFrom(sourceResolvableType)) {
|
||||
|
||||
// Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
|
||||
boolean isAssignable =
|
||||
(sourceResolvableType.hasUnresolvableGenerics() || targetResolvableType.hasUnresolvableGenerics() ?
|
||||
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) :
|
||||
targetResolvableType.isAssignableFrom(sourceResolvableType));
|
||||
|
||||
if (isAssignable) {
|
||||
try {
|
||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
|
||||
readMethod.setAccessible(true);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -92,8 +92,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
|
||||
@Override
|
||||
protected NotWritablePropertyException createNotWritablePropertyException(String propertyName) {
|
||||
PropertyMatches matches = PropertyMatches.forField(propertyName, getRootClass());
|
||||
throw new NotWritablePropertyException(
|
||||
getRootClass(), getNestedPath() + propertyName,
|
||||
throw new NotWritablePropertyException(getRootClass(), getNestedPath() + propertyName,
|
||||
matches.buildErrorMessage(), matches.getPossibleMatches());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,10 +41,10 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
private String propertyName;
|
||||
|
||||
@Nullable
|
||||
private transient Object value;
|
||||
private final transient Object value;
|
||||
|
||||
@Nullable
|
||||
private Class<?> requiredType;
|
||||
private final Class<?> requiredType;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
+106
-83
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -628,46 +628,58 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
Field field = (Field) this.member;
|
||||
Object value;
|
||||
if (this.cached) {
|
||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
||||
try {
|
||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Unexpected removal of target bean for cached argument -> re-resolve
|
||||
value = resolveFieldValue(field, bean, beanName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
|
||||
desc.setContainingClass(bean.getClass());
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
try {
|
||||
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
if (value != null || this.required) {
|
||||
this.cachedFieldValue = desc;
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == 1) {
|
||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
|
||||
this.cachedFieldValue = new ShortcutDependencyDescriptor(
|
||||
desc, autowiredBeanName, field.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.cachedFieldValue = null;
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
value = resolveFieldValue(field, bean, beanName);
|
||||
}
|
||||
if (value != null) {
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
field.set(bean, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
|
||||
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
|
||||
desc.setContainingClass(bean.getClass());
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
Object value;
|
||||
try {
|
||||
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
Object cachedFieldValue = null;
|
||||
if (value != null || this.required) {
|
||||
cachedFieldValue = desc;
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == 1) {
|
||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
|
||||
cachedFieldValue = new ShortcutDependencyDescriptor(
|
||||
desc, autowiredBeanName, field.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cachedFieldValue = cachedFieldValue;
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -696,58 +708,16 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
Method method = (Method) this.member;
|
||||
Object[] arguments;
|
||||
if (this.cached) {
|
||||
// Shortcut for avoiding synchronization...
|
||||
arguments = resolveCachedArguments(beanName);
|
||||
try {
|
||||
arguments = resolveCachedArguments(beanName);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Unexpected removal of target bean for cached argument -> re-resolve
|
||||
arguments = resolveMethodArguments(method, bean, beanName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int argumentCount = method.getParameterCount();
|
||||
arguments = new Object[argumentCount];
|
||||
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
|
||||
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
|
||||
currDesc.setContainingClass(bean.getClass());
|
||||
descriptors[i] = currDesc;
|
||||
try {
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
|
||||
if (arg == null && !this.required) {
|
||||
arguments = null;
|
||||
break;
|
||||
}
|
||||
arguments[i] = arg;
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
|
||||
}
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
if (arguments != null) {
|
||||
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
|
||||
registerDependentBeans(beanName, autowiredBeans);
|
||||
if (autowiredBeans.size() == argumentCount) {
|
||||
Iterator<String> it = autowiredBeans.iterator();
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
String autowiredBeanName = it.next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
|
||||
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
|
||||
descriptors[i], autowiredBeanName, paramTypes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cachedMethodArguments = cachedMethodArguments;
|
||||
}
|
||||
else {
|
||||
this.cachedMethodArguments = null;
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
arguments = resolveMethodArguments(method, bean, beanName);
|
||||
}
|
||||
if (arguments != null) {
|
||||
try {
|
||||
@@ -772,6 +742,59 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
|
||||
int argumentCount = method.getParameterCount();
|
||||
Object[] arguments = new Object[argumentCount];
|
||||
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
|
||||
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
|
||||
currDesc.setContainingClass(bean.getClass());
|
||||
descriptors[i] = currDesc;
|
||||
try {
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
|
||||
if (arg == null && !this.required) {
|
||||
arguments = null;
|
||||
break;
|
||||
}
|
||||
arguments[i] = arg;
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
|
||||
}
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
if (arguments != null) {
|
||||
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
|
||||
registerDependentBeans(beanName, autowiredBeans);
|
||||
if (autowiredBeans.size() == argumentCount) {
|
||||
Iterator<String> it = autowiredBeans.iterator();
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
String autowiredBeanName = it.next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
|
||||
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
|
||||
descriptors[i], autowiredBeanName, paramTypes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cachedMethodArguments = cachedMethodArguments;
|
||||
}
|
||||
else {
|
||||
this.cachedMethodArguments = null;
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-14
@@ -26,9 +26,6 @@ import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
@@ -69,8 +66,6 @@ public class InjectionMetadata {
|
||||
};
|
||||
|
||||
|
||||
private static final Log logger = LogFactory.getLog(InjectionMetadata.class);
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
private final Collection<InjectedElement> injectedElements;
|
||||
@@ -110,9 +105,6 @@ public class InjectionMetadata {
|
||||
if (!beanDefinition.isExternallyManagedConfigMember(member)) {
|
||||
beanDefinition.registerExternallyManagedConfigMember(member);
|
||||
checkedElements.add(element);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.checkedElements = checkedElements;
|
||||
@@ -124,9 +116,6 @@ public class InjectionMetadata {
|
||||
(checkedElements != null ? checkedElements : this.injectedElements);
|
||||
if (!elementsToIterate.isEmpty()) {
|
||||
for (InjectedElement element : elementsToIterate) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
|
||||
}
|
||||
element.inject(target, beanName, pvs);
|
||||
}
|
||||
}
|
||||
@@ -152,12 +141,12 @@ public class InjectionMetadata {
|
||||
* Return an {@code InjectionMetadata} instance, possibly for empty elements.
|
||||
* @param elements the elements to inject (possibly empty)
|
||||
* @param clazz the target class
|
||||
* @return a new {@link #InjectionMetadata(Class, Collection)} instance,
|
||||
* or {@link #EMPTY} in case of no elements
|
||||
* @return a new {@link #InjectionMetadata(Class, Collection)} instance
|
||||
* @since 5.2
|
||||
*/
|
||||
public static InjectionMetadata forElements(Collection<InjectedElement> elements, Class<?> clazz) {
|
||||
return (elements.isEmpty() ? InjectionMetadata.EMPTY : new InjectionMetadata(clazz, elements));
|
||||
return (elements.isEmpty() ? new InjectionMetadata(clazz, Collections.emptyList()) :
|
||||
new InjectionMetadata(clazz, elements));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,7 +40,6 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link AutowireCandidateResolver} implementation that matches bean definition qualifiers
|
||||
@@ -188,7 +187,7 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
||||
foundMeta = true;
|
||||
// Only accept fallback match if @Qualifier annotation has a value...
|
||||
// Otherwise it is just a marker for a custom qualifier annotation.
|
||||
if ((fallbackToMeta && StringUtils.isEmpty(AnnotationUtils.getValue(metaAnn))) ||
|
||||
if ((fallbackToMeta && ObjectUtils.isEmpty(AnnotationUtils.getValue(metaAnn))) ||
|
||||
!checkQualifier(bdHolder, metaAnn, typeConverter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+9
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -52,6 +52,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @author Brian Clozel
|
||||
* @since 4.1
|
||||
*/
|
||||
public abstract class YamlProcessor {
|
||||
@@ -128,10 +129,11 @@ public abstract class YamlProcessor {
|
||||
|
||||
/**
|
||||
* Set the supported types that can be loaded from YAML documents.
|
||||
* <p>If no supported types are configured, all types encountered in YAML
|
||||
* documents will be supported. If an unsupported type is encountered, an
|
||||
* {@link IllegalStateException} will be thrown when the corresponding YAML
|
||||
* node is processed.
|
||||
* <p>If no supported types are configured, only Java standard classes
|
||||
* (as defined in {@link org.yaml.snakeyaml.constructor.SafeConstructor})
|
||||
* encountered in YAML documents will be supported.
|
||||
* If an unsupported type is encountered, an {@link IllegalStateException}
|
||||
* will be thrown when the corresponding YAML node is processed.
|
||||
* @param supportedTypes the supported types, or an empty array to clear the
|
||||
* supported types
|
||||
* @since 5.1.16
|
||||
@@ -182,12 +184,8 @@ public abstract class YamlProcessor {
|
||||
protected Yaml createYaml() {
|
||||
LoaderOptions loaderOptions = new LoaderOptions();
|
||||
loaderOptions.setAllowDuplicateKeys(false);
|
||||
|
||||
if (!this.supportedTypes.isEmpty()) {
|
||||
return new Yaml(new FilteringConstructor(loaderOptions), new Representer(),
|
||||
new DumperOptions(), loaderOptions);
|
||||
}
|
||||
return new Yaml(loaderOptions);
|
||||
return new Yaml(new FilteringConstructor(loaderOptions), new Representer(),
|
||||
new DumperOptions(), loaderOptions);
|
||||
}
|
||||
|
||||
private boolean process(MatchCallback callback, Yaml yaml, Resource resource) {
|
||||
|
||||
+8
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -73,6 +73,7 @@ import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
import org.springframework.core.NativeDetector;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.ResolvableType;
|
||||
@@ -123,14 +124,6 @@ import org.springframework.util.StringUtils;
|
||||
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
|
||||
implements AutowireCapableBeanFactory {
|
||||
|
||||
/**
|
||||
* Whether this environment lives within a native image.
|
||||
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
|
||||
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
|
||||
*/
|
||||
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
|
||||
|
||||
|
||||
/** Strategy for creating bean instances. */
|
||||
private InstantiationStrategy instantiationStrategy;
|
||||
|
||||
@@ -184,7 +177,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
ignoreDependencyInterface(BeanNameAware.class);
|
||||
ignoreDependencyInterface(BeanFactoryAware.class);
|
||||
ignoreDependencyInterface(BeanClassLoaderAware.class);
|
||||
if (IN_NATIVE_IMAGE) {
|
||||
if (NativeDetector.inNativeImage()) {
|
||||
this.instantiationStrategy = new SimpleInstantiationStrategy();
|
||||
}
|
||||
else {
|
||||
@@ -1022,6 +1015,11 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
throw ex;
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
// Don't swallow a linkage error since it contains a full stacktrace on
|
||||
// first occurrence... and just a plain NoClassDefFoundError afterwards.
|
||||
if (ex.contains(LinkageError.class)) {
|
||||
throw ex;
|
||||
}
|
||||
// Instantiation failure, maybe too early...
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Bean creation exception on singleton FactoryBean type check: " + ex);
|
||||
|
||||
+23
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -1194,8 +1194,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
this.primary == that.primary &&
|
||||
this.nonPublicAccessAllowed == that.nonPublicAccessAllowed &&
|
||||
this.lenientConstructorResolution == that.lenientConstructorResolution &&
|
||||
ObjectUtils.nullSafeEquals(this.constructorArgumentValues, that.constructorArgumentValues) &&
|
||||
ObjectUtils.nullSafeEquals(this.propertyValues, that.propertyValues) &&
|
||||
equalsConstructorArgumentValues(that) &&
|
||||
equalsPropertyValues(that) &&
|
||||
ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides) &&
|
||||
ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName) &&
|
||||
ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName) &&
|
||||
@@ -1208,12 +1208,30 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
super.equals(other));
|
||||
}
|
||||
|
||||
private boolean equalsConstructorArgumentValues(AbstractBeanDefinition other) {
|
||||
if (!hasConstructorArgumentValues()) {
|
||||
return !other.hasConstructorArgumentValues();
|
||||
}
|
||||
return ObjectUtils.nullSafeEquals(this.constructorArgumentValues, other.constructorArgumentValues);
|
||||
}
|
||||
|
||||
private boolean equalsPropertyValues(AbstractBeanDefinition other) {
|
||||
if (!hasPropertyValues()) {
|
||||
return !other.hasPropertyValues();
|
||||
}
|
||||
return ObjectUtils.nullSafeEquals(this.propertyValues, other.propertyValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = ObjectUtils.nullSafeHashCode(getBeanClassName());
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.scope);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.constructorArgumentValues);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.propertyValues);
|
||||
if (hasConstructorArgumentValues()) {
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.constructorArgumentValues);
|
||||
}
|
||||
if (hasPropertyValues()) {
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.propertyValues);
|
||||
}
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryBeanName);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryMethodName);
|
||||
hashCode = 29 * hashCode + super.hashCode();
|
||||
|
||||
+14
-11
@@ -250,7 +250,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
throws BeansException {
|
||||
|
||||
String beanName = transformedBeanName(name);
|
||||
Object bean;
|
||||
Object beanInstance;
|
||||
|
||||
// Eagerly check singleton cache for manually registered singletons.
|
||||
Object sharedInstance = getSingleton(beanName);
|
||||
@@ -264,7 +264,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
|
||||
}
|
||||
}
|
||||
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
|
||||
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
|
||||
}
|
||||
|
||||
else {
|
||||
@@ -342,7 +342,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
throw ex;
|
||||
}
|
||||
});
|
||||
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
|
||||
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
|
||||
}
|
||||
|
||||
else if (mbd.isPrototype()) {
|
||||
@@ -355,7 +355,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
finally {
|
||||
afterPrototypeCreation(beanName);
|
||||
}
|
||||
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
|
||||
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
|
||||
}
|
||||
|
||||
else {
|
||||
@@ -377,7 +377,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
afterPrototypeCreation(beanName);
|
||||
}
|
||||
});
|
||||
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
|
||||
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw new ScopeNotActiveException(beanName, scopeName, ex);
|
||||
@@ -395,14 +395,19 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
}
|
||||
}
|
||||
|
||||
return adaptBeanInstance(name, beanInstance, requiredType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> T adaptBeanInstance(String name, Object bean, @Nullable Class<?> requiredType) {
|
||||
// Check if required type matches the type of the actual bean instance.
|
||||
if (requiredType != null && !requiredType.isInstance(bean)) {
|
||||
try {
|
||||
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
|
||||
Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
|
||||
if (convertedBean == null) {
|
||||
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
|
||||
}
|
||||
return convertedBean;
|
||||
return (T) convertedBean;
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
@@ -1288,10 +1293,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
* @param registry the PropertyEditorRegistry to initialize
|
||||
*/
|
||||
protected void registerCustomEditors(PropertyEditorRegistry registry) {
|
||||
PropertyEditorRegistrySupport registrySupport =
|
||||
(registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null);
|
||||
if (registrySupport != null) {
|
||||
registrySupport.useConfigValueEditors();
|
||||
if (registry instanceof PropertyEditorRegistrySupport) {
|
||||
((PropertyEditorRegistrySupport) registry).useConfigValueEditors();
|
||||
}
|
||||
if (!this.propertyEditorRegistrars.isEmpty()) {
|
||||
for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) {
|
||||
|
||||
+7
-5
@@ -67,6 +67,7 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Delegate for resolving constructors and factory methods.
|
||||
*
|
||||
* <p>Performs constructor resolution through argument matching.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
@@ -85,7 +86,7 @@ class ConstructorResolver {
|
||||
private static final Object[] EMPTY_ARGS = new Object[0];
|
||||
|
||||
/**
|
||||
* Marker for autowired arguments in a cached argument array, to be later replaced
|
||||
* Marker for autowired arguments in a cached argument array, to be replaced
|
||||
* by a {@linkplain #resolveAutowiredArgument resolved autowired argument}.
|
||||
*/
|
||||
private static final Object autowiredArgumentMarker = new Object();
|
||||
@@ -149,7 +150,7 @@ class ConstructorResolver {
|
||||
}
|
||||
}
|
||||
if (argsToResolve != null) {
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,6 +411,7 @@ class ConstructorResolver {
|
||||
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
|
||||
throw new ImplicitlyAppearedSingletonException();
|
||||
}
|
||||
this.beanFactory.registerDependentBean(factoryBeanName, beanName);
|
||||
factoryClass = factoryBean.getClass();
|
||||
isStatic = false;
|
||||
}
|
||||
@@ -444,7 +446,7 @@ class ConstructorResolver {
|
||||
}
|
||||
}
|
||||
if (argsToResolve != null) {
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -816,7 +818,7 @@ class ConstructorResolver {
|
||||
* Resolve the prepared arguments stored in the given bean definition.
|
||||
*/
|
||||
private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
|
||||
Executable executable, Object[] argsToResolve, boolean fallback) {
|
||||
Executable executable, Object[] argsToResolve) {
|
||||
|
||||
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
|
||||
TypeConverter converter = (customConverter != null ? customConverter : bw);
|
||||
@@ -829,7 +831,7 @@ class ConstructorResolver {
|
||||
Object argValue = argsToResolve[argIndex];
|
||||
MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex);
|
||||
if (argValue == autowiredArgumentMarker) {
|
||||
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, fallback);
|
||||
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, true);
|
||||
}
|
||||
else if (argValue instanceof BeanMetadataElement) {
|
||||
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
|
||||
|
||||
+17
-4
@@ -1231,8 +1231,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
|
||||
if (candidateNames.length == 1) {
|
||||
String beanName = candidateNames[0];
|
||||
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
|
||||
return resolveNamedBean(candidateNames[0], requiredType, args);
|
||||
}
|
||||
else if (candidateNames.length > 1) {
|
||||
Map<String, Object> candidates = CollectionUtils.newLinkedHashMap(candidateNames.length);
|
||||
@@ -1251,8 +1250,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
if (candidateName != null) {
|
||||
Object beanInstance = candidates.get(candidateName);
|
||||
if (beanInstance == null || beanInstance instanceof Class) {
|
||||
beanInstance = getBean(candidateName, requiredType.toClass(), args);
|
||||
if (beanInstance == null) {
|
||||
return null;
|
||||
}
|
||||
if (beanInstance instanceof Class) {
|
||||
return resolveNamedBean(candidateName, requiredType, args);
|
||||
}
|
||||
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
|
||||
}
|
||||
@@ -1264,6 +1266,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T> NamedBeanHolder<T> resolveNamedBean(
|
||||
String beanName, ResolvableType requiredType, @Nullable Object[] args) throws BeansException {
|
||||
|
||||
Object bean = getBean(beanName, null, args);
|
||||
if (bean instanceof NullBean) {
|
||||
return null;
|
||||
}
|
||||
return new NamedBeanHolder<T>(beanName, adaptBeanInstance(beanName, bean, requiredType.toClass()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
|
||||
|
||||
+75
-74
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -119,14 +119,16 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
}
|
||||
}
|
||||
else {
|
||||
Class<?>[] paramTypes = destroyMethod.getParameterTypes();
|
||||
if (paramTypes.length > 1) {
|
||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||
beanName + "' has more than one parameter - not supported as destroy method");
|
||||
}
|
||||
else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
|
||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||
beanName + "' has a non-boolean parameter - not supported as destroy method");
|
||||
if (destroyMethod.getParameterCount() > 0) {
|
||||
Class<?>[] paramTypes = destroyMethod.getParameterTypes();
|
||||
if (paramTypes.length > 1) {
|
||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||
beanName + "' has more than one parameter - not supported as destroy method");
|
||||
}
|
||||
else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
|
||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||
beanName + "' has a non-boolean parameter - not supported as destroy method");
|
||||
}
|
||||
}
|
||||
destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);
|
||||
}
|
||||
@@ -170,66 +172,6 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the current value of the given beanDefinition's "destroyMethodName" property is
|
||||
* {@link AbstractBeanDefinition#INFER_METHOD}, then attempt to infer a destroy method.
|
||||
* Candidate methods are currently limited to public, no-arg methods named "close" or
|
||||
* "shutdown" (whether declared locally or inherited). The given BeanDefinition's
|
||||
* "destroyMethodName" is updated to be null if no such method is found, otherwise set
|
||||
* to the name of the inferred method. This constant serves as the default for the
|
||||
* {@code @Bean#destroyMethod} attribute and the value of the constant may also be
|
||||
* used in XML within the {@code <bean destroy-method="">} or {@code
|
||||
* <beans default-destroy-method="">} attributes.
|
||||
* <p>Also processes the {@link java.io.Closeable} and {@link java.lang.AutoCloseable}
|
||||
* interfaces, reflectively calling the "close" method on implementing beans as well.
|
||||
*/
|
||||
@Nullable
|
||||
private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
|
||||
String destroyMethodName = beanDefinition.getDestroyMethodName();
|
||||
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
|
||||
(destroyMethodName == null && bean instanceof AutoCloseable)) {
|
||||
// Only perform destroy method inference or Closeable detection
|
||||
// in case of the bean not explicitly implementing DisposableBean
|
||||
if (!(bean instanceof DisposableBean)) {
|
||||
try {
|
||||
return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
try {
|
||||
return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
|
||||
}
|
||||
catch (NoSuchMethodException ex2) {
|
||||
// no candidate destroy method found
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for all DestructionAwareBeanPostProcessors in the List.
|
||||
* @param processors the List to search
|
||||
* @return the filtered List of DestructionAwareBeanPostProcessors
|
||||
*/
|
||||
@Nullable
|
||||
private List<DestructionAwareBeanPostProcessor> filterPostProcessors(
|
||||
List<DestructionAwareBeanPostProcessor> processors, Object bean) {
|
||||
|
||||
List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
|
||||
if (!CollectionUtils.isEmpty(processors)) {
|
||||
filteredPostProcessors = new ArrayList<>(processors.size());
|
||||
for (DestructionAwareBeanPostProcessor processor : processors) {
|
||||
if (processor.requiresDestruction(bean)) {
|
||||
filteredPostProcessors.add(processor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return filteredPostProcessors;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
destroy();
|
||||
@@ -384,12 +326,50 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
|
||||
return true;
|
||||
}
|
||||
String destroyMethodName = beanDefinition.getDestroyMethodName();
|
||||
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) {
|
||||
return (ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME) ||
|
||||
ClassUtils.hasMethod(bean.getClass(), SHUTDOWN_METHOD_NAME));
|
||||
return inferDestroyMethodIfNecessary(bean, beanDefinition) != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the current value of the given beanDefinition's "destroyMethodName" property is
|
||||
* {@link AbstractBeanDefinition#INFER_METHOD}, then attempt to infer a destroy method.
|
||||
* Candidate methods are currently limited to public, no-arg methods named "close" or
|
||||
* "shutdown" (whether declared locally or inherited). The given BeanDefinition's
|
||||
* "destroyMethodName" is updated to be null if no such method is found, otherwise set
|
||||
* to the name of the inferred method. This constant serves as the default for the
|
||||
* {@code @Bean#destroyMethod} attribute and the value of the constant may also be
|
||||
* used in XML within the {@code <bean destroy-method="">} or {@code
|
||||
* <beans default-destroy-method="">} attributes.
|
||||
* <p>Also processes the {@link java.io.Closeable} and {@link java.lang.AutoCloseable}
|
||||
* interfaces, reflectively calling the "close" method on implementing beans as well.
|
||||
*/
|
||||
@Nullable
|
||||
private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
|
||||
String destroyMethodName = beanDefinition.resolvedDestroyMethodName;
|
||||
if (destroyMethodName == null) {
|
||||
destroyMethodName = beanDefinition.getDestroyMethodName();
|
||||
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
|
||||
(destroyMethodName == null && bean instanceof AutoCloseable)) {
|
||||
// Only perform destroy method inference or Closeable detection
|
||||
// in case of the bean not explicitly implementing DisposableBean
|
||||
destroyMethodName = null;
|
||||
if (!(bean instanceof DisposableBean)) {
|
||||
try {
|
||||
destroyMethodName = bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
try {
|
||||
destroyMethodName = bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
|
||||
}
|
||||
catch (NoSuchMethodException ex2) {
|
||||
// no candidate destroy method found
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : "");
|
||||
}
|
||||
return StringUtils.hasLength(destroyMethodName);
|
||||
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -408,4 +388,25 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for all DestructionAwareBeanPostProcessors in the List.
|
||||
* @param processors the List to search
|
||||
* @return the filtered List of DestructionAwareBeanPostProcessors
|
||||
*/
|
||||
@Nullable
|
||||
private static List<DestructionAwareBeanPostProcessor> filterPostProcessors(
|
||||
List<DestructionAwareBeanPostProcessor> processors, Object bean) {
|
||||
|
||||
List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
|
||||
if (!CollectionUtils.isEmpty(processors)) {
|
||||
filteredPostProcessors = new ArrayList<>(processors.size());
|
||||
for (DestructionAwareBeanPostProcessor processor : processors) {
|
||||
if (processor.requiresDestruction(bean)) {
|
||||
filteredPostProcessors.add(processor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return filteredPostProcessors;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -86,6 +86,10 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
@Nullable
|
||||
volatile Method factoryMethodToIntrospect;
|
||||
|
||||
/** Package-visible field for caching a resolved destroy method name (also for inferred). */
|
||||
@Nullable
|
||||
volatile String resolvedDestroyMethodName;
|
||||
|
||||
/** Common lock for the four constructor fields below. */
|
||||
final Object constructorArgumentLock = new Object();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,12 +19,16 @@ package org.springframework.beans;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -196,6 +200,29 @@ class BeanUtilsTests {
|
||||
assertThat(longListHolder.getList()).isEmpty();
|
||||
}
|
||||
|
||||
@Test // gh-26531
|
||||
void copyPropertiesIgnoresGenericsIfSourceOrTargetHasUnresolvableGenerics() throws Exception {
|
||||
Order original = new Order("test", Arrays.asList("foo", "bar"));
|
||||
|
||||
// Create a Proxy that loses the generic type information for the getLineItems() method.
|
||||
OrderSummary proxy = proxyOrder(original);
|
||||
assertThat(OrderSummary.class.getDeclaredMethod("getLineItems").toGenericString())
|
||||
.contains("java.util.List<java.lang.String>");
|
||||
assertThat(proxy.getClass().getDeclaredMethod("getLineItems").toGenericString())
|
||||
.contains("java.util.List")
|
||||
.doesNotContain("<java.lang.String>");
|
||||
|
||||
// Ensure that our custom Proxy works as expected.
|
||||
assertThat(proxy.getId()).isEqualTo("test");
|
||||
assertThat(proxy.getLineItems()).containsExactly("foo", "bar");
|
||||
|
||||
// Copy from proxy to target.
|
||||
Order target = new Order();
|
||||
BeanUtils.copyProperties(proxy, target);
|
||||
assertThat(target.getId()).isEqualTo("test");
|
||||
assertThat(target.getLineItems()).containsExactly("foo", "bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void copyPropertiesWithEditable() throws Exception {
|
||||
TestBean tb = new TestBean();
|
||||
@@ -633,4 +660,77 @@ class BeanUtilsTests {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class Order {
|
||||
|
||||
private String id;
|
||||
private List<String> lineItems;
|
||||
|
||||
|
||||
Order() {
|
||||
}
|
||||
|
||||
Order(String id, List<String> lineItems) {
|
||||
this.id = id;
|
||||
this.lineItems = lineItems;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<String> getLineItems() {
|
||||
return this.lineItems;
|
||||
}
|
||||
|
||||
public void setLineItems(List<String> lineItems) {
|
||||
this.lineItems = lineItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Order [id=" + this.id + ", lineItems=" + this.lineItems + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private interface OrderSummary {
|
||||
|
||||
String getId();
|
||||
|
||||
List<String> getLineItems();
|
||||
}
|
||||
|
||||
|
||||
private OrderSummary proxyOrder(Order order) {
|
||||
return (OrderSummary) Proxy.newProxyInstance(getClass().getClassLoader(),
|
||||
new Class<?>[] { OrderSummary.class }, new OrderInvocationHandler(order));
|
||||
}
|
||||
|
||||
|
||||
private static class OrderInvocationHandler implements InvocationHandler {
|
||||
|
||||
private final Order order;
|
||||
|
||||
|
||||
OrderInvocationHandler(Order order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
try {
|
||||
// Ignore args since OrderSummary doesn't declare any methods with arguments,
|
||||
// and we're not supporting equals(Object), etc.
|
||||
return Order.class.getDeclaredMethod(method.getName()).invoke(this.order);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw ex.getTargetException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-11
@@ -63,9 +63,8 @@ public class BeanFactoryUtilsTests {
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
public void setup() {
|
||||
// Interesting hierarchical factory to test counts.
|
||||
// Slow to read so we cache it.
|
||||
|
||||
DefaultListableBeanFactory grandParent = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(grandParent).loadBeanDefinitions(ROOT_CONTEXT);
|
||||
@@ -93,7 +92,7 @@ public class BeanFactoryUtilsTests {
|
||||
* Check that override doesn't count as two separate beans.
|
||||
*/
|
||||
@Test
|
||||
public void testHierarchicalCountBeansWithOverride() throws Exception {
|
||||
public void testHierarchicalCountBeansWithOverride() {
|
||||
// Leaf count
|
||||
assertThat(this.listableBeanFactory.getBeanDefinitionCount() == 1).isTrue();
|
||||
// Count minus duplicate
|
||||
@@ -101,14 +100,14 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesWithNoMatch() throws Exception {
|
||||
public void testHierarchicalNamesWithNoMatch() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, NoOp.class));
|
||||
assertThat(names.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesWithMatchOnlyInRoot() throws Exception {
|
||||
public void testHierarchicalNamesWithMatchOnlyInRoot() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, IndexedTestBean.class));
|
||||
assertThat(names.size()).isEqualTo(1);
|
||||
@@ -118,7 +117,7 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanNamesForTypeWithOverride() throws Exception {
|
||||
public void testGetBeanNamesForTypeWithOverride() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class));
|
||||
// includes 2 TestBeans from FactoryBeans (DummyFactory definitions)
|
||||
@@ -236,7 +235,7 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalResolutionWithOverride() throws Exception {
|
||||
public void testHierarchicalResolutionWithOverride() {
|
||||
Object test3 = this.listableBeanFactory.getBean("test3");
|
||||
Object test = this.listableBeanFactory.getBean("test");
|
||||
|
||||
@@ -276,14 +275,14 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesForAnnotationWithNoMatch() throws Exception {
|
||||
public void testHierarchicalNamesForAnnotationWithNoMatch() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, Override.class));
|
||||
assertThat(names.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() throws Exception {
|
||||
public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, TestAnnotation.class));
|
||||
assertThat(names.size()).isEqualTo(1);
|
||||
@@ -293,7 +292,7 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanNamesForAnnotationWithOverride() throws Exception {
|
||||
public void testGetBeanNamesForAnnotationWithOverride() {
|
||||
AnnotatedBean annotatedBean = new AnnotatedBean();
|
||||
this.listableBeanFactory.registerSingleton("anotherAnnotatedBean", annotatedBean);
|
||||
List<String> names = Arrays.asList(
|
||||
@@ -433,6 +432,7 @@ public class BeanFactoryUtilsTests {
|
||||
String basePackage() default "";
|
||||
}
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@ControllerAdvice
|
||||
@interface RestControllerAdvice {
|
||||
@@ -444,18 +444,23 @@ public class BeanFactoryUtilsTests {
|
||||
String basePackage() default "";
|
||||
}
|
||||
|
||||
|
||||
@ControllerAdvice("com.example")
|
||||
static class ControllerAdviceClass {
|
||||
}
|
||||
|
||||
|
||||
@RestControllerAdvice("com.example")
|
||||
static class RestControllerAdviceClass {
|
||||
}
|
||||
|
||||
|
||||
static class TestBeanSmartFactoryBean implements SmartFactoryBean<TestBean> {
|
||||
|
||||
private final TestBean testBean = new TestBean("enigma", 42);
|
||||
|
||||
private final boolean singleton;
|
||||
|
||||
private final boolean prototype;
|
||||
|
||||
TestBeanSmartFactoryBean(boolean singleton, boolean prototype) {
|
||||
@@ -478,7 +483,7 @@ public class BeanFactoryUtilsTests {
|
||||
return TestBean.class;
|
||||
}
|
||||
|
||||
public TestBean getObject() throws Exception {
|
||||
public TestBean getObject() {
|
||||
// We don't really care if the actual instance is a singleton or prototype
|
||||
// for the tests that use this factory.
|
||||
return this.testBean;
|
||||
|
||||
+16
-26
@@ -43,8 +43,6 @@ import java.util.stream.IntStream;
|
||||
import javax.annotation.Priority;
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
@@ -121,8 +119,6 @@ import static org.mockito.Mockito.verify;
|
||||
*/
|
||||
class DefaultListableBeanFactoryTests {
|
||||
|
||||
private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class);
|
||||
|
||||
private DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
|
||||
|
||||
@@ -789,12 +785,13 @@ class DefaultListableBeanFactoryTests {
|
||||
factory.registerBeanDefinition("child", childDefinition);
|
||||
factory.registerAlias("parent", "alias");
|
||||
|
||||
TestBean child = (TestBean) factory.getBean("child");
|
||||
TestBean child = factory.getBean("child", TestBean.class);
|
||||
assertThat(child.getName()).isEqualTo(EXPECTED_NAME);
|
||||
assertThat(child.getAge()).isEqualTo(EXPECTED_AGE);
|
||||
Object mergedBeanDefinition2 = factory.getMergedBeanDefinition("child");
|
||||
BeanDefinition mergedBeanDefinition1 = factory.getMergedBeanDefinition("child");
|
||||
BeanDefinition mergedBeanDefinition2 = factory.getMergedBeanDefinition("child");
|
||||
|
||||
assertThat(mergedBeanDefinition2).as("Use cached merged bean definition").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(mergedBeanDefinition1).as("Use cached merged bean definition").isSameAs(mergedBeanDefinition2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1842,8 +1839,7 @@ class DefaultListableBeanFactoryTests {
|
||||
assertThat(factoryBean).as("The FactoryBean should have been registered.").isNotNull();
|
||||
FactoryBeanDependentBean bean = (FactoryBeanDependentBean) lbf.autowire(FactoryBeanDependentBean.class,
|
||||
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
|
||||
Object mergedBeanDefinition2 = bean.getFactoryBean();
|
||||
assertThat(mergedBeanDefinition2).as("The FactoryBeanDependentBean should have been autowired 'by type' with the LazyInitFactory.").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(bean.getFactoryBean()).as("The FactoryBeanDependentBean should have been autowired 'by type' with the LazyInitFactory.").isEqualTo(factoryBean);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2392,8 +2388,7 @@ class DefaultListableBeanFactoryTests {
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount;
|
||||
assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2407,8 +2402,7 @@ class DefaultListableBeanFactoryTests {
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount;
|
||||
assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2423,8 +2417,7 @@ class DefaultListableBeanFactoryTests {
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount;
|
||||
assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2546,14 +2539,15 @@ class DefaultListableBeanFactoryTests {
|
||||
factory.registerBeanDefinition("child", child);
|
||||
|
||||
AbstractBeanDefinition def = (AbstractBeanDefinition) factory.getBeanDefinition("child");
|
||||
Object mergedBeanDefinition2 = def.getScope();
|
||||
assertThat(mergedBeanDefinition2).as("Child 'scope' not overriding parent scope (it must).").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(def.getScope()).as("Child 'scope' not overriding parent scope (it must).").isEqualTo(theChildScope);
|
||||
}
|
||||
|
||||
@Test
|
||||
void scopeInheritanceForChildBeanDefinitions() {
|
||||
String theParentScope = "bonanza!";
|
||||
|
||||
RootBeanDefinition parent = new RootBeanDefinition();
|
||||
parent.setScope("bonanza!");
|
||||
parent.setScope(theParentScope);
|
||||
|
||||
AbstractBeanDefinition child = new ChildBeanDefinition("parent");
|
||||
child.setBeanClass(TestBean.class);
|
||||
@@ -2563,8 +2557,7 @@ class DefaultListableBeanFactoryTests {
|
||||
factory.registerBeanDefinition("child", child);
|
||||
|
||||
BeanDefinition def = factory.getMergedBeanDefinition("child");
|
||||
Object mergedBeanDefinition2 = def.getScope();
|
||||
assertThat(mergedBeanDefinition2).as("Child 'scope' not inherited").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(def.getScope()).as("Child 'scope' not inherited").isEqualTo(theParentScope);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2600,15 +2593,12 @@ class DefaultListableBeanFactoryTests {
|
||||
});
|
||||
lbf.preInstantiateSingletons();
|
||||
TestBean tb = (TestBean) lbf.getBean("test");
|
||||
Object mergedBeanDefinition2 = tb.getName();
|
||||
assertThat(mergedBeanDefinition2).as("Name was set on field by IAPP").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(tb.getName()).as("Name was set on field by IAPP").isEqualTo(nameSetOnField);
|
||||
if (!skipPropertyPopulation) {
|
||||
Object mergedBeanDefinition21 = tb.getAge();
|
||||
assertThat(mergedBeanDefinition21).as("Property value still set").isEqualTo(mergedBeanDefinition21);
|
||||
assertThat(tb.getAge()).as("Property value still set").isEqualTo(ageSetByPropertyValue);
|
||||
}
|
||||
else {
|
||||
Object mergedBeanDefinition21 = tb.getAge();
|
||||
assertThat(mergedBeanDefinition21).as("Property value was NOT set and still has default value").isEqualTo(mergedBeanDefinition21);
|
||||
assertThat(tb.getAge()).as("Property value was NOT set and still has default value").isEqualTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+193
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -297,6 +297,121 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalResourceInjectionWithSingletonRemoval() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(OptionalResourceInjectionBean.class);
|
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", rbd);
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
IndexedTestBean itb = new IndexedTestBean();
|
||||
bf.registerSingleton("indexedTestBean", itb);
|
||||
NestedTestBean ntb1 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean1", ntb1);
|
||||
NestedTestBean ntb2 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
|
||||
bf.destroySingleton("testBean");
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
assertThat(bean.getTestBean4()).isNull();
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
|
||||
bf.registerSingleton("testBean", tb);
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalResourceInjectionWithBeanDefinitionRemoval() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(OptionalResourceInjectionBean.class);
|
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", rbd);
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
IndexedTestBean itb = new IndexedTestBean();
|
||||
bf.registerSingleton("indexedTestBean", itb);
|
||||
NestedTestBean ntb1 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean1", ntb1);
|
||||
NestedTestBean ntb2 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean4()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
|
||||
bf.removeBeanDefinition("testBean");
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
assertThat(bean.getTestBean4()).isNull();
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean4()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalCollectionResourceInjection() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(OptionalCollectionResourceInjectionBean.class);
|
||||
@@ -533,6 +648,83 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorResourceInjectionWithSingletonRemoval() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class);
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
NestedTestBean ntb = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bf.destroySingleton("nestedTestBean");
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isNull();
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorResourceInjectionWithBeanDefinitionRemoval() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class);
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NestedTestBean.class));
|
||||
|
||||
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(bf.getBean("nestedTestBean"));
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bf.removeBeanDefinition("nestedTestBean");
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isNull();
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NestedTestBean.class));
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(bf.getBean("nestedTestBean"));
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorResourceInjectionWithNullFromFactoryBean() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class);
|
||||
|
||||
+27
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,9 +17,11 @@
|
||||
package org.springframework.beans.factory.config;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.yaml.snakeyaml.constructor.ConstructorException;
|
||||
@@ -28,7 +30,6 @@ import org.yaml.snakeyaml.scanner.ScannerException;
|
||||
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
@@ -39,10 +40,12 @@ import static org.assertj.core.api.Assertions.entry;
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class YamlProcessorTests {
|
||||
|
||||
private final YamlProcessor processor = new YamlProcessor() {};
|
||||
private final YamlProcessor processor = new YamlProcessor() {
|
||||
};
|
||||
|
||||
|
||||
@Test
|
||||
@@ -79,8 +82,8 @@ class YamlProcessorTests {
|
||||
void badResource() {
|
||||
setYaml("foo: bar\ncd\nspam:\n foo: baz");
|
||||
assertThatExceptionOfType(ScannerException.class)
|
||||
.isThrownBy(() -> this.processor.process((properties, map) -> {}))
|
||||
.withMessageContaining("line 3, column 1");
|
||||
.isThrownBy(() -> this.processor.process((properties, map) -> {}))
|
||||
.withMessageContaining("line 3, column 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -127,8 +130,8 @@ class YamlProcessorTests {
|
||||
Map<String, Object> bar = (Map<String, Object>) map.get("bar");
|
||||
assertThat(bar.get("spam")).isEqualTo("bucket");
|
||||
|
||||
List<Object> keysFromProperties = properties.keySet().stream().collect(toList());
|
||||
List<String> keysFromFlattenedMap = flattenedMap.keySet().stream().collect(toList());
|
||||
List<Object> keysFromProperties = new ArrayList<>(properties.keySet());
|
||||
List<String> keysFromFlattenedMap = new ArrayList<>(flattenedMap.keySet());
|
||||
assertThat(keysFromProperties).containsExactlyInAnyOrderElementsOf(keysFromFlattenedMap);
|
||||
// Keys in the Properties object are sorted.
|
||||
assertThat(keysFromProperties).containsExactly("bar.spam", "cat", "foo");
|
||||
@@ -138,14 +141,23 @@ class YamlProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void customTypeSupportedByDefault() throws Exception {
|
||||
void standardTypesSupportedByDefault() throws Exception {
|
||||
setYaml("value: !!set\n ? first\n ? second");
|
||||
this.processor.process((properties, map) -> {
|
||||
assertThat(properties).containsExactly(entry("value[0]", "first"), entry("value[1]", "second"));
|
||||
assertThat(map.get("value")).isInstanceOf(Set.class);
|
||||
Set<String> set = (Set<String>) map.get("value");
|
||||
assertThat(set).containsExactly("first", "second");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customTypeNotSupportedByDefault() throws Exception {
|
||||
URL url = new URL("https://localhost:9000/");
|
||||
setYaml("value: !!java.net.URL [\"" + url + "\"]");
|
||||
|
||||
this.processor.process((properties, map) -> {
|
||||
assertThat(properties).containsExactly(entry("value", url));
|
||||
assertThat(map).containsExactly(entry("value", url));
|
||||
});
|
||||
assertThatExceptionOfType(ConstructorException.class)
|
||||
.isThrownBy(() -> this.processor.process((properties, map) -> {}))
|
||||
.withMessageContaining("Unsupported type encountered in YAML document: java.net.URL");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -168,8 +180,8 @@ class YamlProcessorTests {
|
||||
setYaml("value: !!java.net.URL [\"https://localhost:9000/\"]");
|
||||
|
||||
assertThatExceptionOfType(ConstructorException.class)
|
||||
.isThrownBy(() -> this.processor.process((properties, map) -> {}))
|
||||
.withMessageContaining("Unsupported type encountered in YAML document: java.net.URL");
|
||||
.isThrownBy(() -> this.processor.process((properties, map) -> {}))
|
||||
.withMessageContaining("Unsupported type encountered in YAML document: java.net.URL");
|
||||
}
|
||||
|
||||
private void setYaml(String yaml) {
|
||||
|
||||
+11
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -133,6 +133,16 @@ public class BeanDefinitionTests {
|
||||
assertThat(bd.equals(otherBd)).isTrue();
|
||||
assertThat(otherBd.equals(bd)).isTrue();
|
||||
assertThat(bd.hashCode() == otherBd.hashCode()).isTrue();
|
||||
|
||||
bd.getPropertyValues();
|
||||
assertThat(bd.equals(otherBd)).isTrue();
|
||||
assertThat(otherBd.equals(bd)).isTrue();
|
||||
assertThat(bd.hashCode() == otherBd.hashCode()).isTrue();
|
||||
|
||||
bd.getConstructorArgumentValues();
|
||||
assertThat(bd.equals(otherBd)).isTrue();
|
||||
assertThat(otherBd.equals(bd)).isTrue();
|
||||
assertThat(bd.hashCode() == otherBd.hashCode()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -126,7 +126,7 @@ public class DefinitionMetadataEqualsHashCodeTests {
|
||||
assertThat(equal.hashCode()).as("Hash code for equal instances should match").isEqualTo(master.hashCode());
|
||||
|
||||
assertThat(notEqual).as("Should not be equal").isNotEqualTo(master);
|
||||
assertThat(notEqual.hashCode()).as("Hash code for non-equal instances should not match").isNotEqualTo((long) master.hashCode());
|
||||
assertThat(notEqual.hashCode()).as("Hash code for non-equal instances should not match").isNotEqualTo(master.hashCode());
|
||||
|
||||
assertThat(subclass).as("Subclass should be equal").isEqualTo(master);
|
||||
assertThat(subclass.hashCode()).as("Hash code for subclass should match").isEqualTo(master.hashCode());
|
||||
|
||||
+8
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,7 +31,8 @@ import org.springframework.core.annotation.AliasFor;
|
||||
*
|
||||
* <p>In contrast to the {@link Cacheable @Cacheable} annotation, this annotation
|
||||
* does not cause the advised method to be skipped. Rather, it always causes the
|
||||
* method to be invoked and its result to be stored in the associated cache. Note
|
||||
* method to be invoked and its result to be stored in the associated cache if the
|
||||
* {@link #condition()} and {@link #unless()} expressions match accordingly. Note
|
||||
* that Java8's {@code Optional} return types are automatically handled and its
|
||||
* content is stored in the cache if present.
|
||||
*
|
||||
@@ -118,10 +119,15 @@ public @interface CachePut {
|
||||
/**
|
||||
* Spring Expression Language (SpEL) expression used for making the cache
|
||||
* put operation conditional.
|
||||
* <p>This expression is evaluated after the method has been called due to the
|
||||
* nature of the put operation and can therefore refer to the {@code result}.
|
||||
* <p>Default is {@code ""}, meaning the method result is always cached.
|
||||
* <p>The SpEL expression evaluates against a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #result} for a reference to the result of the method invocation. For
|
||||
* supported wrappers such as {@code Optional}, {@code #result} refers to the actual
|
||||
* object, not the wrapper</li>
|
||||
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
|
||||
* references to the {@link java.lang.reflect.Method method}, target object, and
|
||||
* affected cache(s) respectively.</li>
|
||||
@@ -136,8 +142,6 @@ public @interface CachePut {
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) expression used to veto the cache put operation.
|
||||
* <p>Unlike {@link #condition}, this expression is evaluated after the method
|
||||
* has been called and can therefore refer to the {@code result}.
|
||||
* <p>Default is {@code ""}, meaning that caching is never vetoed.
|
||||
* <p>The SpEL expression evaluates against a dedicated context that provides the
|
||||
* following meta-data:
|
||||
|
||||
+1
-2
@@ -155,8 +155,7 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
|
||||
* @param name the name of the cache to be added
|
||||
*/
|
||||
private void updateCacheNames(String name) {
|
||||
Set<String> cacheNames = new LinkedHashSet<>(this.cacheNames.size() + 1);
|
||||
cacheNames.addAll(this.cacheNames);
|
||||
Set<String> cacheNames = new LinkedHashSet<>(this.cacheNames);
|
||||
cacheNames.add(name);
|
||||
this.cacheNames = Collections.unmodifiableSet(cacheNames);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.context;
|
||||
|
||||
import java.util.EventListener;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by application event listeners.
|
||||
@@ -45,4 +46,17 @@ public interface ApplicationListener<E extends ApplicationEvent> extends EventLi
|
||||
*/
|
||||
void onApplicationEvent(E event);
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code ApplicationListener} for the given payload consumer.
|
||||
* @param consumer the event payload consumer
|
||||
* @param <T> the type of the event payload
|
||||
* @return a corresponding {@code ApplicationListener} instance
|
||||
* @since 5.3
|
||||
* @see PayloadApplicationEvent
|
||||
*/
|
||||
static <T> ApplicationListener<PayloadApplicationEvent<T>> forPayload(Consumer<T> consumer) {
|
||||
return event -> consumer.accept(event.getPayload());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.context;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.ResolvableTypeProvider;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -23,11 +25,12 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* An {@link ApplicationEvent} that carries an arbitrary payload.
|
||||
*
|
||||
* <p>Mainly intended for internal use within the framework.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
* @param <T> the payload type of the event
|
||||
* @see ApplicationEventPublisher#publishEvent(Object)
|
||||
* @see ApplicationListener#forPayload(Consumer)
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class PayloadApplicationEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,10 +26,10 @@ import org.springframework.core.io.ResourceLoader;
|
||||
* the {@link org.springframework.context.ApplicationContextAware} interface.
|
||||
*
|
||||
* <p>Note that {@link org.springframework.core.io.Resource} dependencies can also
|
||||
* be exposed as bean properties of type {@code Resource}, populated via Strings
|
||||
* with automatic type conversion by the bean factory. This removes the need for
|
||||
* implementing any callback interface just for the purpose of accessing a
|
||||
* specific file resource.
|
||||
* be exposed as bean properties of type {@code Resource} or {@code Resource[]},
|
||||
* populated via Strings with automatic type conversion by the bean factory. This
|
||||
* removes the need for implementing any callback interface just for the purpose
|
||||
* of accessing specific file resources.
|
||||
*
|
||||
* <p>You typically need a {@link ResourceLoader} when your application object has to
|
||||
* access a variety of file resources whose names are calculated. A good strategy is
|
||||
@@ -48,7 +48,7 @@ import org.springframework.core.io.ResourceLoader;
|
||||
* default; see also the {@code ResourcePatternUtils.getResourcePatternResolver} method.
|
||||
*
|
||||
* <p>As an alternative to a {@code ResourcePatternResolver} dependency, consider
|
||||
* exposing bean properties of type {@code Resource} array, populated via pattern
|
||||
* exposing bean properties of type {@code Resource[]} array, populated via pattern
|
||||
* Strings with automatic type conversion by the bean factory at binding time.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
|
||||
+4
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -52,6 +52,7 @@ import org.springframework.context.ApplicationStartupAware;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration;
|
||||
import org.springframework.core.NativeDetector;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.env.Environment;
|
||||
@@ -99,18 +100,11 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
* @see #setBeanNameGenerator
|
||||
*/
|
||||
public static final AnnotationBeanNameGenerator IMPORT_BEAN_NAME_GENERATOR =
|
||||
new FullyQualifiedAnnotationBeanNameGenerator();
|
||||
FullyQualifiedAnnotationBeanNameGenerator.INSTANCE;
|
||||
|
||||
private static final String IMPORT_REGISTRY_BEAN_NAME =
|
||||
ConfigurationClassPostProcessor.class.getName() + ".importRegistry";
|
||||
|
||||
/**
|
||||
* Whether this environment lives within a native image.
|
||||
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
|
||||
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
|
||||
*/
|
||||
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
|
||||
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@@ -427,15 +421,11 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
|
||||
}
|
||||
}
|
||||
if (configBeanDefs.isEmpty()) {
|
||||
if (configBeanDefs.isEmpty() || NativeDetector.inNativeImage()) {
|
||||
// nothing to enhance -> return immediately
|
||||
enhanceConfigClasses.end();
|
||||
return;
|
||||
}
|
||||
if (IN_NATIVE_IMAGE) {
|
||||
throw new BeanDefinitionStoreException("@Configuration classes need to be marked as " +
|
||||
"proxyBeanMethods=false. Found: " + configBeanDefs.keySet());
|
||||
}
|
||||
|
||||
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
|
||||
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
|
||||
|
||||
+9
@@ -43,6 +43,15 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class FullyQualifiedAnnotationBeanNameGenerator extends AnnotationBeanNameGenerator {
|
||||
|
||||
/**
|
||||
* A convenient constant for a default {@code FullyQualifiedAnnotationBeanNameGenerator}
|
||||
* instance, as used for configuration-level import purposes.
|
||||
* @since 5.2.11
|
||||
*/
|
||||
public static final FullyQualifiedAnnotationBeanNameGenerator INSTANCE =
|
||||
new FullyQualifiedAnnotationBeanNameGenerator();
|
||||
|
||||
|
||||
@Override
|
||||
protected String buildDefaultBeanName(BeanDefinition definition) {
|
||||
String beanClassName = definition.getBeanClassName();
|
||||
|
||||
+16
-1
@@ -37,6 +37,7 @@ import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.PayloadApplicationEvent;
|
||||
import org.springframework.context.expression.AnnotatedElementKey;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.ReactiveAdapter;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.core.ResolvableType;
|
||||
@@ -95,6 +96,12 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
||||
private EventExpressionEvaluator evaluator;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new ApplicationListenerMethodAdapter.
|
||||
* @param beanName the name of the bean to invoke the listener method on
|
||||
* @param targetClass the target class that the method is declared on
|
||||
* @param method the listener method to invoke
|
||||
*/
|
||||
public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) {
|
||||
this.beanName = beanName;
|
||||
this.method = BridgeMethodResolver.findBridgedMethod(method);
|
||||
@@ -135,7 +142,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
||||
|
||||
private static int resolveOrder(Method method) {
|
||||
Order ann = AnnotatedElementUtils.findMergedAnnotation(method, Order.class);
|
||||
return (ann != null ? ann.value() : 0);
|
||||
return (ann != null ? ann.value() : Ordered.LOWEST_PRECEDENCE);
|
||||
}
|
||||
|
||||
|
||||
@@ -332,6 +339,14 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
||||
return this.applicationContext.getBean(this.beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the target listener method.
|
||||
* @since 5.3
|
||||
*/
|
||||
protected Method getTargetMethod() {
|
||||
return this.targetMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the condition to use.
|
||||
* <p>Matches the {@code condition} attribute of the {@link EventListener}
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,6 +29,7 @@ import org.springframework.core.Ordered;
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.2
|
||||
* @see ApplicationListenerMethodAdapter
|
||||
*/
|
||||
public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {
|
||||
|
||||
|
||||
+14
-35
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,9 +24,8 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.PayloadApplicationEvent;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.metrics.ApplicationStartup;
|
||||
import org.springframework.core.metrics.StartupStep;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ErrorHandler;
|
||||
|
||||
@@ -58,7 +57,7 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
|
||||
private ErrorHandler errorHandler;
|
||||
|
||||
@Nullable
|
||||
private ApplicationStartup applicationStartup;
|
||||
private volatile Log lazyLogger;
|
||||
|
||||
|
||||
/**
|
||||
@@ -127,22 +126,6 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
|
||||
return this.errorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ApplicationStartup} to track event listener invocations during startup.
|
||||
* @since 5.3
|
||||
*/
|
||||
public void setApplicationStartup(@Nullable ApplicationStartup applicationStartup) {
|
||||
this.applicationStartup = applicationStartup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current application startup for this multicaster.
|
||||
*/
|
||||
@Nullable
|
||||
public ApplicationStartup getApplicationStartup() {
|
||||
return this.applicationStartup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void multicastEvent(ApplicationEvent event) {
|
||||
multicastEvent(event, resolveDefaultEventType(event));
|
||||
@@ -156,16 +139,6 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
|
||||
if (executor != null) {
|
||||
executor.execute(() -> invokeListener(listener, event));
|
||||
}
|
||||
else if (this.applicationStartup != null) {
|
||||
StartupStep invocationStep = this.applicationStartup.start("spring.event.invoke-listener");
|
||||
invokeListener(listener, event);
|
||||
invocationStep.tag("event", event::toString);
|
||||
if (eventType != null) {
|
||||
invocationStep.tag("eventType", eventType::toString);
|
||||
}
|
||||
invocationStep.tag("listener", listener::toString);
|
||||
invocationStep.end();
|
||||
}
|
||||
else {
|
||||
invokeListener(listener, event);
|
||||
}
|
||||
@@ -204,12 +177,18 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
|
||||
}
|
||||
catch (ClassCastException ex) {
|
||||
String msg = ex.getMessage();
|
||||
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
|
||||
if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
|
||||
(event instanceof PayloadApplicationEvent &&
|
||||
matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
|
||||
// Possibly a lambda-defined listener which we could not resolve the generic event type for
|
||||
// -> let's suppress the exception and just log a debug message.
|
||||
Log logger = LogFactory.getLog(getClass());
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Non-matching event type for listener: " + listener, ex);
|
||||
// -> let's suppress the exception.
|
||||
Log loggerToUse = this.lazyLogger;
|
||||
if (loggerToUse == null) {
|
||||
loggerToUse = LogFactory.getLog(getClass());
|
||||
this.lazyLogger = loggerToUse;
|
||||
}
|
||||
if (loggerToUse.isTraceEnabled()) {
|
||||
loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
+7
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -66,6 +66,7 @@ import org.springframework.context.event.SimpleApplicationEventMulticaster;
|
||||
import org.springframework.context.expression.StandardBeanExpressionResolver;
|
||||
import org.springframework.context.weaving.LoadTimeWeaverAware;
|
||||
import org.springframework.context.weaving.LoadTimeWeaverAwareProcessor;
|
||||
import org.springframework.core.NativeDetector;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.SpringProperties;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
@@ -164,13 +165,6 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
*/
|
||||
private static final boolean shouldIgnoreSpel = SpringProperties.getFlag("spring.spel.ignore");
|
||||
|
||||
/**
|
||||
* Whether this environment lives within a native image.
|
||||
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
|
||||
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
|
||||
*/
|
||||
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
|
||||
|
||||
|
||||
static {
|
||||
// Eagerly load the ContextClosedEvent class to avoid weird classloader issues
|
||||
@@ -711,7 +705,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
|
||||
|
||||
// Detect a LoadTimeWeaver and prepare for weaving, if found.
|
||||
if (!IN_NATIVE_IMAGE && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
|
||||
if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
|
||||
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
|
||||
// Set a temporary ClassLoader for type matching.
|
||||
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
|
||||
@@ -752,7 +746,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
|
||||
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
|
||||
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
|
||||
if (!IN_NATIVE_IMAGE && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
|
||||
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
|
||||
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
|
||||
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
|
||||
}
|
||||
@@ -815,9 +809,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
}
|
||||
}
|
||||
else {
|
||||
SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
|
||||
simpleApplicationEventMulticaster.setApplicationStartup(getApplicationStartup());
|
||||
this.applicationEventMulticaster = simpleApplicationEventMulticaster;
|
||||
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
|
||||
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
|
||||
@@ -945,7 +937,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
publishEvent(new ContextRefreshedEvent(this));
|
||||
|
||||
// Participate in LiveBeansView MBean, if active.
|
||||
if (!IN_NATIVE_IMAGE) {
|
||||
if (!NativeDetector.inNativeImage()) {
|
||||
LiveBeansView.registerApplicationContext(this);
|
||||
}
|
||||
}
|
||||
@@ -1056,7 +1048,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
logger.debug("Closing " + this);
|
||||
}
|
||||
|
||||
if (!IN_NATIVE_IMAGE) {
|
||||
if (!NativeDetector.inNativeImage()) {
|
||||
LiveBeansView.unregisterApplicationContext(this);
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.context.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -74,6 +75,11 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
|
||||
return (clazz.getClassLoader() instanceof ContextOverridingClassLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> publicDefineClass(String name, byte[] b, @Nullable ProtectionDomain protectionDomain) {
|
||||
return defineClass(name, b, 0, b.length, protectionDomain);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ClassLoader to be created for each loaded class.
|
||||
|
||||
+27
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,6 +59,19 @@ final class PostProcessorRegistrationDelegate {
|
||||
public static void invokeBeanFactoryPostProcessors(
|
||||
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
|
||||
|
||||
// WARNING: Although it may appear that the body of this method can be easily
|
||||
// refactored to avoid the use of multiple loops and multiple lists, the use
|
||||
// of multiple lists and multiple passes over the names of processors is
|
||||
// intentional. We must ensure that we honor the contracts for PriorityOrdered
|
||||
// and Ordered processors. Specifically, we must NOT cause processors to be
|
||||
// instantiated (via getBean() invocations) or registered in the ApplicationContext
|
||||
// in the wrong order.
|
||||
//
|
||||
// Before submitting a pull request (PR) to change this method, please review the
|
||||
// list of all declined PRs involving changes to PostProcessorRegistrationDelegate
|
||||
// to ensure that your proposal does not result in a breaking change:
|
||||
// https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
|
||||
|
||||
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
|
||||
Set<String> processedBeans = new HashSet<>();
|
||||
|
||||
@@ -192,6 +205,19 @@ final class PostProcessorRegistrationDelegate {
|
||||
public static void registerBeanPostProcessors(
|
||||
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
|
||||
|
||||
// WARNING: Although it may appear that the body of this method can be easily
|
||||
// refactored to avoid the use of multiple loops and multiple lists, the use
|
||||
// of multiple lists and multiple passes over the names of processors is
|
||||
// intentional. We must ensure that we honor the contracts for PriorityOrdered
|
||||
// and Ordered processors. Specifically, we must NOT cause processors to be
|
||||
// instantiated (via getBean() invocations) or registered in the ApplicationContext
|
||||
// in the wrong order.
|
||||
//
|
||||
// Before submitting a pull request (PR) to change this method, please review the
|
||||
// list of all declined PRs involving changes to PostProcessorRegistrationDelegate
|
||||
// to ensure that your proposal does not result in a breaking change:
|
||||
// https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
|
||||
|
||||
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
|
||||
|
||||
// Register BeanPostProcessorChecker that logs an info message when
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -106,7 +106,6 @@ public @interface DateTimeFormat {
|
||||
/**
|
||||
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSXXX},
|
||||
* e.g. "2000-10-31T01:30:00.000-05:00".
|
||||
* <p>This is the default if no annotation value is specified.
|
||||
*/
|
||||
DATE_TIME,
|
||||
|
||||
|
||||
+3
-4
@@ -19,14 +19,13 @@ package org.springframework.scheduling.support;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Efficient {@link BitSet}-based extension of {@link CronField}.
|
||||
* Efficient bitwise-operator extension of {@link CronField}.
|
||||
* Created using the {@code parse*} methods.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
@@ -130,8 +129,8 @@ final class BitsCronField extends CronField {
|
||||
result.setBits(range);
|
||||
}
|
||||
else {
|
||||
String rangeStr = value.substring(0, slashPos);
|
||||
String deltaStr = value.substring(slashPos + 1);
|
||||
String rangeStr = field.substring(0, slashPos);
|
||||
String deltaStr = field.substring(slashPos + 1);
|
||||
ValueRange range = parseRange(rangeStr, type);
|
||||
if (rangeStr.indexOf('-') == -1) {
|
||||
range = ValueRange.of(range.getMinimum(), type.range().getMaximum());
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.scheduling.support;
|
||||
|
||||
import java.time.temporal.Temporal;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Extension of {@link CronField} that wraps an array of cron fields.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.3.3
|
||||
*/
|
||||
final class CompositeCronField extends CronField {
|
||||
|
||||
private final CronField[] fields;
|
||||
|
||||
private final String value;
|
||||
|
||||
|
||||
private CompositeCronField(Type type, CronField[] fields, String value) {
|
||||
super(type);
|
||||
this.fields = fields;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Composes the given fields into a {@link CronField}.
|
||||
*/
|
||||
public static CronField compose(CronField[] fields, Type type, String value) {
|
||||
Assert.notEmpty(fields, "Fields must not be empty");
|
||||
Assert.hasLength(value, "Value must not be empty");
|
||||
|
||||
if (fields.length == 1) {
|
||||
return fields[0];
|
||||
}
|
||||
else {
|
||||
return new CompositeCronField(type, fields, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T extends Temporal & Comparable<? super T>> T nextOrSame(T temporal) {
|
||||
T result = null;
|
||||
for (CronField field : this.fields) {
|
||||
T candidate = field.nextOrSame(temporal);
|
||||
if (result == null ||
|
||||
candidate != null && candidate.compareTo(result) < 0) {
|
||||
result = candidate;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof CompositeCronField)) {
|
||||
return false;
|
||||
}
|
||||
CompositeCronField other = (CompositeCronField) o;
|
||||
return type() == other.type() &&
|
||||
this.value.equals(other.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type() + " '" + this.value + "'";
|
||||
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,10 @@ import java.time.DateTimeException;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -77,11 +79,18 @@ abstract class CronField {
|
||||
* Parse the given value into a days of months {@code CronField}, the fourth entry of a cron expression.
|
||||
*/
|
||||
public static CronField parseDaysOfMonth(String value) {
|
||||
if (value.contains("L") || value.contains("W")) {
|
||||
return QuartzCronField.parseDaysOfMonth(value);
|
||||
if (!QuartzCronField.isQuartzDaysOfMonthField(value)) {
|
||||
return BitsCronField.parseDaysOfMonth(value);
|
||||
}
|
||||
else {
|
||||
return BitsCronField.parseDaysOfMonth(value);
|
||||
return parseList(value, Type.DAY_OF_MONTH, (field, type) -> {
|
||||
if (QuartzCronField.isQuartzDaysOfMonthField(field)) {
|
||||
return QuartzCronField.parseDaysOfMonth(field);
|
||||
}
|
||||
else {
|
||||
return BitsCronField.parseDaysOfMonth(field);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,15 +107,32 @@ abstract class CronField {
|
||||
*/
|
||||
public static CronField parseDaysOfWeek(String value) {
|
||||
value = replaceOrdinals(value, DAYS);
|
||||
if (value.contains("L") || value.contains("#")) {
|
||||
return QuartzCronField.parseDaysOfWeek(value);
|
||||
if (!QuartzCronField.isQuartzDaysOfWeekField(value)) {
|
||||
return BitsCronField.parseDaysOfWeek(value);
|
||||
}
|
||||
else {
|
||||
return BitsCronField.parseDaysOfWeek(value);
|
||||
return parseList(value, Type.DAY_OF_WEEK, (field, type) -> {
|
||||
if (QuartzCronField.isQuartzDaysOfWeekField(field)) {
|
||||
return QuartzCronField.parseDaysOfWeek(field);
|
||||
}
|
||||
else {
|
||||
return BitsCronField.parseDaysOfWeek(field);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static CronField parseList(String value, Type type, BiFunction<String, Type, CronField> parseFieldFunction) {
|
||||
Assert.hasLength(value, "Value must not be empty");
|
||||
String[] fields = StringUtils.delimitedListToStringArray(value, ",");
|
||||
CronField[] cronFields = new CronField[fields.length];
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
cronFields[i] = parseFieldFunction.apply(fields[i], type);
|
||||
}
|
||||
return CompositeCronField.compose(cronFields, type, value);
|
||||
}
|
||||
|
||||
private static String replaceOrdinals(String value, String[] list) {
|
||||
value = value.toUpperCase();
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
|
||||
+111
-25
@@ -38,24 +38,6 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
final class QuartzCronField extends CronField {
|
||||
|
||||
/**
|
||||
* Temporal adjuster that returns the last weekday of the month.
|
||||
*/
|
||||
private static final TemporalAdjuster lastWeekdayOfMonth = temporal -> {
|
||||
Temporal lastDayOfMonth = TemporalAdjusters.lastDayOfMonth().adjustInto(temporal);
|
||||
int dayOfWeek = lastDayOfMonth.get(ChronoField.DAY_OF_WEEK);
|
||||
if (dayOfWeek == 6) { // Saturday
|
||||
return lastDayOfMonth.minus(1, ChronoUnit.DAYS);
|
||||
}
|
||||
else if (dayOfWeek == 7) { // Sunday
|
||||
return lastDayOfMonth.minus(2, ChronoUnit.DAYS);
|
||||
}
|
||||
else {
|
||||
return lastDayOfMonth;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private final Type rollForwardType;
|
||||
|
||||
private final TemporalAdjuster adjuster;
|
||||
@@ -78,6 +60,12 @@ final class QuartzCronField extends CronField {
|
||||
this.rollForwardType = rollForwardType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given value is a Quartz day-of-month field.
|
||||
*/
|
||||
public static boolean isQuartzDaysOfMonthField(String value) {
|
||||
return value.contains("L") || value.contains("W");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given value into a days of months {@code QuartzCronField}, the fourth entry of a cron expression.
|
||||
@@ -91,11 +79,11 @@ final class QuartzCronField extends CronField {
|
||||
throw new IllegalArgumentException("Unrecognized characters before 'L' in '" + value + "'");
|
||||
}
|
||||
else if (value.length() == 2 && value.charAt(1) == 'W') { // "LW"
|
||||
adjuster = lastWeekdayOfMonth;
|
||||
adjuster = lastWeekdayOfMonth();
|
||||
}
|
||||
else {
|
||||
if (value.length() == 1) { // "L"
|
||||
adjuster = TemporalAdjusters.lastDayOfMonth();
|
||||
adjuster = lastDayOfMonth();
|
||||
}
|
||||
else { // "L-[0-9]+"
|
||||
int offset = Integer.parseInt(value.substring(idx + 1));
|
||||
@@ -125,6 +113,13 @@ final class QuartzCronField extends CronField {
|
||||
throw new IllegalArgumentException("No 'L' or 'W' found in '" + value + "'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given value is a Quartz day-of-week field.
|
||||
*/
|
||||
public static boolean isQuartzDaysOfWeekField(String value) {
|
||||
return value.contains("L") || value.contains("#");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given value into a days of week {@code QuartzCronField}, the sixth entry of a cron expression.
|
||||
* Expects a "L" or "#" in the given value.
|
||||
@@ -142,7 +137,7 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
else { // "[0-7]L"
|
||||
DayOfWeek dayOfWeek = parseDayOfWeek(value.substring(0, idx));
|
||||
adjuster = TemporalAdjusters.lastInMonth(dayOfWeek);
|
||||
adjuster = lastInMonth(dayOfWeek);
|
||||
}
|
||||
return new QuartzCronField(Type.DAY_OF_WEEK, Type.DAY_OF_MONTH, adjuster, value);
|
||||
}
|
||||
@@ -158,14 +153,17 @@ final class QuartzCronField extends CronField {
|
||||
// "[0-7]#[0-9]+"
|
||||
DayOfWeek dayOfWeek = parseDayOfWeek(value.substring(0, idx));
|
||||
int ordinal = Integer.parseInt(value.substring(idx + 1));
|
||||
if (ordinal <= 0) {
|
||||
throw new IllegalArgumentException("Ordinal '" + ordinal + "' in '" + value +
|
||||
"' must be positive number ");
|
||||
}
|
||||
|
||||
TemporalAdjuster adjuster = TemporalAdjusters.dayOfWeekInMonth(ordinal, dayOfWeek);
|
||||
TemporalAdjuster adjuster = dayOfWeekInMonth(ordinal, dayOfWeek);
|
||||
return new QuartzCronField(Type.DAY_OF_WEEK, Type.DAY_OF_MONTH, adjuster, value);
|
||||
}
|
||||
throw new IllegalArgumentException("No 'L' or '#' found in '" + value + "'");
|
||||
}
|
||||
|
||||
|
||||
private static DayOfWeek parseDayOfWeek(String value) {
|
||||
int dayOfWeek = Integer.parseInt(value);
|
||||
if (dayOfWeek == 0) {
|
||||
@@ -180,6 +178,54 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an adjuster that resets to midnight.
|
||||
*/
|
||||
private static TemporalAdjuster atMidnight() {
|
||||
return temporal -> {
|
||||
if (temporal.isSupported(ChronoField.NANO_OF_DAY)) {
|
||||
return temporal.with(ChronoField.NANO_OF_DAY, 0);
|
||||
}
|
||||
else {
|
||||
return temporal;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an adjuster that returns a new temporal set to the last
|
||||
* day of the current month at midnight.
|
||||
*/
|
||||
private static TemporalAdjuster lastDayOfMonth() {
|
||||
TemporalAdjuster adjuster = TemporalAdjusters.lastDayOfMonth();
|
||||
return temporal -> {
|
||||
Temporal result = adjuster.adjustInto(temporal);
|
||||
return rollbackToMidnight(temporal, result);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an adjuster that returns the last weekday of the month.
|
||||
*/
|
||||
private static TemporalAdjuster lastWeekdayOfMonth() {
|
||||
TemporalAdjuster adjuster = TemporalAdjusters.lastDayOfMonth();
|
||||
return temporal -> {
|
||||
Temporal lastDom = adjuster.adjustInto(temporal);
|
||||
Temporal result;
|
||||
int dow = lastDom.get(ChronoField.DAY_OF_WEEK);
|
||||
if (dow == 6) { // Saturday
|
||||
result = lastDom.minus(1, ChronoUnit.DAYS);
|
||||
}
|
||||
else if (dow == 7) { // Sunday
|
||||
result = lastDom.minus(2, ChronoUnit.DAYS);
|
||||
}
|
||||
else {
|
||||
result = lastDom;
|
||||
}
|
||||
return rollbackToMidnight(temporal, result);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a temporal adjuster that finds the nth-to-last day of the month.
|
||||
* @param offset the negative offset, i.e. -3 means third-to-last
|
||||
@@ -187,9 +233,10 @@ final class QuartzCronField extends CronField {
|
||||
*/
|
||||
private static TemporalAdjuster lastDayWithOffset(int offset) {
|
||||
Assert.isTrue(offset < 0, "Offset should be < 0");
|
||||
TemporalAdjuster adjuster = TemporalAdjusters.lastDayOfMonth();
|
||||
return temporal -> {
|
||||
Temporal lastDayOfMonth = TemporalAdjusters.lastDayOfMonth().adjustInto(temporal);
|
||||
return lastDayOfMonth.plus(offset, ChronoUnit.DAYS);
|
||||
Temporal result = adjuster.adjustInto(temporal).plus(offset, ChronoUnit.DAYS);
|
||||
return rollbackToMidnight(temporal, result);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -215,6 +262,7 @@ final class QuartzCronField extends CronField {
|
||||
int count = 0;
|
||||
while (count++ < CronExpression.MAX_ATTEMPTS) {
|
||||
temporal = Type.DAY_OF_MONTH.elapseUntil(cast(temporal), dayOfMonth);
|
||||
temporal = atMidnight().adjustInto(temporal);
|
||||
current = Type.DAY_OF_MONTH.get(temporal);
|
||||
if (current == dayOfMonth) {
|
||||
dayOfWeek = temporal.get(ChronoField.DAY_OF_WEEK);
|
||||
@@ -240,6 +288,44 @@ final class QuartzCronField extends CronField {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a temporal adjuster that finds the last of the given doy-of-week
|
||||
* in a month.
|
||||
*/
|
||||
private static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) {
|
||||
TemporalAdjuster adjuster = TemporalAdjusters.lastInMonth(dayOfWeek);
|
||||
return temporal -> {
|
||||
Temporal result = adjuster.adjustInto(temporal);
|
||||
return rollbackToMidnight(temporal, result);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a temporal adjuster that finds {@code ordinal}-th occurrence of
|
||||
* the given day-of-week in a month.
|
||||
*/
|
||||
private static TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) {
|
||||
TemporalAdjuster adjuster = TemporalAdjusters.dayOfWeekInMonth(ordinal, dayOfWeek);
|
||||
return temporal -> {
|
||||
Temporal result = adjuster.adjustInto(temporal);
|
||||
return rollbackToMidnight(temporal, result);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Rolls back the given {@code result} to midnight. When
|
||||
* {@code current} has the same day of month as {@code result}, the former
|
||||
* is returned, to make sure that we don't end up before where we started.
|
||||
*/
|
||||
private static Temporal rollbackToMidnight(Temporal current, Temporal result) {
|
||||
if (result.get(ChronoField.DAY_OF_MONTH) == current.get(ChronoField.DAY_OF_MONTH)) {
|
||||
return current;
|
||||
}
|
||||
else {
|
||||
return atMidnight().adjustInto(result);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends Temporal & Comparable<? super T>> T cast(Temporal temporal) {
|
||||
return (T) temporal;
|
||||
|
||||
+30
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,8 +17,10 @@
|
||||
package org.springframework.validation.beanvalidation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -291,12 +293,17 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
configureParameterNameProvider(this.parameterNameDiscoverer, configuration);
|
||||
}
|
||||
|
||||
List<InputStream> mappingStreams = null;
|
||||
if (this.mappingLocations != null) {
|
||||
mappingStreams = new ArrayList<>(this.mappingLocations.length);
|
||||
for (Resource location : this.mappingLocations) {
|
||||
try {
|
||||
configuration.addMapping(location.getInputStream());
|
||||
InputStream stream = location.getInputStream();
|
||||
mappingStreams.add(stream);
|
||||
configuration.addMapping(stream);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
closeMappingStreams(mappingStreams);
|
||||
throw new IllegalStateException("Cannot read mapping resource: " + location);
|
||||
}
|
||||
}
|
||||
@@ -307,8 +314,13 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
// Allow for custom post-processing before we actually build the ValidatorFactory.
|
||||
postProcessConfiguration(configuration);
|
||||
|
||||
this.validatorFactory = configuration.buildValidatorFactory();
|
||||
setTargetValidator(this.validatorFactory.getValidator());
|
||||
try {
|
||||
this.validatorFactory = configuration.buildValidatorFactory();
|
||||
setTargetValidator(this.validatorFactory.getValidator());
|
||||
}
|
||||
finally {
|
||||
closeMappingStreams(mappingStreams);
|
||||
}
|
||||
}
|
||||
|
||||
private void configureParameterNameProvider(ParameterNameDiscoverer discoverer, Configuration<?> configuration) {
|
||||
@@ -329,6 +341,18 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
});
|
||||
}
|
||||
|
||||
private void closeMappingStreams(@Nullable List<InputStream> mappingStreams){
|
||||
if (!CollectionUtils.isEmpty(mappingStreams)) {
|
||||
for (InputStream stream : mappingStreams) {
|
||||
try {
|
||||
stream.close();
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process the given Bean Validation configuration,
|
||||
* adding to or overriding any of its settings.
|
||||
@@ -397,7 +421,7 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
return super.unwrap(type);
|
||||
}
|
||||
catch (ValidationException ex) {
|
||||
// ignore - we'll try ValidatorFactory unwrapping next
|
||||
// Ignore - we'll try ValidatorFactory unwrapping next
|
||||
}
|
||||
}
|
||||
if (this.validatorFactory != null) {
|
||||
@@ -405,7 +429,7 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
return this.validatorFactory.unwrap(type);
|
||||
}
|
||||
catch (ValidationException ex) {
|
||||
// ignore if just being asked for ValidatorFactory
|
||||
// Ignore if just being asked for ValidatorFactory
|
||||
if (ValidatorFactory.class == type) {
|
||||
return (T) this.validatorFactory;
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -179,7 +179,7 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
|
||||
}
|
||||
}
|
||||
else {
|
||||
// got no BindingResult - can only do standard rejectValue call
|
||||
// Got no BindingResult - can only do standard rejectValue call
|
||||
// with automatic extraction of the current field value
|
||||
errors.rejectValue(field, errorCode, errorArgs, violation.getMessage());
|
||||
}
|
||||
@@ -386,7 +386,7 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
|
||||
return (type != null ? this.targetValidator.unwrap(type) : (T) this.targetValidator);
|
||||
}
|
||||
catch (ValidationException ex) {
|
||||
// ignore if just being asked for plain Validator
|
||||
// Ignore if just being asked for plain JSR-303 Validator
|
||||
if (javax.validation.Validator.class == type) {
|
||||
return (T) this.targetValidator;
|
||||
}
|
||||
|
||||
+8
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,24 +36,26 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class AtAspectJAfterThrowingTests {
|
||||
|
||||
@Test
|
||||
public void testAccessThrowable() throws Exception {
|
||||
public void testAccessThrowable() {
|
||||
ClassPathXmlApplicationContext ctx =
|
||||
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
|
||||
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
|
||||
|
||||
ITestBean bean = (ITestBean) ctx.getBean("testBean");
|
||||
ExceptionHandlingAspect aspect = (ExceptionHandlingAspect) ctx.getBean("aspect");
|
||||
|
||||
assertThat(AopUtils.isAopProxy(bean)).isTrue();
|
||||
IOException exceptionThrown = null;
|
||||
try {
|
||||
bean.unreliableFileOperation();
|
||||
}
|
||||
catch (IOException e) {
|
||||
//
|
||||
catch (IOException ex) {
|
||||
exceptionThrown = ex;
|
||||
}
|
||||
|
||||
assertThat(aspect.handled).isEqualTo(1);
|
||||
assertThat(aspect.lastException).isNotNull();
|
||||
assertThat(aspect.lastException).isSameAs(exceptionThrown);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class AtAspectJAnnotationBindingTests {
|
||||
|
||||
private AnnotatedTestBean testBean;
|
||||
|
||||
private ClassPathXmlApplicationContext ctx;
|
||||
|
||||
|
||||
@@ -70,8 +71,7 @@ public class AtAspectJAnnotationBindingTests {
|
||||
class AtAspectJAnnotationBindingTestAspect {
|
||||
|
||||
@Around("execution(* *(..)) && @annotation(testAnn)")
|
||||
public Object doWithAnnotation(ProceedingJoinPoint pjp, TestAnnotation testAnn)
|
||||
throws Throwable {
|
||||
public Object doWithAnnotation(ProceedingJoinPoint pjp, TestAnnotation testAnn) throws Throwable {
|
||||
String annValue = testAnn.value();
|
||||
Object result = pjp.proceed();
|
||||
return (result instanceof String ? annValue + " " + result : result);
|
||||
|
||||
+69
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,14 +16,23 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* @author Andy Wilkinson
|
||||
* @author Liu Dongmiao
|
||||
*/
|
||||
public class AggressiveFactoryBeanInstantiationTests {
|
||||
|
||||
@@ -49,17 +58,66 @@ public class AggressiveFactoryBeanInstantiationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkLinkageError() {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
context.register(BeanMethodConfigurationWithExceptionInInitializer.class);
|
||||
context.refresh();
|
||||
fail("Should have thrown BeanCreationException");
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
PrintWriter pw = new PrintWriter(baos);
|
||||
ex.printStackTrace(pw);
|
||||
pw.flush();
|
||||
String stackTrace = baos.toString();
|
||||
assertThat(stackTrace.contains(".<clinit>")).isTrue();
|
||||
assertThat(stackTrace.contains("java.lang.NoClassDefFoundError")).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class BeanMethodConfiguration {
|
||||
|
||||
@Bean
|
||||
public String foo() {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AutowiredBean autowiredBean() {
|
||||
return new AutowiredBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@DependsOn("autowiredBean")
|
||||
public SimpleFactoryBean simpleFactoryBean(ApplicationContext applicationContext) {
|
||||
return new SimpleFactoryBean(applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class BeanMethodConfigurationWithExceptionInInitializer extends BeanMethodConfiguration {
|
||||
|
||||
@Bean
|
||||
@DependsOn("autowiredBean")
|
||||
@Override
|
||||
public SimpleFactoryBean simpleFactoryBean(ApplicationContext applicationContext) {
|
||||
new ExceptionInInitializer();
|
||||
return new SimpleFactoryBean(applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class AutowiredBean {
|
||||
|
||||
@Autowired
|
||||
String foo;
|
||||
}
|
||||
|
||||
|
||||
static class SimpleFactoryBean implements FactoryBean<Object> {
|
||||
|
||||
public SimpleFactoryBean(ApplicationContext applicationContext) {
|
||||
@@ -76,4 +134,14 @@ public class AggressiveFactoryBeanInstantiationTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class ExceptionInInitializer {
|
||||
|
||||
private static final int ERROR = callInClinit();
|
||||
|
||||
private static int callInClinit() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
@@ -271,9 +271,15 @@ class AnnotationConfigApplicationContextTests {
|
||||
assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanA.class), "a")).isTrue();
|
||||
assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanB.class), "b")).isTrue();
|
||||
assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanC.class), "c")).isTrue();
|
||||
|
||||
assertThat(context.getBeansOfType(BeanA.class)).isEmpty();
|
||||
assertThat(context.getBeansOfType(BeanB.class).values().iterator().next()).isSameAs(context.getBean(BeanB.class));
|
||||
assertThat(context.getBeansOfType(BeanC.class).values().iterator().next()).isSameAs(context.getBean(BeanC.class));
|
||||
|
||||
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() ->
|
||||
context.getBeanFactory().resolveNamedBean(BeanA.class));
|
||||
assertThat(context.getBeanFactory().resolveNamedBean(BeanB.class).getBeanInstance()).isSameAs(context.getBean(BeanB.class));
|
||||
assertThat(context.getBeanFactory().resolveNamedBean(BeanC.class).getBeanInstance()).isSameAs(context.getBean(BeanC.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+101
-99
@@ -20,7 +20,6 @@ import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -66,7 +65,6 @@ import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -77,13 +75,13 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class ConfigurationClassPostProcessorTests {
|
||||
class ConfigurationClassPostProcessorTests {
|
||||
|
||||
private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
void setup() {
|
||||
QualifierAnnotationAutowireCandidateResolver acr = new QualifierAnnotationAutowireCandidateResolver();
|
||||
acr.setBeanFactory(this.beanFactory);
|
||||
this.beanFactory.setAutowireCandidateResolver(acr);
|
||||
@@ -99,7 +97,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
* We test for such a case below, and in doing so prove that enhancement is working.
|
||||
*/
|
||||
@Test
|
||||
public void enhancementIsPresentBecauseSingletonSemanticsAreRespected() {
|
||||
void enhancementIsPresentBecauseSingletonSemanticsAreRespected() {
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(SingletonBeanConfig.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
@@ -107,11 +105,13 @@ public class ConfigurationClassPostProcessorTests {
|
||||
Foo foo = beanFactory.getBean("foo", Foo.class);
|
||||
Bar bar = beanFactory.getBean("bar", Bar.class);
|
||||
assertThat(bar.foo).isSameAs(foo);
|
||||
assertThat(Arrays.asList(beanFactory.getDependentBeans("foo")).contains("bar")).isTrue();
|
||||
assertThat(beanFactory.getDependentBeans("foo")).contains("bar");
|
||||
assertThat(beanFactory.getDependentBeans("config")).contains("foo");
|
||||
assertThat(beanFactory.getDependentBeans("config")).contains("bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enhancementIsPresentBecauseSingletonSemanticsAreRespectedUsingAsm() {
|
||||
void enhancementIsPresentBecauseSingletonSemanticsAreRespectedUsingAsm() {
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(SingletonBeanConfig.class.getName()));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
@@ -119,11 +119,13 @@ public class ConfigurationClassPostProcessorTests {
|
||||
Foo foo = beanFactory.getBean("foo", Foo.class);
|
||||
Bar bar = beanFactory.getBean("bar", Bar.class);
|
||||
assertThat(bar.foo).isSameAs(foo);
|
||||
assertThat(Arrays.asList(beanFactory.getDependentBeans("foo")).contains("bar")).isTrue();
|
||||
assertThat(beanFactory.getDependentBeans("foo")).contains("bar");
|
||||
assertThat(beanFactory.getDependentBeans("config")).contains("foo");
|
||||
assertThat(beanFactory.getDependentBeans("config")).contains("bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enhancementIsNotPresentForProxyBeanMethodsFlagSetToFalse() {
|
||||
void enhancementIsNotPresentForProxyBeanMethodsFlagSetToFalse() {
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(NonEnhancedSingletonBeanConfig.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
@@ -134,7 +136,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enhancementIsNotPresentForProxyBeanMethodsFlagSetToFalseUsingAsm() {
|
||||
void enhancementIsNotPresentForProxyBeanMethodsFlagSetToFalseUsingAsm() {
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(NonEnhancedSingletonBeanConfig.class.getName()));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
@@ -145,7 +147,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enhancementIsNotPresentForStaticMethods() {
|
||||
void enhancementIsNotPresentForStaticMethods() {
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(StaticSingletonBeanConfig.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
@@ -158,7 +160,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enhancementIsNotPresentForStaticMethodsUsingAsm() {
|
||||
void enhancementIsNotPresentForStaticMethodsUsingAsm() {
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(StaticSingletonBeanConfig.class.getName()));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
@@ -171,7 +173,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configurationIntrospectionOfInnerClassesWorksWithDotNameSyntax() {
|
||||
void configurationIntrospectionOfInnerClassesWorksWithDotNameSyntax() {
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(getClass().getName() + ".SingletonBeanConfig"));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
@@ -185,7 +187,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
* if a bean class is already loaded.
|
||||
*/
|
||||
@Test
|
||||
public void alreadyLoadedConfigurationClasses() {
|
||||
void alreadyLoadedConfigurationClasses() {
|
||||
beanFactory.registerBeanDefinition("unloadedConfig", new RootBeanDefinition(UnloadedConfig.class.getName()));
|
||||
beanFactory.registerBeanDefinition("loadedConfig", new RootBeanDefinition(LoadedConfig.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
@@ -198,7 +200,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
* Tests whether a bean definition without a specified bean class is handled correctly.
|
||||
*/
|
||||
@Test
|
||||
public void postProcessorIntrospectsInheritedDefinitionsCorrectly() {
|
||||
void postProcessorIntrospectsInheritedDefinitionsCorrectly() {
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(SingletonBeanConfig.class));
|
||||
beanFactory.registerBeanDefinition("parent", new RootBeanDefinition(TestBean.class));
|
||||
beanFactory.registerBeanDefinition("child", new ChildBeanDefinition("parent"));
|
||||
@@ -210,96 +212,96 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithComposedConfigurationUsingReflection() {
|
||||
void postProcessorWorksWithComposedConfigurationUsingReflection() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(ComposedConfigurationClass.class);
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithComposedConfigurationUsingAsm() {
|
||||
void postProcessorWorksWithComposedConfigurationUsingAsm() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(ComposedConfigurationClass.class.getName());
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForBasePackageUsingReflection() {
|
||||
void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForBasePackageUsingReflection() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
ComposedConfigurationWithAttributeOverrideForBasePackage.class);
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForBasePackageUsingAsm() {
|
||||
void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForBasePackageUsingAsm() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
ComposedConfigurationWithAttributeOverrideForBasePackage.class.getName());
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForExcludeFilterUsingReflection() {
|
||||
void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForExcludeFilterUsingReflection() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
ComposedConfigurationWithAttributeOverrideForExcludeFilter.class);
|
||||
assertSupportForComposedAnnotationWithExclude(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForExcludeFilterUsingAsm() {
|
||||
void postProcessorWorksWithComposedConfigurationWithAttributeOverrideForExcludeFilterUsingAsm() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
ComposedConfigurationWithAttributeOverrideForExcludeFilter.class.getName());
|
||||
assertSupportForComposedAnnotationWithExclude(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithExtendedConfigurationWithAttributeOverrideForExcludesFilterUsingReflection() {
|
||||
void postProcessorWorksWithExtendedConfigurationWithAttributeOverrideForExcludesFilterUsingReflection() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
ExtendedConfigurationWithAttributeOverrideForExcludeFilter.class);
|
||||
assertSupportForComposedAnnotationWithExclude(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithExtendedConfigurationWithAttributeOverrideForExcludesFilterUsingAsm() {
|
||||
void postProcessorWorksWithExtendedConfigurationWithAttributeOverrideForExcludesFilterUsingAsm() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
ExtendedConfigurationWithAttributeOverrideForExcludeFilter.class.getName());
|
||||
assertSupportForComposedAnnotationWithExclude(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingReflection() {
|
||||
void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingReflection() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
ComposedComposedConfigurationWithAttributeOverridesClass.class);
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingAsm() {
|
||||
void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingAsm() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
ComposedComposedConfigurationWithAttributeOverridesClass.class.getName());
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesUsingReflection() {
|
||||
void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesUsingReflection() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
MetaComponentScanConfigurationWithAttributeOverridesClass.class);
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesUsingAsm() {
|
||||
void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesUsingAsm() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
MetaComponentScanConfigurationWithAttributeOverridesClass.class.getName());
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesSubclassUsingReflection() {
|
||||
void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesSubclassUsingReflection() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
SubMetaComponentScanConfigurationWithAttributeOverridesClass.class);
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesSubclassUsingAsm() {
|
||||
void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesSubclassUsingAsm() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
SubMetaComponentScanConfigurationWithAttributeOverridesClass.class.getName());
|
||||
assertSupportForComposedAnnotation(beanDefinition);
|
||||
@@ -324,7 +326,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorOverridesNonApplicationBeanDefinitions() {
|
||||
void postProcessorOverridesNonApplicationBeanDefinitions() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
|
||||
rbd.setRole(RootBeanDefinition.ROLE_SUPPORT);
|
||||
beanFactory.registerBeanDefinition("bar", rbd);
|
||||
@@ -337,7 +339,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorDoesNotOverrideRegularBeanDefinitions() {
|
||||
void postProcessorDoesNotOverrideRegularBeanDefinitions() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
|
||||
rbd.setResource(new DescriptiveResource("XML or something"));
|
||||
beanFactory.registerBeanDefinition("bar", rbd);
|
||||
@@ -349,7 +351,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorDoesNotOverrideRegularBeanDefinitionsEvenWithScopedProxy() {
|
||||
void postProcessorDoesNotOverrideRegularBeanDefinitionsEvenWithScopedProxy() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
|
||||
rbd.setResource(new DescriptiveResource("XML or something"));
|
||||
BeanDefinitionHolder proxied = ScopedProxyUtils.createScopedProxy(
|
||||
@@ -363,7 +365,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorFailsOnImplicitOverrideIfOverridingIsNotAllowed() {
|
||||
void postProcessorFailsOnImplicitOverrideIfOverridingIsNotAllowed() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
|
||||
rbd.setResource(new DescriptiveResource("XML or something"));
|
||||
beanFactory.registerBeanDefinition("bar", rbd);
|
||||
@@ -378,7 +380,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test // gh-25430
|
||||
public void detectAliasOverride() {
|
||||
void detectAliasOverride() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
|
||||
beanFactory.setAllowBeanDefinitionOverriding(false);
|
||||
@@ -390,7 +392,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configurationClassesProcessedInCorrectOrder() {
|
||||
void configurationClassesProcessedInCorrectOrder() {
|
||||
beanFactory.registerBeanDefinition("config1", new RootBeanDefinition(OverridingSingletonBeanConfig.class));
|
||||
beanFactory.registerBeanDefinition("config2", new RootBeanDefinition(SingletonBeanConfig.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
@@ -404,7 +406,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configurationClassesWithValidOverridingForProgrammaticCall() {
|
||||
void configurationClassesWithValidOverridingForProgrammaticCall() {
|
||||
beanFactory.registerBeanDefinition("config1", new RootBeanDefinition(OverridingAgainSingletonBeanConfig.class));
|
||||
beanFactory.registerBeanDefinition("config2", new RootBeanDefinition(OverridingSingletonBeanConfig.class));
|
||||
beanFactory.registerBeanDefinition("config3", new RootBeanDefinition(SingletonBeanConfig.class));
|
||||
@@ -419,7 +421,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configurationClassesWithInvalidOverridingForProgrammaticCall() {
|
||||
void configurationClassesWithInvalidOverridingForProgrammaticCall() {
|
||||
beanFactory.registerBeanDefinition("config1", new RootBeanDefinition(InvalidOverridingSingletonBeanConfig.class));
|
||||
beanFactory.registerBeanDefinition("config2", new RootBeanDefinition(OverridingSingletonBeanConfig.class));
|
||||
beanFactory.registerBeanDefinition("config3", new RootBeanDefinition(SingletonBeanConfig.class));
|
||||
@@ -435,7 +437,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test // SPR-15384
|
||||
public void nestedConfigurationClassesProcessedInCorrectOrder() {
|
||||
void nestedConfigurationClassesProcessedInCorrectOrder() {
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithOrderedNestedClasses.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
@@ -448,7 +450,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test // SPR-16734
|
||||
public void innerConfigurationClassesProcessedInCorrectOrder() {
|
||||
void innerConfigurationClassesProcessedInCorrectOrder() {
|
||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithOrderedInnerClasses.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
@@ -462,7 +464,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scopedProxyTargetMarkedAsNonAutowireCandidate() {
|
||||
void scopedProxyTargetMarkedAsNonAutowireCandidate() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
@@ -479,7 +481,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processingAllowedOnlyOncePerProcessorRegistryPair() {
|
||||
void processingAllowedOnlyOncePerProcessorRegistryPair() {
|
||||
DefaultListableBeanFactory bf1 = new DefaultListableBeanFactory();
|
||||
DefaultListableBeanFactory bf2 = new DefaultListableBeanFactory();
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
@@ -492,7 +494,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjection() {
|
||||
void genericsBasedInjection() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
@@ -509,7 +511,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithScoped() {
|
||||
void genericsBasedInjectionWithScoped() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
@@ -526,7 +528,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithScopedProxy() {
|
||||
void genericsBasedInjectionWithScopedProxy() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
@@ -546,7 +548,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithScopedProxyUsingAsm() {
|
||||
void genericsBasedInjectionWithScopedProxyUsingAsm() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
@@ -566,7 +568,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithImplTypeAtInjectionPoint() {
|
||||
void genericsBasedInjectionWithImplTypeAtInjectionPoint() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
@@ -583,7 +585,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithFactoryBean() {
|
||||
void genericsBasedInjectionWithFactoryBean() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
@@ -602,7 +604,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithRawMatch() {
|
||||
void genericsBasedInjectionWithRawMatch() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawMatchingConfiguration.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
@@ -611,7 +613,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithWildcardMatch() {
|
||||
void genericsBasedInjectionWithWildcardMatch() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardMatchingConfiguration.class));
|
||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||
pp.postProcessBeanFactory(beanFactory);
|
||||
@@ -620,7 +622,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithWildcardWithExtendsMatch() {
|
||||
void genericsBasedInjectionWithWildcardWithExtendsMatch() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithExtendsConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
|
||||
@@ -628,7 +630,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithWildcardWithGenericExtendsMatch() {
|
||||
void genericsBasedInjectionWithWildcardWithGenericExtendsMatch() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithGenericExtendsConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
|
||||
@@ -636,12 +638,12 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithEarlyGenericsMatching() {
|
||||
void genericsBasedInjectionWithEarlyGenericsMatching() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -653,13 +655,13 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithLateGenericsMatching() {
|
||||
void genericsBasedInjectionWithLateGenericsMatching() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -671,12 +673,12 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithEarlyGenericsMatchingAndRawFactoryMethod() {
|
||||
void genericsBasedInjectionWithEarlyGenericsMatchingAndRawFactoryMethod() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawFactoryMethodRepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(0);
|
||||
@@ -686,13 +688,13 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithLateGenericsMatchingAndRawFactoryMethod() {
|
||||
void genericsBasedInjectionWithLateGenericsMatchingAndRawFactoryMethod() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawFactoryMethodRepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -704,12 +706,12 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithEarlyGenericsMatchingAndRawInstance() {
|
||||
void genericsBasedInjectionWithEarlyGenericsMatchingAndRawInstance() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawInstanceRepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -721,13 +723,13 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithLateGenericsMatchingAndRawInstance() {
|
||||
void genericsBasedInjectionWithLateGenericsMatchingAndRawInstance() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawInstanceRepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -739,7 +741,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithEarlyGenericsMatchingOnCglibProxy() {
|
||||
void genericsBasedInjectionWithEarlyGenericsMatchingOnCglibProxy() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||
@@ -749,7 +751,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
beanFactory.registerSingleton("traceInterceptor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -763,7 +765,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxy() {
|
||||
void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxy() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||
@@ -774,7 +776,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -788,7 +790,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxyAndRawFactoryMethod() {
|
||||
void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxyAndRawFactoryMethod() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawFactoryMethodRepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||
@@ -799,7 +801,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -813,7 +815,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxyAndRawInstance() {
|
||||
void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxyAndRawInstance() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawInstanceRepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||
@@ -824,7 +826,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -838,7 +840,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithEarlyGenericsMatchingOnJdkProxy() {
|
||||
void genericsBasedInjectionWithEarlyGenericsMatchingOnJdkProxy() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||
@@ -847,7 +849,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
beanFactory.registerSingleton("traceInterceptor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(RepositoryInterface.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -861,7 +863,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxy() {
|
||||
void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxy() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||
@@ -871,7 +873,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(RepositoryInterface.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -885,7 +887,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxyAndRawFactoryMethod() {
|
||||
void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxyAndRawFactoryMethod() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawFactoryMethodRepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||
@@ -895,7 +897,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(RepositoryInterface.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -909,7 +911,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxyAndRawInstance() {
|
||||
void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxyAndRawInstance() {
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawInstanceRepositoryConfiguration.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||
@@ -919,7 +921,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
String[] beanNames = beanFactory.getBeanNamesForType(RepositoryInterface.class);
|
||||
assertThat(ObjectUtils.containsElement(beanNames, "stringRepo")).isTrue();
|
||||
assertThat(beanNames).contains("stringRepo");
|
||||
|
||||
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
@@ -933,7 +935,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelfReferenceExclusionForFactoryMethodOnSameBean() {
|
||||
void testSelfReferenceExclusionForFactoryMethodOnSameBean() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
@@ -947,7 +949,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigWithDefaultMethods() {
|
||||
void testConfigWithDefaultMethods() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
@@ -961,7 +963,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigWithDefaultMethodsUsingAsm() {
|
||||
void testConfigWithDefaultMethodsUsingAsm() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
@@ -975,7 +977,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCircularDependency() {
|
||||
void testCircularDependency() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
@@ -988,38 +990,38 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCircularDependencyWithApplicationContext() {
|
||||
void testCircularDependencyWithApplicationContext() {
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() ->
|
||||
new AnnotationConfigApplicationContext(A.class, AStrich.class))
|
||||
.withMessageContaining("Circular reference");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrototypeArgumentThroughBeanMethodCall() {
|
||||
void testPrototypeArgumentThroughBeanMethodCall() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanArgumentConfigWithPrototype.class);
|
||||
ctx.getBean(FooFactory.class).createFoo(new BarArgument());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingletonArgumentThroughBeanMethodCall() {
|
||||
void testSingletonArgumentThroughBeanMethodCall() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanArgumentConfigWithSingleton.class);
|
||||
ctx.getBean(FooFactory.class).createFoo(new BarArgument());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullArgumentThroughBeanMethodCall() {
|
||||
void testNullArgumentThroughBeanMethodCall() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanArgumentConfigWithNull.class);
|
||||
ctx.getBean("aFoo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInjectionPointMatchForNarrowTargetReturnType() {
|
||||
void testInjectionPointMatchForNarrowTargetReturnType() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(FooBarConfiguration.class);
|
||||
assertThat(ctx.getBean(FooImpl.class).bar).isSameAs(ctx.getBean(BarImpl.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarargOnBeanMethod() {
|
||||
void testVarargOnBeanMethod() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(VarargConfiguration.class, TestBean.class);
|
||||
VarargConfiguration bean = ctx.getBean(VarargConfiguration.class);
|
||||
assertThat(bean.testBeans).isNotNull();
|
||||
@@ -1028,7 +1030,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyVarargOnBeanMethod() {
|
||||
void testEmptyVarargOnBeanMethod() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(VarargConfiguration.class);
|
||||
VarargConfiguration bean = ctx.getBean(VarargConfiguration.class);
|
||||
assertThat(bean.testBeans).isNotNull();
|
||||
@@ -1036,7 +1038,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionArgumentOnBeanMethod() {
|
||||
void testCollectionArgumentOnBeanMethod() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(CollectionArgumentConfiguration.class, TestBean.class);
|
||||
CollectionArgumentConfiguration bean = ctx.getBean(CollectionArgumentConfiguration.class);
|
||||
assertThat(bean.testBeans).isNotNull();
|
||||
@@ -1045,7 +1047,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyCollectionArgumentOnBeanMethod() {
|
||||
void testEmptyCollectionArgumentOnBeanMethod() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(CollectionArgumentConfiguration.class);
|
||||
CollectionArgumentConfiguration bean = ctx.getBean(CollectionArgumentConfiguration.class);
|
||||
assertThat(bean.testBeans).isNotNull();
|
||||
@@ -1053,7 +1055,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapArgumentOnBeanMethod() {
|
||||
void testMapArgumentOnBeanMethod() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(MapArgumentConfiguration.class, DummyRunnable.class);
|
||||
MapArgumentConfiguration bean = ctx.getBean(MapArgumentConfiguration.class);
|
||||
assertThat(bean.testBeans).isNotNull();
|
||||
@@ -1062,7 +1064,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyMapArgumentOnBeanMethod() {
|
||||
void testEmptyMapArgumentOnBeanMethod() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(MapArgumentConfiguration.class);
|
||||
MapArgumentConfiguration bean = ctx.getBean(MapArgumentConfiguration.class);
|
||||
assertThat(bean.testBeans).isNotNull();
|
||||
@@ -1070,7 +1072,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionInjectionFromSameConfigurationClass() {
|
||||
void testCollectionInjectionFromSameConfigurationClass() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(CollectionInjectionConfiguration.class);
|
||||
CollectionInjectionConfiguration bean = ctx.getBean(CollectionInjectionConfiguration.class);
|
||||
assertThat(bean.testBeans).isNotNull();
|
||||
@@ -1079,7 +1081,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapInjectionFromSameConfigurationClass() {
|
||||
void testMapInjectionFromSameConfigurationClass() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(MapInjectionConfiguration.class);
|
||||
MapInjectionConfiguration bean = ctx.getBean(MapInjectionConfiguration.class);
|
||||
assertThat(bean.testBeans).isNotNull();
|
||||
@@ -1088,7 +1090,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeanLookupFromSameConfigurationClass() {
|
||||
void testBeanLookupFromSameConfigurationClass() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanLookupConfiguration.class);
|
||||
BeanLookupConfiguration bean = ctx.getBean(BeanLookupConfiguration.class);
|
||||
assertThat(bean.getTestBean()).isNotNull();
|
||||
@@ -1096,7 +1098,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNameClashBetweenConfigurationClassAndBean() {
|
||||
void testNameClashBetweenConfigurationClassAndBean() {
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class).isThrownBy(() -> {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyTestBean.class);
|
||||
ctx.getBean("myTestBean", TestBean.class);
|
||||
@@ -1104,7 +1106,7 @@ public class ConfigurationClassPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeanDefinitionRegistryPostProcessorConfig() {
|
||||
void testBeanDefinitionRegistryPostProcessorConfig() {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanDefinitionRegistryPostProcessorConfig.class);
|
||||
boolean condition = ctx.getBean("myTestBean") instanceof TestBean;
|
||||
assertThat(condition).isTrue();
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,7 +40,7 @@ public class EnableLoadTimeWeavingTests {
|
||||
@Test
|
||||
public void control() {
|
||||
GenericXmlApplicationContext ctx =
|
||||
new GenericXmlApplicationContext(getClass(), "EnableLoadTimeWeavingTests-context.xml");
|
||||
new GenericXmlApplicationContext(getClass(), "EnableLoadTimeWeavingTests-context.xml");
|
||||
ctx.getBean("loadTimeWeaver", LoadTimeWeaver.class);
|
||||
}
|
||||
|
||||
@@ -73,9 +73,11 @@ public class EnableLoadTimeWeavingTests {
|
||||
verify(loadTimeWeaver).addTransformer(isA(ClassFileTransformer.class));
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.DISABLED)
|
||||
static class EnableLTWConfig_withAjWeavingDisabled implements LoadTimeWeavingConfigurer {
|
||||
|
||||
@Override
|
||||
public LoadTimeWeaver getLoadTimeWeaver() {
|
||||
return mock(LoadTimeWeaver.class);
|
||||
@@ -85,6 +87,7 @@ public class EnableLoadTimeWeavingTests {
|
||||
@Configuration
|
||||
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.AUTODETECT)
|
||||
static class EnableLTWConfig_withAjWeavingAutodetect implements LoadTimeWeavingConfigurer {
|
||||
|
||||
@Override
|
||||
public LoadTimeWeaver getLoadTimeWeaver() {
|
||||
return mock(LoadTimeWeaver.class);
|
||||
@@ -94,9 +97,11 @@ public class EnableLoadTimeWeavingTests {
|
||||
@Configuration
|
||||
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
|
||||
static class EnableLTWConfig_withAjWeavingEnabled implements LoadTimeWeavingConfigurer {
|
||||
|
||||
@Override
|
||||
public LoadTimeWeaver getLoadTimeWeaver() {
|
||||
return mock(LoadTimeWeaver.class);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+129
-91
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,8 +18,10 @@ package org.springframework.context.annotation;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
@@ -31,6 +33,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
@@ -47,13 +50,13 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
*/
|
||||
public class PropertySourceAnnotationTests {
|
||||
|
||||
class PropertySourceAnnotationTests {
|
||||
|
||||
@Test
|
||||
public void withExplicitName() {
|
||||
void withExplicitName() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithExplicitName.class);
|
||||
ctx.refresh();
|
||||
@@ -73,29 +76,25 @@ public class PropertySourceAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withImplicitName() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithImplicitName.class);
|
||||
ctx.refresh();
|
||||
void withImplicitName() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithImplicitName.class);
|
||||
assertThat(ctx.getEnvironment().getPropertySources().contains("class path resource [org/springframework/context/annotation/p1.properties]")).as("property source p1 was not added").isTrue();
|
||||
assertThat(ctx.getBean(TestBean.class).getName()).isEqualTo("p1TestBean");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withTestProfileBeans() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithTestProfileBeans.class);
|
||||
ctx.refresh();
|
||||
void withTestProfileBeans() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithTestProfileBeans.class);
|
||||
assertThat(ctx.containsBean("testBean")).isTrue();
|
||||
assertThat(ctx.containsBean("testProfileBean")).isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the LIFO behavior of @PropertySource annotaitons.
|
||||
* The last one registered should 'win'.
|
||||
* Tests the LIFO behavior of @PropertySource annotations.
|
||||
* <p>The last one registered should 'win'.
|
||||
*/
|
||||
@Test
|
||||
public void orderingIsLifo() {
|
||||
void orderingIsLifo() {
|
||||
{
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithImplicitName.class, P2Config.class);
|
||||
@@ -114,7 +113,7 @@ public class PropertySourceAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withCustomFactory() {
|
||||
void withCustomFactory() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithImplicitName.class, WithCustomFactory.class);
|
||||
ctx.refresh();
|
||||
@@ -122,7 +121,7 @@ public class PropertySourceAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withCustomFactoryAsMeta() {
|
||||
void withCustomFactoryAsMeta() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithImplicitName.class, WithCustomFactoryAsMeta.class);
|
||||
ctx.refresh();
|
||||
@@ -130,59 +129,43 @@ public class PropertySourceAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withUnresolvablePlaceholder() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithUnresolvablePlaceholder.class);
|
||||
try {
|
||||
ctx.refresh();
|
||||
}
|
||||
catch (BeanDefinitionStoreException ex) {
|
||||
assertThat(ex.getCause() instanceof IllegalArgumentException).isTrue();
|
||||
}
|
||||
void withUnresolvablePlaceholder() {
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class)
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithUnresolvablePlaceholder.class))
|
||||
.withCauseInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withUnresolvablePlaceholderAndDefault() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithUnresolvablePlaceholderAndDefault.class);
|
||||
ctx.refresh();
|
||||
void withUnresolvablePlaceholderAndDefault() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithUnresolvablePlaceholderAndDefault.class);
|
||||
assertThat(ctx.getBean(TestBean.class).getName()).isEqualTo("p1TestBean");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withResolvablePlaceholder() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithResolvablePlaceholder.class);
|
||||
void withResolvablePlaceholder() {
|
||||
System.setProperty("path.to.properties", "org/springframework/context/annotation");
|
||||
ctx.refresh();
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithResolvablePlaceholder.class);
|
||||
assertThat(ctx.getBean(TestBean.class).getName()).isEqualTo("p1TestBean");
|
||||
System.clearProperty("path.to.properties");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withResolvablePlaceholderAndFactoryBean() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithResolvablePlaceholderAndFactoryBean.class);
|
||||
void withResolvablePlaceholderAndFactoryBean() {
|
||||
System.setProperty("path.to.properties", "org/springframework/context/annotation");
|
||||
ctx.refresh();
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithResolvablePlaceholderAndFactoryBean.class);
|
||||
assertThat(ctx.getBean(TestBean.class).getName()).isEqualTo("p1TestBean");
|
||||
System.clearProperty("path.to.properties");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withEmptyResourceLocations() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithEmptyResourceLocations.class);
|
||||
try {
|
||||
ctx.refresh();
|
||||
}
|
||||
catch (BeanDefinitionStoreException ex) {
|
||||
assertThat(ex.getCause() instanceof IllegalArgumentException).isTrue();
|
||||
}
|
||||
void withEmptyResourceLocations() {
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class)
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithEmptyResourceLocations.class))
|
||||
.withCauseInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withNameAndMultipleResourceLocations() {
|
||||
void withNameAndMultipleResourceLocations() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithNameAndMultipleResourceLocations.class);
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1")).isTrue();
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2")).isTrue();
|
||||
@@ -191,7 +174,7 @@ public class PropertySourceAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withMultipleResourceLocations() {
|
||||
void withMultipleResourceLocations() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithMultipleResourceLocations.class);
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1")).isTrue();
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2")).isTrue();
|
||||
@@ -200,7 +183,7 @@ public class PropertySourceAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withPropertySources() {
|
||||
void withRepeatedPropertySourcesInContainerAnnotation() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithPropertySources.class);
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1")).isTrue();
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2")).isTrue();
|
||||
@@ -209,7 +192,43 @@ public class PropertySourceAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withNamedPropertySources() {
|
||||
void withRepeatedPropertySources() {
|
||||
try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithRepeatedPropertySourceAnnotations.class)) {
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1")).isTrue();
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2")).isTrue();
|
||||
// p2 should 'win' as it was registered last
|
||||
assertThat(ctx.getEnvironment().getProperty("testbean.name")).isEqualTo("p2TestBean");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void withRepeatedPropertySourcesOnComposedAnnotation() {
|
||||
Class<?> configClass = ConfigWithRepeatedPropertySourceAnnotationsOnComposedAnnotation.class;
|
||||
String key = "custom.config.package";
|
||||
|
||||
System.clearProperty(key);
|
||||
try (ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(configClass)) {
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1")).isTrue();
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2")).isTrue();
|
||||
// p2 should 'win' as it was registered last
|
||||
assertThat(ctx.getEnvironment().getProperty("testbean.name")).isEqualTo("p2TestBean");
|
||||
}
|
||||
|
||||
System.setProperty(key, "org/springframework/context/annotation");
|
||||
try (ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(configClass)) {
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1")).isTrue();
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2")).isTrue();
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p3")).isTrue();
|
||||
// p3 should 'win' as it was registered last
|
||||
assertThat(ctx.getEnvironment().getProperty("testbean.name")).isEqualTo("p3TestBean");
|
||||
}
|
||||
finally {
|
||||
System.clearProperty(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void withNamedPropertySources() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithNamedPropertySources.class);
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1")).isTrue();
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2")).isTrue();
|
||||
@@ -218,21 +237,21 @@ public class PropertySourceAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withMissingPropertySource() {
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class).isThrownBy(() ->
|
||||
new AnnotationConfigApplicationContext(ConfigWithMissingPropertySource.class))
|
||||
void withMissingPropertySource() {
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class)
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithMissingPropertySource.class))
|
||||
.withCauseInstanceOf(FileNotFoundException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withIgnoredPropertySource() {
|
||||
void withIgnoredPropertySource() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithIgnoredPropertySource.class);
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1")).isTrue();
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withSameSourceImportedInDifferentOrder() {
|
||||
void withSameSourceImportedInDifferentOrder() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithSameSourceImportedInDifferentOrder.class);
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1")).isTrue();
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2")).isTrue();
|
||||
@@ -240,7 +259,7 @@ public class PropertySourceAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void orderingWithAndWithoutNameAndMultipleResourceLocations() {
|
||||
void orderingWithAndWithoutNameAndMultipleResourceLocations() {
|
||||
// SPR-10820: p2 should 'win' as it was registered last
|
||||
AnnotationConfigApplicationContext ctxWithName = new AnnotationConfigApplicationContext(ConfigWithNameAndMultipleResourceLocations.class);
|
||||
AnnotationConfigApplicationContext ctxWithoutName = new AnnotationConfigApplicationContext(ConfigWithMultipleResourceLocations.class);
|
||||
@@ -249,14 +268,14 @@ public class PropertySourceAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void orderingWithAndWithoutNameAndFourResourceLocations() {
|
||||
void orderingWithAndWithoutNameAndFourResourceLocations() {
|
||||
// SPR-12198: p4 should 'win' as it was registered last
|
||||
AnnotationConfigApplicationContext ctxWithoutName = new AnnotationConfigApplicationContext(ConfigWithFourResourceLocations.class);
|
||||
assertThat(ctxWithoutName.getEnvironment().getProperty("testbean.name")).isEqualTo("p4TestBean");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void orderingDoesntReplaceExisting() throws Exception {
|
||||
void orderingDoesntReplaceExisting() throws Exception {
|
||||
// SPR-12198: mySource should 'win' as it was registered manually
|
||||
AnnotationConfigApplicationContext ctxWithoutName = new AnnotationConfigApplicationContext();
|
||||
MapPropertySource mySource = new MapPropertySource("mine", Collections.singletonMap("testbean.name", "myTestBean"));
|
||||
@@ -267,51 +286,51 @@ public class PropertySourceAnnotationTests {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource(value="classpath:${unresolvable}/p1.properties")
|
||||
@PropertySource("classpath:${unresolvable}/p1.properties")
|
||||
static class ConfigWithUnresolvablePlaceholder {
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource(value="classpath:${unresolvable:org/springframework/context/annotation}/p1.properties")
|
||||
@PropertySource("classpath:${unresolvable:org/springframework/context/annotation}/p1.properties")
|
||||
static class ConfigWithUnresolvablePlaceholderAndDefault {
|
||||
|
||||
@Inject Environment env;
|
||||
|
||||
@Bean
|
||||
public TestBean testBean() {
|
||||
TestBean testBean() {
|
||||
return new TestBean(env.getProperty("testbean.name"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource(value="classpath:${path.to.properties}/p1.properties")
|
||||
@PropertySource("classpath:${path.to.properties}/p1.properties")
|
||||
static class ConfigWithResolvablePlaceholder {
|
||||
|
||||
@Inject Environment env;
|
||||
|
||||
@Bean
|
||||
public TestBean testBean() {
|
||||
TestBean testBean() {
|
||||
return new TestBean(env.getProperty("testbean.name"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource(value="classpath:${path.to.properties}/p1.properties")
|
||||
@PropertySource("classpath:${path.to.properties}/p1.properties")
|
||||
static class ConfigWithResolvablePlaceholderAndFactoryBean {
|
||||
|
||||
@Inject Environment env;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Bean
|
||||
public FactoryBean testBean() {
|
||||
FactoryBean<TestBean> testBean() {
|
||||
final String name = env.getProperty("testbean.name");
|
||||
return new FactoryBean() {
|
||||
return new FactoryBean<TestBean>() {
|
||||
@Override
|
||||
public Object getObject() {
|
||||
public TestBean getObject() {
|
||||
return new TestBean(name);
|
||||
}
|
||||
@Override
|
||||
@@ -334,7 +353,7 @@ public class PropertySourceAnnotationTests {
|
||||
@Inject Environment env;
|
||||
|
||||
@Bean
|
||||
public TestBean testBean() {
|
||||
TestBean testBean() {
|
||||
return new TestBean(env.getProperty("testbean.name"));
|
||||
}
|
||||
}
|
||||
@@ -347,7 +366,7 @@ public class PropertySourceAnnotationTests {
|
||||
@Inject Environment env;
|
||||
|
||||
@Bean
|
||||
public TestBean testBean() {
|
||||
TestBean testBean() {
|
||||
return new TestBean(env.getProperty("testbean.name"));
|
||||
}
|
||||
}
|
||||
@@ -361,7 +380,7 @@ public class PropertySourceAnnotationTests {
|
||||
@Inject Environment env;
|
||||
|
||||
@Bean @Profile("test")
|
||||
public TestBean testBean() {
|
||||
TestBean testBean() {
|
||||
return new TestBean(env.getProperty("testbean.name"));
|
||||
}
|
||||
}
|
||||
@@ -380,21 +399,21 @@ public class PropertySourceAnnotationTests {
|
||||
|
||||
|
||||
@Configuration
|
||||
@MyPropertySource(value = "classpath:org/springframework/context/annotation/p2.properties")
|
||||
@MyPropertySource("classpath:org/springframework/context/annotation/p2.properties")
|
||||
static class WithCustomFactoryAsMeta {
|
||||
}
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@PropertySource(value = {}, factory = MyCustomFactory.class)
|
||||
public @interface MyPropertySource {
|
||||
@interface MyPropertySource {
|
||||
|
||||
@AliasFor(annotation = PropertySource.class)
|
||||
String value();
|
||||
}
|
||||
|
||||
|
||||
public static class MyCustomFactory implements PropertySourceFactory {
|
||||
static class MyCustomFactory implements PropertySourceFactory {
|
||||
|
||||
@Override
|
||||
public org.springframework.core.env.PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
|
||||
@@ -422,11 +441,10 @@ public class PropertySourceAnnotationTests {
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource(
|
||||
value = {
|
||||
"classpath:org/springframework/context/annotation/p1.properties",
|
||||
"classpath:org/springframework/context/annotation/p2.properties"
|
||||
})
|
||||
@PropertySource({
|
||||
"classpath:org/springframework/context/annotation/p1.properties",
|
||||
"classpath:org/springframework/context/annotation/p2.properties"
|
||||
})
|
||||
static class ConfigWithMultipleResourceLocations {
|
||||
}
|
||||
|
||||
@@ -434,12 +452,33 @@ public class PropertySourceAnnotationTests {
|
||||
@Configuration
|
||||
@PropertySources({
|
||||
@PropertySource("classpath:org/springframework/context/annotation/p1.properties"),
|
||||
@PropertySource("classpath:${base.package}/p2.properties"),
|
||||
@PropertySource("classpath:${base.package}/p2.properties")
|
||||
})
|
||||
static class ConfigWithPropertySources {
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource("classpath:org/springframework/context/annotation/p1.properties")
|
||||
@PropertySource(value = "classpath:${base.package}/p2.properties", ignoreResourceNotFound = true)
|
||||
static class ConfigWithRepeatedPropertySourceAnnotations {
|
||||
}
|
||||
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Configuration
|
||||
@PropertySource("classpath:org/springframework/context/annotation/p1.properties")
|
||||
@PropertySource(value = "classpath:${base.package}/p2.properties", ignoreResourceNotFound = true)
|
||||
@PropertySource(value = "classpath:${custom.config.package:bogus/config}/p3.properties", ignoreResourceNotFound = true)
|
||||
@interface ComposedConfiguration {
|
||||
}
|
||||
|
||||
@ComposedConfiguration
|
||||
static class ConfigWithRepeatedPropertySourceAnnotationsOnComposedAnnotation {
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySources({
|
||||
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p1.properties"),
|
||||
@@ -471,7 +510,7 @@ public class PropertySourceAnnotationTests {
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource(value = {})
|
||||
@PropertySource({})
|
||||
static class ConfigWithEmptyResourceLocations {
|
||||
}
|
||||
|
||||
@@ -482,7 +521,7 @@ public class PropertySourceAnnotationTests {
|
||||
@PropertySource("classpath:org/springframework/context/annotation/p2.properties")
|
||||
})
|
||||
@Configuration
|
||||
public static class ConfigWithSameSourceImportedInDifferentOrder {
|
||||
static class ConfigWithSameSourceImportedInDifferentOrder {
|
||||
|
||||
}
|
||||
|
||||
@@ -492,18 +531,17 @@ public class PropertySourceAnnotationTests {
|
||||
@PropertySource("classpath:org/springframework/context/annotation/p2.properties"),
|
||||
@PropertySource("classpath:org/springframework/context/annotation/p1.properties")
|
||||
})
|
||||
public static class ConfigImportedWithSameSourceImportedInDifferentOrder {
|
||||
static class ConfigImportedWithSameSourceImportedInDifferentOrder {
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource(
|
||||
value = {
|
||||
"classpath:org/springframework/context/annotation/p1.properties",
|
||||
"classpath:org/springframework/context/annotation/p2.properties",
|
||||
"classpath:org/springframework/context/annotation/p3.properties",
|
||||
"classpath:org/springframework/context/annotation/p4.properties"
|
||||
})
|
||||
@PropertySource({
|
||||
"classpath:org/springframework/context/annotation/p1.properties",
|
||||
"classpath:org/springframework/context/annotation/p2.properties",
|
||||
"classpath:org/springframework/context/annotation/p3.properties",
|
||||
"classpath:org/springframework/context/annotation/p4.properties"
|
||||
})
|
||||
static class ConfigWithFourResourceLocations {
|
||||
}
|
||||
|
||||
|
||||
+55
@@ -307,6 +307,23 @@ public class ConfigurationClassProcessingTests {
|
||||
assertThat(tb.getLawyer()).isEqualTo(ctx.getBean(NestedTestBean.class));
|
||||
}
|
||||
|
||||
@Test // gh-26019
|
||||
public void autowiringWithDynamicPrototypeBeanClass() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
|
||||
ConfigWithDynamicPrototype.class, PrototypeDependency.class);
|
||||
|
||||
PrototypeInterface p1 = ctx.getBean(PrototypeInterface.class, 1);
|
||||
assertThat(p1).isInstanceOf(PrototypeOne.class);
|
||||
assertThat(((PrototypeOne) p1).prototypeDependency).isNotNull();
|
||||
|
||||
PrototypeInterface p2 = ctx.getBean(PrototypeInterface.class, 2);
|
||||
assertThat(p2).isInstanceOf(PrototypeTwo.class);
|
||||
|
||||
PrototypeInterface p3 = ctx.getBean(PrototypeInterface.class, 1);
|
||||
assertThat(p3).isInstanceOf(PrototypeOne.class);
|
||||
assertThat(((PrototypeOne) p3).prototypeDependency).isNotNull();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new {@link BeanFactory}, populates it with a {@link BeanDefinition}
|
||||
@@ -632,4 +649,42 @@ public class ConfigurationClassProcessingTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class PrototypeDependency {
|
||||
}
|
||||
|
||||
interface PrototypeInterface {
|
||||
}
|
||||
|
||||
static class PrototypeOne extends AbstractPrototype {
|
||||
|
||||
@Autowired
|
||||
PrototypeDependency prototypeDependency;
|
||||
|
||||
}
|
||||
|
||||
static class PrototypeTwo extends AbstractPrototype {
|
||||
|
||||
// no autowired dependency here, in contrast to above
|
||||
}
|
||||
|
||||
static class AbstractPrototype implements PrototypeInterface {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ConfigWithDynamicPrototype {
|
||||
|
||||
@Bean
|
||||
@Scope(value = "prototype")
|
||||
public PrototypeInterface getDemoBean( int i) {
|
||||
switch ( i) {
|
||||
case 1: return new PrototypeOne();
|
||||
case 2:
|
||||
default:
|
||||
return new PrototypeTwo();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -26,6 +26,7 @@ import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.PayloadApplicationEvent;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.ResolvableTypeProvider;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -161,7 +162,7 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv
|
||||
Method method = ReflectionUtils.findMethod(
|
||||
SampleEvents.class, "handleGenericString", GenericTestEvent.class);
|
||||
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
|
||||
assertThat(adapter.getOrder()).isEqualTo(0);
|
||||
assertThat(adapter.getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+38
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,8 +22,11 @@ import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.PayloadApplicationEvent;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -34,14 +37,46 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class PayloadApplicationEventTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "resource" })
|
||||
public void testEventClassWithInterface() {
|
||||
ApplicationContext ac = new AnnotationConfigApplicationContext(AuditableListener.class);
|
||||
AuditablePayloadEvent event = new AuditablePayloadEvent<>(this, "xyz");
|
||||
|
||||
AuditablePayloadEvent<String> event = new AuditablePayloadEvent<>(this, "xyz");
|
||||
ac.publishEvent(event);
|
||||
assertThat(ac.getBean(AuditableListener.class).events.contains(event)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProgrammaticEventListener() {
|
||||
List<Auditable> events = new ArrayList<>();
|
||||
ApplicationListener<AuditablePayloadEvent<String>> listener = events::add;
|
||||
ApplicationListener<AuditablePayloadEvent<Integer>> mismatch = (event -> event.getPayload().intValue());
|
||||
|
||||
ConfigurableApplicationContext ac = new GenericApplicationContext();
|
||||
ac.addApplicationListener(listener);
|
||||
ac.addApplicationListener(mismatch);
|
||||
ac.refresh();
|
||||
|
||||
AuditablePayloadEvent<String> event = new AuditablePayloadEvent<>(this, "xyz");
|
||||
ac.publishEvent(event);
|
||||
assertThat(events.contains(event)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProgrammaticPayloadListener() {
|
||||
List<String> events = new ArrayList<>();
|
||||
ApplicationListener<PayloadApplicationEvent<String>> listener = ApplicationListener.forPayload(events::add);
|
||||
ApplicationListener<PayloadApplicationEvent<Integer>> mismatch = ApplicationListener.forPayload(payload -> payload.intValue());
|
||||
|
||||
ConfigurableApplicationContext ac = new GenericApplicationContext();
|
||||
ac.addApplicationListener(listener);
|
||||
ac.addApplicationListener(mismatch);
|
||||
ac.refresh();
|
||||
|
||||
AuditablePayloadEvent<String> event = new AuditablePayloadEvent<>(this, "xyz");
|
||||
ac.publishEvent(event);
|
||||
assertThat(events.contains(event.getPayload())).isTrue();
|
||||
}
|
||||
|
||||
|
||||
public interface Auditable {
|
||||
}
|
||||
|
||||
+33
-4
@@ -25,18 +25,47 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link BitsCronField}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class BitsCronFieldTests {
|
||||
class BitsCronFieldTests {
|
||||
|
||||
@Test
|
||||
void parse() {
|
||||
assertThat(BitsCronField.parseSeconds("42")).has(clearRange(0, 41)).has(set(42)).has(clearRange(43, 59));
|
||||
assertThat(BitsCronField.parseMinutes("1,2,5,9")).has(clear(0)).has(set(1, 2)).has(clearRange(3,4)).has(set(5)).has(clearRange(6,8)).has(set(9)).has(clearRange(10,59));
|
||||
assertThat(BitsCronField.parseSeconds("0-4,8-12")).has(setRange(0, 4)).has(clearRange(5,7)).has(setRange(8, 12)).has(clearRange(13,59));
|
||||
assertThat(BitsCronField.parseHours("0-23/2")).has(set(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22)).has(clear(1,3,5,7,9,11,13,15,17,19,21,23));
|
||||
assertThat(BitsCronField.parseDaysOfWeek("0")).has(clearRange(0, 6)).has(set(7, 7));
|
||||
assertThat(BitsCronField.parseSeconds("57/2")).has(clearRange(0, 56)).has(set(57)).has(clear(58)).has(set(59));
|
||||
|
||||
assertThat(BitsCronField.parseMinutes("30")).has(set(30)).has(clearRange(1, 29)).has(clearRange(31, 59));
|
||||
|
||||
assertThat(BitsCronField.parseHours("23")).has(set(23)).has(clearRange(0, 23));
|
||||
assertThat(BitsCronField.parseHours("0-23/2")).has(set(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22)).has(clear(1,3,5,7,9,11,13,15,17,19,21,23));
|
||||
|
||||
assertThat(BitsCronField.parseDaysOfMonth("1")).has(set(1)).has(clearRange(2, 31));
|
||||
|
||||
assertThat(BitsCronField.parseMonth("1")).has(set(1)).has(clearRange(2, 12));
|
||||
|
||||
assertThat(BitsCronField.parseDaysOfWeek("0")).has(set(7, 7)).has(clearRange(0, 6));
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseLists() {
|
||||
assertThat(BitsCronField.parseSeconds("15,30")).has(set(15, 30)).has(clearRange(1, 15)).has(clearRange(31, 59));
|
||||
assertThat(BitsCronField.parseMinutes("1,2,5,9")).has(set(1, 2, 5, 9)).has(clear(0)).has(clearRange(3, 4)).has(clearRange(6, 8)).has(clearRange(10, 59));
|
||||
assertThat(BitsCronField.parseHours("1,2,3")).has(set(1, 2, 3)).has(clearRange(4, 23));
|
||||
assertThat(BitsCronField.parseDaysOfMonth("1,2,3")).has(set(1, 2, 3)).has(clearRange(4, 31));
|
||||
assertThat(BitsCronField.parseMonth("1,2,3")).has(set(1, 2, 3)).has(clearRange(4, 12));
|
||||
assertThat(BitsCronField.parseDaysOfWeek("1,2,3")).has(set(1, 2, 3)).has(clearRange(4, 7));
|
||||
|
||||
assertThat(BitsCronField.parseMinutes("5,10-30/2"))
|
||||
.has(clearRange(0, 5))
|
||||
.has(set(5))
|
||||
.has(clearRange(6,10))
|
||||
.has(set(10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30))
|
||||
.has(clear(11, 13, 15, 17, 19, 21, 23, 25, 27, 29))
|
||||
.has(clearRange(31, 60));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+201
@@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test;
|
||||
import static java.time.DayOfWeek.FRIDAY;
|
||||
import static java.time.DayOfWeek.MONDAY;
|
||||
import static java.time.DayOfWeek.SUNDAY;
|
||||
import static java.time.DayOfWeek.THURSDAY;
|
||||
import static java.time.DayOfWeek.TUESDAY;
|
||||
import static java.time.DayOfWeek.WEDNESDAY;
|
||||
import static java.time.temporal.TemporalAdjusters.next;
|
||||
@@ -116,6 +117,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().withMinute(10);
|
||||
LocalDateTime expected = last.plusMinutes(1).withSecond(0).withNano(0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -149,6 +151,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.of(year, 10, 30, 11, 1);
|
||||
LocalDateTime expected = last.withHour(12).withMinute(0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -173,6 +176,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().withDayOfMonth(1);
|
||||
LocalDateTime expected = last.plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -207,6 +211,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().withMonth(9).withDayOfMonth(30);
|
||||
LocalDateTime expected = LocalDateTime.of(last.getYear(), 10, 1, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -222,6 +227,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().withMonth(8).withDayOfMonth(30);
|
||||
LocalDateTime expected = last.plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -237,6 +243,7 @@ class CronExpressionTests {
|
||||
ZonedDateTime last = ZonedDateTime.now(ZoneId.of("CET")).withMonth(10).withDayOfMonth(30);
|
||||
ZonedDateTime expected = last.withDayOfMonth(31).withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
ZonedDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -251,6 +258,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().withMonth(10).withDayOfMonth(30);
|
||||
LocalDateTime expected = LocalDateTime.of(last.getYear(), 11, 1, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -265,6 +273,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().withYear(2010).withMonth(12).withDayOfMonth(31);
|
||||
LocalDateTime expected = LocalDateTime.of(2011, 1, 1, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -297,6 +306,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().with(next(MONDAY));
|
||||
LocalDateTime expected = last.plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
assertThat(actual.getDayOfWeek()).isEqualTo(TUESDAY);
|
||||
}
|
||||
@@ -308,6 +318,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().with(next(WEDNESDAY));
|
||||
LocalDateTime expected = last.plusDays(6).withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
assertThat(actual.getDayOfWeek()).isEqualTo(TUESDAY);
|
||||
}
|
||||
@@ -319,6 +330,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().withMinute(4).withSecond(54);
|
||||
LocalDateTime expected = last.plusMinutes(1).withSecond(55).withNano(0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -333,6 +345,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().withHour(9).withSecond(54);
|
||||
LocalDateTime expected = last.plusHours(1).withMinute(0).withSecond(55).withNano(0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -347,6 +360,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().withHour(9).withMinute(4);
|
||||
LocalDateTime expected = last.plusHours(1).plusMinutes(1).withSecond(0).withNano(0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -362,6 +376,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().withDayOfMonth(2).withSecond(54);
|
||||
LocalDateTime expected = last.plusDays(1).withHour(0).withMinute(0).withSecond(55).withNano(0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -376,6 +391,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().withMonth(10).withDayOfMonth(2);
|
||||
LocalDateTime expected = LocalDateTime.of(last.getYear(), 11, 3, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -398,6 +414,7 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.now().withYear(2007).withMonth(2).withDayOfMonth(10);
|
||||
LocalDateTime expected = LocalDateTime.of(2008, 2, 29, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -413,12 +430,14 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.of(LocalDate.of(2009, 9, 26), LocalTime.now());
|
||||
LocalDateTime expected = last.plusDays(2).withHour(7).withMinute(0).withSecond(0).withNano(0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
// Next day is a week day so add one
|
||||
last = actual;
|
||||
expected = expected.plusDays(1);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -433,12 +452,14 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.of(LocalDate.of(2010, 12, 30), LocalTime.now());
|
||||
LocalDateTime expected = last.plusMonths(1).withHour(23).withMinute(30).withSecond(0).withSecond(0).withNano(0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
// Next trigger is 3 months later
|
||||
last = actual;
|
||||
expected = expected.plusMonths(3);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -485,11 +506,13 @@ class CronExpressionTests {
|
||||
LocalDateTime expected = LocalDateTime.of(last.getYear() + 1, 1, 1, 0, 0);
|
||||
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
expected = expected.plusYears(1);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -513,11 +536,13 @@ class CronExpressionTests {
|
||||
LocalDateTime expected = LocalDateTime.of(last.getYear(), 11, 1, 0, 0);
|
||||
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
expected = expected.plusMonths(1);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -534,11 +559,13 @@ class CronExpressionTests {
|
||||
LocalDateTime expected = last.with(next(SUNDAY)).withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
expected = expected.plusWeeks(1);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -555,11 +582,13 @@ class CronExpressionTests {
|
||||
LocalDateTime expected = last.plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
expected = expected.plusDays(1);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -583,11 +612,13 @@ class CronExpressionTests {
|
||||
LocalDateTime expected = last.plusHours(1).withMinute(0).withSecond(0).withNano(0);
|
||||
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
expected = expected.plusHours(1);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -603,16 +634,19 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.of(LocalDate.of(2008, 1, 4), LocalTime.now());
|
||||
LocalDateTime expected = LocalDateTime.of(2008, 1, 31, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
expected = LocalDateTime.of(2008, 2, 29, 0, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
expected = LocalDateTime.of(2008, 3, 31, 0, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -628,16 +662,19 @@ class CronExpressionTests {
|
||||
LocalDateTime last = LocalDateTime.of(LocalDate.of(2008, 1, 4), LocalTime.now());
|
||||
LocalDateTime expected = LocalDateTime.of(2008, 1, 28, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
expected = LocalDateTime.of(2008, 2, 26, 0, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
expected = LocalDateTime.of(2008, 3, 28, 0, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
@@ -1042,4 +1079,168 @@ class CronExpressionTests {
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
assertThat(actual.getDayOfWeek()).isEqualTo(WEDNESDAY);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dayOfMonthListWithQuartz() {
|
||||
CronExpression expression = CronExpression.parse("0 0 0 1W,15,LW * ?");
|
||||
|
||||
LocalDateTime last = LocalDateTime.of(2019, 12, 30, 0, 0);
|
||||
LocalDateTime expected = LocalDateTime.of(2019, 12, 31, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
assertThat(actual).is(weekday);
|
||||
|
||||
last = actual;
|
||||
expected = LocalDateTime.of(2020, 1, 1, 0, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
assertThat(actual).is(weekday);
|
||||
|
||||
last = actual;
|
||||
expected = LocalDateTime.of(2020, 1, 15, 0, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
expected = LocalDateTime.of(2020, 1, 31, 0, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
assertThat(actual).is(weekday);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dayOfWeekListWithQuartz() {
|
||||
CronExpression expression = CronExpression.parse("0 0 0 ? * THU#1,THU#3,THU#5");
|
||||
|
||||
LocalDateTime last = LocalDateTime.of(2019, 12, 31, 0, 0);
|
||||
LocalDateTime expected = LocalDateTime.of(2020, 1, 2, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
assertThat(actual.getDayOfWeek()).isEqualTo(THURSDAY);
|
||||
|
||||
last = actual;
|
||||
expected = LocalDateTime.of(2020, 1, 16, 0, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
assertThat(actual.getDayOfWeek()).isEqualTo(THURSDAY);
|
||||
|
||||
last = actual;
|
||||
expected = LocalDateTime.of(2020, 1, 30, 0, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
assertThat(actual.getDayOfWeek()).isEqualTo(THURSDAY);
|
||||
}
|
||||
|
||||
@Test
|
||||
void quartzLastDayOfMonthEveryHour() {
|
||||
CronExpression expression = CronExpression.parse("0 0 * L * *");
|
||||
|
||||
LocalDateTime last = LocalDateTime.of(2021, 1, 30, 0, 1);
|
||||
LocalDateTime expected = LocalDateTime.of(2021, 1, 31, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = LocalDateTime.of(2021, 1, 31, 1, 0);
|
||||
expected = LocalDateTime.of(2021, 1, 31, 2, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void quartzLastDayOfMonthOffsetEveryHour() {
|
||||
CronExpression expression = CronExpression.parse("0 0 * L-1 * *");
|
||||
|
||||
LocalDateTime last = LocalDateTime.of(2021, 1, 29, 0, 1);
|
||||
LocalDateTime expected = LocalDateTime.of(2021, 1, 30, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = LocalDateTime.of(2021, 1, 30, 1, 0);
|
||||
expected = LocalDateTime.of(2021, 1, 30, 2, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void quartzFirstWeekdayOfMonthEveryHour() {
|
||||
CronExpression expression = CronExpression.parse("0 0 * 1W * *");
|
||||
|
||||
LocalDateTime last = LocalDateTime.of(2021, 1, 31, 0, 1);
|
||||
LocalDateTime expected = LocalDateTime.of(2021, 2, 1, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = LocalDateTime.of(2021, 2, 1, 1, 0);
|
||||
expected = LocalDateTime.of(2021, 2, 1, 2, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void quartzLastWeekdayOfMonthEveryHour() {
|
||||
CronExpression expression = CronExpression.parse("0 0 * LW * *");
|
||||
|
||||
LocalDateTime last = LocalDateTime.of(2021, 1, 28, 0, 1);
|
||||
LocalDateTime expected = LocalDateTime.of(2021, 1, 29, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = LocalDateTime.of(2021, 1, 29, 1, 0);
|
||||
expected = LocalDateTime.of(2021, 1, 29, 2, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void quartz5thFridayOfTheMonthEveryHour() {
|
||||
CronExpression expression = CronExpression.parse("0 0 * ? * FRI#5");
|
||||
|
||||
LocalDateTime last = LocalDateTime.of(2021, 1, 28, 0, 1);
|
||||
LocalDateTime expected = LocalDateTime.of(2021, 1, 29, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
|
||||
|
||||
last = LocalDateTime.of(2021, 1, 29, 1, 0);
|
||||
expected = LocalDateTime.of(2021, 1, 29, 2, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void quartzLastFridayOfTheMonthEveryHour() {
|
||||
CronExpression expression = CronExpression.parse("0 0 * ? * FRIL");
|
||||
|
||||
LocalDateTime last = LocalDateTime.of(2021, 1, 28, 0, 1);
|
||||
LocalDateTime expected = LocalDateTime.of(2021, 1, 29, 0, 0);
|
||||
LocalDateTime actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
|
||||
|
||||
last = LocalDateTime.of(2021, 1, 29, 1, 0);
|
||||
expected = LocalDateTime.of(2021, 1, 29, 2, 0);
|
||||
actual = expression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+4
@@ -25,6 +25,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link QuartzCronField}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
class QuartzCronFieldTests {
|
||||
@@ -95,6 +97,8 @@ class QuartzCronFieldTests {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("1#L"));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("L#1"));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("8#1"));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("2#1,2#3,2#5"));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("FRI#-1"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
testbean.name=p3TestBean
|
||||
from.p3=p3Value
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -58,10 +58,10 @@ internal fun <T: Any> monoToDeferred(source: Mono<T>) =
|
||||
* @since 5.2
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun invokeSuspendingFunction(method: Method, bean: Any, vararg args: Any?): Publisher<*> {
|
||||
fun invokeSuspendingFunction(method: Method, target: Any, vararg args: Any?): Publisher<*> {
|
||||
val function = method.kotlinFunction!!
|
||||
val mono = mono(Dispatchers.Unconfined) {
|
||||
function.callSuspend(bean, *args.sliceArray(0..(args.size-2))).let { if (it == Unit) null else it }
|
||||
function.callSuspend(target, *args.sliceArray(0..(args.size-2))).let { if (it == Unit) null else it }
|
||||
}.onErrorMap(InvocationTargetException::class.java) { it.targetException }
|
||||
return if (function.returnType.classifier == Flow::class) {
|
||||
mono.flatMapMany { (it as Flow<Any>).asFlux() }
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
|
||||
plugins {
|
||||
id "com.github.johnrengelman.shadow" version "5.2.0"
|
||||
}
|
||||
|
||||
description = "Spring Core"
|
||||
|
||||
apply plugin: "kotlin"
|
||||
|
||||
// spring-core includes asm and repackages cglib, inlining both into the spring-core jar.
|
||||
// cglib itself depends on asm and is therefore further transformed by the JarJar task to
|
||||
// cglib itself depends on asm and is therefore further transformed by the ShadowJar task to
|
||||
// depend on org.springframework.asm; this avoids including two different copies of asm.
|
||||
def cglibVersion = "3.3.0"
|
||||
def objenesisVersion = "3.1"
|
||||
@@ -55,20 +51,20 @@ dependencies {
|
||||
optional("io.reactivex.rxjava3:rxjava")
|
||||
optional("io.netty:netty-buffer")
|
||||
testCompile("io.projectreactor:reactor-test")
|
||||
testCompile("javax.annotation:javax.annotation-api")
|
||||
testCompile("com.google.code.findbugs:jsr305")
|
||||
testCompile("org.xmlunit:xmlunit-assertj")
|
||||
testCompile("org.xmlunit:xmlunit-matchers")
|
||||
testCompile("javax.annotation:javax.annotation-api")
|
||||
testCompile("javax.xml.bind:jaxb-api")
|
||||
testCompile("com.fasterxml.woodstox:woodstox-core")
|
||||
testCompile("org.xmlunit:xmlunit-assertj")
|
||||
testCompile("org.xmlunit:xmlunit-matchers")
|
||||
testCompile(project(":kotlin-coroutines"))
|
||||
testCompile("io.projectreactor.tools:blockhound")
|
||||
testFixturesImplementation("com.google.code.findbugs:jsr305")
|
||||
testFixturesImplementation("io.projectreactor:reactor-test")
|
||||
testFixturesImplementation("org.assertj:assertj-core")
|
||||
testFixturesImplementation("com.google.code.findbugs:jsr305")
|
||||
testFixturesImplementation("org.junit.platform:junit-platform-launcher")
|
||||
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api")
|
||||
testFixturesImplementation("org.junit.jupiter:junit-jupiter-params")
|
||||
testFixturesImplementation("org.assertj:assertj-core")
|
||||
testFixturesImplementation("org.xmlunit:xmlunit-assertj")
|
||||
}
|
||||
|
||||
@@ -99,7 +95,7 @@ jar {
|
||||
}
|
||||
|
||||
test {
|
||||
// make sure the classes dir is used on the test classpath (required by ResourceTests)
|
||||
// Make sure the classes dir is used on the test classpath (required by ResourceTests)
|
||||
// When test fixtures are involved, the JAR is used by default
|
||||
classpath = sourceSets.main.output.classesDirs + classpath - files(jar.archiveFile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.core.codec;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Level;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.Param;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Benchmarks for {@link DataBufferUtils}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
public class StringDecoderBenchmark {
|
||||
|
||||
@Benchmark
|
||||
public void parseSseLines(SseLinesState state, Blackhole blackhole) {
|
||||
blackhole.consume(state.parseLines().blockLast());
|
||||
}
|
||||
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@SuppressWarnings({"NotNullFieldNotInitialized", "ConstantConditions"})
|
||||
public static class SseLinesState {
|
||||
|
||||
private static final Charset CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
private static final ResolvableType ELEMENT_TYPE = ResolvableType.forClass(String.class);
|
||||
|
||||
|
||||
@Param("10240")
|
||||
int totalSize;
|
||||
|
||||
@Param("2000")
|
||||
int chunkSize;
|
||||
|
||||
List<DataBuffer> chunks;
|
||||
|
||||
StringDecoder decoder = StringDecoder.textPlainOnly(Arrays.asList("\r\n", "\n"), false);
|
||||
|
||||
MimeType mimeType = new MimeType("text", "plain", CHARSET);
|
||||
|
||||
|
||||
@Setup(Level.Trial)
|
||||
public void setup() {
|
||||
String eventTemplate = "id:$1\n" +
|
||||
"event:some-event\n" +
|
||||
":some-comment-$1-aa\n" +
|
||||
":some-comment-$1-bb\n" +
|
||||
"data:abcdefg-$1-hijklmnop-$1-qrstuvw-$1-xyz-$1\n\n";
|
||||
|
||||
int eventLength = String.format(eventTemplate, String.format("%05d", 1)).length();
|
||||
int eventCount = this.totalSize / eventLength;
|
||||
DataBufferFactory bufferFactory = new DefaultDataBufferFactory();
|
||||
|
||||
this.chunks = Flux.range(1, eventCount)
|
||||
.map(index -> String.format(eventTemplate, String.format("%05d", index)))
|
||||
.buffer(this.chunkSize > eventLength ? this.chunkSize / eventLength : 1)
|
||||
.map(strings -> String.join("", strings))
|
||||
.map(chunk -> {
|
||||
byte[] bytes = chunk.getBytes(CHARSET);
|
||||
DataBuffer buffer = bufferFactory.allocateBuffer(bytes.length);
|
||||
buffer.write(bytes);
|
||||
return buffer;
|
||||
})
|
||||
.collectList()
|
||||
.block();
|
||||
}
|
||||
|
||||
public Flux<String> parseLines() {
|
||||
Flux<DataBuffer> input = Flux.fromIterable(this.chunks).doOnNext(DataBufferUtils::retain);
|
||||
return this.decoder.decode(input, ELEMENT_TYPE, this.mimeType, Collections.emptyMap());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public abstract class AnnotationVisitor {
|
||||
&& api != Opcodes.ASM10_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
// SPRING PATCH: no preview mode check for ASM 9 experimental
|
||||
// SPRING PATCH: no preview mode check for ASM experimental
|
||||
this.api = api;
|
||||
this.av = annotationVisitor;
|
||||
}
|
||||
@@ -129,9 +129,9 @@ public abstract class AnnotationVisitor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an array value of the annotation. Note that arrays of primitive types (such as byte,
|
||||
* Visits an array value of the annotation. Note that arrays of primitive values (such as byte,
|
||||
* boolean, short, char, int, long, float or double) can be passed as value to {@link #visit
|
||||
* visit}. This is what {@link ClassReader} does.
|
||||
* visit}. This is what {@link ClassReader} does for non empty arrays of primitive values.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @return a visitor to visit the actual array value elements, or {@literal null} if this visitor
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user