mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-18 00:49:02 +00:00
Compare commits
973
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8dab9416c7 | ||
|
|
a9dd927870 | ||
|
|
323ccf99e5 | ||
|
|
437eca0b25 | ||
|
|
965f3c6434 | ||
|
|
6df7ba2447 | ||
|
|
1d6f71718d | ||
|
|
4a6e9a5557 | ||
|
|
357ca21675 | ||
|
|
874859493b | ||
|
|
75a6f3b2b6 | ||
|
|
88456d4799 | ||
|
|
c44de3c5df | ||
|
|
9d1789e718 | ||
|
|
849b6ccb8b | ||
|
|
997ca5cd3f | ||
|
|
a54bc6650e | ||
|
|
70424a7e3d | ||
|
|
318d04cd2b | ||
|
|
d9ff109b0f | ||
|
|
8501cef98d | ||
|
|
c99a104919 | ||
|
|
193c289080 | ||
|
|
9c3270ad35 | ||
|
|
e4a9ade991 | ||
|
|
fbd83015b1 | ||
|
|
3a15595d0c | ||
|
|
289a6091f1 | ||
|
|
3502f6fdc2 | ||
|
|
8d67a982ec | ||
|
|
c09e10405b | ||
|
|
6a727e1ed7 | ||
|
|
246a6db1ca | ||
|
|
8748ba4c4b | ||
|
|
2989f01013 | ||
|
|
c6a7732a30 | ||
|
|
e54c9d4a93 | ||
|
|
ac19c696fe | ||
|
|
fecbcd4e93 | ||
|
|
59396e1a6f | ||
|
|
c4ef47b29f | ||
|
|
c2fdd56107 | ||
|
|
98536e1387 | ||
|
|
ba13950d3a | ||
|
|
0009806deb | ||
|
|
6deee3e818 | ||
|
|
d3acf45ea4 | ||
|
|
573f1d77f2 | ||
|
|
1ca06537c1 | ||
|
|
1ab0850303 | ||
|
|
2a9eaab674 | ||
|
|
1fbd38c2d8 | ||
|
|
49eafe4261 | ||
|
|
b0ed385f84 | ||
|
|
5d54adfb9a | ||
|
|
1cbc353dd1 | ||
|
|
4cf1795359 | ||
|
|
5629fa2c9f | ||
|
|
2903cb7f50 | ||
|
|
986d219391 | ||
|
|
de4da5ea4e | ||
|
|
e8c656d2bc | ||
|
|
bcda243f63 | ||
|
|
64f304c333 | ||
|
|
5f6b04251e | ||
|
|
618cb6155c | ||
|
|
f3dd22da5b | ||
|
|
6e4bbac6f7 | ||
|
|
2e4963fca3 | ||
|
|
4d0adc7d95 | ||
|
|
3b3f27d5ff | ||
|
|
f32b13c5b3 | ||
|
|
1897d8e858 | ||
|
|
71126faae0 | ||
|
|
9cc03fa8b0 | ||
|
|
59189e5957 | ||
|
|
65a8aa1c09 | ||
|
|
f046a066ec | ||
|
|
6e1cac9145 | ||
|
|
7cafa6764c | ||
|
|
c1cb0311aa | ||
|
|
f2478cf8cf | ||
|
|
977084a6b8 | ||
|
|
0e7e49bab0 | ||
|
|
301ba01427 | ||
|
|
881817678f | ||
|
|
b8c92ce931 | ||
|
|
6158634d67 | ||
|
|
8d8bb04783 | ||
|
|
2cac3a8255 | ||
|
|
25a3019234 | ||
|
|
3dff1b3f6e | ||
|
|
b1295d0499 | ||
|
|
eeeb0a6546 | ||
|
|
1bde920cce | ||
|
|
e02ff3a0da | ||
|
|
ff377a3836 | ||
|
|
ddb2bdf8c6 | ||
|
|
b9ebdaaf37 | ||
|
|
4187e04b69 | ||
|
|
d512cca3fd | ||
|
|
4bc3e0c2b4 | ||
|
|
d57d914b26 | ||
|
|
68463e2018 | ||
|
|
6fa9539ae2 | ||
|
|
ff53a26333 | ||
|
|
b70d400c71 | ||
|
|
346d0e271d | ||
|
|
c15f23bf0c | ||
|
|
0962c66592 | ||
|
|
b643f7836c | ||
|
|
56fdda167e | ||
|
|
017f2a8ccc | ||
|
|
f7898951bd | ||
|
|
bd6b7b08f3 | ||
|
|
bc043245cc | ||
|
|
6e8a3fb4db | ||
|
|
1f12214b45 | ||
|
|
c6bd0c9f3d | ||
|
|
fb22915563 | ||
|
|
c5c27f2963 | ||
|
|
3e6cfb7c6d | ||
|
|
8e68ac44d2 | ||
|
|
81c50dc674 | ||
|
|
57aa3d1e3b | ||
|
|
2c45b09263 | ||
|
|
59f12635f9 | ||
|
|
901d48c803 | ||
|
|
0bc7c47bea | ||
|
|
06e2bada0a | ||
|
|
8181c0237f | ||
|
|
d4af8c86b2 | ||
|
|
39ddd0f349 | ||
|
|
073e78b68d | ||
|
|
f9754f92f4 | ||
|
|
d5f358c33c | ||
|
|
295df21f06 | ||
|
|
57a9e8e6dd | ||
|
|
e83491fbe9 | ||
|
|
37ee264fbf | ||
|
|
8b5563ecab | ||
|
|
0a3a82fd83 | ||
|
|
8b071633d3 | ||
|
|
caed04473e | ||
|
|
87abdb92da | ||
|
|
6d11b40353 | ||
|
|
350f318d2e | ||
|
|
608ef46516 | ||
|
|
d60446a4fe | ||
|
|
722cb36e01 | ||
|
|
5ba37762fe | ||
|
|
f2dc075335 | ||
|
|
3b0eca921c | ||
|
|
efe2539cf3 | ||
|
|
0030ff8711 | ||
|
|
f93ca28884 | ||
|
|
4be416e2ca | ||
|
|
2033f50f22 | ||
|
|
e33fb892f1 | ||
|
|
afe461609c | ||
|
|
33d655a634 | ||
|
|
2654dbfcf1 | ||
|
|
14440949b3 | ||
|
|
05dec6d23e | ||
|
|
cc77b4b995 | ||
|
|
fd964ca4b1 | ||
|
|
5fd761ee39 | ||
|
|
8fda96cadb | ||
|
|
9926b68473 | ||
|
|
d8a2672505 | ||
|
|
b125b5e398 | ||
|
|
65743a68e6 | ||
|
|
f187ca6413 | ||
|
|
13c213481a | ||
|
|
ce9402618c | ||
|
|
a041769799 | ||
|
|
09cb7f4c31 | ||
|
|
04f954956c | ||
|
|
fe4472dbeb | ||
|
|
b708027e94 | ||
|
|
333449598f | ||
|
|
03b2d9399e | ||
|
|
4ccf33e36b | ||
|
|
5eebe946bd | ||
|
|
13fa69bdaf | ||
|
|
4aeca67c4d | ||
|
|
b695b15243 | ||
|
|
ef4b62caa0 | ||
|
|
238e9ae59f | ||
|
|
347f2890df | ||
|
|
8b5a013423 | ||
|
|
a73d9bbed5 | ||
|
|
c1bc74c83f | ||
|
|
f68fdd4454 | ||
|
|
19640ec3f9 | ||
|
|
69c882cfbc | ||
|
|
64af3a0f64 | ||
|
|
d7959edb3e | ||
|
|
0b77c8835c | ||
|
|
28f15057ac | ||
|
|
e5025419c2 | ||
|
|
d53ede9bd3 | ||
|
|
092b3d4a52 | ||
|
|
bf4cadadda | ||
|
|
a9bad580d9 | ||
|
|
6f6ff33202 | ||
|
|
4bb837582e | ||
|
|
3368dcae22 | ||
|
|
86704112b0 | ||
|
|
d62dd2dd8d | ||
|
|
e935018b0c | ||
|
|
0747cd6a70 | ||
|
|
0a30b71dc3 | ||
|
|
03118542f4 | ||
|
|
1b3b058ebd | ||
|
|
8aa94aee27 | ||
|
|
6dbc828aa1 | ||
|
|
3c31e0378f | ||
|
|
e6e6b8f4ad | ||
|
|
4fe94dffc0 | ||
|
|
4b8a937bee | ||
|
|
55fc731c59 | ||
|
|
40a61277e1 | ||
|
|
8c499cb10b | ||
|
|
723b2b19a6 | ||
|
|
f09e252417 | ||
|
|
f3b8d7138c | ||
|
|
47383fce97 | ||
|
|
8206f0652b | ||
|
|
1b58fad228 | ||
|
|
a58ef88f1d | ||
|
|
1d060ecff0 | ||
|
|
122a3fe9fd | ||
|
|
2a309a031a | ||
|
|
03fef655ff | ||
|
|
a9e2040831 | ||
|
|
ffbaa26b4f | ||
|
|
586912792a | ||
|
|
640c8ff693 | ||
|
|
d52d9fd268 | ||
|
|
f861f182fa | ||
|
|
d5f34ed641 | ||
|
|
a88c47a120 | ||
|
|
6dc73469f9 | ||
|
|
59d654b0cf | ||
|
|
9779b8b2ab | ||
|
|
2c8a6bb6f5 | ||
|
|
5800c7a18a | ||
|
|
dc0a934c99 | ||
|
|
9ca4de1ccf | ||
|
|
519195cf66 | ||
|
|
573ff2c58d | ||
|
|
9470719cdb | ||
|
|
97bc2762e1 | ||
|
|
5867ea0c3c | ||
|
|
9cc3349e2d | ||
|
|
8904de2149 | ||
|
|
4208ec0ba8 | ||
|
|
ab19c227d3 | ||
|
|
be5b9354a9 | ||
|
|
c92393b168 | ||
|
|
75a813aff6 | ||
|
|
6446ffd063 | ||
|
|
db7d71503d | ||
|
|
99d39eb2ee | ||
|
|
c32c9ecb61 | ||
|
|
40f3fb20c2 | ||
|
|
268ccb6b6b | ||
|
|
9c7141a24a | ||
|
|
b0ae8f6058 | ||
|
|
d473506d32 | ||
|
|
6f65b638de | ||
|
|
97c63857c4 | ||
|
|
4cc8f4c4d8 | ||
|
|
dff2c84ed1 | ||
|
|
17fb4fed09 | ||
|
|
77bab959a3 | ||
|
|
c2438cb932 | ||
|
|
03be8095ca | ||
|
|
4daf685eee | ||
|
|
b6ca8a9018 | ||
|
|
8071f13481 | ||
|
|
565b20d638 | ||
|
|
7610210a0e | ||
|
|
a4803d8b0f | ||
|
|
ab081c4fab | ||
|
|
dbc04282e2 | ||
|
|
bb41ccefc0 | ||
|
|
d0d4421aea | ||
|
|
1a1d767d59 | ||
|
|
1bf3e7c021 | ||
|
|
40ba95f82e | ||
|
|
cc70fdcbeb | ||
|
|
5f167fd7f8 | ||
|
|
9fdc4404a5 | ||
|
|
18a3322d2f | ||
|
|
87df393f91 | ||
|
|
963dd3f804 | ||
|
|
8e3a55ba89 | ||
|
|
a839477d4a | ||
|
|
53a9697ff1 | ||
|
|
d11bd64e0d | ||
|
|
dedecb9daa | ||
|
|
35af7ff854 | ||
|
|
5e904ddcaa | ||
|
|
74532a24a4 | ||
|
|
c0ee1ff896 | ||
|
|
f944815d92 | ||
|
|
0d0399ac02 | ||
|
|
d1f42ac729 | ||
|
|
17f42fc97a | ||
|
|
fa2c377405 | ||
|
|
9dcdfec2e2 | ||
|
|
07a0a31565 | ||
|
|
f3a2f57696 | ||
|
|
80bf394fdc | ||
|
|
f948742781 | ||
|
|
0088922dfd | ||
|
|
57fbdc0ad5 | ||
|
|
f5d689e764 | ||
|
|
681ced8fd3 | ||
|
|
8b64ad3192 | ||
|
|
35248498ae | ||
|
|
5f07434360 | ||
|
|
cd602e5904 | ||
|
|
0e8bd71d53 | ||
|
|
c752ba5b38 | ||
|
|
12978b8185 | ||
|
|
40b4276475 | ||
|
|
4160ced64c | ||
|
|
a032e86355 | ||
|
|
4b2bad96ce | ||
|
|
1513c4a952 | ||
|
|
bb6d9fabee | ||
|
|
bffcd33ea3 | ||
|
|
c9ffa64140 | ||
|
|
aa0d7a61b6 | ||
|
|
e138d7d29f | ||
|
|
50f8b6b3ab | ||
|
|
121a3bf670 | ||
|
|
e4031f290e | ||
|
|
55fa5f2b65 | ||
|
|
3802aca474 | ||
|
|
a9a4d7cf78 | ||
|
|
17382aec6d | ||
|
|
8ad3c958e1 | ||
|
|
8d743181da | ||
|
|
f92ab75bc9 | ||
|
|
092b5f7556 | ||
|
|
d4d609318d | ||
|
|
501891c749 | ||
|
|
2b0dc8d7ff | ||
|
|
674e2320a8 | ||
|
|
fee259a3c5 | ||
|
|
016b7d753c | ||
|
|
a17255a2e3 | ||
|
|
35efdf6b51 | ||
|
|
b35c238d27 | ||
|
|
db1fd516ea | ||
|
|
b7337b304e | ||
|
|
7cac1f1e6e | ||
|
|
fa09cd3737 | ||
|
|
be93ee77e4 | ||
|
|
8330134757 | ||
|
|
9cb9884533 | ||
|
|
ac25db6d2b | ||
|
|
22bf9febcc | ||
|
|
c6deeb31ec | ||
|
|
f80b2d9a94 | ||
|
|
8c206bf477 | ||
|
|
6aeb8ef56d | ||
|
|
04a96ffa27 | ||
|
|
2677584658 | ||
|
|
99236759ec | ||
|
|
e2aa117ff9 | ||
|
|
8deec9569c | ||
|
|
0f8bf10aa8 | ||
|
|
e0a7b074ed | ||
|
|
4fc41eeeb9 | ||
|
|
81143a80c4 | ||
|
|
9572859a35 | ||
|
|
78931ee3ea | ||
|
|
e522fec611 | ||
|
|
a12bbde87e | ||
|
|
50235be746 | ||
|
|
1332482c40 | ||
|
|
799589ec1c | ||
|
|
16fdda00c1 | ||
|
|
d2985613d1 | ||
|
|
beac891ff0 | ||
|
|
2d1b551248 | ||
|
|
aa8cf190d3 | ||
|
|
d643e57318 | ||
|
|
84d2e5a3c8 | ||
|
|
dab56dbb05 | ||
|
|
9b647021f7 | ||
|
|
38089d8e66 | ||
|
|
554c3f3d7e | ||
|
|
ee40310c92 | ||
|
|
226cddadef | ||
|
|
5a80f4f16e | ||
|
|
bb63ce9935 | ||
|
|
1b4289803b | ||
|
|
3d7576df7f | ||
|
|
8b9e9202f1 | ||
|
|
afe11e7919 | ||
|
|
665e6cf6ca | ||
|
|
fd1d8aeeb4 | ||
|
|
9b2f9e655e | ||
|
|
6c370ed28d | ||
|
|
a2b356162e | ||
|
|
71f7fdd632 | ||
|
|
c35ddf905a | ||
|
|
d866715556 | ||
|
|
a9a1f783c5 | ||
|
|
65d52a4b97 | ||
|
|
3c8fc46568 | ||
|
|
421fabb2c4 | ||
|
|
811d523211 | ||
|
|
40232f4e22 | ||
|
|
80fa3ac907 | ||
|
|
54180f90e2 | ||
|
|
865953f145 | ||
|
|
93fac8882f | ||
|
|
a3d199f4dd | ||
|
|
597fe0720f | ||
|
|
8321f01bf8 | ||
|
|
7e736b69b7 | ||
|
|
8b054840fc | ||
|
|
7f3d0b3e6e | ||
|
|
546d7ddd07 | ||
|
|
95099fd709 | ||
|
|
f65e1edd58 | ||
|
|
0a9f98f0df | ||
|
|
46cf4f9ba1 | ||
|
|
2b930e3858 | ||
|
|
bde2ddbeb1 | ||
|
|
4eb929c105 | ||
|
|
d0d7a88233 | ||
|
|
f7548a87ed | ||
|
|
e0fe7cdc44 | ||
|
|
8289bf0aff | ||
|
|
79d747410d | ||
|
|
70bca99da8 | ||
|
|
83617f382c | ||
|
|
21ac764e5c | ||
|
|
c4fda0e811 | ||
|
|
66670cfd56 | ||
|
|
c31bfe65aa | ||
|
|
22ddb35258 | ||
|
|
d0177b0f55 | ||
|
|
2233ec04ff | ||
|
|
e9ff3bb4e3 | ||
|
|
57c8c759ae | ||
|
|
cfd9b3461f | ||
|
|
d3324c8d4f | ||
|
|
ffe9bae138 | ||
|
|
020e51cb96 | ||
|
|
a78066830b | ||
|
|
77c771e874 | ||
|
|
227ac3faa4 | ||
|
|
98dbc17591 | ||
|
|
e58b17a3a1 | ||
|
|
9de97614a0 | ||
|
|
015e00b5dd | ||
|
|
0bc59225d8 | ||
|
|
d8acc27afb | ||
|
|
a1e4afe338 | ||
|
|
3b9faee335 | ||
|
|
0048ff84ea | ||
|
|
c3f131325d | ||
|
|
b945e0f202 | ||
|
|
ce3cf3251d | ||
|
|
d69fb06852 | ||
|
|
e9de3bb85b | ||
|
|
e6a51e3d29 | ||
|
|
c734c3a3fe | ||
|
|
a48a956c0c | ||
|
|
e5010a823b | ||
|
|
1db42081e5 | ||
|
|
34a0857628 | ||
|
|
ba0484fcac | ||
|
|
f1133a8e56 | ||
|
|
35e37f6b60 | ||
|
|
f117b804a8 | ||
|
|
278199d467 | ||
|
|
fd568f3e96 | ||
|
|
45b27a85f4 | ||
|
|
0f71f58616 | ||
|
|
9834c42b5c | ||
|
|
7879bdfc1d | ||
|
|
dfa8a7c358 | ||
|
|
427fd9b19a | ||
|
|
6417ed47ab | ||
|
|
b0ef80c3ff | ||
|
|
7ed4884eaa | ||
|
|
c3cc42d4d3 | ||
|
|
860e2bcc2d | ||
|
|
06231721c3 | ||
|
|
4d2360e5b5 | ||
|
|
4f52174674 | ||
|
|
7d7c5c9d9c | ||
|
|
08b9e7b83e | ||
|
|
e24c530705 | ||
|
|
5017c05c23 | ||
|
|
6e93834e27 | ||
|
|
5f90a7eee9 | ||
|
|
eff285eb3b | ||
|
|
da7d79b3a1 | ||
|
|
d6216fb74a | ||
|
|
941f3e7166 | ||
|
|
e80c251c7a | ||
|
|
56abc4a429 | ||
|
|
dde9e27630 | ||
|
|
15b174a522 | ||
|
|
1fcb2608fb | ||
|
|
c15d687bf0 | ||
|
|
e038631a6d | ||
|
|
d5daa8e3a7 | ||
|
|
6014ca9140 | ||
|
|
d4010573af | ||
|
|
e3cd5c8ef0 | ||
|
|
dec1c93b24 | ||
|
|
3ef6697536 | ||
|
|
8207c53b9a | ||
|
|
e3be94c961 | ||
|
|
b40f016de2 | ||
|
|
28849e0987 | ||
|
|
b386be1529 | ||
|
|
a98a61852f | ||
|
|
3304efd64d | ||
|
|
b97e7d53bc | ||
|
|
4af6d58d8d | ||
|
|
e2d06eaae5 | ||
|
|
fcfacd9f83 | ||
|
|
bddcc669b3 | ||
|
|
2024b37e65 | ||
|
|
fb3191904a | ||
|
|
9e4d74c502 | ||
|
|
9b221f58b9 | ||
|
|
f7c3b814e3 | ||
|
|
155bbb8466 | ||
|
|
4f690eea2a | ||
|
|
70a1ecba7f | ||
|
|
c8b0ff2fca | ||
|
|
f9a4856c3b | ||
|
|
35b67a54d2 | ||
|
|
78a23be9bc | ||
|
|
09c5958608 | ||
|
|
ffb295971a | ||
|
|
77bb7e6030 | ||
|
|
75daf781c2 | ||
|
|
fcead670f0 | ||
|
|
801b93a078 | ||
|
|
4beeeb8118 | ||
|
|
64d4afad9f | ||
|
|
48f57e3bb2 | ||
|
|
d92f69747b | ||
|
|
315698b50e | ||
|
|
6deccf123d | ||
|
|
391ebc8eda | ||
|
|
28c7f65a25 | ||
|
|
caebe72083 | ||
|
|
f79baec5ff | ||
|
|
d1c0ea7d74 | ||
|
|
53e2d7d160 | ||
|
|
8c62a2f11a | ||
|
|
8656e30550 | ||
|
|
0655d73f8e | ||
|
|
24ebd15f9c | ||
|
|
cce84711c6 | ||
|
|
7f127300f9 | ||
|
|
1521094c5b | ||
|
|
0b8134049c | ||
|
|
70a980db58 | ||
|
|
8b960099f1 | ||
|
|
cc53d597c0 | ||
|
|
5982f732b4 | ||
|
|
c5500b2332 | ||
|
|
de611cb3a9 | ||
|
|
72a76367f2 | ||
|
|
5afc3a3a50 | ||
|
|
2f2ef00d1f | ||
|
|
de7eea4498 | ||
|
|
e9a87de965 | ||
|
|
db7b74feac | ||
|
|
f7d126043b | ||
|
|
55b44b4f86 | ||
|
|
523370b6f2 | ||
|
|
131d2c2051 | ||
|
|
7f05c2a18c | ||
|
|
8fc65ab0a5 | ||
|
|
b6108e3b2d | ||
|
|
26a4aef417 | ||
|
|
050f2c746d | ||
|
|
fd21e0e69a | ||
|
|
794580ffcd | ||
|
|
d44bc27c9a | ||
|
|
243e21a3ea | ||
|
|
20aaa8841c | ||
|
|
d77ab67c56 | ||
|
|
dd2b6a0fc5 | ||
|
|
f949461297 | ||
|
|
9a39a25bb5 | ||
|
|
4b018407c1 | ||
|
|
28e114b569 | ||
|
|
99226e0fa6 | ||
|
|
4a84ee07be | ||
|
|
505480cf63 | ||
|
|
fa2bfdd326 | ||
|
|
afe022853c | ||
|
|
41b834f76e | ||
|
|
a88436c806 | ||
|
|
e2d6e709c3 | ||
|
|
bd7fee5a77 | ||
|
|
709d4ba6e7 | ||
|
|
8d55c7d60a | ||
|
|
9cb4de8b5e | ||
|
|
8662c61a17 | ||
|
|
935671ae32 | ||
|
|
a5ce965d22 | ||
|
|
1e58c80fe7 | ||
|
|
a92ae4ba30 | ||
|
|
b5f2e56e38 | ||
|
|
594f4d56b8 | ||
|
|
2d83ca61e7 | ||
|
|
307e37a69f | ||
|
|
8310eb3b1f | ||
|
|
b9c4f1fa95 | ||
|
|
faab4f9e28 | ||
|
|
271b0abc45 | ||
|
|
f0c3d50408 | ||
|
|
f0fdff1f07 | ||
|
|
d15df3489e | ||
|
|
f3cc4ab09d | ||
|
|
442d8a68a6 | ||
|
|
934fffec68 | ||
|
|
8190e7838f | ||
|
|
4571975414 | ||
|
|
5115c61b03 | ||
|
|
54c7a9ee95 | ||
|
|
0296c7c5b6 | ||
|
|
84d8135cbb | ||
|
|
dd3c370bca | ||
|
|
4e41f74925 | ||
|
|
c6663f59b8 | ||
|
|
ced7503d95 | ||
|
|
04af30daed | ||
|
|
5ccc8e341c | ||
|
|
71977e8f9d | ||
|
|
5e774e0b44 | ||
|
|
e16d753439 | ||
|
|
b14d189db9 | ||
|
|
14de29c031 | ||
|
|
b59455b63c | ||
|
|
1a6dc86fed | ||
|
|
35b0c8b577 | ||
|
|
75034c3710 | ||
|
|
305cea28c5 | ||
|
|
69ba85b051 | ||
|
|
5700d65a53 | ||
|
|
e707c40e0b | ||
|
|
9d37472f23 | ||
|
|
eb97335c6f | ||
|
|
0028b29760 | ||
|
|
1ded1e38e8 | ||
|
|
149acdae7d | ||
|
|
5fee5f39ea | ||
|
|
f16d453805 | ||
|
|
2b0293578f | ||
|
|
66aeeedaef | ||
|
|
af41dd1ed6 | ||
|
|
17f7f1fc15 | ||
|
|
cbc512f3be | ||
|
|
7ac9f92bc2 | ||
|
|
a7ba63d425 | ||
|
|
5ca10b1d67 | ||
|
|
f22a4a4e80 | ||
|
|
b53ee13662 | ||
|
|
8de100b116 | ||
|
|
ac30bcb0eb | ||
|
|
872d6ef55a | ||
|
|
dd3b9c7c35 | ||
|
|
9755ae3cbe | ||
|
|
bc29fb5a09 | ||
|
|
646a574b9c | ||
|
|
8f19650fd7 | ||
|
|
f08980967b | ||
|
|
5285f5300a | ||
|
|
1608d0596d | ||
|
|
62631bfe33 | ||
|
|
7ffed858f0 | ||
|
|
3a1334e0d4 | ||
|
|
37f4f43726 | ||
|
|
db1a84ede1 | ||
|
|
3d2e4c338c | ||
|
|
b42d731fc8 | ||
|
|
fd7045adac | ||
|
|
e26d3505f7 | ||
|
|
fe0249bf8f | ||
|
|
2ac682e125 | ||
|
|
9be1710dca | ||
|
|
7e7504f5ea | ||
|
|
e83c11667f | ||
|
|
05547979de | ||
|
|
9e67ba83a5 | ||
|
|
2bb3522bbb | ||
|
|
8f4ec35697 | ||
|
|
17863dfbda | ||
|
|
56bb20d489 | ||
|
|
5baf32cd81 | ||
|
|
38cd1ecff4 | ||
|
|
77e00f1926 | ||
|
|
ade139f2d0 | ||
|
|
653f35a3d8 | ||
|
|
baa7aecf60 | ||
|
|
d859826be6 | ||
|
|
d759c96a98 | ||
|
|
7cbab0efe3 | ||
|
|
b6b536682e | ||
|
|
edf1df33cc | ||
|
|
bf0df54136 | ||
|
|
7e80d2de79 | ||
|
|
144f687ee9 | ||
|
|
0ee8322947 | ||
|
|
997fb5fb48 | ||
|
|
2b459881bd | ||
|
|
e18e7eca47 | ||
|
|
1c80d2ac2f | ||
|
|
62918ca779 | ||
|
|
3cca57a801 | ||
|
|
5578a2e46d | ||
|
|
fe19cfde28 | ||
|
|
fbad637235 | ||
|
|
01e9307fb7 | ||
|
|
5697cb6c95 | ||
|
|
05ff83f95a | ||
|
|
1e3012cb49 | ||
|
|
45b8cf350e | ||
|
|
2c2c6f8e02 | ||
|
|
4e3a6b9404 | ||
|
|
76bbccb4dc | ||
|
|
1c4433555a | ||
|
|
faaced1d86 | ||
|
|
1a1d17e13a | ||
|
|
4254b6d0e2 | ||
|
|
a211c2a955 | ||
|
|
196200bcc0 | ||
|
|
c062835702 | ||
|
|
664ef756c2 | ||
|
|
9de28d640e | ||
|
|
adb9dc7ede | ||
|
|
f9fcd24315 | ||
|
|
6d95b999ad | ||
|
|
6731e52280 | ||
|
|
970358b2af | ||
|
|
3d68950037 | ||
|
|
d50b2a4804 | ||
|
|
29a946163b | ||
|
|
9472025da7 | ||
|
|
f5cd5387da | ||
|
|
7a8bf8e9a5 | ||
|
|
f5ecdda400 | ||
|
|
c2031aa651 | ||
|
|
8751c9931e | ||
|
|
adbf9922f4 | ||
|
|
b3a1e5f9e9 | ||
|
|
22f70f9ac9 | ||
|
|
d2079f32d8 | ||
|
|
f2ac416f66 | ||
|
|
642fbfba9f | ||
|
|
c98cdd4f4c | ||
|
|
d04567b99c | ||
|
|
f2e1e1b890 | ||
|
|
6c764f6b8a | ||
|
|
49929f1e56 | ||
|
|
acdf139137 | ||
|
|
3346c594e4 | ||
|
|
0bb2cfe440 | ||
|
|
11573b4ea4 | ||
|
|
5934959b62 | ||
|
|
81f6c22e51 | ||
|
|
78a8245f4a | ||
|
|
049861afb4 | ||
|
|
3df7083f69 | ||
|
|
ca17edd5ac | ||
|
|
c26bf871b7 | ||
|
|
15d3e8c3e1 | ||
|
|
66b370e103 | ||
|
|
2bbfbb1d50 | ||
|
|
ace25d4987 | ||
|
|
59cb9a4e60 | ||
|
|
0dce570157 | ||
|
|
7ddaf49eb2 | ||
|
|
e947363a11 | ||
|
|
5dbfe48d24 | ||
|
|
07d5f8b123 | ||
|
|
be99603f1b | ||
|
|
54db496815 | ||
|
|
fbe7ddb640 | ||
|
|
55c37d2a57 | ||
|
|
4b445531f5 | ||
|
|
12afc263a4 | ||
|
|
040d131284 | ||
|
|
73bbe0849a | ||
|
|
09a0615df0 | ||
|
|
669d5815c9 | ||
|
|
bd24b97bd3 | ||
|
|
db196ce5d8 | ||
|
|
4396b211ce | ||
|
|
367949e914 | ||
|
|
ae2bbe7f19 | ||
|
|
819e14f91b | ||
|
|
fcf3ccba98 | ||
|
|
558a10b54f | ||
|
|
43c60a02f7 | ||
|
|
6501bc5d32 | ||
|
|
f3dae0c9ad | ||
|
|
dc2cafc888 | ||
|
|
49fc4923be | ||
|
|
efb5f17a60 | ||
|
|
086e764845 | ||
|
|
c30290b43c | ||
|
|
d26421fe3b | ||
|
|
37670924f6 | ||
|
|
ee5143b54b | ||
|
|
acbb2544bf | ||
|
|
d8f7347000 | ||
|
|
3b91dec462 | ||
|
|
05f74b4218 | ||
|
|
8e98177fb3 | ||
|
|
815a3ad0de | ||
|
|
5075dd4dfa | ||
|
|
ca09dcbe89 | ||
|
|
198a74d793 | ||
|
|
fe404628e9 | ||
|
|
5a004c3b2a | ||
|
|
430180aa96 | ||
|
|
e828be96f0 | ||
|
|
52447efb97 | ||
|
|
d09b0fe83a | ||
|
|
798d8668a4 | ||
|
|
2a82b8fed9 | ||
|
|
696f687419 | ||
|
|
9b91b9db8c | ||
|
|
026473280b | ||
|
|
a7849b2861 | ||
|
|
74bf659c56 | ||
|
|
c2feedb7a2 | ||
|
|
0735e9ba98 | ||
|
|
ab686732d0 | ||
|
|
6d86437369 | ||
|
|
184285ab27 | ||
|
|
1e8065d040 | ||
|
|
f735d12247 | ||
|
|
7135bc2dc2 | ||
|
|
9044706796 | ||
|
|
5f68da3153 | ||
|
|
5222489a01 | ||
|
|
27f830f345 | ||
|
|
8d7db8e450 | ||
|
|
da56758054 | ||
|
|
66dcc4b6db | ||
|
|
6eab5622c7 | ||
|
|
af53f3d6cf | ||
|
|
188e5327ee | ||
|
|
1932a9d729 | ||
|
|
c926ec477a | ||
|
|
7b11fa18a1 | ||
|
|
e6cefdca25 | ||
|
|
fbeff475b3 | ||
|
|
d057099c17 | ||
|
|
411700d7e6 | ||
|
|
b4e9d918f2 | ||
|
|
2756c364d2 | ||
|
|
43faabd4cc | ||
|
|
a4a71a8904 | ||
|
|
e23ac031ff | ||
|
|
79a56967a1 | ||
|
|
0bc0453700 | ||
|
|
35e247aa26 | ||
|
|
67ba187b6f | ||
|
|
67f0b1986c | ||
|
|
60e0177d00 | ||
|
|
4543a28e51 | ||
|
|
aade2d1ec9 | ||
|
|
4627545a3b | ||
|
|
e2ba7c9b8c | ||
|
|
6f5596ac5c | ||
|
|
7d1c2f191a | ||
|
|
4ada571384 | ||
|
|
ad8ebbaa05 | ||
|
|
4854989db4 | ||
|
|
7c5050cf80 | ||
|
|
14ae8be547 | ||
|
|
ff878ea9dc | ||
|
|
7021a4be44 | ||
|
|
5c4737c3d0 | ||
|
|
fbf3807af1 | ||
|
|
703c37ec88 | ||
|
|
96440878bb | ||
|
|
b5c11ffb1c | ||
|
|
7f5b323d50 | ||
|
|
67176e2b75 | ||
|
|
79f3cf3263 | ||
|
|
9ee1dc79fd | ||
|
|
9e2c34dfa6 | ||
|
|
cc93c2a559 | ||
|
|
15c7044c4d | ||
|
|
0ef80d3579 | ||
|
|
95c2e0a996 | ||
|
|
da3e8611e1 | ||
|
|
64595597f3 | ||
|
|
82f2983cd4 | ||
|
|
9451177c35 | ||
|
|
9ed087d5da | ||
|
|
77f22e9674 | ||
|
|
8ccfdbbcf9 | ||
|
|
5a92aa4e06 | ||
|
|
7b1010cf61 | ||
|
|
45b2f5bac4 | ||
|
|
36e1c82ef5 | ||
|
|
503d65d570 | ||
|
|
fe17f8da41 | ||
|
|
b583aa1579 | ||
|
|
e0d81b97bb | ||
|
|
90752f9d87 | ||
|
|
3663aa675a | ||
|
|
1ca4b81856 | ||
|
|
4e7e06f549 | ||
|
|
b2f0bdb0f4 | ||
|
|
d98bd34200 | ||
|
|
940bdd878e | ||
|
|
df556333a8 | ||
|
|
116f05eda6 | ||
|
|
b187bbeca3 | ||
|
|
479a83b628 | ||
|
|
1c18100143 | ||
|
|
5d3c0f33f6 | ||
|
|
afe106e254 | ||
|
|
69dd40ec89 | ||
|
|
dee50d5e28 | ||
|
|
9e93403857 | ||
|
|
12bff6b3a0 | ||
|
|
70e666b4a3 | ||
|
|
29f980ec72 | ||
|
|
1d39d762f0 | ||
|
|
4d6d5e0ddd | ||
|
|
4ea5f070a4 | ||
|
|
da59b4da9b | ||
|
|
0065a160cc | ||
|
|
52f46c7fea | ||
|
|
f0a826ec0c | ||
|
|
5c3c0f73c1 | ||
|
|
be0b71ce31 | ||
|
|
f85d48dd31 | ||
|
|
a1b58ee601 | ||
|
|
e30429051d | ||
|
|
942ead75e2 | ||
|
|
453688f6df | ||
|
|
7d7a161102 | ||
|
|
aaa223ae66 | ||
|
|
d11c624fb0 | ||
|
|
275e51b19d | ||
|
|
ab62edeeaa | ||
|
|
813108a928 | ||
|
|
3c14911401 | ||
|
|
4337f14627 | ||
|
|
92d78c10a2 | ||
|
|
16d5ba9b3a | ||
|
|
52065a736b | ||
|
|
11cb109114 | ||
|
|
d7eadd41d6 |
+4
-5
@@ -88,15 +88,14 @@ present in the framework.
|
||||
1. Preserve existing formatting; i.e. do not reformat code for its own sake
|
||||
1. Search the codebase using `git grep` and other tools to discover common
|
||||
naming conventions, etc.
|
||||
1. Latin-1 (ISO-8859-1) encoding for Java sources; use `native2ascii` to convert
|
||||
if necessary
|
||||
1. UTF-8 encoding for Java sources
|
||||
|
||||
|
||||
### Add Apache license header to all new classes
|
||||
|
||||
```java
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -124,11 +123,11 @@ modified a file in 2015 whose header still reads:
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
```
|
||||
|
||||
Then be sure to update it to 2015 accordingly:
|
||||
Then be sure to update it to 2016 accordingly:
|
||||
|
||||
```java
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
```
|
||||
|
||||
### Use @since tags for newly-added public API types and methods
|
||||
|
||||
+118
-118
@@ -32,51 +32,52 @@ configure(allprojects) { project ->
|
||||
version = qualifyVersionIfNecessary(version)
|
||||
|
||||
ext.aspectjVersion = "1.8.9"
|
||||
ext.caffeineVersion = "2.3.1"
|
||||
ext.caffeineVersion = "2.3.5"
|
||||
ext.eclipselinkVersion = "2.4.2"
|
||||
ext.ehcacheVersion = "2.10.2"
|
||||
ext.ehcacheVersion = "2.10.4"
|
||||
ext.ehcachejcacheVersion = "1.0.1"
|
||||
ext.ehcache3Version = "3.1.0"
|
||||
ext.ehcache3Version = "3.1.4"
|
||||
ext.ejbVersion = "3.0"
|
||||
ext.fileuploadVersion = "1.3.2"
|
||||
ext.fileuploadVersion = "1.3.3"
|
||||
ext.freemarkerVersion = "2.3.23"
|
||||
ext.groovyVersion = "2.4.7"
|
||||
ext.gsonVersion = "2.7"
|
||||
ext.guavaVersion = "19.0"
|
||||
ext.groovyVersion = "2.4.15"
|
||||
ext.gsonVersion = "2.8.2"
|
||||
ext.guavaVersion = "20.0"
|
||||
ext.hamcrestVersion = "1.3"
|
||||
ext.hibernate3Version = "3.6.10.Final"
|
||||
ext.hibernate4Version = "4.3.11.Final"
|
||||
ext.hibernate5Version = "5.2.1.Final"
|
||||
ext.hibernate5Version = "5.2.10.Final"
|
||||
ext.hibval4Version = "4.3.2.Final"
|
||||
ext.hibval5Version = "5.2.4.Final"
|
||||
ext.hibval5Version = "5.2.5.Final"
|
||||
ext.hsqldbVersion = "2.3.4"
|
||||
ext.httpasyncVersion = "4.1.2"
|
||||
ext.httpclientVersion = "4.5.2"
|
||||
ext.jackson2Version = "2.8.0.rc2"
|
||||
ext.httpasyncVersion = "4.1.3"
|
||||
ext.httpclientVersion = "4.5.5"
|
||||
ext.jackson2Version = "2.8.11.1"
|
||||
ext.jasperreportsVersion = "6.2.1" // our tests fail with JR-internal NPEs against 6.2.2 and higher
|
||||
ext.javamailVersion = "1.5.5"
|
||||
ext.jettyVersion = "9.3.10.v20160621"
|
||||
ext.jodaVersion = "2.9.4"
|
||||
ext.jrubyVersion = "1.7.25" // JRuby 9000 only supported through JSR-223 (StandardScriptFactory)
|
||||
ext.javamailVersion = "1.5.6"
|
||||
ext.jettyVersion = "9.3.14.v20161028" // as of 9.3.15, Jetty has hard Servlet 3.1 requirement
|
||||
ext.jetty94Version = "9.4.6.v20170531" // for spring-websocket support, optimized for Jetty 9.4
|
||||
ext.jodaVersion = "2.9.9"
|
||||
ext.jrubyVersion = "1.7.27" // JRuby 9000 primarily supported through JSR-223 (StandardScriptFactory)
|
||||
ext.jtaVersion = "1.2"
|
||||
ext.junitVersion = "4.12"
|
||||
ext.log4jVersion = "1.2.17"
|
||||
ext.nettyVersion = "4.1.1.Final"
|
||||
ext.nettyVersion = "4.1.25.Final"
|
||||
ext.okhttpVersion = "2.7.5"
|
||||
ext.okhttp3Version = "3.3.1"
|
||||
ext.openjpaVersion = "2.4.1"
|
||||
ext.okhttp3Version = "3.8.1"
|
||||
ext.openjpaVersion = "2.4.2"
|
||||
ext.poiVersion = "3.14"
|
||||
ext.reactorVersion = "2.0.8.RELEASE"
|
||||
ext.romeVersion = "1.6.0"
|
||||
ext.romeVersion = "1.7.4"
|
||||
ext.slf4jVersion = "1.7.21"
|
||||
ext.snakeyamlVersion = "1.17"
|
||||
ext.snifferVersion = "1.15"
|
||||
ext.snifferVersion = "1.16"
|
||||
ext.testngVersion = "6.9.10"
|
||||
ext.tiles2Version = "2.2.2"
|
||||
ext.tiles3Version = "3.0.5"
|
||||
ext.tomcatVersion = "8.5.3"
|
||||
ext.tiles3Version = "3.0.7"
|
||||
ext.tomcatVersion = "8.5.31"
|
||||
ext.tyrusVersion = "1.3.5" // constrained by WebLogic 12.1.3 support
|
||||
ext.undertowVersion = "1.4.0.CR2"
|
||||
ext.undertowVersion = "1.3.33.Final"
|
||||
ext.xmlunitVersion = "1.6"
|
||||
ext.xstreamVersion = "1.4.9"
|
||||
|
||||
@@ -110,11 +111,13 @@ configure(allprojects) { project ->
|
||||
compileJava {
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
|
||||
compileTestJava {
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
options.encoding = 'UTF-8'
|
||||
options.compilerArgs += "-parameters"
|
||||
}
|
||||
|
||||
@@ -199,10 +202,10 @@ configure(allprojects) { project ->
|
||||
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
|
||||
"http://ehcache.org/apidocs/${ehcacheVersion}",
|
||||
"http://ehcache.org/apidocs/${ehcache3Version}",
|
||||
"http://quartz-scheduler.org/api/2.2.0/",
|
||||
"http://fasterxml.github.io/jackson-core/javadoc/2.7/",
|
||||
"http://fasterxml.github.io/jackson-databind/javadoc/2.7/",
|
||||
"http://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.7/",
|
||||
"http://quartz-scheduler.org/api/2.2.1/",
|
||||
"http://fasterxml.github.io/jackson-core/javadoc/2.8/",
|
||||
"http://fasterxml.github.io/jackson-databind/javadoc/2.8/",
|
||||
"http://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.8/",
|
||||
"http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/"
|
||||
] as String[]
|
||||
}
|
||||
@@ -214,7 +217,6 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
|
||||
configurations {
|
||||
jacoco
|
||||
}
|
||||
|
||||
dependencies {
|
||||
jacoco("org.jacoco:org.jacoco.agent:0.7.5.201505241946:runtime")
|
||||
}
|
||||
@@ -248,16 +250,16 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
|
||||
options.links(project.ext.javadocLinks)
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
|
||||
// suppress warnings due to cross-module @see and @link references;
|
||||
// note that global 'api' task does display all warnings.
|
||||
// Suppress warnings due to cross-module @see and @link references.
|
||||
// Note that global 'api' task does display all warnings.
|
||||
logging.captureStandardError LogLevel.INFO
|
||||
logging.captureStandardOutput LogLevel.INFO // suppress "## warnings" message
|
||||
logging.captureStandardOutput LogLevel.INFO // suppress "## warnings" message
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||
classifier = 'sources'
|
||||
from sourceSets.main.allSource
|
||||
// don't include or exclude anything explicitly by default. See SPR-12085.
|
||||
// Don't include or exclude anything explicitly by default. See SPR-12085.
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
@@ -273,6 +275,7 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
|
||||
|
||||
project("spring-build-src") {
|
||||
description = "Exposes gradle buildSrc for IDE support"
|
||||
|
||||
apply plugin: "groovy"
|
||||
|
||||
dependencies {
|
||||
@@ -290,8 +293,8 @@ project("spring-core") {
|
||||
// both into the spring-core jar. cglib 3.2 itself depends on asm 5.x and is therefore
|
||||
// further transformed by the JarJar task to depend on org.springframework.asm; this
|
||||
// avoids including two different copies of asm unnecessarily.
|
||||
def cglibVersion = "3.2.4"
|
||||
def objenesisVersion = "2.4"
|
||||
def cglibVersion = "3.2.6"
|
||||
def objenesisVersion = "2.6"
|
||||
|
||||
configurations {
|
||||
jarjar
|
||||
@@ -311,9 +314,9 @@ project("spring-core") {
|
||||
configurations.cglib.each { originalJar ->
|
||||
zipfileset(src: originalJar)
|
||||
}
|
||||
// repackage net.sf.cglib => org.springframework.cglib
|
||||
// Repackage net.sf.cglib => org.springframework.cglib
|
||||
rule(pattern: "net.sf.cglib.**", result: "org.springframework.cglib.@1")
|
||||
// as mentioned above, transform cglib"s internal asm dependencies from
|
||||
// As mentioned above, transform cglib's internal asm dependencies from
|
||||
// org.objectweb.asm => org.springframework.asm. Doing this counts on the
|
||||
// the fact that Spring and cglib depend on the same version of asm!
|
||||
rule(pattern: "org.objectweb.asm.**", result: "org.springframework.asm.@1")
|
||||
@@ -334,7 +337,7 @@ project("spring-core") {
|
||||
configurations.objenesis.each { originalJar ->
|
||||
zipfileset(src: originalJar)
|
||||
}
|
||||
// repackage org.objenesis => org.springframework.objenesis
|
||||
// Repackage org.objenesis => org.springframework.objenesis
|
||||
rule(pattern: "org.objenesis.**", result: "org.springframework.objenesis.@1")
|
||||
}
|
||||
}
|
||||
@@ -351,17 +354,17 @@ project("spring-core") {
|
||||
compile("commons-logging:commons-logging:1.2")
|
||||
optional("commons-codec:commons-codec:1.10")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("net.sf.jopt-simple:jopt-simple:5.0.2")
|
||||
optional("net.sf.jopt-simple:jopt-simple:5.0.3")
|
||||
optional("log4j:log4j:${log4jVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
|
||||
testCompile("com.fasterxml.woodstox:woodstox-core:5.0.2") {
|
||||
testCompile("com.fasterxml.woodstox:woodstox-core:5.0.3") {
|
||||
exclude group: "stax", module: "stax-api"
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
// inline repackaged cglib classes directly into the spring-core jar
|
||||
// Inline repackaged cglib classes directly into spring-core jar
|
||||
dependsOn cglibRepackJar
|
||||
from(zipTree(cglibRepackJar.archivePath)) {
|
||||
include "org/springframework/cglib/**"
|
||||
@@ -390,6 +393,7 @@ project("spring-beans") {
|
||||
|
||||
project("spring-beans-groovy") {
|
||||
description "Groovy Bean Definitions"
|
||||
|
||||
merge.into = project(":spring-beans")
|
||||
apply plugin: "groovy"
|
||||
|
||||
@@ -398,8 +402,8 @@ project("spring-beans-groovy") {
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
}
|
||||
|
||||
// this module's Java and Groovy sources need to be compiled together
|
||||
compileJava.enabled=false
|
||||
// This module's Java and Groovy sources need to be compiled together.
|
||||
compileJava.enabled = false
|
||||
sourceSets {
|
||||
main {
|
||||
groovy {
|
||||
@@ -465,26 +469,27 @@ project("spring-instrument-tomcat") {
|
||||
|
||||
project("spring-context") {
|
||||
description = "Spring Context"
|
||||
|
||||
apply plugin: "groovy"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-aop"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-expression"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-expression"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
optional(project(":spring-instrument"))
|
||||
optional("javax.inject:javax.inject:1")
|
||||
optional("javax.ejb:ejb-api:${ejbVersion}")
|
||||
optional("javax.enterprise.concurrent:javax.enterprise.concurrent-api:1.0")
|
||||
optional("javax.money:money-api:1.0")
|
||||
optional("javax.money:money-api:1.0.1")
|
||||
optional("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
optional("javax.validation:validation-api:1.0.0.GA")
|
||||
optional("org.hibernate:hibernate-validator:${hibval4Version}")
|
||||
optional("joda-time:joda-time:${jodaVersion}")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("org.beanshell:bsh:2.0b4")
|
||||
optional("org.beanshell:bsh:2.0b5")
|
||||
optional("org.jruby:jruby:${jrubyVersion}")
|
||||
testCompile("javax.inject:javax.inject-tck:1")
|
||||
testCompile("org.javamoney:moneta:1.1")
|
||||
@@ -494,13 +499,44 @@ project("spring-context") {
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-oxm") {
|
||||
description = "Spring Object/XML Marshalling"
|
||||
apply from: "oxm.gradle"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
optional("org.codehaus.castor:castor-xml:1.4.1") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
exclude group: "org.springframework", module: "spring-context"
|
||||
}
|
||||
optional("org.apache.xmlbeans:xmlbeans:2.6.0") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
}
|
||||
optional("com.thoughtworks.xstream:xstream:${xstreamVersion}") {
|
||||
exclude group: 'xpp3', module: 'xpp3_min'
|
||||
exclude group: 'xmlpull', module: 'xmlpull'
|
||||
}
|
||||
optional("org.jibx:jibx-run:1.2.6")
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile("org.ogce:xpp3:1.1.6")
|
||||
testCompile("org.codehaus.jettison:jettison:1.3.8") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
}
|
||||
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
|
||||
testCompile(files(genCastor.classesDir).builtBy(genCastor))
|
||||
testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
|
||||
testCompile(files(genXmlbeans.classesDir).builtBy(genXmlbeans))
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-messaging") {
|
||||
description = "Spring Messaging"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
optional(project(":spring-oxm"))
|
||||
optional("io.projectreactor:reactor-core:${reactorVersion}")
|
||||
optional("io.projectreactor:reactor-net:${reactorVersion}") {
|
||||
@@ -552,54 +588,14 @@ project("spring-tx") {
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-oxm") {
|
||||
description = "Spring Object/XML Marshalling"
|
||||
apply from: "oxm.gradle"
|
||||
|
||||
compileTestJava {
|
||||
// necessary to avoid java.lang.VerifyError on jibx compilation
|
||||
// see http://jira.codehaus.org/browse/JIBX-465
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
optional("org.codehaus.castor:castor-xml:1.4.1") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
exclude group: "org.springframework", module: "spring-context"
|
||||
}
|
||||
optional("org.apache.xmlbeans:xmlbeans:2.6.0") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
}
|
||||
optional("com.thoughtworks.xstream:xstream:${xstreamVersion}") {
|
||||
exclude group: 'xpp3', module: 'xpp3_min'
|
||||
exclude group: 'xmlpull', module: 'xmlpull'
|
||||
}
|
||||
optional("org.jibx:jibx-run:1.2.6")
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
|
||||
testCompile("xpp3:xpp3:1.1.4c")
|
||||
testCompile("org.codehaus.jettison:jettison:1.3.7") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
}
|
||||
if (compileTestJava.enabled) {
|
||||
testCompile(files(genCastor.classesDir).builtBy(genCastor))
|
||||
testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
|
||||
testCompile(files(genXmlbeans.classesDir).builtBy(genXmlbeans))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-jms") {
|
||||
description = "Spring JMS"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-aop"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-messaging"))
|
||||
compile(project(":spring-tx"))
|
||||
provided("javax.jms:jms-api:1.1-rev-1")
|
||||
@@ -621,9 +617,9 @@ project("spring-jdbc") {
|
||||
optional("javax.transaction:javax.transaction-api:${jtaVersion}")
|
||||
optional("com.mchange:c3p0:0.9.5.2")
|
||||
optional("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
optional("com.h2database:h2:1.4.192")
|
||||
optional("org.apache.derby:derby:10.12.1.1")
|
||||
optional("org.apache.derby:derbyclient:10.12.1.1")
|
||||
optional("com.h2database:h2:1.4.193")
|
||||
optional("org.apache.derby:derby:10.13.1.1")
|
||||
optional("org.apache.derby:derbyclient:10.13.1.1")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -631,9 +627,9 @@ project("spring-context-support") {
|
||||
description = "Spring Context Support"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
optional(project(":spring-jdbc")) // for Quartz support
|
||||
optional(project(":spring-tx")) // for Quartz support
|
||||
optional("javax.mail:javax.mail-api:${javamailVersion}")
|
||||
@@ -662,11 +658,14 @@ project("spring-context-support") {
|
||||
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
testRuntime("com.sun.mail:javax.mail:${javamailVersion}")
|
||||
testRuntime("org.ehcache:jcache:${ehcachejcacheVersion}")
|
||||
testRuntime("org.ehcache:ehcache:${ehcache3Version}")
|
||||
testRuntime("org.terracotta:management-model:2.3.0")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-web") {
|
||||
description = "Spring Web"
|
||||
|
||||
apply plugin: "groovy"
|
||||
|
||||
// Re-generate Protobuf classes from *.proto files and move them in test sources
|
||||
@@ -705,7 +704,7 @@ project("spring-web") {
|
||||
optional("com.squareup.okhttp:okhttp:${okhttpVersion}")
|
||||
optional("com.squareup.okhttp3:okhttp:${okhttp3Version}")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}")
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.8.11")
|
||||
optional("com.google.code.gson:gson:${gsonVersion}")
|
||||
optional("com.rometools:rome:${romeVersion}")
|
||||
optional("org.eclipse.jetty:jetty-servlet:${jettyVersion}") {
|
||||
@@ -721,12 +720,14 @@ project("spring-web") {
|
||||
testCompile(project(":spring-context-support")) // for JafMediaTypeFactory
|
||||
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("org.skyscreamer:jsonassert:1.4.0")
|
||||
testCompile("org.apache.taglibs:taglibs-standard-jstlel:1.2.1") {
|
||||
exclude group: "org.apache.taglibs", module: "taglibs-standard-spec"
|
||||
}
|
||||
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-joda:${jackson2Version}")
|
||||
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:${jackson2Version}")
|
||||
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-joda:2.8.11")
|
||||
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.8.11")
|
||||
testCompile("com.fasterxml.jackson.module:jackson-module-kotlin:${jackson2Version}")
|
||||
testCompile("com.squareup.okhttp3:mockwebserver:${okhttp3Version}")
|
||||
testRuntime("com.sun.mail:javax.mail:${javamailVersion}")
|
||||
}
|
||||
}
|
||||
@@ -836,7 +837,7 @@ project("spring-webmvc") {
|
||||
exclude group: "org.springframework", module: "spring-context"
|
||||
}
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}")
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.8.11")
|
||||
optional("com.rometools:rome:${romeVersion}")
|
||||
optional("javax.el:javax.el-api:2.2.5")
|
||||
optional("org.apache.tiles:tiles-api:${tiles3Version}")
|
||||
@@ -856,7 +857,7 @@ project("spring-webmvc") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
exclude group: "org.springframework", module: "spring-web"
|
||||
}
|
||||
optional('org.webjars:webjars-locator:0.32')
|
||||
optional('org.webjars:webjars-locator:0.32-1')
|
||||
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
|
||||
testCompile("dom4j:dom4j:1.6.1") {
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
@@ -876,13 +877,13 @@ project("spring-webmvc") {
|
||||
testCompile("org.hibernate:hibernate-validator:${hibval4Version}")
|
||||
testCompile("org.apache.httpcomponents:httpclient:${httpclientVersion}")
|
||||
testCompile("commons-fileupload:commons-fileupload:${fileuploadVersion}")
|
||||
testCompile("commons-io:commons-io:1.3")
|
||||
testCompile("commons-io:commons-io:1.4")
|
||||
testCompile("joda-time:joda-time:${jodaVersion}")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("org.jruby:jruby:${jrubyVersion}")
|
||||
testCompile("org.python:jython-standalone:2.5.3")
|
||||
testCompile("org.mozilla:rhino:1.7.7.1")
|
||||
testCompile("org.webjars:underscorejs:1.8.3")
|
||||
testCompile("org.mozilla:rhino:1.7.7.2")
|
||||
testRuntime("org.jruby:jruby:${jrubyVersion}")
|
||||
testRuntime("org.python:jython-standalone:2.5.3")
|
||||
testRuntime("org.webjars:underscorejs:1.8.3")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,8 +938,8 @@ project("spring-websocket") {
|
||||
description = "Spring WebSocket"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-web"))
|
||||
optional(project(":spring-messaging"))
|
||||
optional(project(":spring-webmvc"))
|
||||
@@ -955,11 +956,11 @@ project("spring-websocket") {
|
||||
optional("org.eclipse.jetty:jetty-webapp:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet"
|
||||
}
|
||||
optional("org.eclipse.jetty.websocket:websocket-server:${jettyVersion}") {
|
||||
optional("org.eclipse.jetty.websocket:websocket-server:${jetty94Version}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet"
|
||||
}
|
||||
optional("org.eclipse.jetty.websocket:websocket-client:${jettyVersion}")
|
||||
optional("org.eclipse.jetty:jetty-client:${jettyVersion}")
|
||||
optional("org.eclipse.jetty.websocket:websocket-client:${jetty94Version}")
|
||||
optional("org.eclipse.jetty:jetty-client:${jetty94Version}")
|
||||
optional("io.undertow:undertow-core:${undertowVersion}")
|
||||
optional("io.undertow:undertow-servlet:${undertowVersion}") {
|
||||
exclude group: "org.jboss.spec.javax.servlet", module: "jboss-servlet-api_3.1_spec"
|
||||
@@ -983,11 +984,12 @@ project("spring-test") {
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
optional(project(":spring-aop"))
|
||||
optional(project(":spring-beans"))
|
||||
optional(project(":spring-context"))
|
||||
optional(project(":spring-jdbc"))
|
||||
optional(project(":spring-tx"))
|
||||
optional(project(":spring-orm"))
|
||||
optional(project(":spring-tx"))
|
||||
optional(project(":spring-web"))
|
||||
optional(project(":spring-webmvc"))
|
||||
optional(project(":spring-webmvc-portlet"))
|
||||
@@ -1008,11 +1010,11 @@ project("spring-test") {
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("org.hamcrest:hamcrest-core:${hamcrestVersion}")
|
||||
optional("xmlunit:xmlunit:${xmlunitVersion}")
|
||||
optional("net.sourceforge.htmlunit:htmlunit:2.22")
|
||||
optional("org.seleniumhq.selenium:htmlunit-driver:2.21")
|
||||
optional("net.sourceforge.htmlunit:htmlunit:2.23")
|
||||
optional("org.seleniumhq.selenium:htmlunit-driver:2.23.2")
|
||||
optional("org.seleniumhq.selenium:selenium-java:2.53.1")
|
||||
optional("org.skyscreamer:jsonassert:1.3.0")
|
||||
optional("com.jayway.jsonpath:json-path:2.2.0")
|
||||
optional("org.skyscreamer:jsonassert:1.4.0")
|
||||
optional("com.jayway.jsonpath:json-path:2.3.0")
|
||||
testCompile(project(":spring-context-support"))
|
||||
testCompile(project(":spring-oxm"))
|
||||
testCompile("javax.mail:javax.mail-api:${javamailVersion}")
|
||||
@@ -1035,8 +1037,6 @@ project("spring-test") {
|
||||
testCompile("org.apache.httpcomponents:httpclient:${httpclientVersion}")
|
||||
testCompile("javax.cache:cache-api:1.0.0")
|
||||
testRuntime("log4j:log4j:${log4jVersion}")
|
||||
testRuntime("org.ehcache:ehcache:${ehcache3Version}")
|
||||
testRuntime("org.terracotta:management-model:2.0.0")
|
||||
}
|
||||
|
||||
task testNG(type: Test) {
|
||||
@@ -1181,7 +1181,7 @@ configure(rootProject) {
|
||||
// don't publish the default jar for the root project
|
||||
configurations.archives.artifacts.clear()
|
||||
|
||||
dependencies { // for integration tests
|
||||
dependencies { // for integration tests
|
||||
testCompile(project(":spring-aop"))
|
||||
testCompile(project(":spring-beans"))
|
||||
testCompile(project(":spring-context"))
|
||||
@@ -1230,11 +1230,11 @@ configure(rootProject) {
|
||||
|
||||
doFirst {
|
||||
classpath = files(
|
||||
// ensure Servlet 3.x and Hibernate 4.x have precedence on the javadoc
|
||||
// Ensure Servlet 3.x and Hibernate 4.x have precedence on the javadoc
|
||||
// classpath over their respective 2.5 and 3.x variants
|
||||
project(":spring-webmvc").sourceSets.main.compileClasspath.files.find { it =~ "servlet-api" },
|
||||
rootProject.sourceSets.test.compileClasspath.files.find { it =~ "hibernate-core" },
|
||||
// ensure the javadoc process can resolve types compiled from .aj sources
|
||||
// Ensure the javadoc process can resolve types compiled from .aj sources
|
||||
project(":spring-aspects").sourceSets.main.output
|
||||
)
|
||||
classpath += files(subprojects.collect { it.sourceSets.main.compileClasspath })
|
||||
@@ -1367,7 +1367,7 @@ configure(rootProject) {
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
description = "Generates gradlew[.bat] scripts"
|
||||
gradleVersion = "2.13"
|
||||
gradleVersion = "2.14.1"
|
||||
|
||||
doLast() {
|
||||
def gradleOpts = "-XX:MaxMetaspaceSize=1024m -Xmx1024m"
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
version=4.3.1.BUILD-SNAPSHOT
|
||||
version=4.3.18.RELEASE
|
||||
|
||||
@@ -29,8 +29,8 @@ def customizePom(pom, gradleProject) {
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name "The Apache Software License, Version 2.0"
|
||||
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
name "Apache License, Version 2.0"
|
||||
url "http://www.apache.org/licenses/LICENSE-2.0"
|
||||
distribution "repo"
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-2
@@ -1,6 +1,6 @@
|
||||
#Wed Jun 15 12:59:30 CEST 2016
|
||||
#Wed Aug 17 21:21:18 CEST 2016
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-bin.zip
|
||||
|
||||
@@ -46,7 +46,7 @@ public interface MethodInterceptor extends Interceptor {
|
||||
* after the invocation. Polite implementations would certainly
|
||||
* like to invoke {@link Joinpoint#proceed()}.
|
||||
* @param invocation the method invocation joinpoint
|
||||
* @return the result of the call to {@link Joinpoint#proceed();
|
||||
* @return the result of the call to {@link Joinpoint#proceed()};
|
||||
* might be intercepted by the interceptor
|
||||
* @throws Throwable if the interceptors or the target object
|
||||
* throws an exception
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*<
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -34,9 +34,8 @@ public interface TargetSource extends TargetClassAware {
|
||||
|
||||
/**
|
||||
* Return the type of targets returned by this {@link TargetSource}.
|
||||
* <p>Can return {@code null}, although certain usages of a
|
||||
* {@code TargetSource} might just work with a predetermined
|
||||
* target class.
|
||||
* <p>Can return {@code null}, although certain usages of a {@code TargetSource}
|
||||
* might just work with a predetermined target class.
|
||||
* @return the type of targets returned by this {@link TargetSource}
|
||||
*/
|
||||
@Override
|
||||
@@ -44,9 +43,8 @@ public interface TargetSource extends TargetClassAware {
|
||||
|
||||
/**
|
||||
* Will all calls to {@link #getTarget()} return the same object?
|
||||
* <p>In that case, there will be no need to invoke
|
||||
* {@link #releaseTarget(Object)}, and the AOP framework can cache
|
||||
* the return value of {@link #getTarget()}.
|
||||
* <p>In that case, there will be no need to invoke {@link #releaseTarget(Object)},
|
||||
* and the AOP framework can cache the return value of {@link #getTarget()}.
|
||||
* @return {@code true} if the target is immutable
|
||||
* @see #getTarget
|
||||
*/
|
||||
@@ -55,14 +53,15 @@ public interface TargetSource extends TargetClassAware {
|
||||
/**
|
||||
* Return a target instance. Invoked immediately before the
|
||||
* AOP framework calls the "target" of an AOP method invocation.
|
||||
* @return the target object, which contains the joinpoint
|
||||
* @return the target object which contains the joinpoint,
|
||||
* or {@code null} if there is no actual target instance
|
||||
* @throws Exception if the target object can't be resolved
|
||||
*/
|
||||
Object getTarget() throws Exception;
|
||||
|
||||
/**
|
||||
* Release the given target object obtained from the
|
||||
* {@link #getTarget()} method.
|
||||
* {@link #getTarget()} method, if any.
|
||||
* @param target object obtained from a call to {@link #getTarget()}
|
||||
* @throws Exception if the object can't be released
|
||||
*/
|
||||
|
||||
+14
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -103,8 +103,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
private final AspectInstanceFactory aspectInstanceFactory;
|
||||
|
||||
/**
|
||||
* The name of the aspect (ref bean) in which this advice was defined (used
|
||||
* when determining advice precedence so that we can determine
|
||||
* The name of the aspect (ref bean) in which this advice was defined
|
||||
* (used when determining advice precedence so that we can determine
|
||||
* whether two pieces of advice come from the same aspect).
|
||||
*/
|
||||
private String aspectName;
|
||||
@@ -118,13 +118,13 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
* This will be non-null if the creator of this advice object knows the argument names
|
||||
* and sets them explicitly
|
||||
*/
|
||||
private String[] argumentNames = null;
|
||||
private String[] argumentNames;
|
||||
|
||||
/** Non-null if after throwing advice binds the thrown value */
|
||||
private String throwingName = null;
|
||||
private String throwingName;
|
||||
|
||||
/** Non-null if after returning advice binds the return value */
|
||||
private String returningName = null;
|
||||
private String returningName;
|
||||
|
||||
private Class<?> discoveredReturningType = Object.class;
|
||||
|
||||
@@ -227,7 +227,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <b>declaration order</b> of this advice within the aspect
|
||||
* Set the declaration order of this advice within the aspect.
|
||||
*/
|
||||
public void setDeclarationOrder(int order) {
|
||||
this.declarationOrder = order;
|
||||
@@ -295,8 +295,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalArgumentException("Returning name '" + name +
|
||||
"' is neither a valid argument name nor the fully-qualified name of a Java type on the classpath. " +
|
||||
"Root cause: " + ex);
|
||||
"' is neither a valid argument name nor the fully-qualified " +
|
||||
"name of a Java type on the classpath. Root cause: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,8 +329,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalArgumentException("Throwing name '" + name +
|
||||
"' is neither a valid argument name nor the fully-qualified name of a Java type on the classpath. " +
|
||||
"Root cause: " + ex);
|
||||
"' is neither a valid argument name nor the fully-qualified " +
|
||||
"name of a Java type on the classpath. Root cause: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,7 +366,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
* to which argument name. There are multiple strategies for determining
|
||||
* this binding, which are arranged in a ChainOfResponsibility.
|
||||
*/
|
||||
public synchronized final void calculateArgumentBindings() {
|
||||
public final synchronized void calculateArgumentBindings() {
|
||||
// The simple case... nothing to bind.
|
||||
if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
|
||||
return;
|
||||
@@ -374,10 +374,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
|
||||
int numUnboundArgs = this.parameterTypes.length;
|
||||
Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
|
||||
if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0])) {
|
||||
numUnboundArgs--;
|
||||
}
|
||||
else if (maybeBindJoinPointStaticPart(parameterTypes[0])) {
|
||||
if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0]) ||
|
||||
maybeBindJoinPointStaticPart(parameterTypes[0])) {
|
||||
numUnboundArgs--;
|
||||
}
|
||||
|
||||
|
||||
+12
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -113,6 +113,7 @@ import org.springframework.util.StringUtils;
|
||||
* returning {@code null} in the case that the parameter names cannot be discovered.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscoverer {
|
||||
@@ -154,23 +155,17 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
}
|
||||
|
||||
|
||||
/** The pointcut expression associated with the advice, as a simple String */
|
||||
private String pointcutExpression;
|
||||
|
||||
private boolean raiseExceptions;
|
||||
|
||||
/**
|
||||
* If the advice is afterReturning, and binds the return value, this is the parameter name used.
|
||||
*/
|
||||
/** If the advice is afterReturning, and binds the return value, this is the parameter name used */
|
||||
private String returningName;
|
||||
|
||||
/**
|
||||
* If the advice is afterThrowing, and binds the thrown value, this is the parameter name used.
|
||||
*/
|
||||
/** If the advice is afterThrowing, and binds the thrown value, this is the parameter name used */
|
||||
private String throwingName;
|
||||
|
||||
/**
|
||||
* The pointcut expression associated with the advice, as a simple String.
|
||||
*/
|
||||
private String pointcutExpression;
|
||||
|
||||
private Class<?>[] argumentTypes;
|
||||
|
||||
private String[] parameterNameBindings;
|
||||
@@ -186,6 +181,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
this.pointcutExpression = pointcutExpression;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicate whether {@link IllegalArgumentException} and {@link AmbiguousBindingException}
|
||||
* must be thrown as appropriate in the case of failing to deduce advice parameter names.
|
||||
@@ -213,6 +209,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
this.throwingName = throwingName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deduce the parameter names for an advice method.
|
||||
* <p>See the {@link AspectJAdviceParameterNameDiscoverer class level javadoc}
|
||||
@@ -418,7 +415,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(this.pointcutExpression, " ");
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
String toMatch = tokens[i];
|
||||
int firstParenIndex = toMatch.indexOf("(");
|
||||
int firstParenIndex = toMatch.indexOf('(');
|
||||
if (firstParenIndex != -1) {
|
||||
toMatch = toMatch.substring(0, firstParenIndex);
|
||||
}
|
||||
@@ -474,7 +471,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
* If the token starts meets Java identifier conventions, it's in.
|
||||
*/
|
||||
private String maybeExtractVariableName(String candidateToken) {
|
||||
if (candidateToken == null || candidateToken.equals("")) {
|
||||
if (!StringUtils.hasLength(candidateToken)) {
|
||||
return null;
|
||||
}
|
||||
if (Character.isJavaIdentifierStart(candidateToken.charAt(0)) &&
|
||||
@@ -578,7 +575,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
if (toMatch.startsWith("!")) {
|
||||
toMatch = toMatch.substring(1);
|
||||
}
|
||||
int firstParenIndex = toMatch.indexOf("(");
|
||||
int firstParenIndex = toMatch.indexOf('(');
|
||||
if (firstParenIndex != -1) {
|
||||
toMatch = toMatch.substring(0, firstParenIndex);
|
||||
}
|
||||
|
||||
+44
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -28,7 +28,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.aspectj.weaver.BCException;
|
||||
import org.aspectj.weaver.patterns.NamePattern;
|
||||
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
|
||||
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
||||
@@ -187,13 +186,24 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
throw new IllegalStateException("Must set property 'expression' before attempting to match");
|
||||
}
|
||||
if (this.pointcutExpression == null) {
|
||||
this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
this.pointcutClassLoader = determinePointcutClassLoader();
|
||||
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the ClassLoader to use for pointcut evaluation.
|
||||
*/
|
||||
private ClassLoader determinePointcutClassLoader() {
|
||||
if (this.beanFactory instanceof ConfigurableBeanFactory) {
|
||||
return ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader();
|
||||
}
|
||||
if (this.pointcutDeclarationScope != null) {
|
||||
return this.pointcutDeclarationScope.getClassLoader();
|
||||
}
|
||||
return ClassUtils.getDefaultClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
@@ -258,7 +268,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (BCException ex) {
|
||||
catch (Throwable ex) {
|
||||
logger.debug("PointcutExpression matching rejected target class", ex);
|
||||
}
|
||||
return false;
|
||||
@@ -326,7 +336,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// No current invocation...
|
||||
// TODO: Should we really proceed here?
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not access current invocation - matching with limited context: " + ex);
|
||||
}
|
||||
@@ -413,39 +422,46 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
shadowMatch = this.shadowMatchCache.get(targetMethod);
|
||||
if (shadowMatch == null) {
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorldException ex) {
|
||||
// Failed to introspect target method, probably because it has been loaded
|
||||
// in a special ClassLoader. Let's try the declaring ClassLoader instead...
|
||||
try {
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex2) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
if (shadowMatch == null && targetMethod != originalMethod) {
|
||||
methodToMatch = originalMethod;
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorldException ex3) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's try the original method's declaring class before we give up...
|
||||
catch (ReflectionWorldException ex) {
|
||||
// Failed to introspect target method, probably because it has been loaded
|
||||
// in a special ClassLoader. Let's try the declaring ClassLoader instead...
|
||||
try {
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex4) {
|
||||
catch (ReflectionWorldException ex2) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
if (shadowMatch == null && targetMethod != originalMethod) {
|
||||
methodToMatch = originalMethod;
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorldException ex3) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's try the original method's declaring class before we give up...
|
||||
try {
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex4) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Possibly AspectJ 1.8.10 encountering an invalid signature
|
||||
logger.debug("PointcutExpression matching rejected target method", ex);
|
||||
fallbackExpression = null;
|
||||
}
|
||||
if (shadowMatch == null) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
|
||||
+18
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 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,6 +18,8 @@ package org.springframework.aop.aspectj;
|
||||
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.support.AbstractGenericPointcutAdvisor;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
|
||||
/**
|
||||
* Spring AOP Advisor that can be used for any AspectJ pointcut expression.
|
||||
@@ -26,16 +28,11 @@ import org.springframework.aop.support.AbstractGenericPointcutAdvisor;
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor {
|
||||
public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor implements BeanFactoryAware {
|
||||
|
||||
private final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
|
||||
|
||||
@Override
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
public void setExpression(String expression) {
|
||||
this.pointcut.setExpression(expression);
|
||||
}
|
||||
@@ -52,12 +49,22 @@ public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdv
|
||||
return this.pointcut.getLocation();
|
||||
}
|
||||
|
||||
public void setParameterTypes(Class<?>[] types) {
|
||||
this.pointcut.setParameterTypes(types);
|
||||
}
|
||||
|
||||
public void setParameterNames(String... names) {
|
||||
this.pointcut.setParameterNames(names);
|
||||
}
|
||||
|
||||
public void setParameterTypes(Class<?>... types) {
|
||||
this.pointcut.setParameterTypes(types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.pointcut.setBeanFactory(beanFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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,7 +22,6 @@ import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.PointcutAdvisor;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* AspectJPointcutAdvisor that adapts an {@link AbstractAspectJAdvice}
|
||||
@@ -51,11 +50,11 @@ public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered {
|
||||
this.pointcut = advice.buildSafePointcut();
|
||||
}
|
||||
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPerInstance() {
|
||||
return true;
|
||||
@@ -91,12 +90,12 @@ public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered {
|
||||
return false;
|
||||
}
|
||||
AspectJPointcutAdvisor otherAdvisor = (AspectJPointcutAdvisor) other;
|
||||
return (ObjectUtils.nullSafeEquals(this.advice, otherAdvisor.advice));
|
||||
return this.advice.equals(otherAdvisor.advice);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return AspectJPointcutAdvisor.class.hashCode();
|
||||
return AspectJPointcutAdvisor.class.hashCode() * 29 + this.advice.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2018 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 org.aopalliance.aop.Advice;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.IntroductionAdvisor;
|
||||
import org.springframework.aop.IntroductionInterceptor;
|
||||
import org.springframework.aop.support.ClassFilters;
|
||||
import org.springframework.aop.support.DelegatePerTargetObjectIntroductionInterceptor;
|
||||
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
|
||||
@@ -34,12 +35,12 @@ import org.springframework.aop.support.DelegatingIntroductionInterceptor;
|
||||
*/
|
||||
public class DeclareParentsAdvisor implements IntroductionAdvisor {
|
||||
|
||||
private final Advice advice;
|
||||
|
||||
private final Class<?> introducedInterface;
|
||||
|
||||
private final ClassFilter typePatternClassFilter;
|
||||
|
||||
private final Advice advice;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new advisor for this DeclareParents field.
|
||||
@@ -48,8 +49,8 @@ public class DeclareParentsAdvisor implements IntroductionAdvisor {
|
||||
* @param defaultImpl the default implementation class
|
||||
*/
|
||||
public DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Class<?> defaultImpl) {
|
||||
this(interfaceType, typePattern, defaultImpl,
|
||||
new DelegatePerTargetObjectIntroductionInterceptor(defaultImpl, interfaceType));
|
||||
this(interfaceType, typePattern,
|
||||
new DelegatePerTargetObjectIntroductionInterceptor(defaultImpl, interfaceType));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,8 +60,7 @@ public class DeclareParentsAdvisor implements IntroductionAdvisor {
|
||||
* @param delegateRef the delegate implementation object
|
||||
*/
|
||||
public DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Object delegateRef) {
|
||||
this(interfaceType, typePattern, delegateRef.getClass(),
|
||||
new DelegatingIntroductionInterceptor(delegateRef));
|
||||
this(interfaceType, typePattern, new DelegatingIntroductionInterceptor(delegateRef));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,23 +68,21 @@ public class DeclareParentsAdvisor implements IntroductionAdvisor {
|
||||
* (cannot use method such as init() to share common code, due the use of final fields)
|
||||
* @param interfaceType static field defining the introduction
|
||||
* @param typePattern type pattern the introduction is restricted to
|
||||
* @param implementationClass implementation class
|
||||
* @param advice delegation advice
|
||||
* @param interceptor the delegation advice as {@link IntroductionInterceptor}
|
||||
*/
|
||||
private DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Class<?> implementationClass, Advice advice) {
|
||||
private DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, IntroductionInterceptor interceptor) {
|
||||
this.advice = interceptor;
|
||||
this.introducedInterface = interfaceType;
|
||||
ClassFilter typePatternFilter = new TypePatternClassFilter(typePattern);
|
||||
|
||||
// Excludes methods implemented.
|
||||
ClassFilter typePatternFilter = new TypePatternClassFilter(typePattern);
|
||||
ClassFilter exclusion = new ClassFilter() {
|
||||
@Override
|
||||
public boolean matches(Class<?> clazz) {
|
||||
return !(introducedInterface.isAssignableFrom(clazz));
|
||||
return !introducedInterface.isAssignableFrom(clazz);
|
||||
}
|
||||
};
|
||||
|
||||
this.typePatternClassFilter = ClassFilters.intersection(typePatternFilter, exclusion);
|
||||
this.advice = advice;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+14
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -32,17 +32,15 @@ import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation of AspectJ ProceedingJoinPoint interface
|
||||
* wrapping an AOP Alliance MethodInvocation.
|
||||
* An implementation of the AspectJ {@link ProceedingJoinPoint} interface
|
||||
* wrapping an AOP Alliance {@link org.aopalliance.intercept.MethodInvocation}.
|
||||
*
|
||||
* <p><b>Note</b>: the {@code getThis()} method returns the current Spring AOP proxy.
|
||||
* <p><b>Note</b>: The {@code getThis()} method returns the current Spring AOP proxy.
|
||||
* The {@code getTarget()} method returns the current Spring AOP target (which may be
|
||||
* {@code null} if there is no target), and is a plain POJO without any advice.
|
||||
* <b>If you want to call the object and have the advice take effect, use
|
||||
* {@code getThis()}.</b> A common example is casting the object to an
|
||||
* introduced interface in the implementation of an introduction.
|
||||
*
|
||||
* <p>Of course there is no such distinction between target and proxy in AspectJ.
|
||||
* {@code null} if there is no target instance) as a plain POJO without any advice.
|
||||
* <b>If you want to call the object and have the advice take effect, use {@code getThis()}.</b>
|
||||
* A common example is casting the object to an introduced interface in the implementation of
|
||||
* an introduction. There is no such distinction between target and proxy in AspectJ itself.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -56,7 +54,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
|
||||
|
||||
private final ProxyMethodInvocation methodInvocation;
|
||||
|
||||
private Object[] defensiveCopyOfArgs;
|
||||
private Object[] args;
|
||||
|
||||
/** Lazily initialized signature object */
|
||||
private Signature signature;
|
||||
@@ -75,6 +73,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
|
||||
this.methodInvocation = methodInvocation;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void set$AroundClosure(AroundClosure aroundClosure) {
|
||||
throw new UnsupportedOperationException();
|
||||
@@ -115,12 +114,10 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
|
||||
|
||||
@Override
|
||||
public Object[] getArgs() {
|
||||
if (this.defensiveCopyOfArgs == null) {
|
||||
Object[] argsSource = this.methodInvocation.getArguments();
|
||||
this.defensiveCopyOfArgs = new Object[argsSource.length];
|
||||
System.arraycopy(argsSource, 0, this.defensiveCopyOfArgs, 0, argsSource.length);
|
||||
if (this.args == null) {
|
||||
this.args = this.methodInvocation.getArguments().clone();
|
||||
}
|
||||
return this.defensiveCopyOfArgs;
|
||||
return this.args;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -128,7 +125,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
|
||||
if (this.signature == null) {
|
||||
this.signature = new MethodSignatureImpl();
|
||||
}
|
||||
return signature;
|
||||
return this.signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+6
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2018 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,6 +41,7 @@ public class SimpleAspectInstanceFactory implements AspectInstanceFactory {
|
||||
this.aspectClass = aspectClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the specified aspect class (never {@code null}).
|
||||
*/
|
||||
@@ -48,17 +49,18 @@ public class SimpleAspectInstanceFactory implements AspectInstanceFactory {
|
||||
return this.aspectClass;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final Object getAspectInstance() {
|
||||
try {
|
||||
return this.aspectClass.newInstance();
|
||||
}
|
||||
catch (InstantiationException ex) {
|
||||
throw new AopConfigException("Unable to instantiate aspect class [" + this.aspectClass.getName() + "]", ex);
|
||||
throw new AopConfigException(
|
||||
"Unable to instantiate aspect class: " + this.aspectClass.getName(), ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new AopConfigException("Cannot access element class [" + this.aspectClass.getName() + "]", ex);
|
||||
throw new AopConfigException(
|
||||
"Could not access aspect constructor: " + this.aspectClass.getName(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -27,6 +27,7 @@ import org.springframework.util.StringUtils;
|
||||
* Spring AOP {@link ClassFilter} implementation using AspectJ type matching.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class TypePatternClassFilter implements ClassFilter {
|
||||
@@ -76,17 +77,21 @@ public class TypePatternClassFilter implements ClassFilter {
|
||||
* or is recognized as invalid
|
||||
*/
|
||||
public void setTypePattern(String typePattern) {
|
||||
Assert.notNull(typePattern);
|
||||
Assert.notNull(typePattern, "Type pattern must not be null");
|
||||
this.typePattern = typePattern;
|
||||
this.aspectJTypePatternMatcher =
|
||||
PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution().
|
||||
parseTypePattern(replaceBooleanOperators(typePattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the AspectJ type pattern to match.
|
||||
*/
|
||||
public String getTypePattern() {
|
||||
return typePattern;
|
||||
return this.typePattern;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Should the pointcut apply to the given interface or target class?
|
||||
* @param clazz candidate target class
|
||||
@@ -95,9 +100,7 @@ public class TypePatternClassFilter implements ClassFilter {
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(Class<?> clazz) {
|
||||
if (this.aspectJTypePatternMatcher == null) {
|
||||
throw new IllegalStateException("No 'typePattern' has been set via ctor/setter.");
|
||||
}
|
||||
Assert.state(this.aspectJTypePatternMatcher != null, "No type pattern has been set");
|
||||
return this.aspectJTypePatternMatcher.matches(clazz);
|
||||
}
|
||||
|
||||
@@ -108,9 +111,8 @@ public class TypePatternClassFilter implements ClassFilter {
|
||||
* <p>This method converts back to {@code &&} for the AspectJ pointcut parser.
|
||||
*/
|
||||
private String replaceBooleanOperators(String pcExpr) {
|
||||
pcExpr = StringUtils.replace(pcExpr," and "," && ");
|
||||
pcExpr = StringUtils.replace(pcExpr, " or ", " || ");
|
||||
pcExpr = StringUtils.replace(pcExpr, " not ", " ! ");
|
||||
return pcExpr;
|
||||
String result = StringUtils.replace(pcExpr," and "," && ");
|
||||
result = StringUtils.replace(result, " or ", " || ");
|
||||
return StringUtils.replace(result, " not ", " ! ");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-45
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -38,7 +38,6 @@ import org.aspectj.lang.reflect.AjType;
|
||||
import org.aspectj.lang.reflect.AjTypeSystem;
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
@@ -121,49 +120,6 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The pointcut and advice annotations both have an "argNames" member which contains a
|
||||
* comma-separated list of the argument names. We use this (if non-empty) to build the
|
||||
* formal parameters for the pointcut.
|
||||
*/
|
||||
protected AspectJExpressionPointcut createPointcutExpression(
|
||||
Method annotatedMethod, Class<?> declarationScope, String[] pointcutParameterNames) {
|
||||
|
||||
Class<?> [] pointcutParameterTypes = new Class<?>[0];
|
||||
if (pointcutParameterNames != null) {
|
||||
pointcutParameterTypes = extractPointcutParameterTypes(pointcutParameterNames,annotatedMethod);
|
||||
}
|
||||
|
||||
AspectJExpressionPointcut ajexp =
|
||||
new AspectJExpressionPointcut(declarationScope,pointcutParameterNames,pointcutParameterTypes);
|
||||
ajexp.setLocation(annotatedMethod.toString());
|
||||
return ajexp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the pointcut parameters needed by aspectj based on the given argument names
|
||||
* and the argument types that are available from the adviceMethod. Needs to take into
|
||||
* account (ignore) any JoinPoint based arguments as these are not pointcut context but
|
||||
* rather part of the advice execution context (thisJoinPoint, thisJoinPointStaticPart)
|
||||
*/
|
||||
private Class<?>[] extractPointcutParameterTypes(String[] argNames, Method adviceMethod) {
|
||||
Class<?>[] ret = new Class<?>[argNames.length];
|
||||
Class<?>[] paramTypes = adviceMethod.getParameterTypes();
|
||||
if (argNames.length > paramTypes.length) {
|
||||
throw new IllegalStateException("Expecting at least " + argNames.length +
|
||||
" arguments in the advice declaration, but only found " + paramTypes.length);
|
||||
}
|
||||
|
||||
// Make the simplifying assumption for now that all of the JoinPoint based arguments
|
||||
// come first in the advice declaration.
|
||||
int typeOffset = paramTypes.length - argNames.length;
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = paramTypes[i + typeOffset];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find and return the first AspectJ annotation on the given method
|
||||
* (there <i>should</i> only be one anyway...)
|
||||
|
||||
+6
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -50,7 +50,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
|
||||
private List<Pattern> includePatterns;
|
||||
|
||||
private AspectJAdvisorFactory aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory();
|
||||
private AspectJAdvisorFactory aspectJAdvisorFactory;
|
||||
|
||||
private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;
|
||||
|
||||
@@ -74,6 +74,9 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
@Override
|
||||
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
super.initBeanFactory(beanFactory);
|
||||
if (this.aspectJAdvisorFactory == null) {
|
||||
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
|
||||
}
|
||||
this.aspectJAdvisorsBuilder =
|
||||
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
|
||||
}
|
||||
@@ -130,6 +133,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
|
||||
public BeanFactoryAspectJAdvisorsBuilderAdapter(
|
||||
ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
|
||||
|
||||
super(beanFactory, advisorFactory);
|
||||
}
|
||||
|
||||
|
||||
+25
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 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,9 +16,9 @@
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
@@ -50,7 +50,7 @@ import org.springframework.util.ClassUtils;
|
||||
public class AspectJProxyFactory extends ProxyCreatorSupport {
|
||||
|
||||
/** Cache for singleton aspect instances */
|
||||
private static final Map<Class<?>, Object> aspectCache = new HashMap<Class<?>, Object>();
|
||||
private static final Map<Class<?>, Object> aspectCache = new ConcurrentHashMap<Class<?>, Object>();
|
||||
|
||||
private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory();
|
||||
|
||||
@@ -144,7 +144,7 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
|
||||
private MetadataAwareAspectInstanceFactory createAspectInstanceFactory(
|
||||
AspectMetadata am, Class<?> aspectClass, String aspectName) {
|
||||
|
||||
MetadataAwareAspectInstanceFactory instanceFactory = null;
|
||||
MetadataAwareAspectInstanceFactory instanceFactory;
|
||||
if (am.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
|
||||
// Create a shared aspect instance.
|
||||
Object instance = getSingletonAspectInstance(aspectClass);
|
||||
@@ -162,23 +162,29 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
|
||||
* is created if one cannot be found in the instance cache.
|
||||
*/
|
||||
private Object getSingletonAspectInstance(Class<?> aspectClass) {
|
||||
synchronized (aspectCache) {
|
||||
Object instance = aspectCache.get(aspectClass);
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
}
|
||||
try {
|
||||
instance = aspectClass.newInstance();
|
||||
aspectCache.put(aspectClass, instance);
|
||||
return instance;
|
||||
}
|
||||
catch (InstantiationException ex) {
|
||||
throw new AopConfigException("Unable to instantiate aspect class [" + aspectClass.getName() + "]", ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new AopConfigException("Cannot access aspect class [" + aspectClass.getName() + "]", ex);
|
||||
// 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) {
|
||||
try {
|
||||
instance = aspectClass.newInstance();
|
||||
aspectCache.put(aspectClass, instance);
|
||||
}
|
||||
catch (InstantiationException ex) {
|
||||
throw new AopConfigException(
|
||||
"Unable to instantiate aspect class: " + aspectClass.getName(), ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new AopConfigException(
|
||||
"Could not access aspect constructor: " + aspectClass.getName(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+12
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -35,9 +35,8 @@ import org.springframework.aop.support.ComposablePointcut;
|
||||
* Metadata for an AspectJ aspect class, with an additional Spring AOP pointcut
|
||||
* for the per clause.
|
||||
*
|
||||
* <p>Uses AspectJ 5 AJType reflection API, so is only supported on Java 5.
|
||||
* Enables us to work with different AspectJ instantiation models such as
|
||||
* "singleton", "pertarget" and "perthis".
|
||||
* <p>Uses AspectJ 5 AJType reflection API, enabling us to work with different
|
||||
* AspectJ instantiation models such as "singleton", "pertarget" and "perthis".
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -102,20 +101,22 @@ public class AspectMetadata implements Serializable {
|
||||
this.ajType = ajType;
|
||||
|
||||
switch (this.ajType.getPerClause().getKind()) {
|
||||
case SINGLETON :
|
||||
case SINGLETON:
|
||||
this.perClausePointcut = Pointcut.TRUE;
|
||||
return;
|
||||
case PERTARGET : case PERTHIS :
|
||||
case PERTARGET:
|
||||
case PERTHIS:
|
||||
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
|
||||
ajexp.setLocation("@Aspect annotation on " + aspectClass.getName());
|
||||
ajexp.setLocation(aspectClass.getName());
|
||||
ajexp.setExpression(findPerClause(aspectClass));
|
||||
ajexp.setPointcutDeclarationScope(aspectClass);
|
||||
this.perClausePointcut = ajexp;
|
||||
return;
|
||||
case PERTYPEWITHIN :
|
||||
case PERTYPEWITHIN:
|
||||
// Works with a type pattern
|
||||
this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));
|
||||
return;
|
||||
default :
|
||||
default:
|
||||
throw new AopConfigException(
|
||||
"PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass);
|
||||
}
|
||||
@@ -125,10 +126,8 @@ public class AspectMetadata implements Serializable {
|
||||
* Extract contents from String of form {@code pertarget(contents)}.
|
||||
*/
|
||||
private String findPerClause(Class<?> aspectClass) {
|
||||
// TODO when AspectJ provides this, we can remove this hack. Hence we don't
|
||||
// bother to make it elegant. Or efficient. Or robust :-)
|
||||
String str = aspectClass.getAnnotation(Aspect.class).value();
|
||||
str = str.substring(str.indexOf("(") + 1);
|
||||
str = str.substring(str.indexOf('(') + 1);
|
||||
str = str.substring(0, str.length() - 1);
|
||||
return str;
|
||||
}
|
||||
@@ -149,7 +148,7 @@ public class AspectMetadata implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the aspect class.
|
||||
* Return the aspect name.
|
||||
*/
|
||||
public String getAspectName() {
|
||||
return this.aspectName;
|
||||
|
||||
+13
-2
@@ -97,8 +97,19 @@ public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInst
|
||||
|
||||
@Override
|
||||
public Object getAspectCreationMutex() {
|
||||
return (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex() : this);
|
||||
if (this.beanFactory != null) {
|
||||
if (this.beanFactory.isSingleton(name)) {
|
||||
// Rely on singleton semantics provided by the factory -> no local lock.
|
||||
return null;
|
||||
}
|
||||
else if (this.beanFactory instanceof ConfigurableBeanFactory) {
|
||||
// No singleton guarantees from the factory -> let's lock locally but
|
||||
// reuse the factory's singleton lock, just in case a lazy dependency
|
||||
// of our advice bean happens to trigger the singleton lock implicitly...
|
||||
return ((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex();
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+49
-48
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2016 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,10 +17,10 @@
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
@@ -43,12 +43,12 @@ public class BeanFactoryAspectJAdvisorsBuilder {
|
||||
|
||||
private final AspectJAdvisorFactory advisorFactory;
|
||||
|
||||
private List<String> aspectBeanNames;
|
||||
private volatile List<String> aspectBeanNames;
|
||||
|
||||
private final Map<String, List<Advisor>> advisorsCache = new HashMap<String, List<Advisor>>();
|
||||
private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<String, List<Advisor>>();
|
||||
|
||||
private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache =
|
||||
new HashMap<String, MetadataAwareAspectInstanceFactory>();
|
||||
new ConcurrentHashMap<String, MetadataAwareAspectInstanceFactory>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -56,7 +56,7 @@ public class BeanFactoryAspectJAdvisorsBuilder {
|
||||
* @param beanFactory the ListableBeanFactory to scan
|
||||
*/
|
||||
public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory) {
|
||||
this(beanFactory, new ReflectiveAspectJAdvisorFactory());
|
||||
this(beanFactory, new ReflectiveAspectJAdvisorFactory(beanFactory));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,56 +80,57 @@ public class BeanFactoryAspectJAdvisorsBuilder {
|
||||
* @see #isEligibleBean
|
||||
*/
|
||||
public List<Advisor> buildAspectJAdvisors() {
|
||||
List<String> aspectNames = null;
|
||||
List<String> aspectNames = this.aspectBeanNames;
|
||||
|
||||
synchronized (this) {
|
||||
aspectNames = this.aspectBeanNames;
|
||||
if (aspectNames == null) {
|
||||
List<Advisor> advisors = new LinkedList<Advisor>();
|
||||
aspectNames = new LinkedList<String>();
|
||||
String[] beanNames =
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
|
||||
for (String beanName : beanNames) {
|
||||
if (!isEligibleBean(beanName)) {
|
||||
continue;
|
||||
}
|
||||
// We must be careful not to instantiate beans eagerly as in this
|
||||
// case they would be cached by the Spring container but would not
|
||||
// have been weaved
|
||||
Class<?> beanType = this.beanFactory.getType(beanName);
|
||||
if (beanType == null) {
|
||||
continue;
|
||||
}
|
||||
if (this.advisorFactory.isAspect(beanType)) {
|
||||
aspectNames.add(beanName);
|
||||
AspectMetadata amd = new AspectMetadata(beanType, beanName);
|
||||
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
|
||||
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
this.advisorsCache.put(beanName, classAdvisors);
|
||||
if (aspectNames == null) {
|
||||
synchronized (this) {
|
||||
aspectNames = this.aspectBeanNames;
|
||||
if (aspectNames == null) {
|
||||
List<Advisor> advisors = new LinkedList<Advisor>();
|
||||
aspectNames = new LinkedList<String>();
|
||||
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
|
||||
this.beanFactory, Object.class, true, false);
|
||||
for (String beanName : beanNames) {
|
||||
if (!isEligibleBean(beanName)) {
|
||||
continue;
|
||||
}
|
||||
// We must be careful not to instantiate beans eagerly as in this case they
|
||||
// would be cached by the Spring container but would not have been weaved.
|
||||
Class<?> beanType = this.beanFactory.getType(beanName);
|
||||
if (beanType == null) {
|
||||
continue;
|
||||
}
|
||||
if (this.advisorFactory.isAspect(beanType)) {
|
||||
aspectNames.add(beanName);
|
||||
AspectMetadata amd = new AspectMetadata(beanType, beanName);
|
||||
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
|
||||
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
this.advisorsCache.put(beanName, classAdvisors);
|
||||
}
|
||||
else {
|
||||
this.aspectFactoryCache.put(beanName, factory);
|
||||
}
|
||||
advisors.addAll(classAdvisors);
|
||||
}
|
||||
else {
|
||||
// Per target or per this.
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
throw new IllegalArgumentException("Bean with name '" + beanName +
|
||||
"' is a singleton, but aspect instantiation model is not singleton");
|
||||
}
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
|
||||
this.aspectFactoryCache.put(beanName, factory);
|
||||
advisors.addAll(this.advisorFactory.getAdvisors(factory));
|
||||
}
|
||||
advisors.addAll(classAdvisors);
|
||||
}
|
||||
else {
|
||||
// Per target or per this.
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
throw new IllegalArgumentException("Bean with name '" + beanName +
|
||||
"' is a singleton, but aspect instantiation model is not singleton");
|
||||
}
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
|
||||
this.aspectFactoryCache.put(beanName, factory);
|
||||
advisors.addAll(this.advisorFactory.getAdvisors(factory));
|
||||
}
|
||||
}
|
||||
this.aspectBeanNames = aspectNames;
|
||||
return advisors;
|
||||
}
|
||||
this.aspectBeanNames = aspectNames;
|
||||
return advisors;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-3
@@ -48,9 +48,15 @@ public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwar
|
||||
@Override
|
||||
public Object getAspectInstance() {
|
||||
if (this.materialized == null) {
|
||||
synchronized (this.maaif.getAspectCreationMutex()) {
|
||||
if (this.materialized == null) {
|
||||
this.materialized = this.maaif.getAspectInstance();
|
||||
Object mutex = this.maaif.getAspectCreationMutex();
|
||||
if (mutex == null) {
|
||||
this.materialized = this.maaif.getAspectInstance();
|
||||
}
|
||||
else {
|
||||
synchronized (mutex) {
|
||||
if (this.materialized == null) {
|
||||
this.materialized = this.maaif.getAspectInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactor
|
||||
|
||||
/**
|
||||
* Return the best possible creation mutex for this factory.
|
||||
* @return the mutex object (never {@code null})
|
||||
* @return the mutex object (may be {@code null} for no mutex to use)
|
||||
* @since 4.3
|
||||
*/
|
||||
Object getAspectCreationMutex();
|
||||
|
||||
+28
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -46,6 +46,7 @@ import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
|
||||
import org.springframework.aop.aspectj.DeclareParentsAdvisor;
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.ConvertingComparator;
|
||||
@@ -95,6 +96,30 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
}
|
||||
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code ReflectiveAspectJAdvisorFactory}.
|
||||
*/
|
||||
public ReflectiveAspectJAdvisorFactory() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code ReflectiveAspectJAdvisorFactory}, propagating the given
|
||||
* {@link BeanFactory} to the created {@link AspectJExpressionPointcut} instances,
|
||||
* for bean pointcut handling as well as consistent {@link ClassLoader} resolution.
|
||||
* @param beanFactory the BeanFactory to propagate (may be {@code null}}
|
||||
* @since 4.3.6
|
||||
* @see AspectJExpressionPointcut#setBeanFactory
|
||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#getBeanClassLoader()
|
||||
*/
|
||||
public ReflectiveAspectJAdvisorFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
|
||||
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
|
||||
@@ -161,9 +186,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
}
|
||||
|
||||
if (DeclareParents.class == declareParents.defaultImpl()) {
|
||||
// This is what comes back if it wasn't set. This seems bizarre...
|
||||
// TODO this restriction possibly should be relaxed
|
||||
throw new IllegalStateException("defaultImpl must be set on DeclareParents");
|
||||
throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
|
||||
}
|
||||
|
||||
return new DeclareParentsAdvisor(
|
||||
@@ -197,6 +220,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
AspectJExpressionPointcut ajexp =
|
||||
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
|
||||
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
|
||||
ajexp.setBeanFactory(this.beanFactory);
|
||||
return ajexp;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -71,7 +71,7 @@ public abstract class AbstractInterceptorDrivenBeanDefinitionDecorator implement
|
||||
BeanDefinition interceptorDefinition = createInterceptorDefinition(node);
|
||||
|
||||
// generate name and register the interceptor
|
||||
String interceptorName = existingBeanName + "." + getInterceptorNameSuffix(interceptorDefinition);
|
||||
String interceptorName = existingBeanName + '.' + getInterceptorNameSuffix(interceptorDefinition);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(
|
||||
new BeanDefinitionHolder(interceptorDefinition, interceptorName), registry);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -81,11 +81,11 @@ public abstract class AopNamespaceUtils {
|
||||
|
||||
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
|
||||
if (sourceElement != null) {
|
||||
boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
|
||||
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
|
||||
if (proxyTargetClass) {
|
||||
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
|
||||
}
|
||||
boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
|
||||
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
|
||||
if (exposeProxy) {
|
||||
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
|
||||
}
|
||||
|
||||
+3
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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,8 +21,8 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link AspectInstanceFactory} that locates the aspect from the
|
||||
@@ -50,9 +50,7 @@ public class SimpleBeanFactoryAwareAspectInstanceFactory implements AspectInstan
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
if (!StringUtils.hasText(this.aspectBeanName)) {
|
||||
throw new IllegalArgumentException("'aspectBeanName' is required");
|
||||
}
|
||||
Assert.notNull(this.aspectBeanName, "'aspectBeanName' is required");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -234,7 +234,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getProxiedInterfaces() {
|
||||
return this.interfaces.toArray(new Class<?>[this.interfaces.size()]);
|
||||
return ClassUtils.toClassArray(this.interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -43,6 +43,25 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
public abstract class AopProxyUtils {
|
||||
|
||||
/**
|
||||
* Obtain the singleton target object behind the given proxy, if any.
|
||||
* @param candidate the (potential) proxy to check
|
||||
* @return the singleton target object managed in a {@link SingletonTargetSource},
|
||||
* or {@code null} in any other case (not a proxy, not an existing singleton target)
|
||||
* @since 4.3.8
|
||||
* @see Advised#getTargetSource()
|
||||
* @see SingletonTargetSource#getTarget()
|
||||
*/
|
||||
public static Object getSingletonTarget(Object candidate) {
|
||||
if (candidate instanceof Advised) {
|
||||
TargetSource targetSource = ((Advised) candidate).getTargetSource();
|
||||
if (targetSource instanceof SingletonTargetSource) {
|
||||
return ((SingletonTargetSource) targetSource).getTarget();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the ultimate target class of the given bean instance, traversing
|
||||
* not only a top-level proxy but any number of nested proxies as well —
|
||||
@@ -59,14 +78,7 @@ public abstract class AopProxyUtils {
|
||||
Class<?> result = null;
|
||||
while (current instanceof TargetClassAware) {
|
||||
result = ((TargetClassAware) current).getTargetClass();
|
||||
Object nested = null;
|
||||
if (current instanceof Advised) {
|
||||
TargetSource targetSource = ((Advised) current).getTargetSource();
|
||||
if (targetSource instanceof SingletonTargetSource) {
|
||||
nested = ((SingletonTargetSource) targetSource).getTarget();
|
||||
}
|
||||
}
|
||||
current = nested;
|
||||
current = getSingletonTarget(current);
|
||||
}
|
||||
if (result == null) {
|
||||
result = (AopUtils.isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -23,6 +23,7 @@ import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
@@ -56,9 +57,6 @@ import org.springframework.util.ObjectUtils;
|
||||
/**
|
||||
* CGLIB-based {@link AopProxy} implementation for the Spring AOP framework.
|
||||
*
|
||||
* <p>Formerly named {@code Cglib2AopProxy}, as of Spring 3.2, this class depends on
|
||||
* Spring's own internally repackaged version of CGLIB 3.</i>.
|
||||
*
|
||||
* <p>Objects of this type should be obtained through proxy factories,
|
||||
* configured by an {@link AdvisedSupport} object. This class is internal
|
||||
* to Spring's AOP framework and need not be used directly by client code.
|
||||
@@ -203,18 +201,16 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
return createProxyClassAndInstance(enhancer, callbacks);
|
||||
}
|
||||
catch (CodeGenerationException ex) {
|
||||
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
|
||||
this.advised.getTargetClass() + "]: " +
|
||||
"Common causes of this problem include using a final class or a non-visible class",
|
||||
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
|
||||
": Common causes of this problem include using a final class or a non-visible class",
|
||||
ex);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
|
||||
this.advised.getTargetClass() + "]: " +
|
||||
"Common causes of this problem include using a final class or a non-visible class",
|
||||
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
|
||||
": Common causes of this problem include using a final class or a non-visible class",
|
||||
ex);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
catch (Throwable ex) {
|
||||
// TargetSource.getTarget() failed
|
||||
throw new AopConfigException("Unexpected AOP exception", ex);
|
||||
}
|
||||
@@ -241,10 +237,11 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
* validates it if not.
|
||||
*/
|
||||
private void validateClassIfNecessary(Class<?> proxySuperClass, ClassLoader proxyClassLoader) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
synchronized (validatedClasses) {
|
||||
if (!validatedClasses.containsKey(proxySuperClass)) {
|
||||
doValidateClass(proxySuperClass, proxyClassLoader);
|
||||
doValidateClass(proxySuperClass, proxyClassLoader,
|
||||
ClassUtils.getAllInterfacesForClassAsSet(proxySuperClass));
|
||||
validatedClasses.put(proxySuperClass, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
@@ -255,30 +252,35 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
* Checks for final methods on the given {@code Class}, as well as package-visible
|
||||
* methods across ClassLoaders, and writes warnings to the log for each one found.
|
||||
*/
|
||||
private void doValidateClass(Class<?> proxySuperClass, ClassLoader proxyClassLoader) {
|
||||
if (Object.class != proxySuperClass) {
|
||||
private void doValidateClass(Class<?> proxySuperClass, ClassLoader proxyClassLoader, Set<Class<?>> ifcs) {
|
||||
if (proxySuperClass != Object.class) {
|
||||
Method[] methods = proxySuperClass.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
int mod = method.getModifiers();
|
||||
if (!Modifier.isStatic(mod)) {
|
||||
if (!Modifier.isStatic(mod) && !Modifier.isPrivate(mod)) {
|
||||
if (Modifier.isFinal(mod)) {
|
||||
logger.info("Unable to proxy method [" + method + "] because it is final: " +
|
||||
"All calls to this method via a proxy will NOT be routed to the target instance.");
|
||||
if (implementsInterface(method, ifcs)) {
|
||||
logger.warn("Unable to proxy interface-implementing method [" + method + "] because " +
|
||||
"it is marked as final: Consider using interface-based JDK proxies instead!");
|
||||
}
|
||||
logger.info("Final method [" + method + "] cannot get proxied via CGLIB: " +
|
||||
"Calls to this method will NOT be routed to the target instance and " +
|
||||
"might lead to NPEs against uninitialized fields in the proxy instance.");
|
||||
}
|
||||
else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) && !Modifier.isPrivate(mod) &&
|
||||
else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) &&
|
||||
proxyClassLoader != null && proxySuperClass.getClassLoader() != proxyClassLoader) {
|
||||
logger.info("Unable to proxy method [" + method + "] because it is package-visible " +
|
||||
"across different ClassLoaders: All calls to this method via a proxy will " +
|
||||
"NOT be routed to the target instance.");
|
||||
logger.info("Method [" + method + "] is package-visible across different ClassLoaders " +
|
||||
"and cannot get proxied via CGLIB: Declare this method as public or protected " +
|
||||
"if you need to support invocations through the proxy.");
|
||||
}
|
||||
}
|
||||
}
|
||||
doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader);
|
||||
doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader, ifcs);
|
||||
}
|
||||
}
|
||||
|
||||
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
|
||||
// Parameters used for optimisation choices...
|
||||
// Parameters used for optimization choices...
|
||||
boolean exposeProxy = this.advised.isExposeProxy();
|
||||
boolean isFrozen = this.advised.isFrozen();
|
||||
boolean isStatic = this.advised.getTargetSource().isStatic();
|
||||
@@ -317,14 +319,14 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
Callback[] callbacks;
|
||||
|
||||
// If the target is a static one and the advice chain is frozen,
|
||||
// then we can make some optimisations by sending the AOP calls
|
||||
// then we can make some optimizations by sending the AOP calls
|
||||
// direct to the target using the fixed chain for that method.
|
||||
if (isStatic && isFrozen) {
|
||||
Method[] methods = rootClass.getMethods();
|
||||
Callback[] fixedCallbacks = new Callback[methods.length];
|
||||
this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
|
||||
|
||||
// TODO: small memory optimisation here (can skip creation for methods with no advice)
|
||||
// TODO: small memory optimization here (can skip creation for methods with no advice)
|
||||
for (int x = 0; x < methods.length; x++) {
|
||||
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
|
||||
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
|
||||
@@ -345,25 +347,6 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a return value. Wraps a return of {@code this} if necessary to be the
|
||||
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
|
||||
*/
|
||||
private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) {
|
||||
// Massage return value if necessary
|
||||
if (retVal != null && retVal == target && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this". Note that we can't help
|
||||
// if the target sets a reference to itself in another returned object.
|
||||
retVal = proxy;
|
||||
}
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
|
||||
throw new AopInvocationException(
|
||||
"Null return value from advice does not match primitive return type for: " + method);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
@@ -377,6 +360,39 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the given method is declared on any of the given interfaces.
|
||||
*/
|
||||
private static boolean implementsInterface(Method method, Set<Class<?>> ifcs) {
|
||||
for (Class<?> ifc : ifcs) {
|
||||
if (ClassUtils.hasMethod(ifc, method.getName(), method.getParameterTypes())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a return value. Wraps a return of {@code this} if necessary to be the
|
||||
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
|
||||
*/
|
||||
private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) {
|
||||
// Massage return value if necessary
|
||||
if (retVal != null && retVal == target &&
|
||||
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this". Note that we can't help
|
||||
// if the target sets a reference to itself in another returned object.
|
||||
retVal = proxy;
|
||||
}
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
|
||||
throw new AopInvocationException(
|
||||
"Null return value from advice does not match primitive return type for: " + method);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializable replacement for CGLIB's NoOp interface.
|
||||
* Public to allow use elsewhere in the framework.
|
||||
@@ -822,51 +838,42 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
// Else use the AOP_PROXY.
|
||||
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method has advice and optimisations are enabled: " + method);
|
||||
logger.debug("Method has advice and optimizations are enabled: " + method);
|
||||
}
|
||||
// We know that we are optimising so we can use the FixedStaticChainInterceptors.
|
||||
// We know that we are optimizing so we can use the FixedStaticChainInterceptors.
|
||||
int index = this.fixedInterceptorMap.get(key);
|
||||
return (index + this.fixedInterceptorOffset);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Unable to apply any optimisations to advised method: " + method);
|
||||
logger.debug("Unable to apply any optimizations to advised method: " + method);
|
||||
}
|
||||
return AOP_PROXY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// See if the return type of the method is outside the class hierarchy
|
||||
// of the target type. If so we know it never needs to have return type
|
||||
// massage and can use a dispatcher.
|
||||
// If the proxy is being exposed, then must use the interceptor the
|
||||
// correct one is already configured. If the target is not static, then
|
||||
// cannot use a dispatcher because the target cannot be released.
|
||||
// See if the return type of the method is outside the class hierarchy of the target type.
|
||||
// If so we know it never needs to have return type massage and can use a dispatcher.
|
||||
// If the proxy is being exposed, then must use the interceptor the correct one is already
|
||||
// configured. If the target is not static, then we cannot use a dispatcher because the
|
||||
// target needs to be explicitly released after the invocation.
|
||||
if (exposeProxy || !isStatic) {
|
||||
return INVOKE_TARGET;
|
||||
}
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (targetClass == returnType) {
|
||||
if (returnType.isAssignableFrom(targetClass)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method " + method +
|
||||
"has return type same as target type (may return this) - using INVOKE_TARGET");
|
||||
logger.debug("Method return type is assignable from target type and " +
|
||||
"may therefore return 'this' - using INVOKE_TARGET: " + method);
|
||||
}
|
||||
return INVOKE_TARGET;
|
||||
}
|
||||
else if (returnType.isPrimitive() || !returnType.isAssignableFrom(targetClass)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method " + method +
|
||||
" has return type that ensures this cannot be returned- using DISPATCH_TARGET");
|
||||
}
|
||||
return DISPATCH_TARGET;
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method " + method +
|
||||
"has return type that is assignable from the target type (may return this) - " +
|
||||
"using INVOKE_TARGET");
|
||||
logger.debug("Method return type ensures 'this' cannot be returned - " +
|
||||
"using DISPATCH_TARGET: " + method);
|
||||
}
|
||||
return INVOKE_TARGET;
|
||||
return DISPATCH_TARGET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,8 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
|
||||
|
||||
// Massage return value if necessary.
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
|
||||
if (retVal != null && retVal == target &&
|
||||
returnType != Object.class && returnType.isInstance(proxy) &&
|
||||
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this" and the return type of the method
|
||||
// is type-compatible. Note that we can't help if the target sets
|
||||
|
||||
+10
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2018 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.aop.framework;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
import org.springframework.beans.factory.Aware;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
@@ -48,9 +50,9 @@ public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanC
|
||||
|
||||
|
||||
/**
|
||||
* Set the ordering which will apply to this class's implementation
|
||||
* of Ordered, used when applying multiple processors.
|
||||
* <p>Default value is {@code Integer.MAX_VALUE}, meaning that it's non-ordered.
|
||||
* Set the ordering which will apply to this processor's implementation
|
||||
* of {@link Ordered}, used when applying multiple processors.
|
||||
* <p>The default value is {@code Ordered.LOWEST_PRECEDENCE}, meaning non-ordered.
|
||||
* @param order the ordering value
|
||||
*/
|
||||
public void setOrder(int order) {
|
||||
@@ -127,6 +129,7 @@ public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanC
|
||||
*/
|
||||
protected boolean isConfigurationCallbackInterface(Class<?> ifc) {
|
||||
return (InitializingBean.class == ifc || DisposableBean.class == ifc ||
|
||||
Closeable.class == ifc || "java.lang.AutoCloseable".equals(ifc.getName()) ||
|
||||
ObjectUtils.containsElement(ifc.getInterfaces(), Aware.class));
|
||||
}
|
||||
|
||||
@@ -139,7 +142,9 @@ public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanC
|
||||
* @return whether the given interface is an internal language interface
|
||||
*/
|
||||
protected boolean isInternalLanguageInterface(Class<?> ifc) {
|
||||
return ifc.getName().equals("groovy.lang.GroovyObject");
|
||||
return (ifc.getName().equals("groovy.lang.GroovyObject") ||
|
||||
ifc.getName().endsWith(".cglib.proxy.Factory") ||
|
||||
ifc.getName().endsWith(".bytebuddy.MockAccess"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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,7 +26,7 @@ import org.springframework.aop.AfterReturningAdvice;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Interceptor to wrap am {@link org.springframework.aop.AfterReturningAdvice}.
|
||||
* Interceptor to wrap an {@link org.springframework.aop.AfterReturningAdvice}.
|
||||
* Used internally by the AOP framework; application developers should not need
|
||||
* to use this class directly.
|
||||
*
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -54,7 +54,8 @@ public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyC
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
super.setBeanFactory(beanFactory);
|
||||
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
|
||||
throw new IllegalStateException("Cannot use AdvisorAutoProxyCreator without a ConfigurableListableBeanFactory");
|
||||
throw new IllegalArgumentException(
|
||||
"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
|
||||
}
|
||||
initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
|
||||
}
|
||||
|
||||
+26
-30
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -55,26 +55,25 @@ import org.springframework.util.StringUtils;
|
||||
* before invoking the bean itself.
|
||||
*
|
||||
* <p>This class distinguishes between "common" interceptors: shared for all proxies it
|
||||
* creates, and "specific" interceptors: unique per bean instance. There need not
|
||||
* be any common interceptors. If there are, they are set using the interceptorNames
|
||||
* property. As with ProxyFactoryBean, interceptors names in the current factory
|
||||
* are used rather than bean references to allow correct handling of prototype
|
||||
* advisors and interceptors: for example, to support stateful mixins.
|
||||
* Any advice type is supported for "interceptorNames" entries.
|
||||
* creates, and "specific" interceptors: unique per bean instance. There need not be any
|
||||
* common interceptors. If there are, they are set using the interceptorNames property.
|
||||
* As with {@link org.springframework.aop.framework.ProxyFactoryBean}, interceptors names
|
||||
* in the current factory are used rather than bean references to allow correct handling
|
||||
* of prototype advisors and interceptors: for example, to support stateful mixins.
|
||||
* Any advice type is supported for {@link #setInterceptorNames "interceptorNames"} entries.
|
||||
*
|
||||
* <p>Such auto-proxying is particularly useful if there's a large number of beans that
|
||||
* need to be wrapped with similar proxies, i.e. delegating to the same interceptors.
|
||||
* Instead of x repetitive proxy definitions for x target beans, you can register
|
||||
* one single such post processor with the bean factory to achieve the same effect.
|
||||
*
|
||||
* <p>Subclasses can apply any strategy to decide if a bean is to be proxied,
|
||||
* e.g. by type, by name, by definition details, etc. They can also return
|
||||
* additional interceptors that should just be applied to the specific bean
|
||||
* instance. The default concrete implementation is BeanNameAutoProxyCreator,
|
||||
* identifying the beans to be proxied via a list of bean names.
|
||||
* <p>Subclasses can apply any strategy to decide if a bean is to be proxied, e.g. by type,
|
||||
* by name, by definition details, etc. They can also return additional interceptors that
|
||||
* should just be applied to the specific bean instance. A simple concrete implementation is
|
||||
* {@link BeanNameAutoProxyCreator}, identifying the beans to be proxied via given names.
|
||||
*
|
||||
* <p>Any number of {@link TargetSourceCreator} implementations can be used to create
|
||||
* a custom target source - for example, to pool prototype objects. Auto-proxying will
|
||||
* a custom target source: for example, to pool prototype objects. Auto-proxying will
|
||||
* occur even if there is no advice, as long as a TargetSourceCreator specifies a custom
|
||||
* {@link org.springframework.aop.TargetSource}. If there are no TargetSourceCreators set,
|
||||
* or if none matches, a {@link org.springframework.aop.target.SingletonTargetSource}
|
||||
@@ -156,8 +155,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the AdvisorAdapterRegistry to use.
|
||||
* Default is the global AdvisorAdapterRegistry.
|
||||
* Specify the {@link AdvisorAdapterRegistry} to use.
|
||||
* <p>Default is the global {@link AdvisorAdapterRegistry}.
|
||||
* @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry
|
||||
*/
|
||||
public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
|
||||
@@ -165,18 +164,18 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom TargetSourceCreators to be applied in this order.
|
||||
* If the list is empty, or they all return null, a SingletonTargetSource
|
||||
* Set custom {@code TargetSourceCreators} to be applied in this order.
|
||||
* If the list is empty, or they all return null, a {@link SingletonTargetSource}
|
||||
* will be created for each bean.
|
||||
* <p>Note that TargetSourceCreators will kick in even for target beans
|
||||
* where no advices or advisors have been found. If a TargetSourceCreator
|
||||
* returns a TargetSource for a specific bean, that bean will be proxied
|
||||
* where no advices or advisors have been found. If a {@code TargetSourceCreator}
|
||||
* returns a {@link TargetSource} for a specific bean, that bean will be proxied
|
||||
* in any case.
|
||||
* <p>TargetSourceCreators can only be invoked if this post processor is used
|
||||
* in a BeanFactory, and its BeanFactoryAware callback is used.
|
||||
* @param targetSourceCreators list of TargetSourceCreator.
|
||||
* Ordering is significant: The TargetSource returned from the first matching
|
||||
* TargetSourceCreator (that is, the first that returns non-null) will be used.
|
||||
* <p>{@code TargetSourceCreators} can only be invoked if this post processor is used
|
||||
* in a {@link BeanFactory} and its {@link BeanFactoryAware} callback is triggered.
|
||||
* @param targetSourceCreators the list of {@code TargetSourceCreators}.
|
||||
* Ordering is significant: The {@code TargetSource} returned from the first matching
|
||||
* {@code TargetSourceCreator} (that is, the first that returns non-null) will be used.
|
||||
*/
|
||||
public void setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators) {
|
||||
this.customTargetSourceCreators = targetSourceCreators;
|
||||
@@ -207,8 +206,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the owning BeanFactory.
|
||||
* May be {@code null}, as this object doesn't need to belong to a bean factory.
|
||||
* Return the owning {@link BeanFactory}.
|
||||
* May be {@code null}, as this post-processor doesn't need to belong to a bean factory.
|
||||
*/
|
||||
protected BeanFactory getBeanFactory() {
|
||||
return this.beanFactory;
|
||||
@@ -455,10 +454,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
}
|
||||
|
||||
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
|
||||
for (Advisor advisor : advisors) {
|
||||
proxyFactory.addAdvisor(advisor);
|
||||
}
|
||||
|
||||
proxyFactory.addAdvisors(advisors);
|
||||
proxyFactory.setTargetSource(targetSource);
|
||||
customizeProxyFactory(proxyFactory);
|
||||
|
||||
|
||||
+15
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 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,15 +19,16 @@ package org.springframework.aop.framework.autoproxy;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
|
||||
/**
|
||||
* BeanPostProcessor implementation that creates AOP proxies based on all candidate
|
||||
* Advisors in the current BeanFactory. This class is completely generic; it contains
|
||||
* no special code to handle any particular aspects, such as pooling aspects.
|
||||
* {@code BeanPostProcessor} implementation that creates AOP proxies based on all
|
||||
* candidate {@code Advisor}s in the current {@code BeanFactory}. This class is
|
||||
* completely generic; it contains no special code to handle any particular aspects,
|
||||
* such as pooling aspects.
|
||||
*
|
||||
* <p>It's possible to filter out advisors - for example, to use multiple post processors
|
||||
* of this type in the same factory - by setting the {@code usePrefix} property
|
||||
* to true, in which case only advisors beginning with the DefaultAdvisorAutoProxyCreator's
|
||||
* bean name followed by a dot (like "aapc.") will be used. This default prefix can be
|
||||
* changed from the bean name by setting the {@code advisorBeanNamePrefix} property.
|
||||
* of this type in the same factory - by setting the {@code usePrefix} property to true,
|
||||
* in which case only advisors beginning with the DefaultAdvisorAutoProxyCreator's bean
|
||||
* name followed by a dot (like "aapc.") will be used. This default prefix can be changed
|
||||
* from the bean name by setting the {@code advisorBeanNamePrefix} property.
|
||||
* The separator (.) will also be used in this case.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
@@ -40,22 +41,22 @@ public class DefaultAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCrea
|
||||
public final static String SEPARATOR = ".";
|
||||
|
||||
|
||||
private boolean usePrefix;
|
||||
private boolean usePrefix = false;
|
||||
|
||||
private String advisorBeanNamePrefix;
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to exclude advisors with a certain prefix
|
||||
* in the bean name.
|
||||
* Set whether to only include advisors with a certain prefix in the bean name.
|
||||
* <p>Default is {@code false}, including all beans of type {@code Advisor}.
|
||||
* @see #setAdvisorBeanNamePrefix
|
||||
*/
|
||||
public void setUsePrefix(boolean usePrefix) {
|
||||
this.usePrefix = usePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to exclude advisors with a certain prefix
|
||||
* in the bean name.
|
||||
* Return whether to only include advisors with a certain prefix in the bean name.
|
||||
*/
|
||||
public boolean isUsePrefix() {
|
||||
return this.usePrefix;
|
||||
@@ -89,7 +90,7 @@ public class DefaultAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCrea
|
||||
|
||||
|
||||
/**
|
||||
* Consider Advisor beans with the specified prefix as eligible, if activated.
|
||||
* Consider {@code Advisor} beans with the specified prefix as eligible, if activated.
|
||||
* @see #setUsePrefix
|
||||
* @see #setAdvisorBeanNamePrefix
|
||||
*/
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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,12 +22,12 @@ import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
/**
|
||||
* Base class for monitoring interceptors, such as performance monitors.
|
||||
* Provides {@code prefix} and {@code suffix} properties
|
||||
* that help to classify/group performance monitoring results.
|
||||
* Provides configurable "prefix and "suffix" properties that help to
|
||||
* classify/group performance monitoring results.
|
||||
*
|
||||
* <p>Subclasses should call the {@code createInvocationTraceName(MethodInvocation)}
|
||||
* method to create a name for the given trace that includes information about the
|
||||
* method invocation under trace along with the prefix and suffix added as appropriate.
|
||||
* <p>In their {@link #invokeUnderTrace} implementation, subclasses should call the
|
||||
* {@link #createInvocationTraceName} method to create a name for the given trace,
|
||||
* including information about the method invocation along with a prefix/suffix.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
|
||||
+56
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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,6 +58,12 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
|
||||
*/
|
||||
private boolean hideProxyClassNames = false;
|
||||
|
||||
/**
|
||||
* Indicates whether to pass an exception to the logger.
|
||||
* @see #writeToLog(Log, String, Throwable)
|
||||
*/
|
||||
private boolean logExceptionStackTrace = true;
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to use a dynamic logger or a static logger.
|
||||
@@ -98,6 +104,17 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
|
||||
this.hideProxyClassNames = hideProxyClassNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to pass an exception to the logger, suggesting inclusion
|
||||
* of its stack trace into the log. Default is "true"; set this to "false"
|
||||
* in order to reduce the log output to just the trace message (which may
|
||||
* include the exception class name and exception message, if applicable).
|
||||
* @since 4.3.10
|
||||
*/
|
||||
public void setLogExceptionStackTrace(boolean logExceptionStackTrace) {
|
||||
this.logExceptionStackTrace = logExceptionStackTrace;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether or not logging is enabled for the particular {@code MethodInvocation}.
|
||||
@@ -171,6 +188,40 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
|
||||
return logger.isTraceEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the supplied trace message to the supplied {@code Log} instance.
|
||||
* <p>To be called by {@link #invokeUnderTrace} for enter/exit messages.
|
||||
* <p>Delegates to {@link #writeToLog(Log, String, Throwable)} as the
|
||||
* ultimate delegate that controls the underlying logger invocation.
|
||||
* @since 4.3.10
|
||||
* @see #writeToLog(Log, String, Throwable)
|
||||
*/
|
||||
protected void writeToLog(Log logger, String message) {
|
||||
writeToLog(logger, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the supplied trace message and {@link Throwable} to the
|
||||
* supplied {@code Log} instance.
|
||||
* <p>To be called by {@link #invokeUnderTrace} for enter/exit outcomes,
|
||||
* potentially including an exception. Note that an exception's stack trace
|
||||
* won't get logged when {@link #setLogExceptionStackTrace} is "false".
|
||||
* <p>By default messages are written at {@code TRACE} level. Subclasses
|
||||
* can override this method to control which level the message is written
|
||||
* at, typically also overriding {@link #isLogEnabled} accordingly.
|
||||
* @since 4.3.10
|
||||
* @see #setLogExceptionStackTrace
|
||||
* @see #isLogEnabled
|
||||
*/
|
||||
protected void writeToLog(Log logger, String message, Throwable ex) {
|
||||
if (ex != null && this.logExceptionStackTrace) {
|
||||
logger.trace(message, ex);
|
||||
}
|
||||
else {
|
||||
logger.trace(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses must override this method to perform any tracing around the
|
||||
@@ -180,13 +231,15 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
|
||||
* <p>By default, the passed-in {@code Log} instance will have log level
|
||||
* "trace" enabled. Subclasses do not have to check for this again, unless
|
||||
* they overwrite the {@code isInterceptorEnabled} method to modify
|
||||
* the default behavior.
|
||||
* the default behavior, and may delegate to {@code writeToLog} for actual
|
||||
* messages to be written.
|
||||
* @param logger the {@code Log} to write trace messages to
|
||||
* @return the result of the call to {@code MethodInvocation.proceed()}
|
||||
* @throws Throwable if the call to {@code MethodInvocation.proceed()}
|
||||
* encountered any errors
|
||||
* @see #isInterceptorEnabled
|
||||
* @see #isLogEnabled
|
||||
* @see #writeToLog(Log, String)
|
||||
* @see #writeToLog(Log, String, Throwable)
|
||||
*/
|
||||
protected abstract Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable;
|
||||
|
||||
|
||||
+9
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -228,6 +228,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
return beanFactory.getBean(TaskExecutor.class);
|
||||
}
|
||||
catch (NoUniqueBeanDefinitionException ex) {
|
||||
logger.debug("Could not find unique TaskExecutor bean", ex);
|
||||
try {
|
||||
return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
|
||||
}
|
||||
@@ -241,8 +242,14 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
logger.debug("Could not find default TaskExecutor bean", ex);
|
||||
try {
|
||||
return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex2) {
|
||||
logger.info("No task executor bean found for async processing: " +
|
||||
"no bean of type TaskExecutor and no bean named 'taskExecutor' either");
|
||||
}
|
||||
// Giving up -> either using local default executor or none at all...
|
||||
logger.info("No TaskExecutor bean found for async processing");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
+20
-45
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -128,20 +128,20 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
/**
|
||||
* The default message used for writing method entry messages.
|
||||
*/
|
||||
private static final String DEFAULT_ENTER_MESSAGE =
|
||||
"Entering method '" + PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
|
||||
private static final String DEFAULT_ENTER_MESSAGE = "Entering method '" +
|
||||
PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
|
||||
|
||||
/**
|
||||
* The default message used for writing method exit messages.
|
||||
*/
|
||||
private static final String DEFAULT_EXIT_MESSAGE =
|
||||
"Exiting method '" + PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
|
||||
private static final String DEFAULT_EXIT_MESSAGE = "Exiting method '" +
|
||||
PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
|
||||
|
||||
/**
|
||||
* The default message used for writing exception messages.
|
||||
*/
|
||||
private static final String DEFAULT_EXCEPTION_MESSAGE =
|
||||
"Exception thrown in method '" + PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
|
||||
private static final String DEFAULT_EXCEPTION_MESSAGE = "Exception thrown in method '" +
|
||||
PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
|
||||
|
||||
/**
|
||||
* The {@code Pattern} used to match placeholders.
|
||||
@@ -182,14 +182,14 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
* </ul>
|
||||
*/
|
||||
public void setEnterMessage(String enterMessage) throws IllegalArgumentException {
|
||||
Assert.hasText(enterMessage, "'enterMessage' must not be empty");
|
||||
Assert.hasText(enterMessage, "enterMessage must not be empty");
|
||||
checkForInvalidPlaceholders(enterMessage);
|
||||
Assert.doesNotContain(enterMessage, PLACEHOLDER_RETURN_VALUE,
|
||||
"enterMessage cannot contain placeholder [" + PLACEHOLDER_RETURN_VALUE + "]");
|
||||
"enterMessage cannot contain placeholder " + PLACEHOLDER_RETURN_VALUE);
|
||||
Assert.doesNotContain(enterMessage, PLACEHOLDER_EXCEPTION,
|
||||
"enterMessage cannot contain placeholder [" + PLACEHOLDER_EXCEPTION + "]");
|
||||
"enterMessage cannot contain placeholder " + PLACEHOLDER_EXCEPTION);
|
||||
Assert.doesNotContain(enterMessage, PLACEHOLDER_INVOCATION_TIME,
|
||||
"enterMessage cannot contain placeholder [" + PLACEHOLDER_INVOCATION_TIME + "]");
|
||||
"enterMessage cannot contain placeholder " + PLACEHOLDER_INVOCATION_TIME);
|
||||
this.enterMessage = enterMessage;
|
||||
}
|
||||
|
||||
@@ -206,10 +206,10 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
* </ul>
|
||||
*/
|
||||
public void setExitMessage(String exitMessage) {
|
||||
Assert.hasText(exitMessage, "'exitMessage' must not be empty");
|
||||
Assert.hasText(exitMessage, "exitMessage must not be empty");
|
||||
checkForInvalidPlaceholders(exitMessage);
|
||||
Assert.doesNotContain(exitMessage, PLACEHOLDER_EXCEPTION,
|
||||
"exitMessage cannot contain placeholder [" + PLACEHOLDER_EXCEPTION + "]");
|
||||
"exitMessage cannot contain placeholder" + PLACEHOLDER_EXCEPTION);
|
||||
this.exitMessage = exitMessage;
|
||||
}
|
||||
|
||||
@@ -225,12 +225,10 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
* </ul>
|
||||
*/
|
||||
public void setExceptionMessage(String exceptionMessage) {
|
||||
Assert.hasText(exceptionMessage, "'exceptionMessage' must not be empty");
|
||||
Assert.hasText(exceptionMessage, "exceptionMessage must not be empty");
|
||||
checkForInvalidPlaceholders(exceptionMessage);
|
||||
Assert.doesNotContain(exceptionMessage, PLACEHOLDER_RETURN_VALUE,
|
||||
"exceptionMessage cannot contain placeholder [" + PLACEHOLDER_RETURN_VALUE + "]");
|
||||
Assert.doesNotContain(exceptionMessage, PLACEHOLDER_INVOCATION_TIME,
|
||||
"exceptionMessage cannot contain placeholder [" + PLACEHOLDER_INVOCATION_TIME + "]");
|
||||
"exceptionMessage cannot contain placeholder " + PLACEHOLDER_RETURN_VALUE);
|
||||
this.exceptionMessage = exceptionMessage;
|
||||
}
|
||||
|
||||
@@ -246,7 +244,7 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
*/
|
||||
@Override
|
||||
protected Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable {
|
||||
String name = invocation.getMethod().getDeclaringClass().getName() + "." + invocation.getMethod().getName();
|
||||
String name = ClassUtils.getQualifiedMethodName(invocation.getMethod());
|
||||
StopWatch stopWatch = new StopWatch(name);
|
||||
Object returnValue = null;
|
||||
boolean exitThroughException = false;
|
||||
@@ -262,8 +260,8 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
stopWatch.stop();
|
||||
}
|
||||
exitThroughException = true;
|
||||
writeToLog(logger,
|
||||
replacePlaceholders(this.exceptionMessage, invocation, null, ex, stopWatch.getTotalTimeMillis()), ex);
|
||||
writeToLog(logger, replacePlaceholders(
|
||||
this.exceptionMessage, invocation, null, ex, stopWatch.getTotalTimeMillis()), ex);
|
||||
throw ex;
|
||||
}
|
||||
finally {
|
||||
@@ -271,35 +269,12 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
if (stopWatch.isRunning()) {
|
||||
stopWatch.stop();
|
||||
}
|
||||
writeToLog(logger,
|
||||
replacePlaceholders(this.exitMessage, invocation, returnValue, null, stopWatch.getTotalTimeMillis()));
|
||||
writeToLog(logger, replacePlaceholders(
|
||||
this.exitMessage, invocation, returnValue, null, stopWatch.getTotalTimeMillis()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the supplied message to the supplied {@code Log} instance.
|
||||
* @see #writeToLog(org.apache.commons.logging.Log, String, Throwable)
|
||||
*/
|
||||
protected void writeToLog(Log logger, String message) {
|
||||
writeToLog(logger, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the supplied message and {@link Throwable} to the
|
||||
* supplied {@code Log} instance. By default messages are written
|
||||
* at {@code TRACE} level. Sub-classes can override this method
|
||||
* to control which level the message is written at.
|
||||
*/
|
||||
protected void writeToLog(Log logger, String message, Throwable ex) {
|
||||
if (ex != null) {
|
||||
logger.trace(message, ex);
|
||||
}
|
||||
else {
|
||||
logger.trace(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the placeholders in the given message with the supplied values,
|
||||
* or values derived from those supplied.
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -121,7 +121,7 @@ public class JamonPerformanceMonitorInterceptor extends AbstractMonitoringInterc
|
||||
finally {
|
||||
monitor.stop();
|
||||
if (!this.trackAllInvocations || isLogEnabled(logger)) {
|
||||
logger.trace("JAMon performance statistics for method [" + name + "]:\n" + monitor);
|
||||
writeToLog(logger, "JAMon performance statistics for method [" + name + "]:\n" + monitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -63,7 +63,7 @@ public class PerformanceMonitorInterceptor extends AbstractMonitoringInterceptor
|
||||
}
|
||||
finally {
|
||||
stopWatch.stop();
|
||||
logger.trace(stopWatch.shortSummary());
|
||||
writeToLog(logger, stopWatch.shortSummary());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -55,14 +55,14 @@ public class SimpleTraceInterceptor extends AbstractTraceInterceptor {
|
||||
@Override
|
||||
protected Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable {
|
||||
String invocationDescription = getInvocationDescription(invocation);
|
||||
logger.trace("Entering " + invocationDescription);
|
||||
writeToLog(logger, "Entering " + invocationDescription);
|
||||
try {
|
||||
Object rval = invocation.proceed();
|
||||
logger.trace("Exiting " + invocationDescription);
|
||||
writeToLog(logger, "Exiting " + invocationDescription);
|
||||
return rval;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.trace("Exception thrown in " + invocationDescription, ex);
|
||||
writeToLog(logger, "Exception thrown in " + invocationDescription, ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -89,7 +89,7 @@ public abstract class ScopedProxyUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the bean name that is used within the scoped proxy to reference the target bean.
|
||||
* Generate the bean name that is used within the scoped proxy to reference the target bean.
|
||||
* @param originalBeanName the original name of bean
|
||||
* @return the generated bean to be used to reference the target bean
|
||||
*/
|
||||
|
||||
+22
-6
@@ -46,7 +46,7 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private transient Advice advice;
|
||||
private transient volatile Advice advice;
|
||||
|
||||
private transient volatile Object adviceMonitor = new Object();
|
||||
|
||||
@@ -98,12 +98,28 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
|
||||
|
||||
@Override
|
||||
public Advice getAdvice() {
|
||||
synchronized (this.adviceMonitor) {
|
||||
if (this.advice == null && this.adviceBeanName != null) {
|
||||
Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
|
||||
this.advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
|
||||
Advice advice = this.advice;
|
||||
if (advice != null || this.adviceBeanName == null) {
|
||||
return advice;
|
||||
}
|
||||
|
||||
Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
|
||||
if (this.beanFactory.isSingleton(this.adviceBeanName)) {
|
||||
// Rely on singleton semantics provided by the factory.
|
||||
advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
|
||||
this.advice = advice;
|
||||
return advice;
|
||||
}
|
||||
else {
|
||||
// No singleton guarantees from the factory -> let's lock locally but
|
||||
// reuse the factory's singleton lock, just in case a lazy dependency
|
||||
// of our advice bean happens to trigger the singleton lock implicitly...
|
||||
synchronized (this.adviceMonitor) {
|
||||
if (this.advice == null) {
|
||||
this.advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
|
||||
}
|
||||
return this.advice;
|
||||
}
|
||||
return this.advice;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 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,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -129,8 +130,8 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return ((targetClass != null && matchesPattern(targetClass.getName() + "." + method.getName())) ||
|
||||
matchesPattern(method.getDeclaringClass().getName() + "." + method.getName()));
|
||||
return ((targetClass != null && matchesPattern(ClassUtils.getQualifiedMethodName(method, targetClass))) ||
|
||||
matchesPattern(ClassUtils.getQualifiedMethodName(method)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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,7 +22,6 @@ import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Convenient class for building up pointcuts. All methods return
|
||||
@@ -188,21 +187,14 @@ public class ComposablePointcut implements Pointcut, Serializable {
|
||||
if (!(other instanceof ComposablePointcut)) {
|
||||
return false;
|
||||
}
|
||||
ComposablePointcut that = (ComposablePointcut) other;
|
||||
return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) &&
|
||||
ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher);
|
||||
ComposablePointcut otherPointcut = (ComposablePointcut) other;
|
||||
return (this.classFilter.equals(otherPointcut.classFilter) &&
|
||||
this.methodMatcher.equals(otherPointcut.methodMatcher));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = 17;
|
||||
if (this.classFilter != null) {
|
||||
code = 37 * code + this.classFilter.hashCode();
|
||||
}
|
||||
if (this.methodMatcher != null) {
|
||||
code = 37 * code + this.methodMatcher.hashCode();
|
||||
}
|
||||
return code;
|
||||
return this.classFilter.hashCode() * 37 + this.methodMatcher.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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,6 @@ import java.lang.reflect.Method;
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.core.ControlFlow;
|
||||
import org.springframework.core.ControlFlowFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -34,7 +32,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
* @see org.springframework.core.ControlFlow
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable {
|
||||
@@ -43,7 +41,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
|
||||
|
||||
private String methodName;
|
||||
|
||||
private int evaluations;
|
||||
private volatile int evaluations;
|
||||
|
||||
|
||||
/**
|
||||
@@ -55,11 +53,11 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new pointcut that matches all calls below the
|
||||
* given method in the given class. If the method name is null,
|
||||
* matches all control flows below that class.
|
||||
* Construct a new pointcut that matches all calls below the given method
|
||||
* in the given class. If no method name is given, matches all control flows
|
||||
* below the given class.
|
||||
* @param clazz the clazz
|
||||
* @param methodName the name of the method
|
||||
* @param methodName the name of the method (may be {@code null})
|
||||
*/
|
||||
public ControlFlowPointcut(Class<?> clazz, String methodName) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
@@ -93,8 +91,14 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass, Object... args) {
|
||||
this.evaluations++;
|
||||
ControlFlow cflow = ControlFlowFactory.createControlFlow();
|
||||
return (this.methodName != null ? cflow.under(this.clazz, this.methodName) : cflow.under(this.clazz));
|
||||
|
||||
for (StackTraceElement element : new Throwable().getStackTrace()) {
|
||||
if (element.getClassName().equals(this.clazz.getName()) &&
|
||||
(this.methodName == null || element.getMethodName().equals(this.methodName))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,8 +134,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = 17;
|
||||
code = 37 * code + this.clazz.hashCode();
|
||||
int code = this.clazz.hashCode();
|
||||
if (this.methodName != null) {
|
||||
code = 37 * code + this.methodName.hashCode();
|
||||
}
|
||||
|
||||
+3
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -45,7 +45,7 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil
|
||||
|
||||
private final Set<Class<?>> interfaces = new LinkedHashSet<Class<?>>();
|
||||
|
||||
private int order = Integer.MAX_VALUE;
|
||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||
|
||||
|
||||
/**
|
||||
@@ -104,7 +104,7 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil
|
||||
|
||||
@Override
|
||||
public Class<?>[] getInterfaces() {
|
||||
return this.interfaces.toArray(new Class<?>[this.interfaces.size()]);
|
||||
return ClassUtils.toClassArray(this.interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,7 +118,6 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
@@ -128,7 +127,6 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil
|
||||
return this.order;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Advice getAdvice() {
|
||||
return this.advice;
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -53,15 +53,15 @@ public class IntroductionInfoSupport implements IntroductionInfo, Serializable {
|
||||
* due to the delegate implementing it. Call this method to exclude
|
||||
* internal interfaces from being visible at the proxy level.
|
||||
* <p>Does nothing if the interface is not implemented by the delegate.
|
||||
* @param intf the interface to suppress
|
||||
* @param ifc the interface to suppress
|
||||
*/
|
||||
public void suppressInterface(Class<?> intf) {
|
||||
this.publishedInterfaces.remove(intf);
|
||||
public void suppressInterface(Class<?> ifc) {
|
||||
this.publishedInterfaces.remove(ifc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getInterfaces() {
|
||||
return this.publishedInterfaces.toArray(new Class<?>[this.publishedInterfaces.size()]);
|
||||
return ClassUtils.toClassArray(this.publishedInterfaces);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -27,7 +27,7 @@ import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
/**
|
||||
* Pointcut bean for simple method name matches, as alternative to regexp patterns.
|
||||
* Does not handle overloaded methods: all methods *with a given name will be eligible.
|
||||
* Does not handle overloaded methods: all methods with a given name will be eligible.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rod Johnson
|
||||
|
||||
@@ -94,7 +94,7 @@ public abstract class Pointcuts {
|
||||
@SuppressWarnings("serial")
|
||||
private static class SetterPointcut extends StaticMethodMatcherPointcut implements Serializable {
|
||||
|
||||
public static SetterPointcut INSTANCE = new SetterPointcut();
|
||||
public static final SetterPointcut INSTANCE = new SetterPointcut();
|
||||
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
@@ -115,7 +115,7 @@ public abstract class Pointcuts {
|
||||
@SuppressWarnings("serial")
|
||||
private static class GetterPointcut extends StaticMethodMatcherPointcut implements Serializable {
|
||||
|
||||
public static GetterPointcut INSTANCE = new GetterPointcut();
|
||||
public static final GetterPointcut INSTANCE = new GetterPointcut();
|
||||
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2018 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,10 +36,10 @@ import org.springframework.util.Assert;
|
||||
public abstract class StaticMethodMatcherPointcutAdvisor extends StaticMethodMatcherPointcut
|
||||
implements PointcutAdvisor, Ordered, Serializable {
|
||||
|
||||
private int order = Integer.MAX_VALUE;
|
||||
|
||||
private Advice advice;
|
||||
|
||||
private int order = Integer.MAX_VALUE;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new StaticMethodMatcherPointcutAdvisor,
|
||||
|
||||
+9
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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,7 +22,6 @@ import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Simple Pointcut that looks for a specific Java 5 annotation
|
||||
@@ -46,16 +45,15 @@ public class AnnotationMatchingPointcut implements Pointcut {
|
||||
* @param classAnnotationType the annotation type to look for at the class level
|
||||
*/
|
||||
public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType) {
|
||||
this.classFilter = new AnnotationClassFilter(classAnnotationType);
|
||||
this.methodMatcher = MethodMatcher.TRUE;
|
||||
this(classAnnotationType, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new AnnotationMatchingPointcut for the given annotation type.
|
||||
* @param classAnnotationType the annotation type to look for at the class level
|
||||
* @param checkInherited whether to explicitly check the superclasses and
|
||||
* interfaces for the annotation type as well (even if the annotation type
|
||||
* is not marked as inherited itself)
|
||||
* @param checkInherited whether to also check the superclasses and interfaces
|
||||
* as well as meta-annotations for the annotation type
|
||||
* @see AnnotationClassFilter#AnnotationClassFilter(Class, boolean)
|
||||
*/
|
||||
public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType, boolean checkInherited) {
|
||||
this.classFilter = new AnnotationClassFilter(classAnnotationType, checkInherited);
|
||||
@@ -109,21 +107,14 @@ public class AnnotationMatchingPointcut implements Pointcut {
|
||||
if (!(other instanceof AnnotationMatchingPointcut)) {
|
||||
return false;
|
||||
}
|
||||
AnnotationMatchingPointcut that = (AnnotationMatchingPointcut) other;
|
||||
return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) &&
|
||||
ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher);
|
||||
AnnotationMatchingPointcut otherPointcut = (AnnotationMatchingPointcut) other;
|
||||
return (this.classFilter.equals(otherPointcut.classFilter) &&
|
||||
this.methodMatcher.equals(otherPointcut.methodMatcher));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = 17;
|
||||
if (this.classFilter != null) {
|
||||
code = 37 * code + this.classFilter.hashCode();
|
||||
}
|
||||
if (this.methodMatcher != null) {
|
||||
code = 37 * code + this.methodMatcher.hashCode();
|
||||
}
|
||||
return code;
|
||||
return this.classFilter.hashCode() * 37 + this.methodMatcher.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+21
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -60,7 +60,7 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
|
||||
private String targetBeanName;
|
||||
|
||||
/** Class of the target */
|
||||
private Class<?> targetClass;
|
||||
private volatile Class<?> targetClass;
|
||||
|
||||
/**
|
||||
* BeanFactory that owns this TargetSource. We need to hold onto this
|
||||
@@ -120,21 +120,28 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized Class<?> getTargetClass() {
|
||||
if (this.targetClass == null && this.beanFactory != null) {
|
||||
// Determine type of the target bean.
|
||||
this.targetClass = this.beanFactory.getType(this.targetBeanName);
|
||||
if (this.targetClass == null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Getting bean with name '" + this.targetBeanName + "' in order to determine type");
|
||||
public Class<?> getTargetClass() {
|
||||
Class<?> targetClass = this.targetClass;
|
||||
if (targetClass != null) {
|
||||
return targetClass;
|
||||
}
|
||||
synchronized (this) {
|
||||
// Full check within synchronization, entering the BeanFactory interaction algorithm only once...
|
||||
targetClass = this.targetClass;
|
||||
if (targetClass == null && this.beanFactory != null) {
|
||||
// Determine type of the target bean.
|
||||
targetClass = this.beanFactory.getType(this.targetBeanName);
|
||||
if (targetClass == null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Getting bean with name '" + this.targetBeanName + "' for type determination");
|
||||
}
|
||||
Object beanInstance = this.beanFactory.getBean(this.targetBeanName);
|
||||
targetClass = beanInstance.getClass();
|
||||
}
|
||||
Object beanInstance = this.beanFactory.getBean(this.targetBeanName);
|
||||
if (beanInstance != null) {
|
||||
this.targetClass = beanInstance.getClass();
|
||||
}
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
return targetClass;
|
||||
}
|
||||
return this.targetClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -39,7 +39,7 @@ import org.springframework.aop.TargetSource;
|
||||
public abstract class AbstractRefreshableTargetSource implements TargetSource, Refreshable {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected Log logger = LogFactory.getLog(getClass());
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected Object targetObject;
|
||||
|
||||
|
||||
+9
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -37,26 +37,26 @@ import static org.junit.Assert.*;
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public final class ArgumentBindingTests {
|
||||
public class ArgumentBindingTests {
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testBindingInPointcutUsedByAdvice() {
|
||||
TestBean tb = new TestBean();
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
|
||||
proxyFactory.addAspect(NamedPointcutWithArgs.class);
|
||||
|
||||
ITestBean proxiedTestBean = (ITestBean) proxyFactory.getProxy();
|
||||
proxiedTestBean.setName("Supercalifragalisticexpialidocious"); // should throw
|
||||
ITestBean proxiedTestBean = proxyFactory.getProxy();
|
||||
proxiedTestBean.setName("Supercalifragalisticexpialidocious");
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testAnnotationArgumentNameBinding() {
|
||||
TransactionalBean tb = new TransactionalBean();
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
|
||||
proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
|
||||
|
||||
ITransactionalBean proxiedTestBean = (ITransactionalBean) proxyFactory.getProxy();
|
||||
proxiedTestBean.doInTransaction(); // should throw
|
||||
ITransactionalBean proxiedTestBean = proxyFactory.getProxy();
|
||||
proxiedTestBean.doInTransaction();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -71,6 +71,7 @@ public final class ArgumentBindingTests {
|
||||
assertEquals("formal", pnames[0]);
|
||||
}
|
||||
|
||||
|
||||
public void methodWithOneParam(String aParam) {
|
||||
}
|
||||
|
||||
@@ -100,9 +101,6 @@ public final class ArgumentBindingTests {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@Aspect
|
||||
class PointcutWithAnnotationArgument {
|
||||
|
||||
@@ -115,9 +113,6 @@ class PointcutWithAnnotationArgument {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
*/
|
||||
@Aspect
|
||||
class NamedPointcutWithArgs {
|
||||
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -47,7 +47,7 @@ public final class ConcurrencyThrottleInterceptorTests {
|
||||
public void testSerializable() throws Exception {
|
||||
DerivedTestBean tb = new DerivedTestBean();
|
||||
ProxyFactory proxyFactory = new ProxyFactory();
|
||||
proxyFactory.setInterfaces(new Class[] {ITestBean.class});
|
||||
proxyFactory.setInterfaces(ITestBean.class);
|
||||
ConcurrencyThrottleInterceptor cti = new ConcurrencyThrottleInterceptor();
|
||||
proxyFactory.addAdvice(cti);
|
||||
proxyFactory.setTarget(tb);
|
||||
@@ -75,7 +75,7 @@ public final class ConcurrencyThrottleInterceptorTests {
|
||||
private void testMultipleThreads(int concurrencyLimit) {
|
||||
TestBean tb = new TestBean();
|
||||
ProxyFactory proxyFactory = new ProxyFactory();
|
||||
proxyFactory.setInterfaces(new Class[] {ITestBean.class});
|
||||
proxyFactory.setInterfaces(ITestBean.class);
|
||||
ConcurrencyThrottleInterceptor cti = new ConcurrencyThrottleInterceptor();
|
||||
cti.setConcurrencyLimit(concurrencyLimit);
|
||||
proxyFactory.addAdvice(cti);
|
||||
@@ -95,7 +95,7 @@ public final class ConcurrencyThrottleInterceptorTests {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
threads[i] = new ConcurrencyThread(proxy,
|
||||
i % 2 == 0 ? (Throwable) new OutOfMemoryError() : (Throwable) new IllegalStateException());
|
||||
i % 2 == 0 ? new OutOfMemoryError() : new IllegalStateException());
|
||||
threads[i].start();
|
||||
}
|
||||
for (int i = 0; i < NR_OF_THREADS; i++) {
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -83,7 +83,7 @@ public final class CustomizableTraceInterceptorTests {
|
||||
public void testSunnyDayPathLogsCorrectly() throws Throwable {
|
||||
|
||||
MethodInvocation methodInvocation = mock(MethodInvocation.class);
|
||||
given(methodInvocation.getMethod()).willReturn(String.class.getMethod("toString", new Class[]{}));
|
||||
given(methodInvocation.getMethod()).willReturn(String.class.getMethod("toString"));
|
||||
given(methodInvocation.getThis()).willReturn(this);
|
||||
|
||||
Log log = mock(Log.class);
|
||||
@@ -101,7 +101,7 @@ public final class CustomizableTraceInterceptorTests {
|
||||
MethodInvocation methodInvocation = mock(MethodInvocation.class);
|
||||
|
||||
IllegalArgumentException exception = new IllegalArgumentException();
|
||||
given(methodInvocation.getMethod()).willReturn(String.class.getMethod("toString", new Class[]{}));
|
||||
given(methodInvocation.getMethod()).willReturn(String.class.getMethod("toString"));
|
||||
given(methodInvocation.getThis()).willReturn(this);
|
||||
given(methodInvocation.proceed()).willThrow(exception);
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -34,7 +34,7 @@ public final class SimpleTraceInterceptorTests {
|
||||
@Test
|
||||
public void testSunnyDayPathLogsCorrectly() throws Throwable {
|
||||
MethodInvocation mi = mock(MethodInvocation.class);
|
||||
given(mi.getMethod()).willReturn(String.class.getMethod("toString", new Class[]{}));
|
||||
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
|
||||
given(mi.getThis()).willReturn(this);
|
||||
|
||||
Log log = mock(Log.class);
|
||||
@@ -48,7 +48,7 @@ public final class SimpleTraceInterceptorTests {
|
||||
@Test
|
||||
public void testExceptionPathStillLogsCorrectly() throws Throwable {
|
||||
MethodInvocation mi = mock(MethodInvocation.class);
|
||||
given(mi.getMethod()).willReturn(String.class.getMethod("toString", new Class[]{}));
|
||||
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
|
||||
given(mi.getThis()).willReturn(this);
|
||||
IllegalArgumentException exception = new IllegalArgumentException();
|
||||
given(mi.proceed()).willThrow(exception);
|
||||
|
||||
+15
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 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.aop.scope;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
@@ -27,19 +29,24 @@ import static org.springframework.tests.TestResourceUtils.*;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public final class ScopedProxyAutowireTests {
|
||||
public class ScopedProxyAutowireTests {
|
||||
|
||||
private static final Class<?> CLASS = ScopedProxyAutowireTests.class;
|
||||
private static final Resource SCOPED_AUTOWIRE_FALSE_CONTEXT =
|
||||
qualifiedResource(ScopedProxyAutowireTests.class, "scopedAutowireFalse.xml");
|
||||
private static final Resource SCOPED_AUTOWIRE_TRUE_CONTEXT =
|
||||
qualifiedResource(ScopedProxyAutowireTests.class, "scopedAutowireTrue.xml");
|
||||
|
||||
private static final Resource SCOPED_AUTOWIRE_TRUE_CONTEXT = qualifiedResource(CLASS, "scopedAutowireTrue.xml");
|
||||
private static final Resource SCOPED_AUTOWIRE_FALSE_CONTEXT = qualifiedResource(CLASS, "scopedAutowireFalse.xml");
|
||||
|
||||
@Test
|
||||
public void testScopedProxyInheritsAutowireCandidateFalse() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(SCOPED_AUTOWIRE_FALSE_CONTEXT);
|
||||
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, false, false)).contains("scoped"));
|
||||
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, true, false)).contains("scoped"));
|
||||
assertFalse(bf.containsSingleton("scoped"));
|
||||
TestBean autowired = (TestBean) bf.getBean("autowired");
|
||||
TestBean unscoped = (TestBean) bf.getBean("unscoped");
|
||||
assertSame(unscoped, autowired.getChild());
|
||||
@@ -49,6 +56,9 @@ public final class ScopedProxyAutowireTests {
|
||||
public void testScopedProxyReplacesAutowireCandidateTrue() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(SCOPED_AUTOWIRE_TRUE_CONTEXT);
|
||||
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, true, false)).contains("scoped"));
|
||||
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, false, false)).contains("scoped"));
|
||||
assertFalse(bf.containsSingleton("scoped"));
|
||||
TestBean autowired = (TestBean) bf.getBean("autowired");
|
||||
TestBean scoped = (TestBean) bf.getBean("scoped");
|
||||
assertSame(scoped, autowired.getChild());
|
||||
|
||||
+10
-13
@@ -1,6 +1,5 @@
|
||||
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 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,27 +28,21 @@ public class NopInterceptor implements MethodInterceptor {
|
||||
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* @see org.aopalliance.intercept.MethodInterceptor#invoke(MethodInvocation)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
increment();
|
||||
return invocation.proceed();
|
||||
}
|
||||
|
||||
protected void increment() {
|
||||
this.count++;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return this.count;
|
||||
}
|
||||
|
||||
protected void increment() {
|
||||
++count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
@@ -62,5 +55,9 @@ public class NopInterceptor implements MethodInterceptor {
|
||||
return this.count == ((NopInterceptor) other).count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return NopInterceptor.class.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -28,22 +28,10 @@ import org.springframework.util.ObjectUtils;
|
||||
@SuppressWarnings("serial")
|
||||
public class SerializablePerson implements Person, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
private String name;
|
||||
|
||||
private int age;
|
||||
|
||||
@Override
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -55,6 +43,16 @@ public class SerializablePerson implements Person, Serializable {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object echo(Object o) throws Throwable {
|
||||
if (o instanceof Throwable) {
|
||||
@@ -63,10 +61,6 @@ public class SerializablePerson implements Person, Serializable {
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
@@ -77,4 +71,9 @@ public class SerializablePerson implements Person, Serializable {
|
||||
return p.age == age && ObjectUtils.nullSafeEquals(name, p.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return SerializablePerson.class.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
<config xmlns="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
|
||||
|
||||
<pointcut id="testPointcut" expression="execution(* foo(..)) and within(springbank.dao.AccountDao+)"/>
|
||||
<pointcut id="testPointcut1" expression="execution(* springbank.dao.AccountDao.foo(..))"/>
|
||||
@@ -9,4 +9,4 @@
|
||||
<after method="foo" pointcut-ref="testPointcut"/>
|
||||
</aspect>
|
||||
|
||||
</config>
|
||||
</config>
|
||||
|
||||
+9
-9
@@ -1,16 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
|
||||
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" scope="prototype" autowire-candidate="false">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
|
||||
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true"/>
|
||||
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true"/>
|
||||
|
||||
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
|
||||
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
|
||||
|
||||
</beans>
|
||||
|
||||
+9
-9
@@ -1,16 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
|
||||
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" scope="singleton" autowire-candidate="true">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
|
||||
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false"/>
|
||||
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false"/>
|
||||
|
||||
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
|
||||
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// redefine the compileJava and compileTestJava tasks in order to
|
||||
// compile sources with ajc instead of javac
|
||||
// Redefine the compileJava and compileTestJava tasks in order to compile sources with ajc instead of javac
|
||||
|
||||
configurations {
|
||||
rt
|
||||
@@ -8,22 +7,14 @@ configurations {
|
||||
ajInpath
|
||||
}
|
||||
|
||||
// exclude spring-aspects as a module within IDEA until IDEA-64446 is resolved
|
||||
tasks.getByName("idea").onlyIf { false }
|
||||
tasks.getByName("ideaModule").onlyIf { false }
|
||||
|
||||
compileJava {
|
||||
actions = []
|
||||
dependsOn configurations.ajc.getTaskDependencyFromProjectDependency(true, "compileJava")
|
||||
|
||||
def outputDir = project.sourceSets.main.output.classesDir
|
||||
|
||||
inputs.files(project.sourceSets.main.allSource + project.sourceSets.main.compileClasspath)
|
||||
outputs.dir outputDir
|
||||
|
||||
ext.sourceCompatibility = project(":spring-core").compileJava.sourceCompatibility
|
||||
ext.targetCompatibility = project(":spring-core").compileJava.targetCompatibility
|
||||
|
||||
doLast{
|
||||
// Assemble runtime classpath from folders and JARs that actually exist
|
||||
def runtimeClasspath = project.files(sourceSets.main.runtimeClasspath.files.findAll({ it.exists() }))
|
||||
@@ -53,13 +44,9 @@ compileTestJava {
|
||||
dependsOn jar
|
||||
|
||||
def outputDir = project.sourceSets.test.output.classesDir
|
||||
|
||||
inputs.files(project.sourceSets.test.allSource + project.sourceSets.test.compileClasspath)
|
||||
outputs.dir outputDir
|
||||
|
||||
ext.sourceCompatibility = project(":spring-core").compileTestJava.sourceCompatibility
|
||||
ext.targetCompatibility = project(":spring-core").compileTestJava.targetCompatibility
|
||||
|
||||
doLast{
|
||||
// Assemble runtime classpath from folders and JARs that actually exist
|
||||
def runtimeClasspath = project.files(sourceSets.test.runtimeClasspath.files.findAll({ it.exists() }))
|
||||
|
||||
Vendored
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -34,6 +34,7 @@ import org.springframework.context.annotation.Role;
|
||||
* @see org.springframework.cache.annotation.CachingConfigurationSelector
|
||||
*/
|
||||
@Configuration
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class AspectJCachingConfiguration extends AbstractCachingConfiguration {
|
||||
|
||||
@Bean(name = CacheManagementConfigUtils.CACHE_ASPECT_BEAN_NAME)
|
||||
|
||||
Vendored
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -34,6 +34,7 @@ import org.springframework.context.annotation.Role;
|
||||
* @see org.springframework.cache.annotation.CachingConfigurationSelector
|
||||
*/
|
||||
@Configuration
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class AspectJJCacheConfiguration extends AbstractJCacheConfiguration {
|
||||
|
||||
@Bean(name = CacheManagementConfigUtils.JCACHE_ASPECT_BEAN_NAME)
|
||||
|
||||
+2
@@ -36,7 +36,9 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
* @deprecated as of Spring 4.3, in favor of a custom aspect for such purposes
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {
|
||||
|
||||
private final Expectations expectations = new Expectations();
|
||||
|
||||
+2
@@ -59,7 +59,9 @@ import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
* @see MockStaticEntityMethods
|
||||
* @deprecated as of Spring 4.3, in favor of a custom aspect for such purposes
|
||||
*/
|
||||
@Deprecated
|
||||
@RequiredTypes("javax.persistence.Entity")
|
||||
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
|
||||
|
||||
|
||||
+2
@@ -29,7 +29,9 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Sam Brannen
|
||||
* @deprecated as of Spring 4.3, in favor of a custom aspect for such purposes
|
||||
*/
|
||||
@Deprecated
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface MockStaticEntityMethods {
|
||||
|
||||
+42
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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,55 +18,45 @@ package org.springframework.transaction.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.tests.transaction.CallCountingTransactionManager;
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class TransactionAspectTests extends org.springframework.test.AbstractDependencyInjectionSpringContextTests {
|
||||
public class TransactionAspectTests {
|
||||
|
||||
private CallCountingTransactionManager txManager;
|
||||
private final CallCountingTransactionManager txManager = new CallCountingTransactionManager();
|
||||
|
||||
private TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface;
|
||||
private final TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface =
|
||||
new TransactionalAnnotationOnlyOnClassWithNoInterface();
|
||||
|
||||
private ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod;
|
||||
private final ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod =
|
||||
new ClassWithProtectedAnnotatedMember();
|
||||
|
||||
private ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod;
|
||||
private final ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod =
|
||||
new ClassWithPrivateAnnotatedMember();
|
||||
|
||||
private MethodAnnotationOnClassWithNoInterface methodAnnotationOnly = new MethodAnnotationOnClassWithNoInterface();
|
||||
private final MethodAnnotationOnClassWithNoInterface methodAnnotationOnly =
|
||||
new MethodAnnotationOnClassWithNoInterface();
|
||||
|
||||
|
||||
public void setAnnotationOnlyOnClassWithNoInterface(
|
||||
TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface) {
|
||||
this.annotationOnlyOnClassWithNoInterface = annotationOnlyOnClassWithNoInterface;
|
||||
}
|
||||
|
||||
public void setClassWithAnnotatedProtectedMethod(ClassWithProtectedAnnotatedMember aBean) {
|
||||
this.beanWithAnnotatedProtectedMethod = aBean;
|
||||
}
|
||||
|
||||
public void setClassWithAnnotatedPrivateMethod(ClassWithPrivateAnnotatedMember aBean) {
|
||||
this.beanWithAnnotatedPrivateMethod = aBean;
|
||||
}
|
||||
|
||||
public void setTransactionAspect(TransactionAspectSupport transactionAspect) {
|
||||
this.txManager = (CallCountingTransactionManager) transactionAspect.getTransactionManager();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String[] getConfigPaths() {
|
||||
return new String[] { "TransactionAspectTests-context.xml" };
|
||||
@Before
|
||||
public void initContext() {
|
||||
AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCommitOnAnnotatedClass() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -74,6 +64,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommitOnAnnotatedProtectedMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -81,6 +72,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommitOnAnnotatedPrivateMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -88,6 +80,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoCommitOnNonAnnotatedNonPublicMethodInTransactionalType() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0,txManager.begun);
|
||||
@@ -95,6 +88,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(0,txManager.begun);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommitOnAnnotatedMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -102,6 +96,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotTransactional() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -109,6 +104,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(0, txManager.begun);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommitOnAnnotatedClass() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
try {
|
||||
@@ -125,6 +121,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultRollbackOnAnnotatedClass() throws Throwable {
|
||||
final RuntimeException ex = new RuntimeException();
|
||||
try {
|
||||
@@ -141,10 +138,11 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommitOnSubclassOfAnnotatedClass() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
try {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
@Override
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return new SubclassOfClassWithTransactionalAnnotation().echo(ex);
|
||||
@@ -157,6 +155,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
try {
|
||||
@@ -173,6 +172,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommitOnImplementationOfAnnotatedInterface() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
testNotTransactional(new TransactionOperationCallback() {
|
||||
@@ -185,16 +185,19 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
|
||||
/**
|
||||
* Note: resolution does not occur. Thus we can't make a class transactional if
|
||||
* it implements a transactionally annotated interface. This behaviour could only
|
||||
* it implements a transactionally annotated interface. This behavior could only
|
||||
* be changed in AbstractFallbackTransactionAttributeSource in Spring proper.
|
||||
* See SPR-14322.
|
||||
*/
|
||||
@Test
|
||||
public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws Exception {
|
||||
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
|
||||
Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
|
||||
TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class);
|
||||
Method method = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
|
||||
TransactionAttribute ta = atas.getTransactionAttribute(method, ImplementsAnnotatedInterface.class);
|
||||
assertNull(ta);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultRollbackOnImplementationOfAnnotatedInterface() throws Throwable {
|
||||
final Exception rollbackProvokingException = new RuntimeException();
|
||||
testNotTransactional(new TransactionOperationCallback() {
|
||||
@@ -237,15 +240,19 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
|
||||
|
||||
private interface TransactionOperationCallback {
|
||||
|
||||
Object performTransactionalOperation() throws Throwable;
|
||||
}
|
||||
|
||||
|
||||
public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface {
|
||||
}
|
||||
|
||||
|
||||
public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface {
|
||||
}
|
||||
|
||||
|
||||
public static class ImplementsAnnotatedInterface implements ITransactional {
|
||||
|
||||
@Override
|
||||
@@ -257,6 +264,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class NotTransactional {
|
||||
|
||||
public void noop() {
|
||||
|
||||
+19
-22
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -237,6 +237,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
Closure beans = new Closure(this) {
|
||||
@Override
|
||||
public Object call(Object[] args) {
|
||||
invokeBeanDefiningClosure((Closure) args[0]);
|
||||
return null;
|
||||
@@ -303,7 +304,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
Collection constructorArgs = null;
|
||||
if (!ObjectUtils.isEmpty(args)) {
|
||||
int index = args.length;
|
||||
Object lastArg = args[index-1];
|
||||
Object lastArg = args[index - 1];
|
||||
if (lastArg instanceof Closure) {
|
||||
callable = (Closure) lastArg;
|
||||
index--;
|
||||
@@ -380,10 +381,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
refName = args[0].toString();
|
||||
}
|
||||
boolean parentRef = false;
|
||||
if (args.length > 1) {
|
||||
if (args[1] instanceof Boolean) {
|
||||
parentRef = (Boolean) args[1];
|
||||
}
|
||||
if (args.length > 1 && args[1] instanceof Boolean) {
|
||||
parentRef = (Boolean) args[1];
|
||||
}
|
||||
return new RuntimeBeanReference(refName, parentRef);
|
||||
}
|
||||
@@ -410,12 +409,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
private boolean addDeferredProperty(String property, Object newValue) {
|
||||
if (newValue instanceof List) {
|
||||
this.deferredProperties.put(this.currentBeanDefinition.getBeanName() + '.' + property,
|
||||
new DeferredProperty(this.currentBeanDefinition, property, newValue));
|
||||
return true;
|
||||
}
|
||||
else if (newValue instanceof Map) {
|
||||
if (newValue instanceof List || newValue instanceof Map) {
|
||||
this.deferredProperties.put(this.currentBeanDefinition.getBeanName() + '.' + property,
|
||||
new DeferredProperty(this.currentBeanDefinition, property, newValue));
|
||||
return true;
|
||||
@@ -456,14 +450,14 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
* @return the bean definition wrapper
|
||||
*/
|
||||
private GroovyBeanDefinitionWrapper invokeBeanDefiningMethod(String beanName, Object[] args) {
|
||||
boolean hasClosureArgument = args[args.length - 1] instanceof Closure;
|
||||
boolean hasClosureArgument = (args[args.length - 1] instanceof Closure);
|
||||
if (args[0] instanceof Class) {
|
||||
Class<?> beanClass = (args[0] instanceof Class ? (Class) args[0] : args[0].getClass());
|
||||
Class<?> beanClass = (Class<?>) args[0];
|
||||
if (args.length >= 1) {
|
||||
if (hasClosureArgument) {
|
||||
if (args.length-1 != 1) {
|
||||
if (args.length - 1 != 1) {
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(
|
||||
beanName, beanClass, resolveConstructorArguments(args,1,args.length-1));
|
||||
beanName, beanClass, resolveConstructorArguments(args, 1, args.length - 1));
|
||||
}
|
||||
else {
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, beanClass);
|
||||
@@ -471,7 +465,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
else {
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(
|
||||
beanName, beanClass, resolveConstructorArguments(args,1,args.length));
|
||||
beanName, beanClass, resolveConstructorArguments(args, 1, args.length));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -483,7 +477,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
else if (args[0] instanceof Map) {
|
||||
// named constructor arguments
|
||||
if (args.length > 1 && args[1] instanceof Class) {
|
||||
List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length-1 : args.length);
|
||||
List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length);
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class)args[1], constructorArgs);
|
||||
Map namedArgs = (Map)args[0];
|
||||
for (Object o : namedArgs.keySet()) {
|
||||
@@ -519,18 +513,18 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
this.currentBeanDefinition.getBeanDefinition().setAbstract(true);
|
||||
}
|
||||
else {
|
||||
List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length-1 : args.length);
|
||||
List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length - 1 : args.length);
|
||||
currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, null, constructorArgs);
|
||||
}
|
||||
|
||||
if (hasClosureArgument) {
|
||||
Closure callable = (Closure)args[args.length-1];
|
||||
Closure callable = (Closure) args[args.length - 1];
|
||||
callable.setDelegate(this);
|
||||
callable.setResolveStrategy(Closure.DELEGATE_FIRST);
|
||||
callable.call(new Object[]{currentBeanDefinition});
|
||||
callable.call(this.currentBeanDefinition);
|
||||
}
|
||||
|
||||
GroovyBeanDefinitionWrapper beanDefinition = currentBeanDefinition;
|
||||
GroovyBeanDefinitionWrapper beanDefinition = this.currentBeanDefinition;
|
||||
this.currentBeanDefinition = null;
|
||||
beanDefinition.getBeanDefinition().setAttribute(GroovyBeanDefinitionWrapper.class.getName(), beanDefinition);
|
||||
getRegistry().registerBeanDefinition(beanName, beanDefinition.getBeanDefinition());
|
||||
@@ -818,14 +812,17 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invokeMethod(String name, Object args) {
|
||||
return InvokerHelper.invokeMethod(this.propertyValue, name, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
return InvokerHelper.getProperty(this.propertyValue, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(String name, Object value) {
|
||||
InvokerHelper.setProperty(this.propertyValue, name, value);
|
||||
}
|
||||
|
||||
+3
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -162,6 +162,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getProperty(String property) {
|
||||
if (this.definitionWrapper.isReadableProperty(property)) {
|
||||
return this.definitionWrapper.getPropertyValue(property);
|
||||
@@ -172,6 +173,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||
return super.getProperty(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(String property, Object newValue) {
|
||||
if (PARENT.equals(property)) {
|
||||
setParent(newValue);
|
||||
|
||||
+190
-183
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -55,10 +55,10 @@ import org.springframework.util.StringUtils;
|
||||
* as String arrays are converted in such a format if the array itself is not
|
||||
* assignable.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Stephane Nicoll
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
* @since 4.2
|
||||
* @see #registerCustomEditor
|
||||
* @see #setPropertyValues
|
||||
@@ -94,11 +94,9 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
|
||||
private String nestedPath = "";
|
||||
|
||||
private Object rootObject;
|
||||
Object rootObject;
|
||||
|
||||
/**
|
||||
* Map with cached nested Accessors: nested path -> Accessor instance.
|
||||
*/
|
||||
/** Map with cached nested Accessors: nested path -> Accessor instance */
|
||||
private Map<String, AbstractNestablePropertyAccessor> nestedPropertyAccessors;
|
||||
|
||||
|
||||
@@ -284,198 +282,212 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
|
||||
String propertyName = tokens.canonicalName;
|
||||
String actualName = tokens.actualName;
|
||||
|
||||
if (tokens.keys != null) {
|
||||
// Apply indexes and map keys: fetch value for all keys but the last one.
|
||||
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
|
||||
getterTokens.canonicalName = tokens.canonicalName;
|
||||
getterTokens.actualName = tokens.actualName;
|
||||
getterTokens.keys = new String[tokens.keys.length - 1];
|
||||
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);
|
||||
Object propValue;
|
||||
processKeyedProperty(tokens, pv);
|
||||
}
|
||||
else {
|
||||
processLocalProperty(tokens, pv);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) {
|
||||
Object propValue = getPropertyHoldingValue(tokens);
|
||||
String lastKey = tokens.keys[tokens.keys.length - 1];
|
||||
|
||||
if (propValue.getClass().isArray()) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
|
||||
Class<?> requiredType = propValue.getClass().getComponentType();
|
||||
int arrayIndex = Integer.parseInt(lastKey);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
propValue = getPropertyValue(getterTokens);
|
||||
}
|
||||
catch (NotReadablePropertyException ex) {
|
||||
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + propertyName + "'", ex);
|
||||
}
|
||||
// Set value for last key.
|
||||
String key = tokens.keys[tokens.keys.length - 1];
|
||||
if (propValue == null) {
|
||||
// null map value case
|
||||
if (isAutoGrowNestedPaths()) {
|
||||
// TODO: cleanup, this is pretty hacky
|
||||
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
|
||||
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
|
||||
propValue = setDefaultValue(getterTokens);
|
||||
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
|
||||
oldValue = Array.get(propValue, arrayIndex);
|
||||
}
|
||||
else {
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + propertyName + "': returned null");
|
||||
}
|
||||
}
|
||||
if (propValue.getClass().isArray()) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(actualName);
|
||||
Class<?> requiredType = propValue.getClass().getComponentType();
|
||||
int arrayIndex = Integer.parseInt(key);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
|
||||
oldValue = Array.get(propValue, arrayIndex);
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
requiredType, ph.nested(tokens.keys.length));
|
||||
int length = Array.getLength(propValue);
|
||||
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
|
||||
Class<?> componentType = propValue.getClass().getComponentType();
|
||||
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
|
||||
System.arraycopy(propValue, 0, newArray, 0, length);
|
||||
setPropertyValue(actualName, newArray);
|
||||
propValue = getPropertyValue(actualName);
|
||||
}
|
||||
Array.set(propValue, arrayIndex, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Invalid array index in property path '" + propertyName + "'", ex);
|
||||
}
|
||||
}
|
||||
else if (propValue instanceof List) {
|
||||
PropertyHandler ph = getPropertyHandler(actualName);
|
||||
Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
|
||||
List<Object> list = (List<Object>) propValue;
|
||||
int index = Integer.parseInt(key);
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor() && index < list.size()) {
|
||||
oldValue = list.get(index);
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
|
||||
requiredType, ph.nested(tokens.keys.length));
|
||||
int size = list.size();
|
||||
if (index >= size && index < this.autoGrowCollectionLimit) {
|
||||
for (int i = size; i < index; i++) {
|
||||
try {
|
||||
list.add(null);
|
||||
}
|
||||
catch (NullPointerException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot set element with index " + index + " in List of size " +
|
||||
size + ", accessed using property path '" + propertyName +
|
||||
"': List does not support filling up gaps with null elements");
|
||||
}
|
||||
}
|
||||
list.add(convertedValue);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
list.set(index, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Invalid list index in property path '" + propertyName + "'", ex);
|
||||
}
|
||||
int length = Array.getLength(propValue);
|
||||
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
|
||||
Class<?> componentType = propValue.getClass().getComponentType();
|
||||
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
|
||||
System.arraycopy(propValue, 0, newArray, 0, length);
|
||||
setPropertyValue(tokens.actualName, newArray);
|
||||
propValue = getPropertyValue(tokens.actualName);
|
||||
}
|
||||
Array.set(propValue, arrayIndex, convertedValue);
|
||||
}
|
||||
else if (propValue instanceof Map) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(actualName);
|
||||
Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
|
||||
Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);
|
||||
Map<Object, Object> map = (Map<Object, Object>) propValue;
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
|
||||
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor()) {
|
||||
oldValue = map.get(convertedMapKey);
|
||||
}
|
||||
// Pass full property name and old value in here, since we want full
|
||||
// conversion ability for map values.
|
||||
Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
mapValueType, ph.nested(tokens.keys.length));
|
||||
map.put(convertedMapKey, convertedMapValue);
|
||||
}
|
||||
else {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Property referenced in indexed property path '" + propertyName +
|
||||
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Invalid array index in property path '" + tokens.canonicalName + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
PropertyHandler ph = getLocalPropertyHandler(actualName);
|
||||
if (ph == null || !ph.isWritable()) {
|
||||
if (pv.isOptional()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Ignoring optional value for property '" + actualName +
|
||||
"' - property not found on bean class [" + getRootClass().getName() + "]");
|
||||
else if (propValue instanceof List) {
|
||||
PropertyHandler ph = getPropertyHandler(tokens.actualName);
|
||||
Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
|
||||
List<Object> list = (List<Object>) propValue;
|
||||
int index = Integer.parseInt(lastKey);
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor() && index < list.size()) {
|
||||
oldValue = list.get(index);
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
|
||||
requiredType, ph.nested(tokens.keys.length));
|
||||
int size = list.size();
|
||||
if (index >= size && index < this.autoGrowCollectionLimit) {
|
||||
for (int i = size; i < index; i++) {
|
||||
try {
|
||||
list.add(null);
|
||||
}
|
||||
catch (NullPointerException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Cannot set element with index " + index + " in List of size " +
|
||||
size + ", accessed using property path '" + tokens.canonicalName +
|
||||
"': List does not support filling up gaps with null elements");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw createNotWritablePropertyException(propertyName);
|
||||
list.add(convertedValue);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
list.set(index, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Invalid list index in property path '" + tokens.canonicalName + "'", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (propValue instanceof Map) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
|
||||
Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
|
||||
Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);
|
||||
Map<Object, Object> map = (Map<Object, Object>) propValue;
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
|
||||
Object convertedMapKey = convertIfNecessary(null, null, lastKey, mapKeyType, typeDescriptor);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
Object originalValue = pv.getValue();
|
||||
Object valueToApply = originalValue;
|
||||
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
|
||||
if (pv.isConverted()) {
|
||||
valueToApply = pv.getConvertedValue();
|
||||
}
|
||||
else {
|
||||
if (isExtractOldValueForEditor() && ph.isReadable()) {
|
||||
try {
|
||||
oldValue = ph.getValue();
|
||||
if (isExtractOldValueForEditor()) {
|
||||
oldValue = map.get(convertedMapKey);
|
||||
}
|
||||
// Pass full property name and old value in here, since we want full
|
||||
// conversion ability for map values.
|
||||
Object convertedMapValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
|
||||
mapValueType, ph.nested(tokens.keys.length));
|
||||
map.put(convertedMapKey, convertedMapValue);
|
||||
}
|
||||
|
||||
else {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Property referenced in indexed property path '" + tokens.canonicalName +
|
||||
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private Object getPropertyHoldingValue(PropertyTokenHolder tokens) {
|
||||
// Apply indexes and map keys: fetch value for all keys but the last one.
|
||||
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
|
||||
getterTokens.canonicalName = tokens.canonicalName;
|
||||
getterTokens.actualName = tokens.actualName;
|
||||
getterTokens.keys = new String[tokens.keys.length - 1];
|
||||
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);
|
||||
|
||||
Object propValue;
|
||||
try {
|
||||
propValue = getPropertyValue(getterTokens);
|
||||
}
|
||||
catch (NotReadablePropertyException ex) {
|
||||
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + tokens.canonicalName + "'", ex);
|
||||
}
|
||||
|
||||
if (propValue == null) {
|
||||
// null map value case
|
||||
if (isAutoGrowNestedPaths()) {
|
||||
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
|
||||
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
|
||||
propValue = setDefaultValue(getterTokens);
|
||||
}
|
||||
else {
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + tokens.canonicalName + "': returned null");
|
||||
}
|
||||
}
|
||||
return propValue;
|
||||
}
|
||||
|
||||
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
|
||||
if (ph == null || !ph.isWritable()) {
|
||||
if (pv.isOptional()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Ignoring optional value for property '" + tokens.actualName +
|
||||
"' - property not found on bean class [" + getRootClass().getName() + "]");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw createNotWritablePropertyException(tokens.canonicalName);
|
||||
}
|
||||
}
|
||||
|
||||
Object oldValue = null;
|
||||
try {
|
||||
Object originalValue = pv.getValue();
|
||||
Object valueToApply = originalValue;
|
||||
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
|
||||
if (pv.isConverted()) {
|
||||
valueToApply = pv.getConvertedValue();
|
||||
}
|
||||
else {
|
||||
if (isExtractOldValueForEditor() && ph.isReadable()) {
|
||||
try {
|
||||
oldValue = ph.getValue();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex instanceof PrivilegedActionException) {
|
||||
ex = ((PrivilegedActionException) ex).getException();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex instanceof PrivilegedActionException) {
|
||||
ex = ((PrivilegedActionException) ex).getException();
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not read previous value of property '" +
|
||||
this.nestedPath + propertyName + "'", ex);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not read previous value of property '" +
|
||||
this.nestedPath + tokens.canonicalName + "'", ex);
|
||||
}
|
||||
}
|
||||
valueToApply = convertForProperty(
|
||||
propertyName, oldValue, originalValue, ph.toTypeDescriptor());
|
||||
}
|
||||
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
|
||||
valueToApply = convertForProperty(
|
||||
tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
|
||||
}
|
||||
ph.setValue(this.wrappedObject, valueToApply);
|
||||
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
throw ex;
|
||||
ph.setValue(this.wrappedObject, valueToApply);
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
|
||||
this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
|
||||
if (ex.getTargetException() instanceof ClassCastException) {
|
||||
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
PropertyChangeEvent propertyChangeEvent =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
if (ex.getTargetException() instanceof ClassCastException) {
|
||||
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
|
||||
}
|
||||
else {
|
||||
Throwable cause = ex.getTargetException();
|
||||
if (cause instanceof UndeclaredThrowableException) {
|
||||
// May happen e.g. with Groovy-generated methods
|
||||
cause = cause.getCause();
|
||||
}
|
||||
throw new MethodInvocationException(propertyChangeEvent, cause);
|
||||
else {
|
||||
Throwable cause = ex.getTargetException();
|
||||
if (cause instanceof UndeclaredThrowableException) {
|
||||
// May happen e.g. with Groovy-generated methods
|
||||
cause = cause.getCause();
|
||||
}
|
||||
throw new MethodInvocationException(propertyChangeEvent, cause);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
throw new MethodInvocationException(pce, ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
PropertyChangeEvent pce = new PropertyChangeEvent(
|
||||
this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
|
||||
throw new MethodInvocationException(pce, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,7 +602,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
|
||||
throw new ConversionNotSupportedException(pce, requiredType, ex);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
catch (IllegalArgumentException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
|
||||
throw new TypeMismatchException(pce, requiredType, ex);
|
||||
@@ -914,11 +926,9 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
return BeanUtils.instantiate(type);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// TODO: Root cause exception context is lost here; just exception message preserved.
|
||||
// Should we throw another exception type that preserves context instead?
|
||||
catch (Throwable ex) {
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name,
|
||||
"Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path: " + ex);
|
||||
"Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -975,9 +985,6 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle a given property.
|
||||
*/
|
||||
protected abstract static class PropertyHandler {
|
||||
|
||||
private final Class<?> propertyType;
|
||||
|
||||
@@ -148,7 +148,7 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyAccessException if the property was valid but the
|
||||
* accessor method failed or a type mismatch occured
|
||||
* accessor method failed or a type mismatch occurred
|
||||
*/
|
||||
@Override
|
||||
public abstract void setPropertyValue(String propertyName, Object value) throws BeansException;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -63,11 +63,10 @@ public abstract class BeanUtils {
|
||||
|
||||
/**
|
||||
* Convenience method to instantiate a class using its no-arg constructor.
|
||||
* As this method doesn't try to load classes by name, it should avoid
|
||||
* class-loading issues.
|
||||
* @param clazz class to instantiate
|
||||
* @return the new instance
|
||||
* @throws BeanInstantiationException if the bean cannot be instantiated
|
||||
* @see Class#newInstance()
|
||||
*/
|
||||
public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
@@ -87,13 +86,12 @@ public abstract class BeanUtils {
|
||||
|
||||
/**
|
||||
* Instantiate a class using its no-arg constructor.
|
||||
* As this method doesn't try to load classes by name, it should avoid
|
||||
* class-loading issues.
|
||||
* <p>Note that this method tries to set the constructor accessible
|
||||
* if given a non-accessible (that is, non-public) constructor.
|
||||
* @param clazz class to instantiate
|
||||
* @return the new instance
|
||||
* @throws BeanInstantiationException if the bean cannot be instantiated
|
||||
* @see Constructor#newInstance
|
||||
*/
|
||||
public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
@@ -111,17 +109,15 @@ public abstract class BeanUtils {
|
||||
/**
|
||||
* Instantiate a class using its no-arg constructor and return the new instance
|
||||
* as the specified assignable type.
|
||||
* <p>Useful in cases where
|
||||
* the type of the class to instantiate (clazz) is not available, but the type
|
||||
* desired (assignableTo) is known.
|
||||
* <p>As this method doesn't try to load classes by name, it should avoid
|
||||
* class-loading issues.
|
||||
* <p>Note that this method tries to set the constructor accessible
|
||||
* if given a non-accessible (that is, non-public) constructor.
|
||||
* <p>Useful in cases where the type of the class to instantiate (clazz) is not
|
||||
* available, but the type desired (assignableTo) is known.
|
||||
* <p>Note that this method tries to set the constructor accessible if given a
|
||||
* non-accessible (that is, non-public) constructor.
|
||||
* @param clazz class to instantiate
|
||||
* @param assignableTo type that clazz must be assignableTo
|
||||
* @return the new instance
|
||||
* @throws BeanInstantiationException if the bean cannot be instantiated
|
||||
* @see Constructor#newInstance
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo) throws BeanInstantiationException {
|
||||
@@ -131,14 +127,13 @@ public abstract class BeanUtils {
|
||||
|
||||
/**
|
||||
* Convenience method to instantiate a class using the given constructor.
|
||||
* As this method doesn't try to load classes by name, it should avoid
|
||||
* class-loading issues.
|
||||
* <p>Note that this method tries to set the constructor accessible
|
||||
* if given a non-accessible (that is, non-public) constructor.
|
||||
* <p>Note that this method tries to set the constructor accessible if given a
|
||||
* non-accessible (that is, non-public) constructor.
|
||||
* @param ctor the constructor to instantiate
|
||||
* @param args the constructor arguments to apply
|
||||
* @return the new instance
|
||||
* @throws BeanInstantiationException if the bean cannot be instantiated
|
||||
* @see Constructor#newInstance
|
||||
*/
|
||||
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
|
||||
Assert.notNull(ctor, "Constructor must not be null");
|
||||
@@ -316,23 +311,23 @@ public abstract class BeanUtils {
|
||||
public static Method resolveSignature(String signature, Class<?> clazz) {
|
||||
Assert.hasText(signature, "'signature' must not be empty");
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
int firstParen = signature.indexOf("(");
|
||||
int lastParen = signature.indexOf(")");
|
||||
if (firstParen > -1 && lastParen == -1) {
|
||||
int startParen = signature.indexOf('(');
|
||||
int endParen = signature.indexOf(')');
|
||||
if (startParen > -1 && endParen == -1) {
|
||||
throw new IllegalArgumentException("Invalid method signature '" + signature +
|
||||
"': expected closing ')' for args list");
|
||||
}
|
||||
else if (lastParen > -1 && firstParen == -1) {
|
||||
else if (startParen == -1 && endParen > -1) {
|
||||
throw new IllegalArgumentException("Invalid method signature '" + signature +
|
||||
"': expected opening '(' for args list");
|
||||
}
|
||||
else if (firstParen == -1 && lastParen == -1) {
|
||||
else if (startParen == -1 && endParen == -1) {
|
||||
return findMethodWithMinimalParameters(clazz, signature);
|
||||
}
|
||||
else {
|
||||
String methodName = signature.substring(0, firstParen);
|
||||
String methodName = signature.substring(0, startParen);
|
||||
String[] parameterTypeNames =
|
||||
StringUtils.commaDelimitedListToStringArray(signature.substring(firstParen + 1, lastParen));
|
||||
StringUtils.commaDelimitedListToStringArray(signature.substring(startParen + 1, endParen));
|
||||
Class<?>[] parameterTypes = new Class<?>[parameterTypeNames.length];
|
||||
for (int i = 0; i < parameterTypeNames.length; i++) {
|
||||
String parameterTypeName = parameterTypeNames[i].trim();
|
||||
@@ -511,13 +506,14 @@ public abstract class BeanUtils {
|
||||
|
||||
/**
|
||||
* Check if the given type represents a "simple" value type:
|
||||
* a primitive, a String or other CharSequence, a Number, a Date,
|
||||
* a primitive, an enum, a String or other CharSequence, a Number, a Date,
|
||||
* a URI, a URL, a Locale or a Class.
|
||||
* @param clazz the type to check
|
||||
* @return whether the given type represents a "simple" value type
|
||||
*/
|
||||
public static boolean isSimpleValueType(Class<?> clazz) {
|
||||
return (ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.isEnum() ||
|
||||
return (ClassUtils.isPrimitiveOrWrapper(clazz) ||
|
||||
Enum.class.isAssignableFrom(clazz) ||
|
||||
CharSequence.class.isAssignableFrom(clazz) ||
|
||||
Number.class.isAssignableFrom(clazz) ||
|
||||
Date.class.isAssignableFrom(clazz) ||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -141,6 +141,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||
*/
|
||||
public void setBeanInstance(Object object) {
|
||||
this.wrappedObject = object;
|
||||
this.rootObject = object;
|
||||
this.typeConverterDelegate = new TypeConverterDelegate(this, this.wrappedObject);
|
||||
setIntrospectionClass(object.getClass());
|
||||
}
|
||||
@@ -223,10 +224,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||
@Override
|
||||
protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
|
||||
if (pd != null) {
|
||||
return new BeanPropertyHandler(pd);
|
||||
}
|
||||
return null;
|
||||
return (pd != null ? new BeanPropertyHandler(pd) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -237,8 +235,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||
@Override
|
||||
protected NotWritablePropertyException createNotWritablePropertyException(String propertyName) {
|
||||
PropertyMatches matches = PropertyMatches.forProperty(propertyName, getRootClass());
|
||||
throw new NotWritablePropertyException(
|
||||
getRootClass(), getNestedPath() + propertyName,
|
||||
throw new NotWritablePropertyException(getRootClass(), getNestedPath() + propertyName,
|
||||
matches.buildErrorMessage(), matches.getPossibleMatches());
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -339,10 +339,10 @@ public class CachedIntrospectionResults {
|
||||
PropertyDescriptor getPropertyDescriptor(String name) {
|
||||
PropertyDescriptor pd = this.propertyDescriptorCache.get(name);
|
||||
if (pd == null && StringUtils.hasLength(name)) {
|
||||
// Same lenient fallback checking as in PropertyTypeDescriptor...
|
||||
pd = this.propertyDescriptorCache.get(name.substring(0, 1).toLowerCase() + name.substring(1));
|
||||
// Same lenient fallback checking as in Property...
|
||||
pd = this.propertyDescriptorCache.get(StringUtils.uncapitalize(name));
|
||||
if (pd == null) {
|
||||
pd = this.propertyDescriptorCache.get(name.substring(0, 1).toUpperCase() + name.substring(1));
|
||||
pd = this.propertyDescriptorCache.get(StringUtils.capitalize(name));
|
||||
}
|
||||
}
|
||||
return (pd == null || pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -76,8 +76,8 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
|
||||
Field field = ReflectionUtils.findField(getWrappedClass(), propertyName);
|
||||
if (field != null) {
|
||||
propertyHandler = new FieldPropertyHandler(field);
|
||||
this.fieldMap.put(propertyName, propertyHandler);
|
||||
}
|
||||
this.fieldMap.put(propertyName, propertyHandler);
|
||||
}
|
||||
return propertyHandler;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2018 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,7 +41,7 @@ public interface Mergeable {
|
||||
* @param parent the object to merge with
|
||||
* @return the result of the merge operation
|
||||
* @throws IllegalArgumentException if the supplied parent is {@code null}
|
||||
* @exception IllegalStateException if merging is not enabled for this instance
|
||||
* @throws IllegalStateException if merging is not enabled for this instance
|
||||
* (i.e. {@code mergeEnabled} equals {@code false}).
|
||||
*/
|
||||
Object merge(Object parent);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -262,7 +262,7 @@ public class MutablePropertyValues implements PropertyValues, Serializable {
|
||||
/**
|
||||
* Get the raw property value, if any.
|
||||
* @param propertyName the name to search for
|
||||
* @return the raw property value, or {@code null}
|
||||
* @return the raw property value, or {@code null} if none found
|
||||
* @since 4.0
|
||||
* @see #getPropertyValue(String)
|
||||
* @see PropertyValue#getValue()
|
||||
@@ -283,11 +283,7 @@ public class MutablePropertyValues implements PropertyValues, Serializable {
|
||||
for (PropertyValue newPv : this.propertyValueList) {
|
||||
// if there wasn't an old one, add it
|
||||
PropertyValue pvOld = old.getPropertyValue(newPv.getName());
|
||||
if (pvOld == null) {
|
||||
changes.addPropertyValue(newPv);
|
||||
}
|
||||
else if (!pvOld.equals(newPv)) {
|
||||
// it's changed
|
||||
if (pvOld == null || !pvOld.equals(newPv)) {
|
||||
changes.addPropertyValue(newPv);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 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,6 +24,7 @@ package org.springframework.beans;
|
||||
* spouse property of the target object has a null value.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class NullValueInNestedPathException extends InvalidPropertyException {
|
||||
@@ -47,4 +48,16 @@ public class NullValueInNestedPathException extends InvalidPropertyException {
|
||||
super(beanClass, propertyName, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new NullValueInNestedPathException.
|
||||
* @param beanClass the offending bean class
|
||||
* @param propertyName the offending property
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public NullValueInNestedPathException(Class<?> beanClass, String propertyName, String msg, Throwable cause) {
|
||||
super(beanClass, propertyName, msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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,6 @@ package org.springframework.beans;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
|
||||
import org.springframework.core.ErrorCoded;
|
||||
|
||||
/**
|
||||
* Superclass for exceptions related to a property access,
|
||||
* such as type mismatch or invocation target exception.
|
||||
@@ -27,8 +25,8 @@ import org.springframework.core.ErrorCoded;
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class PropertyAccessException extends BeansException implements ErrorCoded {
|
||||
@SuppressWarnings({"serial", "deprecation"})
|
||||
public abstract class PropertyAccessException extends BeansException implements org.springframework.core.ErrorCoded {
|
||||
|
||||
private transient PropertyChangeEvent propertyChangeEvent;
|
||||
|
||||
@@ -77,4 +75,10 @@ public abstract class PropertyAccessException extends BeansException implements
|
||||
return (this.propertyChangeEvent != null ? this.propertyChangeEvent.getNewValue() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a corresponding error code for this type of exception.
|
||||
*/
|
||||
@Override
|
||||
public abstract String getErrorCode();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -81,8 +81,6 @@ public interface PropertyAccessor {
|
||||
* (may be a nested path and/or an indexed/mapped property)
|
||||
* @return the property type for the particular property,
|
||||
* or {@code null} if not determinable
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't readable
|
||||
* @throws PropertyAccessException if the property was valid but the
|
||||
* accessor method failed
|
||||
*/
|
||||
@@ -95,8 +93,8 @@ public interface PropertyAccessor {
|
||||
* (may be a nested path and/or an indexed/mapped property)
|
||||
* @return the property type for the particular property,
|
||||
* or {@code null} if not determinable
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't readable
|
||||
* @throws PropertyAccessException if the property was valid but the
|
||||
* accessor method failed
|
||||
*/
|
||||
TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException;
|
||||
|
||||
@@ -120,7 +118,7 @@ public interface PropertyAccessor {
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyAccessException if the property was valid but the
|
||||
* accessor method failed or a type mismatch occured
|
||||
* accessor method failed or a type mismatch occurred
|
||||
*/
|
||||
void setPropertyValue(String propertyName, Object value) throws BeansException;
|
||||
|
||||
@@ -130,7 +128,7 @@ public interface PropertyAccessor {
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyAccessException if the property was valid but the
|
||||
* accessor method failed or a type mismatch occured
|
||||
* accessor method failed or a type mismatch occurred
|
||||
*/
|
||||
void setPropertyValue(PropertyValue pv) throws BeansException;
|
||||
|
||||
@@ -144,7 +142,7 @@ public interface PropertyAccessor {
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyBatchUpdateException if one or more PropertyAccessExceptions
|
||||
* occured for specific properties during the batch update. This exception bundles
|
||||
* occurred for specific properties during the batch update. This exception bundles
|
||||
* all individual PropertyAccessExceptions. All other properties will have been
|
||||
* successfully updated.
|
||||
*/
|
||||
@@ -164,7 +162,7 @@ public interface PropertyAccessor {
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyBatchUpdateException if one or more PropertyAccessExceptions
|
||||
* occured for specific properties during the batch update. This exception bundles
|
||||
* occurred for specific properties during the batch update. This exception bundles
|
||||
* all individual PropertyAccessExceptions. All other properties will have been
|
||||
* successfully updated.
|
||||
* @see #setPropertyValues(PropertyValues, boolean, boolean)
|
||||
@@ -185,7 +183,7 @@ public interface PropertyAccessor {
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyBatchUpdateException if one or more PropertyAccessExceptions
|
||||
* occured for specific properties during the batch update. This exception bundles
|
||||
* occurred for specific properties during the batch update. This exception bundles
|
||||
* all individual PropertyAccessExceptions. All other properties will have been
|
||||
* successfully updated.
|
||||
* @see #setPropertyValues(PropertyValues, boolean, boolean)
|
||||
@@ -208,7 +206,7 @@ public interface PropertyAccessor {
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyBatchUpdateException if one or more PropertyAccessExceptions
|
||||
* occured for specific properties during the batch update. This exception bundles
|
||||
* occurred for specific properties during the batch update. This exception bundles
|
||||
* all individual PropertyAccessExceptions. All other properties will have been
|
||||
* successfully updated.
|
||||
*/
|
||||
|
||||
@@ -75,7 +75,7 @@ class PropertyDescriptorUtils {
|
||||
}
|
||||
|
||||
if (writeMethod != null) {
|
||||
Class<?> params[] = writeMethod.getParameterTypes();
|
||||
Class<?>[] params = writeMethod.getParameterTypes();
|
||||
if (params.length != 1) {
|
||||
throw new IntrospectionException("Bad write method arg count: " + writeMethod);
|
||||
}
|
||||
@@ -109,7 +109,7 @@ class PropertyDescriptorUtils {
|
||||
Class<?> indexedPropertyType = null;
|
||||
|
||||
if (indexedReadMethod != null) {
|
||||
Class<?> params[] = indexedReadMethod.getParameterTypes();
|
||||
Class<?>[] params = indexedReadMethod.getParameterTypes();
|
||||
if (params.length != 1) {
|
||||
throw new IntrospectionException("Bad indexed read method arg count: " + indexedReadMethod);
|
||||
}
|
||||
@@ -123,7 +123,7 @@ class PropertyDescriptorUtils {
|
||||
}
|
||||
|
||||
if (indexedWriteMethod != null) {
|
||||
Class<?> params[] = indexedWriteMethod.getParameterTypes();
|
||||
Class<?>[] params = indexedWriteMethod.getParameterTypes();
|
||||
if (params.length != 2) {
|
||||
throw new IntrospectionException("Bad indexed write method arg count: " + indexedWriteMethod);
|
||||
}
|
||||
|
||||
+15
-1
@@ -59,6 +59,7 @@ import org.springframework.beans.propertyeditors.FileEditor;
|
||||
import org.springframework.beans.propertyeditors.InputSourceEditor;
|
||||
import org.springframework.beans.propertyeditors.InputStreamEditor;
|
||||
import org.springframework.beans.propertyeditors.LocaleEditor;
|
||||
import org.springframework.beans.propertyeditors.PathEditor;
|
||||
import org.springframework.beans.propertyeditors.PatternEditor;
|
||||
import org.springframework.beans.propertyeditors.PropertiesEditor;
|
||||
import org.springframework.beans.propertyeditors.ReaderEditor;
|
||||
@@ -87,11 +88,21 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
||||
|
||||
private static Class<?> pathClass;
|
||||
|
||||
private static Class<?> zoneIdClass;
|
||||
|
||||
static {
|
||||
ClassLoader cl = PropertyEditorRegistrySupport.class.getClassLoader();
|
||||
try {
|
||||
zoneIdClass = ClassUtils.forName("java.time.ZoneId", PropertyEditorRegistrySupport.class.getClassLoader());
|
||||
pathClass = ClassUtils.forName("java.nio.file.Path", cl);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Java 7 Path class not available
|
||||
pathClass = null;
|
||||
}
|
||||
try {
|
||||
zoneIdClass = ClassUtils.forName("java.time.ZoneId", cl);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Java 8 ZoneId class not available
|
||||
@@ -211,6 +222,9 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
||||
this.defaultEditors.put(InputStream.class, new InputStreamEditor());
|
||||
this.defaultEditors.put(InputSource.class, new InputSourceEditor());
|
||||
this.defaultEditors.put(Locale.class, new LocaleEditor());
|
||||
if (pathClass != null) {
|
||||
this.defaultEditors.put(pathClass, new PathEditor());
|
||||
}
|
||||
this.defaultEditors.put(Pattern.class, new PatternEditor());
|
||||
this.defaultEditors.put(Properties.class, new PropertiesEditor());
|
||||
this.defaultEditors.put(Reader.class, new ReaderEditor());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -30,8 +30,8 @@ import org.springframework.util.StringUtils;
|
||||
* Helper class for calculating property matches, according to a configurable
|
||||
* distance. Provide the list of potential matches and an easy way to generate
|
||||
* an error message. Works for both java bean properties and fields.
|
||||
* <p>
|
||||
* Mainly for use within the framework and in particular the binding facility
|
||||
*
|
||||
* <p>Mainly for use within the framework and in particular the binding facility.
|
||||
*
|
||||
* @author Alef Arendsen
|
||||
* @author Arjen Poutsma
|
||||
@@ -43,14 +43,12 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class PropertyMatches {
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Static section
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/** Default maximum property distance: 2 */
|
||||
public static final int DEFAULT_MAX_DISTANCE = 2;
|
||||
|
||||
|
||||
// Static factory methods
|
||||
|
||||
/**
|
||||
* Create PropertyMatches for the given bean property.
|
||||
* @param propertyName the name of the property to find possible matches for
|
||||
@@ -90,9 +88,7 @@ public abstract class PropertyMatches {
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Instance section
|
||||
//---------------------------------------------------------------------
|
||||
// Instance state
|
||||
|
||||
private final String propertyName;
|
||||
|
||||
@@ -107,18 +103,19 @@ public abstract class PropertyMatches {
|
||||
this.possibleMatches = possibleMatches;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of the requested property.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
return this.propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the calculated possible matches.
|
||||
*/
|
||||
public String[] getPossibleMatches() {
|
||||
return possibleMatches;
|
||||
return this.possibleMatches;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,6 +124,9 @@ public abstract class PropertyMatches {
|
||||
*/
|
||||
public abstract String buildErrorMessage();
|
||||
|
||||
|
||||
// Implementation support for subclasses
|
||||
|
||||
protected void appendHintMessage(StringBuilder msg) {
|
||||
msg.append("Did you mean ");
|
||||
for (int i = 0; i < this.possibleMatches.length; i++) {
|
||||
@@ -150,14 +150,14 @@ public abstract class PropertyMatches {
|
||||
* @return the distance value
|
||||
*/
|
||||
private static int calculateStringDistance(String s1, String s2) {
|
||||
if (s1.length() == 0) {
|
||||
if (s1.isEmpty()) {
|
||||
return s2.length();
|
||||
}
|
||||
if (s2.length() == 0) {
|
||||
if (s2.isEmpty()) {
|
||||
return s1.length();
|
||||
}
|
||||
int d[][] = new int[s1.length() + 1][s2.length() + 1];
|
||||
|
||||
int[][] d = new int[s1.length() + 1][s2.length() + 1];
|
||||
for (int i = 0; i <= s1.length(); i++) {
|
||||
d[i][0] = i;
|
||||
}
|
||||
@@ -166,45 +166,46 @@ public abstract class PropertyMatches {
|
||||
}
|
||||
|
||||
for (int i = 1; i <= s1.length(); i++) {
|
||||
char s_i = s1.charAt(i - 1);
|
||||
char c1 = s1.charAt(i - 1);
|
||||
for (int j = 1; j <= s2.length(); j++) {
|
||||
int cost;
|
||||
char t_j = s2.charAt(j - 1);
|
||||
if (s_i == t_j) {
|
||||
char c2 = s2.charAt(j - 1);
|
||||
if (c1 == c2) {
|
||||
cost = 0;
|
||||
}
|
||||
else {
|
||||
cost = 1;
|
||||
}
|
||||
d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1),
|
||||
d[i - 1][j - 1] + cost);
|
||||
d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1), d[i - 1][j - 1] + cost);
|
||||
}
|
||||
}
|
||||
|
||||
return d[s1.length()][s2.length()];
|
||||
}
|
||||
|
||||
|
||||
// Concrete subclasses
|
||||
|
||||
private static class BeanPropertyMatches extends PropertyMatches {
|
||||
|
||||
private BeanPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
super(propertyName, calculateMatches(propertyName,
|
||||
BeanUtils.getPropertyDescriptors(beanClass), maxDistance));
|
||||
public BeanPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
super(propertyName,
|
||||
calculateMatches(propertyName, BeanUtils.getPropertyDescriptors(beanClass), maxDistance));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate possible property alternatives for the given property and
|
||||
* class. Internally uses the {@code getStringDistance} method, which
|
||||
* in turn uses the Levenshtein algorithm to determine the distance between
|
||||
* two Strings.
|
||||
* @param propertyDescriptors the JavaBeans property descriptors to search
|
||||
* Generate possible property alternatives for the given property and class.
|
||||
* Internally uses the {@code getStringDistance} method, which in turn uses
|
||||
* the Levenshtein algorithm to determine the distance between two Strings.
|
||||
* @param descriptors the JavaBeans property descriptors to search
|
||||
* @param maxDistance the maximum distance to accept
|
||||
*/
|
||||
private static String[] calculateMatches(String propertyName, PropertyDescriptor[] propertyDescriptors, int maxDistance) {
|
||||
private static String[] calculateMatches(String name, PropertyDescriptor[] descriptors, int maxDistance) {
|
||||
List<String> candidates = new ArrayList<String>();
|
||||
for (PropertyDescriptor pd : propertyDescriptors) {
|
||||
for (PropertyDescriptor pd : descriptors) {
|
||||
if (pd.getWriteMethod() != null) {
|
||||
String possibleAlternative = pd.getName();
|
||||
if (calculateStringDistance(propertyName, possibleAlternative) <= maxDistance) {
|
||||
if (calculateStringDistance(name, possibleAlternative) <= maxDistance) {
|
||||
candidates.add(possibleAlternative);
|
||||
}
|
||||
}
|
||||
@@ -213,40 +214,35 @@ public abstract class PropertyMatches {
|
||||
return StringUtils.toStringArray(candidates);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String buildErrorMessage() {
|
||||
String propertyName = getPropertyName();
|
||||
String[] possibleMatches = getPossibleMatches();
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Bean property '");
|
||||
msg.append(propertyName);
|
||||
msg.append("' is not writable or has an invalid setter method. ");
|
||||
|
||||
if (ObjectUtils.isEmpty(possibleMatches)) {
|
||||
msg.append("Does the parameter type of the setter match the return type of the getter?");
|
||||
StringBuilder msg = new StringBuilder(160);
|
||||
msg.append("Bean property '").append(getPropertyName()).append(
|
||||
"' is not writable or has an invalid setter method. ");
|
||||
if (!ObjectUtils.isEmpty(getPossibleMatches())) {
|
||||
appendHintMessage(msg);
|
||||
}
|
||||
else {
|
||||
appendHintMessage(msg);
|
||||
msg.append("Does the parameter type of the setter match the return type of the getter?");
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class FieldPropertyMatches extends PropertyMatches {
|
||||
|
||||
private FieldPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
public FieldPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
super(propertyName, calculateMatches(propertyName, beanClass, maxDistance));
|
||||
}
|
||||
|
||||
private static String[] calculateMatches(final String propertyName, Class<?> beanClass, final int maxDistance) {
|
||||
private static String[] calculateMatches(final String name, Class<?> clazz, final int maxDistance) {
|
||||
final List<String> candidates = new ArrayList<String>();
|
||||
ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
|
||||
ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {
|
||||
@Override
|
||||
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
|
||||
String possibleAlternative = field.getName();
|
||||
if (calculateStringDistance(propertyName, possibleAlternative) <= maxDistance) {
|
||||
if (calculateStringDistance(name, possibleAlternative) <= maxDistance) {
|
||||
candidates.add(possibleAlternative);
|
||||
}
|
||||
}
|
||||
@@ -255,22 +251,16 @@ public abstract class PropertyMatches {
|
||||
return StringUtils.toStringArray(candidates);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String buildErrorMessage() {
|
||||
String propertyName = getPropertyName();
|
||||
String[] possibleMatches = getPossibleMatches();
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Bean property '");
|
||||
msg.append(propertyName);
|
||||
msg.append("' has no matching field. ");
|
||||
|
||||
if (!ObjectUtils.isEmpty(possibleMatches)) {
|
||||
StringBuilder msg = new StringBuilder(80);
|
||||
msg.append("Bean property '").append(getPropertyName()).append("' has no matching field.");
|
||||
if (!ObjectUtils.isEmpty(getPossibleMatches())) {
|
||||
msg.append(' ');
|
||||
appendHintMessage(msg);
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -45,8 +45,6 @@ public class PropertyValue extends BeanMetadataAttributeAccessor implements Seri
|
||||
|
||||
private final Object value;
|
||||
|
||||
private Object source;
|
||||
|
||||
private boolean optional = false;
|
||||
|
||||
private boolean converted = false;
|
||||
@@ -78,12 +76,12 @@ public class PropertyValue extends BeanMetadataAttributeAccessor implements Seri
|
||||
Assert.notNull(original, "Original must not be null");
|
||||
this.name = original.getName();
|
||||
this.value = original.getValue();
|
||||
this.source = original.getSource();
|
||||
this.optional = original.isOptional();
|
||||
this.converted = original.converted;
|
||||
this.convertedValue = original.convertedValue;
|
||||
this.conversionNecessary = original.conversionNecessary;
|
||||
this.resolvedTokens = original.resolvedTokens;
|
||||
setSource(original.getSource());
|
||||
copyAttributesFrom(original);
|
||||
}
|
||||
|
||||
@@ -97,10 +95,10 @@ public class PropertyValue extends BeanMetadataAttributeAccessor implements Seri
|
||||
Assert.notNull(original, "Original must not be null");
|
||||
this.name = original.getName();
|
||||
this.value = newValue;
|
||||
this.source = original;
|
||||
this.optional = original.isOptional();
|
||||
this.conversionNecessary = original.conversionNecessary;
|
||||
this.resolvedTokens = original.resolvedTokens;
|
||||
setSource(original);
|
||||
copyAttributesFrom(original);
|
||||
}
|
||||
|
||||
@@ -129,16 +127,28 @@ public class PropertyValue extends BeanMetadataAttributeAccessor implements Seri
|
||||
*/
|
||||
public PropertyValue getOriginalPropertyValue() {
|
||||
PropertyValue original = this;
|
||||
while (original.source instanceof PropertyValue && original.source != original) {
|
||||
original = (PropertyValue) original.source;
|
||||
Object source = getSource();
|
||||
while (source instanceof PropertyValue && source != original) {
|
||||
original = (PropertyValue) source;
|
||||
source = original.getSource();
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this is an optional value, that is, to be ignored
|
||||
* when no corresponding property exists on the target class.
|
||||
* @since 3.0
|
||||
*/
|
||||
public void setOptional(boolean optional) {
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this is an optional value, that is, to be ignored
|
||||
* when no corresponding property exists on the target class.
|
||||
* @since 3.0
|
||||
*/
|
||||
public boolean isOptional() {
|
||||
return this.optional;
|
||||
}
|
||||
@@ -180,7 +190,7 @@ public class PropertyValue extends BeanMetadataAttributeAccessor implements Seri
|
||||
PropertyValue otherPv = (PropertyValue) other;
|
||||
return (this.name.equals(otherPv.name) &&
|
||||
ObjectUtils.nullSafeEquals(this.value, otherPv.value) &&
|
||||
ObjectUtils.nullSafeEquals(this.source, otherPv.source));
|
||||
ObjectUtils.nullSafeEquals(getSource(), otherPv.getSource()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -35,6 +35,7 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.NumberUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -269,7 +270,7 @@ class TypeConverterDelegate {
|
||||
}
|
||||
else {
|
||||
// convertedValue == null
|
||||
if (javaUtilOptionalEmpty != null && requiredType.equals(javaUtilOptionalEmpty.getClass())) {
|
||||
if (javaUtilOptionalEmpty != null && requiredType == javaUtilOptionalEmpty.getClass()) {
|
||||
convertedValue = javaUtilOptionalEmpty;
|
||||
}
|
||||
}
|
||||
@@ -290,15 +291,15 @@ class TypeConverterDelegate {
|
||||
|
||||
// Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Cannot convert value of type [").append(ClassUtils.getDescriptiveType(newValue));
|
||||
msg.append("] to required type [").append(ClassUtils.getQualifiedName(requiredType)).append("]");
|
||||
msg.append("Cannot convert value of type '").append(ClassUtils.getDescriptiveType(newValue));
|
||||
msg.append("' to required type '").append(ClassUtils.getQualifiedName(requiredType)).append("'");
|
||||
if (propertyName != null) {
|
||||
msg.append(" for property '").append(propertyName).append("'");
|
||||
}
|
||||
if (editor != null) {
|
||||
msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
|
||||
"] returned inappropriate value of type [").append(
|
||||
ClassUtils.getDescriptiveType(convertedValue)).append("]");
|
||||
"] returned inappropriate value of type '").append(
|
||||
ClassUtils.getDescriptiveType(convertedValue)).append("'");
|
||||
throw new IllegalArgumentException(msg.toString());
|
||||
}
|
||||
else {
|
||||
@@ -324,7 +325,7 @@ class TypeConverterDelegate {
|
||||
|
||||
if (Enum.class == requiredType) {
|
||||
// target type is declared as raw enum, treat the trimmed value as <enum.fqn>.FIELD_NAME
|
||||
int index = trimmedValue.lastIndexOf(".");
|
||||
int index = trimmedValue.lastIndexOf('.');
|
||||
if (index > - 1) {
|
||||
String enumType = trimmedValue.substring(0, index);
|
||||
String fieldName = trimmedValue.substring(index + 1);
|
||||
@@ -353,6 +354,7 @@ class TypeConverterDelegate {
|
||||
// to be checked, hence we don't return it right away.
|
||||
try {
|
||||
Field enumField = requiredType.getField(trimmedValue);
|
||||
ReflectionUtils.makeAccessible(enumField);
|
||||
convertedValue = enumField.get(null);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
|
||||
@@ -73,7 +73,7 @@ public abstract class TypeConverterSupport extends PropertyEditorRegistrySupport
|
||||
catch (IllegalStateException ex) {
|
||||
throw new ConversionNotSupportedException(value, requiredType, ex);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
catch (IllegalArgumentException ex) {
|
||||
throw new TypeMismatchException(value, requiredType, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 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,7 +41,7 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
|
||||
|
||||
/**
|
||||
* Create a new TypeMismatchException.
|
||||
* Create a new {@code TypeMismatchException}.
|
||||
* @param propertyChangeEvent the PropertyChangeEvent that resulted in the problem
|
||||
* @param requiredType the required target type
|
||||
*/
|
||||
@@ -50,17 +50,17 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new TypeMismatchException.
|
||||
* Create a new {@code TypeMismatchException}.
|
||||
* @param propertyChangeEvent the PropertyChangeEvent that resulted in the problem
|
||||
* @param requiredType the required target type (or {@code null} if not known)
|
||||
* @param cause the root cause (may be {@code null})
|
||||
*/
|
||||
public TypeMismatchException(PropertyChangeEvent propertyChangeEvent, Class<?> requiredType, Throwable cause) {
|
||||
super(propertyChangeEvent,
|
||||
"Failed to convert property value of type [" +
|
||||
ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "]" +
|
||||
"Failed to convert property value of type '" +
|
||||
ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "'" +
|
||||
(requiredType != null ?
|
||||
" to required type [" + ClassUtils.getQualifiedName(requiredType) + "]" : "") +
|
||||
" to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : "") +
|
||||
(propertyChangeEvent.getPropertyName() != null ?
|
||||
" for property '" + propertyChangeEvent.getPropertyName() + "'" : ""),
|
||||
cause);
|
||||
@@ -69,7 +69,7 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new TypeMismatchException without PropertyChangeEvent.
|
||||
* Create a new {@code TypeMismatchException} without a {@code PropertyChangeEvent}.
|
||||
* @param value the offending value that couldn't be converted (may be {@code null})
|
||||
* @param requiredType the required target type (or {@code null} if not known)
|
||||
*/
|
||||
@@ -78,14 +78,14 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new TypeMismatchException without PropertyChangeEvent.
|
||||
* Create a new {@code TypeMismatchException} without a {@code PropertyChangeEvent}.
|
||||
* @param value the offending value that couldn't be converted (may be {@code null})
|
||||
* @param requiredType the required target type (or {@code null} if not known)
|
||||
* @param cause the root cause (may be {@code null})
|
||||
*/
|
||||
public TypeMismatchException(Object value, Class<?> requiredType, Throwable cause) {
|
||||
super("Failed to convert value of type [" + ClassUtils.getDescriptiveType(value) + "]" +
|
||||
(requiredType != null ? " to required type [" + ClassUtils.getQualifiedName(requiredType) + "]" : ""),
|
||||
super("Failed to convert value of type '" + ClassUtils.getDescriptiveType(value) + "'" +
|
||||
(requiredType != null ? " to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : ""),
|
||||
cause);
|
||||
this.value = value;
|
||||
this.requiredType = requiredType;
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ public class BeanCreationException extends FatalBeanException {
|
||||
|
||||
/**
|
||||
* Add a related cause to this bean creation exception,
|
||||
* not being a direct cause of the failure but having occured
|
||||
* not being a direct cause of the failure but having occurred
|
||||
* earlier in the creation of the same bean instance.
|
||||
* @param ex the related cause to add
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -63,28 +63,35 @@ import org.springframework.core.ResolvableType;
|
||||
* are supposed to override beans of the same name in any parent factory.
|
||||
*
|
||||
* <p>Bean factory implementations should support the standard bean lifecycle interfaces
|
||||
* as far as possible. The full set of initialization methods and their standard order is:<br>
|
||||
* 1. BeanNameAware's {@code setBeanName}<br>
|
||||
* 2. BeanClassLoaderAware's {@code setBeanClassLoader}<br>
|
||||
* 3. BeanFactoryAware's {@code setBeanFactory}<br>
|
||||
* 4. ResourceLoaderAware's {@code setResourceLoader}
|
||||
* (only applicable when running in an application context)<br>
|
||||
* 5. ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
|
||||
* (only applicable when running in an application context)<br>
|
||||
* 6. MessageSourceAware's {@code setMessageSource}
|
||||
* (only applicable when running in an application context)<br>
|
||||
* 7. ApplicationContextAware's {@code setApplicationContext}
|
||||
* (only applicable when running in an application context)<br>
|
||||
* 8. ServletContextAware's {@code setServletContext}
|
||||
* (only applicable when running in a web application context)<br>
|
||||
* 9. {@code postProcessBeforeInitialization} methods of BeanPostProcessors<br>
|
||||
* 10. InitializingBean's {@code afterPropertiesSet}<br>
|
||||
* 11. a custom init-method definition<br>
|
||||
* 12. {@code postProcessAfterInitialization} methods of BeanPostProcessors
|
||||
* as far as possible. The full set of initialization methods and their standard order is:
|
||||
* <ol>
|
||||
* <li>BeanNameAware's {@code setBeanName}
|
||||
* <li>BeanClassLoaderAware's {@code setBeanClassLoader}
|
||||
* <li>BeanFactoryAware's {@code setBeanFactory}
|
||||
* <li>EnvironmentAware's {@code setEnvironment}
|
||||
* <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
|
||||
* <li>ResourceLoaderAware's {@code setResourceLoader}
|
||||
* (only applicable when running in an application context)
|
||||
* <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
|
||||
* (only applicable when running in an application context)
|
||||
* <li>MessageSourceAware's {@code setMessageSource}
|
||||
* (only applicable when running in an application context)
|
||||
* <li>ApplicationContextAware's {@code setApplicationContext}
|
||||
* (only applicable when running in an application context)
|
||||
* <li>ServletContextAware's {@code setServletContext}
|
||||
* (only applicable when running in a web application context)
|
||||
* <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
|
||||
* <li>InitializingBean's {@code afterPropertiesSet}
|
||||
* <li>a custom init-method definition
|
||||
* <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
|
||||
* </ol>
|
||||
*
|
||||
* <p>On shutdown of a bean factory, the following lifecycle methods apply:<br>
|
||||
* 1. DisposableBean's {@code destroy}<br>
|
||||
* 2. a custom destroy-method definition
|
||||
* <p>On shutdown of a bean factory, the following lifecycle methods apply:
|
||||
* <ol>
|
||||
* <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
|
||||
* <li>DisposableBean's {@code destroy}
|
||||
* <li>a custom destroy-method definition
|
||||
* </ol>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -151,23 +158,6 @@ public interface BeanFactory {
|
||||
*/
|
||||
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
|
||||
|
||||
/**
|
||||
* Return the bean instance that uniquely matches the given object type, if any.
|
||||
* @param requiredType type the bean must match; can be an interface or superclass.
|
||||
* {@code null} is disallowed.
|
||||
* <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
|
||||
* but may also be translated into a conventional by-name lookup based on the name
|
||||
* of the given type. For more extensive retrieval operations across sets of beans,
|
||||
* use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}.
|
||||
* @return an instance of the single bean matching the required type
|
||||
* @throws NoSuchBeanDefinitionException if no bean of the given type was found
|
||||
* @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found
|
||||
* @throws BeansException if the bean could not be created
|
||||
* @since 3.0
|
||||
* @see ListableBeanFactory
|
||||
*/
|
||||
<T> T getBean(Class<T> requiredType) throws BeansException;
|
||||
|
||||
/**
|
||||
* Return an instance, which may be shared or independent, of the specified bean.
|
||||
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
|
||||
@@ -184,6 +174,23 @@ public interface BeanFactory {
|
||||
*/
|
||||
Object getBean(String name, Object... args) throws BeansException;
|
||||
|
||||
/**
|
||||
* Return the bean instance that uniquely matches the given object type, if any.
|
||||
* <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
|
||||
* but may also be translated into a conventional by-name lookup based on the name
|
||||
* of the given type. For more extensive retrieval operations across sets of beans,
|
||||
* use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}.
|
||||
* @param requiredType type the bean must match; can be an interface or superclass.
|
||||
* {@code null} is disallowed.
|
||||
* @return an instance of the single bean matching the required type
|
||||
* @throws NoSuchBeanDefinitionException if no bean of the given type was found
|
||||
* @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found
|
||||
* @throws BeansException if the bean could not be created
|
||||
* @since 3.0
|
||||
* @see ListableBeanFactory
|
||||
*/
|
||||
<T> T getBean(Class<T> requiredType) throws BeansException;
|
||||
|
||||
/**
|
||||
* Return an instance, which may be shared or independent, of the specified bean.
|
||||
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
|
||||
|
||||
+30
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -147,14 +147,7 @@ public abstract class BeanFactoryUtils {
|
||||
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
|
||||
String[] parentResult = beanNamesForTypeIncludingAncestors(
|
||||
(ListableBeanFactory) hbf.getParentBeanFactory(), type);
|
||||
List<String> resultList = new ArrayList<String>();
|
||||
resultList.addAll(Arrays.asList(result));
|
||||
for (String beanName : parentResult) {
|
||||
if (!resultList.contains(beanName) && !hbf.containsLocalBean(beanName)) {
|
||||
resultList.add(beanName);
|
||||
}
|
||||
}
|
||||
result = StringUtils.toStringArray(resultList);
|
||||
result = mergeNamesWithParent(result, parentResult, hbf);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -180,14 +173,7 @@ public abstract class BeanFactoryUtils {
|
||||
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
|
||||
String[] parentResult = beanNamesForTypeIncludingAncestors(
|
||||
(ListableBeanFactory) hbf.getParentBeanFactory(), type);
|
||||
List<String> resultList = new ArrayList<String>();
|
||||
resultList.addAll(Arrays.asList(result));
|
||||
for (String beanName : parentResult) {
|
||||
if (!resultList.contains(beanName) && !hbf.containsLocalBean(beanName)) {
|
||||
resultList.add(beanName);
|
||||
}
|
||||
}
|
||||
result = StringUtils.toStringArray(resultList);
|
||||
result = mergeNamesWithParent(result, parentResult, hbf);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -223,14 +209,7 @@ public abstract class BeanFactoryUtils {
|
||||
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
|
||||
String[] parentResult = beanNamesForTypeIncludingAncestors(
|
||||
(ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
|
||||
List<String> resultList = new ArrayList<String>();
|
||||
resultList.addAll(Arrays.asList(result));
|
||||
for (String beanName : parentResult) {
|
||||
if (!resultList.contains(beanName) && !hbf.containsLocalBean(beanName)) {
|
||||
resultList.add(beanName);
|
||||
}
|
||||
}
|
||||
result = StringUtils.toStringArray(resultList);
|
||||
result = mergeNamesWithParent(result, parentResult, hbf);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -446,6 +425,29 @@ public abstract class BeanFactoryUtils {
|
||||
return uniqueBean(type, beansOfType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merge the given bean names result with the given parent result.
|
||||
* @param result the local bean name result
|
||||
* @param parentResult the parent bean name result (possibly empty)
|
||||
* @param hbf the local bean factory
|
||||
* @return the merged result (possibly the local result as-is)
|
||||
* @since 4.3.15
|
||||
*/
|
||||
private static String[] mergeNamesWithParent(String[] result, String[] parentResult, HierarchicalBeanFactory hbf) {
|
||||
if (parentResult.length == 0) {
|
||||
return result;
|
||||
}
|
||||
List<String> merged = new ArrayList<String>(result.length + parentResult.length);
|
||||
merged.addAll(Arrays.asList(result));
|
||||
for (String beanName : parentResult) {
|
||||
if (!merged.contains(beanName) && !hbf.containsLocalBean(beanName)) {
|
||||
merged.add(beanName);
|
||||
}
|
||||
}
|
||||
return StringUtils.toStringArray(merged);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a unique bean for the given type from the given Map of matching beans.
|
||||
* @param type type of bean to match
|
||||
@@ -455,11 +457,11 @@ public abstract class BeanFactoryUtils {
|
||||
* @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found
|
||||
*/
|
||||
private static <T> T uniqueBean(Class<T> type, Map<String, T> matchingBeans) {
|
||||
int nrFound = matchingBeans.size();
|
||||
if (nrFound == 1) {
|
||||
int count = matchingBeans.size();
|
||||
if (count == 1) {
|
||||
return matchingBeans.values().iterator().next();
|
||||
}
|
||||
else if (nrFound > 1) {
|
||||
else if (count > 1) {
|
||||
throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
|
||||
}
|
||||
else {
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 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.beans.factory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Thrown when a bean doesn't match the expected type.
|
||||
@@ -45,8 +46,8 @@ public class BeanNotOfRequiredTypeException extends BeansException {
|
||||
* the expected type
|
||||
*/
|
||||
public BeanNotOfRequiredTypeException(String beanName, Class<?> requiredType, Class<?> actualType) {
|
||||
super("Bean named '" + beanName + "' must be of type [" + requiredType.getName() +
|
||||
"], but was actually of type [" + actualType.getName() + "]");
|
||||
super("Bean named '" + beanName + "' is expected to be of type '" + ClassUtils.getQualifiedName(requiredType) +
|
||||
"' but was actually of type '" + ClassUtils.getQualifiedName(actualType) + "'");
|
||||
this.beanName = beanName;
|
||||
this.requiredType = requiredType;
|
||||
this.actualType = actualType;
|
||||
|
||||
+6
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -46,8 +46,8 @@ public class CannotLoadBeanClassException extends FatalBeanException {
|
||||
public CannotLoadBeanClassException(
|
||||
String resourceDescription, String beanName, String beanClassName, ClassNotFoundException cause) {
|
||||
|
||||
super("Cannot find class [" + beanClassName + "] for bean with name '" + beanName +
|
||||
"' defined in " + resourceDescription, cause);
|
||||
super("Cannot find class [" + beanClassName + "] for bean with name '" + beanName + "'" +
|
||||
(resourceDescription != null ? " defined in " + resourceDescription : ""), cause);
|
||||
this.resourceDescription = resourceDescription;
|
||||
this.beanName = beanName;
|
||||
this.beanClassName = beanClassName;
|
||||
@@ -64,8 +64,9 @@ public class CannotLoadBeanClassException extends FatalBeanException {
|
||||
public CannotLoadBeanClassException(
|
||||
String resourceDescription, String beanName, String beanClassName, LinkageError cause) {
|
||||
|
||||
super("Error loading class [" + beanClassName + "] for bean with name '" + beanName +
|
||||
"' defined in " + resourceDescription + ": problem with class file or dependent class", cause);
|
||||
super("Error loading class [" + beanClassName + "] for bean with name '" + beanName + "'" +
|
||||
(resourceDescription != null ? " defined in " + resourceDescription : "") +
|
||||
": problem with class file or dependent class", cause);
|
||||
this.resourceDescription = resourceDescription;
|
||||
this.beanName = beanName;
|
||||
this.beanClassName = beanClassName;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user