mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
799 Commits
4.0.x
...
v4.1.0.RC2
| Author | SHA1 | Date | |
|---|---|---|---|
| c125f44d17 | |||
| 8b86519b94 | |||
| 66250b1f8e | |||
| b3add794d7 | |||
| d2e269e697 | |||
| 69587f3fa4 | |||
| eb0ab8431b | |||
| e753f23110 | |||
| e6d16148e5 | |||
| e142fd11e0 | |||
| ebc726a915 | |||
| 181299cc6c | |||
| f4c23d8715 | |||
| 2cbd5ba993 | |||
| 3e2138855a | |||
| f2ac02566c | |||
| 2cf4147ba8 | |||
| 6665634675 | |||
| 92bd240474 | |||
| 626a5fe4eb | |||
| 887815f4fa | |||
| fd5dbddac4 | |||
| 8dbfa80b13 | |||
| 71c6eb2bb5 | |||
| f1f1c4c980 | |||
| f56000b825 | |||
| 29cb7808f2 | |||
| d6fd40d6dc | |||
| 01cbf9b9ee | |||
| ac8326d2df | |||
| 4db258b9e3 | |||
| d100eef829 | |||
| c0ea87010f | |||
| d6370965eb | |||
| e2aba3d317 | |||
| 7c57424b48 | |||
| a05b748d42 | |||
| c06ac06bdd | |||
| 6b6ca4889b | |||
| 5cbb1fc498 | |||
| 562916b69c | |||
| cbda722329 | |||
| e08c56fcae | |||
| 53192bb6f4 | |||
| 5b35fc2d77 | |||
| ad475ffadf | |||
| 47006eeff1 | |||
| c1d149591a | |||
| f2e4ad2364 | |||
| ef51d4dbdb | |||
| a635c36470 | |||
| 4a1a622004 | |||
| 3a419872c8 | |||
| 5862ddc869 | |||
| 3227569a38 | |||
| 0b2c0cfb4f | |||
| e010309530 | |||
| 3922f6fc53 | |||
| 095bd99951 | |||
| c29937196f | |||
| d0e6f0f73f | |||
| ebc5fea77b | |||
| d6b1cdc55f | |||
| 3c72849ee4 | |||
| 59c5d7d1ca | |||
| 32975be2a2 | |||
| 3da68cfe21 | |||
| 6cfe76eeec | |||
| 154cf5dc7e | |||
| b5e1198bd2 | |||
| a11b62540a | |||
| fe88b6e054 | |||
| 28c70baf61 | |||
| 95e9b380d3 | |||
| 7d1e33d88d | |||
| 25decee1a4 | |||
| 87273d1b83 | |||
| 70ccbbfab1 | |||
| 5859649af7 | |||
| c4d7976c37 | |||
| e4182da4eb | |||
| 8751936b12 | |||
| 813cc3b339 | |||
| 135a3ff3d8 | |||
| 41cdc92fc3 | |||
| c68b4c01e1 | |||
| ba952ca331 | |||
| 057efa0676 | |||
| 9fe7780865 | |||
| ce5ce77283 | |||
| c7babab2dd | |||
| 515b9649fa | |||
| 16273473cb | |||
| f50cb06dc2 | |||
| 20c9a8bad4 | |||
| 8e38b7ede6 | |||
| d30174897d | |||
| 59080ff2b2 | |||
| 968492c28b | |||
| 1fe742addf | |||
| 9be04b3883 | |||
| 3bcfc591e9 | |||
| 89d63eb79b | |||
| 8f484d382e | |||
| 7bc966032b | |||
| d917b8a923 | |||
| 9f3c1cf762 | |||
| f732a441c8 | |||
| 8cc0fa5ae1 | |||
| a3163ceb88 | |||
| 036896a6b8 | |||
| 7971f6b638 | |||
| 9bf73f3ab8 | |||
| f862a009a7 | |||
| 9fa4dad13c | |||
| 92c657e12d | |||
| b6389a6c66 | |||
| c89325b9ca | |||
| 0ad5de3f77 | |||
| 5a483f347a | |||
| d144e2918e | |||
| 0d4526e050 | |||
| 170d6c9fb9 | |||
| 0a46f38527 | |||
| 105a6023b3 | |||
| 35c372f200 | |||
| d4fe732f46 | |||
| 88d8dff3ac | |||
| afb56681ac | |||
| e74ac06733 | |||
| 78484129f5 | |||
| b75eb60943 | |||
| fe05e7e5b3 | |||
| 0ce90f1d16 | |||
| 496492b2d8 | |||
| df3b1f2565 | |||
| 8d8d47fb4e | |||
| e849bc3e90 | |||
| 7ce709309d | |||
| db5cebc681 | |||
| d9e0b292ab | |||
| 5be1ff281c | |||
| b56703eadc | |||
| 105ea196e4 | |||
| 1b53882f55 | |||
| 73267d7523 | |||
| 71b63cd972 | |||
| 988499f7dc | |||
| 6c4aff4c9d | |||
| 9092102a83 | |||
| e41b14449e | |||
| f0bcb773f9 | |||
| c082220b34 | |||
| 5e2fbe7355 | |||
| 4b09fcc67c | |||
| 3013558e3d | |||
| dd2bf28a4f | |||
| a10537447e | |||
| 7d2ef69c6d | |||
| 97dad7e2ea | |||
| b16e6cc44e | |||
| 526b4b647f | |||
| da324e3984 | |||
| 9d6c38bd54 | |||
| 188e58c46a | |||
| 3be190df6a | |||
| a9100c427c | |||
| 3e5946db37 | |||
| 7808996d71 | |||
| 829d204663 | |||
| 7412d43acd | |||
| 682e8fb3ad | |||
| dd713c70aa | |||
| 90f8e4b71f | |||
| 29c6c9a375 | |||
| 27153b2982 | |||
| 84c11a5cc7 | |||
| 52f1be7ade | |||
| 1ad22b922f | |||
| 0bbb7704b5 | |||
| 0e2c5ee96c | |||
| dfcc1d7e8c | |||
| 7f7fd7d311 | |||
| 61ec8fd236 | |||
| 2e75adb04c | |||
| 44e4569150 | |||
| 59f39706dc | |||
| e8d8c3390a | |||
| d23b0fec0c | |||
| 80f4ea13c7 | |||
| b18ed6b724 | |||
| dfcb2a2875 | |||
| 91c9bad12e | |||
| c290839914 | |||
| 48fea0bafa | |||
| a53987ace1 | |||
| da5b0b97d3 | |||
| 5cb046da3d | |||
| a488515097 | |||
| 6d6f008faa | |||
| c1a2f5efa4 | |||
| fac0599aef | |||
| 35226695eb | |||
| bbfc31b11f | |||
| 628806e85b | |||
| 4e25a14f6c | |||
| 86e8bdab6b | |||
| b1b7f8ab1f | |||
| 980f971236 | |||
| bad74dc836 | |||
| 8fb592712c | |||
| d6950d8add | |||
| 89b202029a | |||
| c2b0fac852 | |||
| d86e4cf203 | |||
| ea7ae8949e | |||
| c18b6bf0b7 | |||
| bbf5800831 | |||
| 10a4c2cd81 | |||
| be4d73e92d | |||
| 4dd5c274a0 | |||
| 6d6cc0ecec | |||
| 85c175059a | |||
| 61e77eeb61 | |||
| 6557800f97 | |||
| 2665d56209 | |||
| a4968b9015 | |||
| ab2526a586 | |||
| 928a466b5d | |||
| b676c41805 | |||
| 29bdbceaa2 | |||
| 5e1a5c8d51 | |||
| f54cee47b0 | |||
| 5bc793768c | |||
| cc7e8f5558 | |||
| a26b1ef8d9 | |||
| 92402e7715 | |||
| b318880661 | |||
| 85cdb9196e | |||
| 2ba8fd7e59 | |||
| 2c77de10dd | |||
| 2f371e5aeb | |||
| f8e4547228 | |||
| 670c216d38 | |||
| 2ebc921545 | |||
| d73c1d5693 | |||
| 6937eea48a | |||
| 2eeb2e9235 | |||
| e254b558f0 | |||
| bf7dac5fc8 | |||
| f11815c960 | |||
| 2bd6e24b65 | |||
| 29f6f3d7e7 | |||
| eaad0a0f52 | |||
| 6f062581a6 | |||
| 0d4ff1adbf | |||
| fa4f51c5d0 | |||
| 1fadd1c954 | |||
| bf9ccc8138 | |||
| 3c726aa6c1 | |||
| 777085bbfc | |||
| a6a86b8025 | |||
| fa33ed4b4b | |||
| 0d5c5a3d33 | |||
| 19760f9eb9 | |||
| a4484bb767 | |||
| bc62d63fdd | |||
| 48236be4a2 | |||
| ab4864da2a | |||
| b78b2e9a03 | |||
| ea16ce0aa0 | |||
| 01264dc673 | |||
| 1115374188 | |||
| b559f15a00 | |||
| 387da221c3 | |||
| 6bcb48f95d | |||
| e549103ca0 | |||
| 55c351523d | |||
| 4082274630 | |||
| 1222ca38fb | |||
| e20ac27fb4 | |||
| a8848cb670 | |||
| 11532794f4 | |||
| b9a70c6000 | |||
| 6fd0fc7005 | |||
| 6c41cc354c | |||
| 7a7641bd23 | |||
| 4e257243f2 | |||
| 58955236ee | |||
| b6a7957dc4 | |||
| c2da846732 | |||
| 134e5a2aec | |||
| b5a5fffdfd | |||
| af13310da0 | |||
| 0d710f197e | |||
| 62351e0f6e | |||
| bdceaa481b | |||
| 90f0d14c8e | |||
| f667e43ca2 | |||
| 526b463474 | |||
| 6d15fcc4a6 | |||
| 59e02e63c4 | |||
| 5614e257d1 | |||
| c84b30d4a4 | |||
| ea4a5d4722 | |||
| 87cbade8be | |||
| 367b0394a2 | |||
| 32b87079cb | |||
| 476864f3e9 | |||
| 9e52004222 | |||
| d870b382da | |||
| d3a87a13f7 | |||
| f6fbdafb6a | |||
| b7984f21d8 | |||
| ec4e6e0b0e | |||
| 7a1f19b96c | |||
| ce20abde51 | |||
| 083d415fc4 | |||
| 669386abac | |||
| c60c1cec45 | |||
| f40d67cfec | |||
| ba522e5e55 | |||
| 5ed20d21b1 | |||
| 49e960c151 | |||
| f8b6114440 | |||
| 0451232eb4 | |||
| 7497391497 | |||
| e90143e03b | |||
| 9c46cb6f49 | |||
| 37ba1b966e | |||
| 06d3e1b94e | |||
| db616dc438 | |||
| cee53e9330 | |||
| 71b942698d | |||
| b1aebb2c0c | |||
| 974bd43f28 | |||
| fab67b0595 | |||
| cb40908a7d | |||
| 2b1ff4c5db | |||
| 9880d2b5f4 | |||
| 7441f23012 | |||
| 7da3fb4ce6 | |||
| 7dc2b2927e | |||
| 3af488a701 | |||
| 86de416908 | |||
| fac2d80054 | |||
| 0232739293 | |||
| 1c91a52639 | |||
| 9aa53abdf9 | |||
| 045d7357d5 | |||
| cab0b97a83 | |||
| 7a5b3c1eed | |||
| 682a910bb6 | |||
| b0979cbab6 | |||
| 17d15cc495 | |||
| bc714888c4 | |||
| 113fd1180a | |||
| b2f6445058 | |||
| 24cdefb785 | |||
| 8221c9abc5 | |||
| 442bd682a7 | |||
| a9b650fd0f | |||
| 9796af72db | |||
| a3fa9c9797 | |||
| 98d6f7b443 | |||
| 35067790f3 | |||
| 46dc07a005 | |||
| 50b21d061f | |||
| 158cb346a5 | |||
| e73b8b31f8 | |||
| 8ea0d8eea1 | |||
| cc917de24d | |||
| b3e3c5312f | |||
| 591f79514d | |||
| 9919a98231 | |||
| 0f47732523 | |||
| 502022acca | |||
| 6ad79e03c6 | |||
| 3ed9885dc5 | |||
| 1e342e4dbf | |||
| 5d2e6f6d4c | |||
| fcf6ae8328 | |||
| e82df99a22 | |||
| dc1d85d045 | |||
| c14ba1a0ff | |||
| c86f711de5 | |||
| b6255128bf | |||
| d239016a8c | |||
| f966bf683c | |||
| 779ca99f38 | |||
| b4e16eacc5 | |||
| 2d892da641 | |||
| 938a2846c8 | |||
| d6635802c4 | |||
| a6f3f101e4 | |||
| 13c4a0396d | |||
| 18131bf611 | |||
| 2c0c081bbb | |||
| fd809cd18e | |||
| f1517f03ff | |||
| 0c1249fe42 | |||
| abdb010fc8 | |||
| d801f9da89 | |||
| dfc370c368 | |||
| 03f3412434 | |||
| 6f68b034ca | |||
| ab5aea5a13 | |||
| bc1f19ce18 | |||
| cff36d68b1 | |||
| ef25b9e7af | |||
| 88eabe874c | |||
| bb4a9cca1b | |||
| cf9d519e97 | |||
| 0640a32863 | |||
| 38b525aa9e | |||
| 0dc6082b01 | |||
| c2356e57c8 | |||
| 4d328d6188 | |||
| 98a224fed9 | |||
| 72baa9bf27 | |||
| e18e44980d | |||
| 9f4d4d1829 | |||
| c809143cc4 | |||
| d746e3fbfa | |||
| ce0473f926 | |||
| f829cd1b35 | |||
| 80a16c6d10 | |||
| 014ea963fe | |||
| 0dc52a8343 | |||
| 9ba9f562f2 | |||
| b214db3fc8 | |||
| 6b129c52e3 | |||
| 2140648246 | |||
| 5b02222a9f | |||
| 0ecfa8e404 | |||
| 6b6b008c1f | |||
| 5cc779ab35 | |||
| d1c780f5b5 | |||
| c7b106577f | |||
| 2ede219e66 | |||
| fc91add35e | |||
| 0cb6f8c88c | |||
| 5dc27ee134 | |||
| 56a82c1cbe | |||
| e374769ecc | |||
| f442ce180e | |||
| af4621d996 | |||
| ea346d59b3 | |||
| ae66e45887 | |||
| 85b2c7d116 | |||
| de1a41ac27 | |||
| c269d27bde | |||
| 9706e5cc99 | |||
| 5cb3f8eada | |||
| 7d03daf8cb | |||
| 6aa9c40552 | |||
| bb8d0f1740 | |||
| abc377603d | |||
| f48bdafd52 | |||
| 56ad0cf3e1 | |||
| f2c37fcdb4 | |||
| ae29f48f5f | |||
| 5fd6ebb548 | |||
| 8fb0f5c7d1 | |||
| 5a8e470ede | |||
| 2cf88ac6a3 | |||
| f7b465390c | |||
| 77cbc53d1e | |||
| 8b8afe3def | |||
| 001d0e734c | |||
| 64bb308763 | |||
| 674bad4cfa | |||
| aaae10ce3b | |||
| c9d0ebd730 | |||
| 2655c507e0 | |||
| 5eecb138f6 | |||
| 31f2f20307 | |||
| b4954780aa | |||
| 4372dac002 | |||
| 0dddb6f3e1 | |||
| 5ed9bedf32 | |||
| e4aabd5288 | |||
| 4e17685008 | |||
| e4ad9c5204 | |||
| 987806f7c2 | |||
| 8ee94a4392 | |||
| 4b291c665c | |||
| d46b29e71f | |||
| 12a9df8a1c | |||
| 8dec1db914 | |||
| 3944f7ad97 | |||
| 6966e89578 | |||
| e3e8a3eb40 | |||
| 8220832c4e | |||
| 22a38d4547 | |||
| d9f8ee886e | |||
| 8f2ed66b4a | |||
| bb6e07bd3a | |||
| 05041ff39a | |||
| 9fabcad3dd | |||
| 31c07dbfa4 | |||
| 8d306bfbc0 | |||
| e3a6fce403 | |||
| bc3ca2dea1 | |||
| 811330f5c8 | |||
| 9952973e01 | |||
| 1338d46a6e | |||
| 05e96ee448 | |||
| c7d1c49d6d | |||
| 6fef8b996c | |||
| 8e096aeef5 | |||
| 61b47ba7d9 | |||
| a16eeabc4e | |||
| d9b39ad691 | |||
| 73c9d09024 | |||
| 03ce4a5024 | |||
| cfc720db25 | |||
| 295a6aeed6 | |||
| 1285467fe6 | |||
| 51fc3b4aaf | |||
| 96b18c8dc2 | |||
| f73a8baec7 | |||
| 2619955fc3 | |||
| 41ed228450 | |||
| 6188550a48 | |||
| 3c45bc4a50 | |||
| 7469159bf1 | |||
| 82336c320d | |||
| f29d6eb5f6 | |||
| ea88bc2c81 | |||
| 5faacd5a3d | |||
| 52f44b340e | |||
| be0b69cbf1 | |||
| 673a497923 | |||
| 8ee4651038 | |||
| 3bdf8aefa9 | |||
| 0499fcbeb2 | |||
| 8614df8bd4 | |||
| 0d22719e06 | |||
| 7230d6a1aa | |||
| 6560aed1c8 | |||
| b0f0d2f289 | |||
| 0728e32e7f | |||
| 551950cdc0 | |||
| f651065b5e | |||
| a072b3f20d | |||
| eb65a37f4b | |||
| 04e6575db6 | |||
| 2750ab6734 | |||
| b43fc7ac0f | |||
| b64b308f62 | |||
| e04fb15a5e | |||
| 782d10c66f | |||
| 2c4cbb617e | |||
| 66c63c374b | |||
| b4d447fc3d | |||
| 89fc3c0257 | |||
| 49040a2925 | |||
| 6a0483128a | |||
| 97fb308b6b | |||
| 3c7bb9c279 | |||
| 6c1f8de5fa | |||
| 8c9116fd4b | |||
| 580e52372f | |||
| 7b7fe9aa17 | |||
| 98738c0bbb | |||
| 426b77b834 | |||
| 9d479feadd | |||
| 381ccde48d | |||
| bea34ea41c | |||
| db5d651057 | |||
| 43e4dbadfe | |||
| e246010df7 | |||
| e18308851d | |||
| 371e3a7ac0 | |||
| 658f7f58df | |||
| ae30a60d03 | |||
| 5a1b7c6ce7 | |||
| 6551aa61fa | |||
| cb2834c10a | |||
| 8e1a5b9999 | |||
| f2991da6d6 | |||
| 676282c66e | |||
| 0d2aa51576 | |||
| c50887c877 | |||
| 9598a1e2ef | |||
| 088b80f4c5 | |||
| a653c06711 | |||
| a842b933a9 | |||
| 842a8a851d | |||
| 39e1342302 | |||
| 5dcd55b23b | |||
| d52f07aa1b | |||
| 1958ae3a62 | |||
| 209bb4ee4b | |||
| bd85c916eb | |||
| e84f61bb9d | |||
| adb616b67b | |||
| c124d3b6c6 | |||
| 90081f787f | |||
| 6a9b229249 | |||
| c879796e00 | |||
| 1054080b24 | |||
| 02aca9c754 | |||
| 58adc150c9 | |||
| 56d26443e2 | |||
| 13be6d2321 | |||
| 01fe2923ee | |||
| dc2e62fab9 | |||
| 1b2014a52d | |||
| e510f6393a | |||
| a0658c5832 | |||
| 26a9c4bc01 | |||
| 77a250ef92 | |||
| 59a050f3b9 | |||
| 86785f340e | |||
| be5f2a8b4e | |||
| ab24dda4ff | |||
| ce4912b627 | |||
| 8e6e6c22af | |||
| 299776fd80 | |||
| 0ef29b204b | |||
| 6f2e61b19f | |||
| 63733c4805 | |||
| 6cb45f714e | |||
| ce1954da1e | |||
| 310bdbcb15 | |||
| 1f630a5fb9 | |||
| e24b876164 | |||
| 70fd33236f | |||
| 1200755125 | |||
| 564a555619 | |||
| c319b5fa82 | |||
| 09341b996e | |||
| f5cbd9aa4a | |||
| 6aa16b745f | |||
| c4843577ba | |||
| bded025d9f | |||
| 4b0aba63df | |||
| 08f0395033 | |||
| 9353332a61 | |||
| c05ab3e2e8 | |||
| ec7d80b851 | |||
| 21f9ca088d | |||
| b1158aa913 | |||
| 9cb5f48459 | |||
| 794e859e68 | |||
| 5b47816183 | |||
| fb66567bba | |||
| 6b20439202 | |||
| 3f392e32f5 | |||
| 700c3b257f | |||
| 5ab7076118 | |||
| 945335d14b | |||
| 10e1a80540 | |||
| 3d18cfeab6 | |||
| cd13b4882c | |||
| 16410cad4d | |||
| 5559209233 | |||
| 36456f0f62 | |||
| 1e8c799a60 | |||
| 21de937b2f | |||
| 404eb48f95 | |||
| 7cbfc4d2f8 | |||
| 4ff1e197e3 | |||
| 917e044e54 | |||
| d00d0b0274 | |||
| b3492f61c2 | |||
| 84f6d17c7b | |||
| 54db2fba48 | |||
| 5ae1c8a242 | |||
| 75d4512326 | |||
| e98d3f790b | |||
| c15997340b | |||
| eb5f397a39 | |||
| 9ca9363c2f | |||
| fc3df29b2e | |||
| e014608e99 | |||
| 7a7be598c2 | |||
| 408fe42df2 | |||
| 5365171f24 | |||
| 66bae99d86 | |||
| 566e0fb317 | |||
| e1720d89fc | |||
| a0b6175d78 | |||
| 50c5cc0bd2 | |||
| 3a5de00c41 | |||
| 1697cd15b2 | |||
| a5e1932c2c | |||
| 086f1eda71 | |||
| 48c977afdc | |||
| 28887750b0 | |||
| 47c57a84c5 | |||
| 4612559446 | |||
| 713dd60fa7 | |||
| 6cb9a144db | |||
| f5cce14fe7 | |||
| 53162e78e4 | |||
| 90309ab0b5 | |||
| 7bc2168aa7 | |||
| 637ad20cd3 | |||
| 49e3c2a0c7 | |||
| 973780efd5 | |||
| 9a59292603 | |||
| 397aa82984 | |||
| 4e1781ae8c | |||
| 95e25d4e6f | |||
| 09248a0b37 | |||
| 65b17b80ba | |||
| 1369ff4d84 | |||
| fda9c633c4 | |||
| ae942ffdb8 | |||
| 4867546aec | |||
| b4995f7e4f | |||
| 84f678a06b | |||
| 8fecee8c8a | |||
| 910dd41467 | |||
| 1753f5d1ca | |||
| cc0ae3a881 | |||
| 2a937a369e | |||
| 49916bb7eb | |||
| 14f9dbf70c | |||
| ba3c7e588f | |||
| 3fef35879d | |||
| 37679384e8 | |||
| 1bbc55d63c | |||
| 5df60a2bec | |||
| e1a1e1205f | |||
| b308659cda | |||
| a281bdbfc5 | |||
| 196cdef182 | |||
| a167a1b591 | |||
| 9e1631db03 | |||
| 0041e245a1 | |||
| d4b0ae9787 | |||
| 8f28a9352e | |||
| 8d8766dda9 | |||
| 1f2d5b5d89 | |||
| 2b89c1a87e | |||
| 3cda355e7f | |||
| 0bdece700f | |||
| d53b498839 | |||
| a1486e46c8 | |||
| a198026469 | |||
| 7b5e9e8c8e | |||
| f3b8a4103e | |||
| 47a4327193 | |||
| 4cd075bb96 | |||
| 711c95d7d2 | |||
| d9ee44cd7c | |||
| 0eba1f818f | |||
| 2e674c24f8 | |||
| ddf8750511 | |||
| 1eee339c15 | |||
| 5e925ac03c | |||
| ec0b672baa | |||
| 990f5bb720 | |||
| 3e74d3b2fb | |||
| 8ed490c4d7 | |||
| 8006696613 | |||
| 3a96f16654 | |||
| 54f66e451d | |||
| fd5672cba1 | |||
| db23ec733b | |||
| 59703981c4 | |||
| 89a4c291c3 | |||
| 8e89aff48f | |||
| 1f017c4acb | |||
| 8edbdf4ddb | |||
| a6b167dd48 | |||
| 8ab8448148 | |||
| 73ecbc047c | |||
| a805f12374 | |||
| ea762b2c74 | |||
| 6ec3de6029 | |||
| fb7d81c4a2 | |||
| 119dfd9cf9 | |||
| dcf5f4a6a3 | |||
| 5fe8f52c02 | |||
| 48221798f5 | |||
| 3c28301ded | |||
| 6a8cf28665 | |||
| f06cad91c0 | |||
| 81c208098f | |||
| 906321dcdd | |||
| 5d049e0de8 | |||
| b766686c40 | |||
| c38600762d | |||
| 34eb4dba3a | |||
| 6aaae7e258 | |||
| db66ef0f6f | |||
| 75439c7836 | |||
| e3ef3fffa5 | |||
| ace6bd2418 | |||
| ea1e27efa2 | |||
| 5c577451f3 | |||
| d19e30e2f8 | |||
| c924d659eb | |||
| 0b115d7a1e |
@@ -0,0 +1,14 @@
|
||||
Juergen Hoeller <jhoeller@vmware.com> jhoeller <jhoeller@vmware.com>
|
||||
<rstoyanchev@gopivotal.com> <rstoyanchev@vmware.com>
|
||||
<pwebb@gopivotal.com> <pwebb@vmware.com>
|
||||
<cbeams@gopivotal.com> <cbeams@vmware.com>
|
||||
<cbeams@gopivotal.com> <cbeams@gmail.com>
|
||||
<apoutsma@gopivotal.com> <apoutsma@vmware.com>
|
||||
<apoutsma@gopivotal.com> <poutsma@mac.com>
|
||||
<ogierke@gopivotal.com> <ogierke@vmware.com>
|
||||
<dsyer@gopivotal.com> <david_syer@hotmail.com>
|
||||
<dsyer@gopivotal.com> <dsyer@vmware.com>
|
||||
<aclement@gopivotal.com> <andrew.clement@gmail.com>
|
||||
<aclement@gopivotal.com> <aclement@vmware.com>
|
||||
<dmitry.katsubo@gmail.com> <dmitry.katsubo@gmai.com>
|
||||
Nick Williams <nicholas@nicholaswilliams.net> Nicholas Williams <nicholas@nicholaswilliams.net>
|
||||
+279
-129
@@ -3,40 +3,65 @@ buildscript {
|
||||
maven { url "http://repo.springsource.org/plugins-release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.5")
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
|
||||
classpath("org.asciidoctor:asciidoctor-gradle-plugin:0.7.0")
|
||||
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.8")
|
||||
classpath("io.spring.gradle:docbook-reference-plugin:0.3.0")
|
||||
classpath("ws.antonov.gradle.plugins:gradle-plugin-protobuf:0.9.1")
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
linkHomepage = 'https://projects.spring.io/spring-framework'
|
||||
linkCi = 'https://build.spring.io/browse/SPR'
|
||||
linkIssue = 'https://jira.spring.io/browse/SPR'
|
||||
linkScmUrl = 'https://github.com/spring-projects/spring-framework'
|
||||
linkScmConnection = 'scm:git:git://github.com/spring-projects/spring-framework.git'
|
||||
linkScmDevConnection = 'scm:git:ssh://git@github.com:spring-projects/spring-framwork.git'
|
||||
}
|
||||
|
||||
configure(allprojects) { project ->
|
||||
group = "org.springframework"
|
||||
version = qualifyVersionIfNecessary(version)
|
||||
|
||||
ext.aspectjVersion = "1.7.4"
|
||||
ext.groovyVersion = "1.8.9"
|
||||
ext.aspectjVersion = "1.8.1"
|
||||
ext.eclipseLinkVersion = "2.4.2"
|
||||
ext.ehcacheVersion = "2.8.3"
|
||||
ext.ehcacheJCacheVersion = "1.0.0"
|
||||
ext.groovyVersion = "2.3.6"
|
||||
ext.hibernate3Version = "3.6.10.Final"
|
||||
ext.hibernate4Version = "4.2.11.Final"
|
||||
ext.hibValVersion = "4.3.1.Final"
|
||||
ext.hibernate4Version = "4.3.6.Final"
|
||||
ext.hibVal4Version = "4.3.2.Final"
|
||||
ext.hibVal5Version = "5.1.2.Final"
|
||||
ext.hsqldbVersion = "2.3.2"
|
||||
ext.jackson1Version = "1.9.13"
|
||||
ext.jackson2Version = "2.3.1"
|
||||
ext.jasperReportsVersion = "5.5.1"
|
||||
ext.jettyVersion = "9.1.3.v20140225"
|
||||
ext.jodaVersion = "2.3"
|
||||
ext.jackson2Version = "2.4.1"
|
||||
ext.gsonVersion = "2.3"
|
||||
ext.jasperReportsVersion = "5.6.0"
|
||||
ext.jettyVersion = "9.2.2.v20140723"
|
||||
ext.jodaVersion = "2.4"
|
||||
ext.junitVersion = "4.11"
|
||||
ext.slf4jVersion = "1.7.6"
|
||||
ext.openJpaVersion = "2.2.2" // 2.3.0 not Java 8 compatible (based on ASM 4)
|
||||
ext.slf4jVersion = "1.7.7"
|
||||
ext.snakeYamlVersion = "1.13"
|
||||
ext.snifferVersion = "1.11"
|
||||
ext.tiles2Version = "2.2.2"
|
||||
ext.tiles3Version = "3.0.3"
|
||||
ext.tiles3Version = "3.0.4"
|
||||
ext.tomcatVersion = "8.0.9"
|
||||
ext.xstreamVersion = "1.4.7"
|
||||
ext.protobufVersion = "2.5.0"
|
||||
ext.woodstoxVersion = "4.1.6"
|
||||
|
||||
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"
|
||||
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"
|
||||
|
||||
apply plugin: "propdeps"
|
||||
apply plugin: "java"
|
||||
apply plugin: "test-source-set-dependencies"
|
||||
apply from: "${gradleScriptDir}/ide.gradle"
|
||||
|
||||
configurations {
|
||||
sniffer
|
||||
javaApiSignature
|
||||
}
|
||||
|
||||
compileJava.options*.compilerArgs = [
|
||||
"-Xlint:serial", "-Xlint:varargs", "-Xlint:cast", "-Xlint:classfile",
|
||||
"-Xlint:dep-ann", "-Xlint:divzero", "-Xlint:empty", "-Xlint:finally",
|
||||
@@ -58,8 +83,9 @@ configure(allprojects) { project ->
|
||||
}
|
||||
|
||||
compileTestJava {
|
||||
sourceCompatibility=1.7
|
||||
targetCompatibility=1.7
|
||||
sourceCompatibility=1.8
|
||||
targetCompatibility=1.8
|
||||
options.compilerArgs += "-parameters"
|
||||
}
|
||||
|
||||
sourceSets.test.resources.srcDirs = ["src/test/resources", "src/test/java"]
|
||||
@@ -71,14 +97,12 @@ configure(allprojects) { project ->
|
||||
include(["**/*Tests.class", "**/*Test.class"])
|
||||
// Since we set scanForTestClasses to false, we need to filter out inner
|
||||
// classes with the "$" pattern; otherwise, using -Dtest.single=MyTests to
|
||||
// run MyTests by itself will fail if MyTests contains any inner classes.
|
||||
// run MyTests by itself will fail if MyTests contains any inner classes.
|
||||
exclude(["**/Abstract*.class", '**/*$*'])
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url "http://repo.spring.io/libs-release" }
|
||||
maven { url "http://repo.spring.io/milestone" } // for AspectJ 1.8.0.M1
|
||||
maven { url "https://oss.sonatype.org/content/repositories/releases" } // javax.cache
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -89,12 +113,53 @@ configure(allprojects) { project ->
|
||||
exclude group:'org.hamcrest', module:'hamcrest-core'
|
||||
}
|
||||
testCompile("org.hamcrest:hamcrest-all:1.3")
|
||||
testCompile("org.mockito:mockito-core:1.9.5")
|
||||
|
||||
sniffer("org.codehaus.mojo:animal-sniffer-ant-tasks:${snifferVersion}")
|
||||
javaApiSignature("org.codehaus.mojo.signature:java16:1.1@signature") // as from JDK 6 update 18
|
||||
}
|
||||
|
||||
task copyJavaApiSignature(type: Copy) {
|
||||
ext.to = file("$buildDir/javaApiSignature/")
|
||||
description "Copy the resolved Animal Sniffer signature dependency artifact to a known location and name"
|
||||
from configurations.javaApiSignature
|
||||
into to
|
||||
rename '.*signature', 'javaApi.signature'
|
||||
}
|
||||
|
||||
task sniff {
|
||||
group = "Verification"
|
||||
description = "Checks the Java API signatures"
|
||||
|
||||
dependsOn compileJava
|
||||
dependsOn copyJavaApiSignature
|
||||
|
||||
inputs.dir sourceSets.main.output.classesDir
|
||||
inputs.dir copyJavaApiSignature.to
|
||||
outputs.upToDateWhen { true }
|
||||
|
||||
doLast {
|
||||
ant.taskdef(
|
||||
name: 'animalSniffer',
|
||||
classname: 'org.codehaus.mojo.animal_sniffer.ant.CheckSignatureTask',
|
||||
classpath: configurations.sniffer.asPath
|
||||
)
|
||||
|
||||
ant.animalSniffer(
|
||||
signature: "$buildDir/javaApiSignature/javaApi.signature",
|
||||
classpath: sourceSets.main.compileClasspath.asPath) {
|
||||
path(path: sourceSets.main.output.classesDir)
|
||||
annotation(className: "org.springframework.lang.UsesJava7")
|
||||
annotation(className: "org.springframework.lang.UsesJava8")
|
||||
annotation(className: "org.springframework.lang.UsesSunHttpServer")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ext.javadocLinks = [
|
||||
"http://docs.oracle.com/javase/7/docs/api/",
|
||||
"http://docs.oracle.com/javaee/6/api/",
|
||||
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
|
||||
"http://docs.oracle.com/javase/8/docs/api/",
|
||||
"http://docs.oracle.com/javaee/7/api/",
|
||||
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
|
||||
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
|
||||
"http://glassfish.java.net/nonav/docs/v3/api/",
|
||||
"http://docs.jboss.org/jbossas/javadoc/4.0.5/connector/",
|
||||
@@ -108,11 +173,10 @@ configure(allprojects) { project ->
|
||||
"http://aopalliance.sourceforge.net/doc/",
|
||||
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
|
||||
"http://ehcache.org/apidocs/",
|
||||
"http://quartz-scheduler.org/api/2.1.7/",
|
||||
"http://jackson.codehaus.org/1.9.4/javadoc/",
|
||||
"http://quartz-scheduler.org/api/2.2.0/",
|
||||
"http://fasterxml.github.com/jackson-core/javadoc/2.3.0/",
|
||||
"http://fasterxml.github.com/jackson-databind/javadoc/2.3.0/",
|
||||
"http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs"
|
||||
"http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/"
|
||||
] as String[]
|
||||
}
|
||||
|
||||
@@ -120,6 +184,20 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
|
||||
apply plugin: "merge"
|
||||
apply from: "${gradleScriptDir}/publish-maven.gradle"
|
||||
|
||||
configurations {
|
||||
jacoco
|
||||
}
|
||||
|
||||
dependencies {
|
||||
jacoco("org.jacoco:org.jacoco.agent:0.7.1.201405082137:runtime")
|
||||
}
|
||||
|
||||
gradle.taskGraph.whenReady {taskGraph ->
|
||||
if (taskGraph.hasTask(':sonarRunner')) {
|
||||
test.jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=org.springframework.*"
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest.attributes["Created-By"] =
|
||||
"${System.getProperty("java.version")} (${System.getProperty("java.specification.vendor")})"
|
||||
@@ -243,11 +321,13 @@ project("spring-core") {
|
||||
|
||||
compile(files(cglibRepackJar))
|
||||
compile("commons-logging:commons-logging:1.1.3")
|
||||
optional("commons-codec:commons-codec:1.9")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("net.sf.jopt-simple:jopt-simple:4.6")
|
||||
optional("log4j:log4j:1.2.17")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
testCompile("xmlunit:xmlunit:1.5")
|
||||
testCompile("org.codehaus.woodstox:wstx-asl:3.2.7") {
|
||||
testCompile("org.codehaus.woodstox:woodstox-core-asl:${woodstoxVersion}") {
|
||||
exclude group: "stax", module: "stax-api"
|
||||
}
|
||||
}
|
||||
@@ -264,12 +344,6 @@ project("spring-core") {
|
||||
include "org/springframework/objenesis/**"
|
||||
}
|
||||
}
|
||||
|
||||
compileTestJava {
|
||||
sourceCompatibility=1.8
|
||||
targetCompatibility=1.8
|
||||
compileTestJava.options.compilerArgs += "-parameters"
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-beans") {
|
||||
@@ -279,9 +353,11 @@ project("spring-beans") {
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
optional("javax.inject:javax.inject:1")
|
||||
optional("javax.el:javax.el-api:2.2.4")
|
||||
optional("javax.el:javax.el-api:2.2.5")
|
||||
optional("org.yaml:snakeyaml:${snakeYamlVersion}")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
}
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-beans-groovy") {
|
||||
@@ -321,7 +397,7 @@ project("spring-aop") {
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("commons-pool:commons-pool:1.6")
|
||||
optional("com.jamonapi:jamon:2.4")
|
||||
optional("com.jamonapi:jamon:2.76")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,12 +447,12 @@ project("spring-context") {
|
||||
optional("javax.enterprise.concurrent:javax.enterprise.concurrent-api:1.0")
|
||||
optional("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
optional("javax.validation:validation-api:1.0.0.GA")
|
||||
optional("org.hibernate:hibernate-validator:${hibValVersion}")
|
||||
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.jruby:jruby:1.7.10")
|
||||
optional("org.jruby:jruby:1.7.12")
|
||||
testCompile("javax.inject:javax.inject-tck:1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.4")
|
||||
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
@@ -384,10 +460,6 @@ project("spring-context") {
|
||||
|
||||
// pick up RmiInvocationWrapperRTD.xml in src/main
|
||||
sourceSets.main.resources.srcDirs += "src/main/java"
|
||||
|
||||
test {
|
||||
jvmArgs = ["-disableassertions:org.aspectj.weaver.UnresolvedType"] // SPR-7989
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-messaging") {
|
||||
@@ -397,8 +469,8 @@ project("spring-messaging") {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-context"))
|
||||
optional("org.projectreactor:reactor-core:1.0.1.RELEASE")
|
||||
optional("org.projectreactor:reactor-tcp:1.0.1.RELEASE")
|
||||
optional("org.projectreactor:reactor-core:1.1.3.RELEASE")
|
||||
optional("org.projectreactor:reactor-net:1.1.3.RELEASE")
|
||||
optional("org.eclipse.jetty.websocket:websocket-server:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet-api"
|
||||
}
|
||||
@@ -417,9 +489,9 @@ project("spring-messaging") {
|
||||
testCompile("org.eclipse.jetty:jetty-webapp:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet-api"
|
||||
}
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.4")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
@@ -458,8 +530,9 @@ project("spring-oxm") {
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
optional("org.codehaus.castor:castor-xml:1.3.2") {
|
||||
optional("org.codehaus.castor:castor-xml:1.3.3") {
|
||||
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'
|
||||
@@ -489,13 +562,13 @@ project("spring-jms") {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-aop"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-messaging"))
|
||||
compile(project(":spring-tx"))
|
||||
provided("javax.jms:jms-api:1.1-rev-1")
|
||||
optional(project(":spring-oxm"))
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("javax.transaction:javax.transaction-api:1.2")
|
||||
optional("javax.resource:connector-api:1.5")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:${jackson1Version}")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
}
|
||||
}
|
||||
@@ -509,11 +582,11 @@ project("spring-jdbc") {
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-context")) // for JndiDataSourceLookup
|
||||
optional("javax.transaction:javax.transaction-api:1.2")
|
||||
optional("c3p0:c3p0:0.9.1.2")
|
||||
optional("com.mchange:c3p0:0.9.2.1")
|
||||
optional("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
optional("com.h2database:h2:1.0.71")
|
||||
optional("org.apache.derby:derby:10.10.1.1")
|
||||
optional("org.apache.derby:derbyclient:10.10.1.1")
|
||||
optional("com.h2database:h2:1.4.180")
|
||||
optional("org.apache.derby:derby:10.10.2.0")
|
||||
optional("org.apache.derby:derbyclient:10.10.2.0")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,23 +599,30 @@ project("spring-context-support") {
|
||||
compile(project(":spring-context"))
|
||||
optional(project(":spring-jdbc")) // for Quartz support
|
||||
optional(project(":spring-tx")) // for Quartz support
|
||||
optional("javax.mail:mail:1.4.7")
|
||||
optional("javax.cache:cache-api:1.0.0-RC1")
|
||||
optional("com.google.guava:guava:16.0.1")
|
||||
optional("net.sf.ehcache:ehcache-core:2.6.5")
|
||||
optional("org.quartz-scheduler:quartz:1.8.6") {
|
||||
exclude group: "org.slf4j", module: "slf4j-log4j12"
|
||||
}
|
||||
optional("javax.mail:javax.mail-api:1.5.2")
|
||||
optional("javax.cache:cache-api:1.0.0")
|
||||
optional("com.google.guava:guava:17.0")
|
||||
optional("net.sf.ehcache:ehcache:${ehcacheVersion}")
|
||||
optional("org.quartz-scheduler:quartz:2.2.1")
|
||||
optional("org.codehaus.fabric3.api:commonj:1.1.0")
|
||||
optional("org.apache.velocity:velocity:1.7")
|
||||
optional("org.freemarker:freemarker:2.3.20")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("net.sf.jasperreports:jasperreports:$jasperReportsVersion")
|
||||
testCompile("org.apache.poi:poi:3.9")
|
||||
optional("net.sf.jasperreports:jasperreports:$jasperReportsVersion") {
|
||||
exclude group: "com.fasterxml.jackson.core", module: "jackson-annotations"
|
||||
exclude group: "com.fasterxml.jackson.core", module: "jackson-core"
|
||||
exclude group: "com.fasterxml.jackson.core", module: "jackson-databind"
|
||||
exclude group: "org.olap4j", module: "olap4j"
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
}
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile("org.apache.poi:poi:3.10-FINAL")
|
||||
testCompile("commons-beanutils:commons-beanutils:1.8.0") // for Velocity/JasperReports
|
||||
testCompile("commons-digester:commons-digester:1.8.1") // for Velocity/JasperReports
|
||||
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
testCompile("org.ehcache:jcache:${ehcacheJCacheVersion}")
|
||||
testRuntime("com.sun.mail:javax.mail:1.5.2")
|
||||
}
|
||||
|
||||
// pick up **/*.types files in src/main
|
||||
@@ -551,6 +631,22 @@ project("spring-context-support") {
|
||||
|
||||
project("spring-web") {
|
||||
description = "Spring Web"
|
||||
apply plugin: "groovy"
|
||||
|
||||
// Re-generate Protobuf classes from *.proto files and move them in test sources
|
||||
if (project.hasProperty('genProtobuf')) {
|
||||
apply plugin: 'protobuf'
|
||||
|
||||
task updateGenProtobuf(type:Copy, dependsOn: ":spring-web:generateTestProto") {
|
||||
from "${project.buildDir}/generated-sources/test/"
|
||||
into "${projectDir}/src/test/java"
|
||||
doLast {
|
||||
project.delete "${project.buildDir}/generated-sources/test"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.getByPath("compileTestJava").dependsOn "updateGenProtobuf"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-aop")) // for JaxWsPortProxyFactoryBean
|
||||
@@ -559,19 +655,20 @@ project("spring-web") {
|
||||
compile(project(":spring-core"))
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional(project(":spring-oxm")) // for MarshallingHttpMessageConverter
|
||||
optional("javax.servlet.jsp:jsp-api:2.2")
|
||||
optional("javax.servlet.jsp:javax.servlet.jsp-api:2.2.1")
|
||||
optional("javax.portlet:portlet-api:2.0")
|
||||
optional("javax.el:javax.el-api:2.2.4")
|
||||
optional("javax.el:javax.el-api:2.2.5")
|
||||
optional("javax.faces:javax.faces-api:2.2")
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("com.caucho:hessian:4.0.7")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("com.caucho:hessian:4.0.38")
|
||||
optional("commons-fileupload:commons-fileupload:1.3.1")
|
||||
optional("org.apache.httpcomponents:httpclient:4.3.3")
|
||||
optional("org.apache.httpcomponents:httpclient:4.3.4")
|
||||
optional("org.apache.httpcomponents:httpasyncclient:4.0.1")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:${jackson1Version}")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
optional("rome:rome:1.0")
|
||||
optional("taglibs:standard:1.1.2")
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}")
|
||||
optional("com.google.code.gson:gson:${gsonVersion}")
|
||||
optional("com.rometools:rome:1.5.0")
|
||||
optional("org.eclipse.jetty:jetty-servlet:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet-api"
|
||||
}
|
||||
@@ -579,9 +676,14 @@ project("spring-web") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet-api"
|
||||
}
|
||||
optional("log4j:log4j:1.2.17")
|
||||
optional("com.googlecode.protobuf-java-format:protobuf-java-format:1.2")
|
||||
optional("com.google.protobuf:protobuf-java:${protobufVersion}")
|
||||
testCompile(project(":spring-context-support")) // for JafMediaTypeFactory
|
||||
testCompile("xmlunit:xmlunit:1.5")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("org.apache.taglibs:taglibs-standard-jstlel:1.2.1") {
|
||||
exclude group: "org.apache.taglibs", module: "taglibs-standard-spec"
|
||||
}
|
||||
}
|
||||
|
||||
// pick up ContextLoader.properties in src/main
|
||||
@@ -599,12 +701,14 @@ project("spring-websocket") {
|
||||
optional(project(":spring-webmvc"))
|
||||
optional("javax.servlet:javax.servlet-api:3.1.0")
|
||||
optional("javax.websocket:javax.websocket-api:1.0")
|
||||
optional("org.apache.tomcat:tomcat-websocket:8.0.3") {
|
||||
optional("org.apache.tomcat:tomcat-websocket:${tomcatVersion}") {
|
||||
exclude group: "org.apache.tomcat", module: "tomcat-websocket-api"
|
||||
exclude group: "org.apache.tomcat", module: "tomcat-servlet-api"
|
||||
}
|
||||
optional("org.glassfish.tyrus:tyrus-websocket-core:1.2.1")
|
||||
optional("org.glassfish.tyrus:tyrus-container-servlet:1.2.1")
|
||||
optional("org.glassfish.tyrus:tyrus-spi:1.3.5")
|
||||
optional("org.glassfish.tyrus:tyrus-core:1.3.5")
|
||||
optional("org.glassfish.tyrus:tyrus-server:1.3.5")
|
||||
optional("org.glassfish.tyrus:tyrus-container-servlet:1.3.5")
|
||||
optional("org.eclipse.jetty:jetty-webapp:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet"
|
||||
}
|
||||
@@ -612,20 +716,21 @@ project("spring-websocket") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet"
|
||||
}
|
||||
optional("org.eclipse.jetty.websocket:websocket-client:${jettyVersion}")
|
||||
optional("io.undertow:undertow-core:1.0.0.Final")
|
||||
optional("io.undertow:undertow-servlet:1.0.0.Final") {
|
||||
optional("org.eclipse.jetty:jetty-client:${jettyVersion}")
|
||||
optional("io.undertow:undertow-core:1.0.15.Final")
|
||||
optional("io.undertow:undertow-servlet:1.0.15.Final") {
|
||||
exclude group: "org.jboss.spec.javax.servlet", module: "jboss-servlet-api_3.1_spec"
|
||||
exclude group: "org.jboss.spec.javax.annotation", module: "jboss-annotations-api_1.2_spec"
|
||||
}
|
||||
optional("io.undertow:undertow-websockets-jsr:1.0.0.Final") {
|
||||
optional("io.undertow:undertow-websockets-jsr:1.0.15.Final") {
|
||||
exclude group: "org.jboss.spec.javax.websocket", module: "jboss-websocket-api_1.0_spec"
|
||||
}
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:8.0.3")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:8.0.3")
|
||||
testCompile("org.projectreactor:reactor-core:1.0.1.RELEASE")
|
||||
testCompile("org.projectreactor:reactor-tcp:1.0.1.RELEASE")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}")
|
||||
testCompile("org.projectreactor:reactor-core:1.1.3.RELEASE")
|
||||
testCompile("org.projectreactor:reactor-net:1.1.3.RELEASE")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
@@ -643,9 +748,9 @@ project("spring-orm") {
|
||||
optional(project(":spring-context"))
|
||||
optional(project(":spring-web"))
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.core:2.4.0")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:2.4.0") {
|
||||
optional("org.eclipse.persistence:javax.persistence:2.0.5")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.core:${eclipseLinkVersion}")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:${eclipseLinkVersion}") {
|
||||
exclude group: 'org.eclipse.persistence', module: 'javax.persistence'
|
||||
}
|
||||
optional("org.hibernate:hibernate-core:${hibernate3Version}") {
|
||||
@@ -655,17 +760,18 @@ project("spring-orm") {
|
||||
optional("org.hibernate:hibernate-entitymanager:${hibernate3Version}") {
|
||||
exclude group: 'org.hibernate.javax.persistence', module: 'hibernate-jpa-2.0-api'
|
||||
}
|
||||
optional("org.apache.openjpa:openjpa:2.2.1") {
|
||||
optional("org.apache.openjpa:openjpa:${openJpaVersion}") {
|
||||
exclude group: 'junit', module: 'junit'
|
||||
exclude group: 'org.apache.geronimo.specs', module: 'geronimo-jpa_2.0_spec'
|
||||
exclude group: 'org.apache.geronimo.specs', module: 'geronimo-jta_1.1_spec'
|
||||
exclude group: 'org.apache.geronimo.specs', module: 'geronimo-jms_1.1_spec'
|
||||
}
|
||||
optional("javax.jdo:jdo-api:3.0") {
|
||||
optional("javax.jdo:jdo-api:3.0.1") {
|
||||
exclude group: 'javax.transaction', module: 'transaction-api'
|
||||
}
|
||||
optional("javax.servlet:javax.servlet-api:3.0.1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.4")
|
||||
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
@@ -682,6 +788,11 @@ project("spring-orm-hibernate4") {
|
||||
optional("org.hibernate:hibernate-core:${hibernate4Version}")
|
||||
optional("org.hibernate:hibernate-entitymanager:${hibernate4Version}")
|
||||
optional("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
testCompile("javax.validation:validation-api:1.1.0.GA")
|
||||
testCompile("org.hibernate:hibernate-validator:${hibVal5Version}")
|
||||
testCompile("javax.el:javax.el-api:2.2.5")
|
||||
testCompile("org.glassfish.web:javax.el:2.2.6")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -698,36 +809,41 @@ project("spring-webmvc") {
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional(project(":spring-context-support")) // for Velocity support
|
||||
optional(project(":spring-oxm")) // for MarshallingView
|
||||
optional("javax.servlet.jsp:jsp-api:2.2")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("javax.servlet.jsp:javax.servlet.jsp-api:2.2.1")
|
||||
optional("javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1")
|
||||
optional("net.sourceforge.jexcelapi:jxl:2.6.12")
|
||||
optional("org.apache.poi:poi:3.9")
|
||||
optional("org.apache.poi:poi:3.10-FINAL")
|
||||
optional("org.apache.velocity:velocity:1.7")
|
||||
optional("velocity-tools:velocity-tools-view:1.4")
|
||||
optional("org.freemarker:freemarker:2.3.20")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("net.sf.jasperreports:jasperreports:$jasperReportsVersion") {
|
||||
exclude group: "com.fasterxml.jackson.core", module: "jackson-annotations"
|
||||
exclude group: "com.fasterxml.jackson.core", module: "jackson-core"
|
||||
exclude group: "com.fasterxml.jackson.core", module: "jackson-databind"
|
||||
exclude group: "org.olap4j", module: "olap4j"
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
}
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:${jackson1Version}")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
optional("rome:rome:1.0")
|
||||
optional("org.apache.tiles:tiles-api:${tiles2Version}")
|
||||
optional("org.apache.tiles:tiles-core:${tiles2Version}") {
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}")
|
||||
optional("com.rometools:rome:1.5.0")
|
||||
optional("javax.el:javax.el-api:2.2.5")
|
||||
optional("org.apache.tiles:tiles-api:${tiles3Version}")
|
||||
optional("org.apache.tiles:tiles-core:${tiles3Version}") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-servlet:${tiles2Version}") {
|
||||
optional("org.apache.tiles:tiles-servlet:${tiles3Version}") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-jsp:${tiles2Version}") {
|
||||
optional("org.apache.tiles:tiles-jsp:${tiles3Version}") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-el:${tiles2Version}") {
|
||||
optional("org.apache.tiles:tiles-el:${tiles3Version}") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-extras:${tiles2Version}") {
|
||||
optional("org.apache.tiles:tiles-extras:${tiles3Version}") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
exclude group: "org.apache.velocity", module: "velocity-tools"
|
||||
exclude group: "org.springframework", module: "spring-web"
|
||||
}
|
||||
testCompile(project(":spring-aop"))
|
||||
@@ -748,8 +864,8 @@ project("spring-webmvc") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet"
|
||||
}
|
||||
testCompile("javax.validation:validation-api:1.0.0.GA")
|
||||
testCompile("org.hibernate:hibernate-validator:${hibValVersion}")
|
||||
testCompile("org.apache.httpcomponents:httpclient:4.3.3")
|
||||
testCompile("org.hibernate:hibernate-validator:${hibVal4Version}")
|
||||
testCompile("org.apache.httpcomponents:httpclient:4.3.4")
|
||||
testCompile("commons-fileupload:commons-fileupload:1.3.1")
|
||||
testCompile("commons-io:commons-io:1.3")
|
||||
testCompile("joda-time:joda-time:${jodaVersion}")
|
||||
@@ -760,32 +876,32 @@ project("spring-webmvc") {
|
||||
sourceSets.main.resources.srcDirs += "src/main/java"
|
||||
}
|
||||
|
||||
project("spring-webmvc-tiles3") {
|
||||
description = "Spring Framework Tiles3 Integration"
|
||||
project("spring-webmvc-tiles2") {
|
||||
description = "Spring Framework Tiles2 Integration"
|
||||
merge.into = project(":spring-webmvc")
|
||||
|
||||
dependencies {
|
||||
provided(project(":spring-context"))
|
||||
provided(project(":spring-web"))
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional("javax.servlet.jsp:jsp-api:2.2")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("javax.el:javax.el-api:2.2.4")
|
||||
optional("org.apache.tiles:tiles-api:${tiles3Version}")
|
||||
optional("org.apache.tiles:tiles-core:${tiles3Version}") {
|
||||
optional("javax.servlet.jsp:javax.servlet.jsp-api:2.2.1")
|
||||
optional("javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1")
|
||||
optional("org.apache.tiles:tiles-api:${tiles2Version}")
|
||||
optional("org.apache.tiles:tiles-core:${tiles2Version}") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-servlet:${tiles3Version}") {
|
||||
optional("org.apache.tiles:tiles-servlet:${tiles2Version}") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-jsp:${tiles3Version}") {
|
||||
optional("org.apache.tiles:tiles-jsp:${tiles2Version}") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-el:${tiles3Version}") {
|
||||
optional("org.apache.tiles:tiles-el:${tiles2Version}") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-extras:${tiles3Version}") {
|
||||
optional("org.apache.tiles:tiles-extras:${tiles2Version}") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
exclude group: "org.apache.velocity", module: "velocity-tools"
|
||||
exclude group: "org.springframework", module: "spring-web"
|
||||
}
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
@@ -827,29 +943,29 @@ project("spring-test") {
|
||||
optional("org.testng:testng:6.8.8")
|
||||
optional("javax.inject:javax.inject:1")
|
||||
optional("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional("javax.servlet.jsp:jsp-api:2.2")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("javax.servlet.jsp:javax.servlet.jsp-api:2.2.1")
|
||||
optional("javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1")
|
||||
optional("org.apache.taglibs:taglibs-standard-jstlel:1.2.1") {
|
||||
exclude group: "org.apache.taglibs", module: "taglibs-standard-spec"
|
||||
}
|
||||
optional("javax.portlet:portlet-api:2.0")
|
||||
optional("javax.el:javax.el-api:2.2.4")
|
||||
optional("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
optional("javax.el:javax.el-api:2.2.5")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("org.hamcrest:hamcrest-core:1.3")
|
||||
optional("com.jayway.jsonpath:json-path:0.9.0")
|
||||
optional("org.skyscreamer:jsonassert:1.2.3")
|
||||
optional("xmlunit:xmlunit:1.5")
|
||||
testCompile(project(":spring-context-support"))
|
||||
testCompile(project(":spring-oxm"))
|
||||
testCompile(project(":spring-webmvc-tiles3"))
|
||||
testCompile("javax.mail:mail:1.4.7")
|
||||
testCompile("javax.mail:javax.mail-api:1.5.2")
|
||||
testCompile("javax.ejb:ejb-api:3.0")
|
||||
testCompile("org.hibernate:hibernate-core:${hibernate3Version}") {
|
||||
exclude group: 'org.hibernate.javax.persistence', module: 'hibernate-jpa-2.0-api'
|
||||
}
|
||||
testCompile("org.hibernate:hibernate-entitymanager:${hibernate3Version}")
|
||||
testCompile("org.hibernate:hibernate-validator:${hibValVersion}")
|
||||
testCompile("org.hibernate:hibernate-core:${hibernate4Version}")
|
||||
testCompile("org.hibernate:hibernate-entitymanager:${hibernate4Version}")
|
||||
testCompile("org.hibernate:hibernate-validator:${hibVal5Version}")
|
||||
testCompile("com.thoughtworks.xstream:xstream:${xstreamVersion}")
|
||||
testCompile("org.codehaus.jackson:jackson-mapper-asl:${jackson1Version}")
|
||||
testCompile("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
testCompile("rome:rome:1.0")
|
||||
testCompile("com.rometools:rome:1.5.0")
|
||||
testCompile("org.apache.tiles:tiles-api:${tiles3Version}")
|
||||
testCompile("org.apache.tiles:tiles-core:${tiles3Version}") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
@@ -863,6 +979,7 @@ project("spring-test") {
|
||||
|
||||
task testNG(type: Test) {
|
||||
useTestNG()
|
||||
scanForTestClasses = false
|
||||
include(["**/testng/**/*Tests.class", "**/testng/**/*Test.class"])
|
||||
// Show STD_OUT & STD_ERR of the test JVM(s) on the console:
|
||||
// testLogging.showStandardStreams = true
|
||||
@@ -889,19 +1006,20 @@ project("spring-aspects") {
|
||||
|
||||
dependencies {
|
||||
aspects(project(":spring-orm"))
|
||||
ajc("org.aspectj:aspectjtools:1.8.0.RC2") // needed for ajc on JDK 8 only
|
||||
rt("org.aspectj:aspectjrt:1.8.0.RC2") // needed for ajc on JDK 8 only
|
||||
compile("org.aspectj:aspectjweaver:${aspectjVersion}") // exposing regular AspectJ version to users
|
||||
ajc("org.aspectj:aspectjtools:${aspectjVersion}")
|
||||
rt("org.aspectj:aspectjrt:${aspectjVersion}")
|
||||
compile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
provided("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
optional(project(":spring-aop")) // for @Async support
|
||||
optional(project(":spring-beans")) // for @Configurable support
|
||||
optional(project(":spring-context")) // for @Enable* support
|
||||
optional(project(":spring-context-support")) // for JavaMail support
|
||||
optional(project(":spring-context-support")) // for JavaMail and JSR-107 support
|
||||
optional(project(":spring-orm")) // for JPA exception translation support
|
||||
optional(project(":spring-tx")) // for JPA, @Transactional support
|
||||
optional("javax.cache:cache-api:1.0.0")
|
||||
testCompile(project(":spring-core")) // for CodeStyleAspect
|
||||
testCompile(project(":spring-test"))
|
||||
testCompile("javax.mail:mail:1.4.7")
|
||||
testCompile("javax.mail:javax.mail-api:1.5.2")
|
||||
}
|
||||
|
||||
eclipse.project {
|
||||
@@ -946,6 +1064,22 @@ project("spring-framework-bom") {
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'sonar-runner'
|
||||
|
||||
sonarRunner {
|
||||
sonarProperties {
|
||||
property "sonar.projectName", "Spring Framework"
|
||||
property "sonar.profile", "Spring Framework"
|
||||
property "sonar.jacoco.reportPath", "${buildDir.name}/jacoco.exec"
|
||||
property "sonar.links.homepage", linkHomepage
|
||||
property "sonar.links.ci", linkCi
|
||||
property "sonar.links.issue", linkIssue
|
||||
property "sonar.links.scm", linkScmUrl
|
||||
property "sonar.links.scm_dev", linkScmDevConnection
|
||||
property "sonar.java.coveragePlugin", "jacoco"
|
||||
}
|
||||
}
|
||||
|
||||
configure(rootProject) {
|
||||
description = "Spring Framework"
|
||||
|
||||
@@ -973,6 +1107,7 @@ configure(rootProject) {
|
||||
reference {
|
||||
sourceDir = asciidoctor.outputDir
|
||||
pdfFilename = "spring-framework-reference.pdf"
|
||||
epubFilename = "spring-framework-reference.epub"
|
||||
expandPlaceholders = ""
|
||||
}
|
||||
|
||||
@@ -1075,7 +1210,7 @@ configure(rootProject) {
|
||||
classifier = "schema"
|
||||
description = "Builds -${classifier} archive containing all " +
|
||||
"XSDs for deployment at http://springframework.org/schema."
|
||||
|
||||
duplicatesStrategy 'exclude'
|
||||
subprojects.each { subproject ->
|
||||
def Properties schemas = new Properties();
|
||||
|
||||
@@ -1175,7 +1310,7 @@ configure(rootProject) {
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
description = "Generates gradlew[.bat] scripts"
|
||||
gradleVersion = "1.11"
|
||||
gradleVersion = "1.12"
|
||||
|
||||
doLast() {
|
||||
def gradleOpts = "-XX:MaxMetaspaceSize=1024m -Xmx1024m"
|
||||
@@ -1191,6 +1326,21 @@ configure(rootProject) {
|
||||
|
||||
}
|
||||
|
||||
configure([project(':spring-build-src'), project(':spring-framework-bom')]) {
|
||||
sonarRunner {
|
||||
skipProject = true
|
||||
}
|
||||
}
|
||||
|
||||
configure(project(':spring-core')) {
|
||||
sonarRunner {
|
||||
sonarProperties {
|
||||
property "sonar.exclusions",
|
||||
"src/main/java/org/springframework/cglib/**/*,src/main/java/org/springframework/asm/**/*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Support publication of artifacts versioned by topic branch.
|
||||
* CI builds supply `-P BRANCH_NAME=<TOPIC>` to gradle at build time.
|
||||
|
||||
@@ -21,13 +21,10 @@ import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ProjectDependency;
|
||||
import org.gradle.api.artifacts.maven.Conf2ScopeMapping
|
||||
import org.gradle.api.plugins.MavenPlugin
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.plugins.ide.eclipse.EclipsePlugin
|
||||
import org.gradle.plugins.ide.eclipse.model.EclipseClasspath;
|
||||
import org.gradle.plugins.ide.idea.IdeaPlugin
|
||||
import org.gradle.api.invocation.*
|
||||
|
||||
|
||||
/**
|
||||
* Gradle plugin that allows projects to merged together. Primarily developed to
|
||||
* allow Spring to support multiple incompatible versions of third-party
|
||||
@@ -71,18 +68,18 @@ class MergePlugin implements Plugin<Project> {
|
||||
Configuration runtimeMerge = project.configurations.create("runtimeMerge")
|
||||
|
||||
// Ensure the IDE can reference merged projects
|
||||
project.eclipse.classpath.plusConfigurations += [runtimeMerge]
|
||||
project.idea.module.scopes.PROVIDED.plus += runtimeMerge
|
||||
project.eclipse.classpath.plusConfigurations += [ runtimeMerge ]
|
||||
project.idea.module.scopes.PROVIDED.plus += [ runtimeMerge ]
|
||||
|
||||
// Hook to perform the actual merge logic
|
||||
project.afterEvaluate{
|
||||
if(it.merge.into != null) {
|
||||
if (it.merge.into != null) {
|
||||
setup(it)
|
||||
}
|
||||
}
|
||||
|
||||
// Hook to build runtimeMerge dependencies
|
||||
if(!attachedProjectsEvaluated) {
|
||||
if (!attachedProjectsEvaluated) {
|
||||
project.gradle.projectsEvaluated{
|
||||
postProcessProjects(it)
|
||||
}
|
||||
@@ -102,7 +99,7 @@ class MergePlugin implements Plugin<Project> {
|
||||
// invoking a task will invoke the task with the same name on 'into' project
|
||||
["sourcesJar", "jar", "javadocJar", "javadoc", "install", "artifactoryPublish"].each {
|
||||
def task = project.tasks.findByPath(it)
|
||||
if(task) {
|
||||
if (task) {
|
||||
task.enabled = false
|
||||
task.dependsOn(project.merge.into.tasks.findByPath(it))
|
||||
}
|
||||
@@ -120,7 +117,7 @@ class MergePlugin implements Plugin<Project> {
|
||||
private void setupMaven(Project project) {
|
||||
project.configurations.each { configuration ->
|
||||
Conf2ScopeMapping mapping = project.conf2ScopeMappings.getMapping([configuration])
|
||||
if(mapping.scope) {
|
||||
if (mapping.scope) {
|
||||
Configuration intoConfiguration = project.merge.into.configurations.create(
|
||||
project.name + "-" + configuration.name)
|
||||
configuration.excludeRules.each {
|
||||
@@ -131,7 +128,7 @@ class MergePlugin implements Plugin<Project> {
|
||||
configuration.dependencies.each {
|
||||
def intoCompile = project.merge.into.configurations.getByName("compile")
|
||||
// Protect against changing a compile scope dependency (SPR-10218)
|
||||
if(!intoCompile.dependencies.contains(it)) {
|
||||
if (!intoCompile.dependencies.contains(it)) {
|
||||
intoConfiguration.dependencies.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,7 +21,6 @@ import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.artifacts.ProjectDependency;
|
||||
|
||||
|
||||
/**
|
||||
* Gradle plugin that automatically updates testCompile dependencies to include
|
||||
* the test source sets of project dependencies.
|
||||
@@ -41,11 +40,10 @@ class TestSourceSetDependenciesPlugin implements Plugin<Project> {
|
||||
}
|
||||
}
|
||||
|
||||
private void collectProjectDependencies(Set<ProjectDependency> projectDependencies,
|
||||
Project project) {
|
||||
for(def configurationName in ["compile", "optional", "provided", "testCompile"]) {
|
||||
private void collectProjectDependencies(Set<ProjectDependency> projectDependencies, Project project) {
|
||||
for (def configurationName in ["compile", "optional", "provided", "testCompile"]) {
|
||||
Configuration configuration = project.getConfigurations().findByName(configurationName)
|
||||
if(configuration) {
|
||||
if (configuration) {
|
||||
configuration.dependencies.findAll { it instanceof ProjectDependency }.each {
|
||||
projectDependencies.add(it)
|
||||
collectProjectDependencies(projectDependencies, it.dependencyProject)
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
version=4.0.4.BUILD-SNAPSHOT
|
||||
version=4.1.0.RC2
|
||||
|
||||
+15
-5
@@ -5,19 +5,19 @@ import org.gradle.plugins.ide.eclipse.model.SourceFolder
|
||||
apply plugin: "propdeps-eclipse"
|
||||
apply plugin: "propdeps-idea"
|
||||
|
||||
// Until eclipse fully supports Java 8 use 1.7 source level
|
||||
eclipse.jdt {
|
||||
sourceCompatibility = 1.7
|
||||
targetCompatibility = 1.7
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
}
|
||||
|
||||
// Replace classpath entries with project dependencies (GRADLE-1116)
|
||||
// http://issues.gradle.org/browse/GRADLE-1116
|
||||
eclipse.classpath.file.whenMerged { classpath ->
|
||||
def regexp = /.*?\/([^\/]+)\/build\/[^\/]+\/(?:main|test)/ // only match those that end in main or test (avoids removing necessary entries like build/classes/jaxb)
|
||||
def projectOutputDependencies = classpath.entries.findAll { entry -> entry.path =~ regexp }
|
||||
projectOutputDependencies.each { entry ->
|
||||
def matcher = (entry.path =~ regexp)
|
||||
if(matcher) {
|
||||
if (matcher) {
|
||||
def projectName = matcher[0][1]
|
||||
def path = "/${projectName}"
|
||||
if(!classpath.entries.find { e -> e instanceof ProjectDependency && e.path == path }) {
|
||||
@@ -47,10 +47,20 @@ eclipse.classpath.file.whenMerged { classpath ->
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure project dependencies come after 3rd-party libs (SPR-11836)
|
||||
// https://jira.spring.io/browse/SPR-11836
|
||||
eclipse.classpath.file.whenMerged { classpath ->
|
||||
classpath.entries.findAll { it instanceof ProjectDependency }.each {
|
||||
// delete from original position
|
||||
classpath.entries.remove(it)
|
||||
// append to end of classpath
|
||||
classpath.entries.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
// Allow projects to be used as WPT modules
|
||||
eclipse.project.natures "org.eclipse.wst.common.project.facet.core.nature"
|
||||
|
||||
|
||||
// Include project specific settings
|
||||
task eclipseSettings(type: Copy) {
|
||||
from rootProject.files(
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-2
@@ -1,6 +1,6 @@
|
||||
#Wed Feb 12 23:28:21 CET 2014
|
||||
#Wed Apr 30 13:06:57 CEST 2014
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-all.zip
|
||||
|
||||
+51
-35
@@ -1,22 +1,38 @@
|
||||
STS_TEST_VERSION='2.9.2.RELEASE'
|
||||
|
||||
cd `dirname $0`
|
||||
clear
|
||||
cat <<EOM
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
Spring Framework Eclipse/STS project import guide
|
||||
------------------------------------------------------------------------
|
||||
Spring Framework - Eclipse/STS Project Import Guide
|
||||
|
||||
This script will guide you through the process of importing the
|
||||
Spring Framework sources into Eclipse/STS. It is recommended that you
|
||||
have a recent version of the SpringSource Tool Suite (this script has
|
||||
been tested against STS $STS_TEST_VERSION), but at the minimum you will
|
||||
need Eclipse + AJDT.
|
||||
This script will guide you through the process of importing the Spring
|
||||
Framework projects into Eclipse or the Spring Tool Suite (STS). It is
|
||||
recommended that you have a recent version of Eclipse or STS. As a bare
|
||||
minimum you will need Eclipse with full Java 8 support, AJDT, and the
|
||||
Groovy Compiler.
|
||||
|
||||
If you need to download and install STS, please do that now by
|
||||
visiting http://spring.io/tools/sts/all
|
||||
This script has been tested against:
|
||||
|
||||
Otherwise, press enter and we'll begin.
|
||||
- Eclipse: integration build I20140528-2000 (Luna 4.4)
|
||||
- STS: nightly build 3.6.0.CI-B1890632 (Luna 4.4)
|
||||
- AJDT: CI build AJDT-AE44-66 (Luna 4.4)
|
||||
|
||||
If you need to download and install Eclipse or STS, please do that now
|
||||
by visiting one of the following sites:
|
||||
|
||||
- Eclipse downloads: http://download.eclipse.org/eclipse/downloads/
|
||||
- STS downloads: http://spring.io/tools/sts/all
|
||||
- STS nightly builds: http://dist.springsource.com/snapshot/STS/nightly-distributions.html
|
||||
|
||||
If you need to install a recent CI build for AJDT (i.e., so that the
|
||||
spring-aspects module properly compiles in Eclipse/STS), click on the
|
||||
"Artifacts" tab of a successful CI build and copy the link to the
|
||||
"update site" which you can then use to install or update AJDT within
|
||||
Eclipse/STS.
|
||||
|
||||
- AJDT CI builds: https://build.spring.io/browse/AJDT-AE44
|
||||
|
||||
Once Eclipse/STS is installed, press enter, and we'll begin.
|
||||
EOM
|
||||
|
||||
read
|
||||
@@ -31,14 +47,14 @@ COMMAND="./gradlew cleanEclipse :spring-oxm:compileTestJava eclipse -x :eclipse"
|
||||
|
||||
cat <<EOM
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
------------------------------------------------------------------------
|
||||
STEP 1: Generate subproject Eclipse metadata
|
||||
|
||||
The first step will be to generate Eclipse project metadata for each
|
||||
of the spring-* subprojects. This happens via the built-in
|
||||
"Gradle wrapper" script (./gradlew in this directory). If this is your
|
||||
first time using the Gradle wrapper, this step may take a few minutes
|
||||
while a Gradle distribution is downloaded for you.
|
||||
The first step will be to generate Eclipse project metadata for each of
|
||||
the spring-* subprojects. This happens via the built-in "Gradle wrapper"
|
||||
script (./gradlew in this directory). If this is your first time using
|
||||
the Gradle wrapper, this step may take a few minutes while a Gradle
|
||||
distribution is downloaded for you.
|
||||
|
||||
The command run will be:
|
||||
|
||||
@@ -53,16 +69,16 @@ $COMMAND || exit
|
||||
|
||||
cat <<EOM
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
------------------------------------------------------------------------
|
||||
STEP 2: Import subprojects into Eclipse/STS
|
||||
|
||||
Within Eclipse/STS, do the following:
|
||||
|
||||
File > Import... > Existing Projects into Workspace
|
||||
> When prompted for the 'root directory', provide $PWD
|
||||
> Press enter. You will see the modules show up under "Projects"
|
||||
> All projects should be selected/checked. Click Finish.
|
||||
> When the project import is complete, you should have no errors.
|
||||
- File > Import... > Existing Projects into Workspace
|
||||
- When prompted for the 'root directory', provide $PWD.
|
||||
- Press enter. You will see the modules show up under "Projects".
|
||||
- All projects should be selected/checked. Click Finish.
|
||||
- When the project import is complete, you should have no errors.
|
||||
|
||||
When the above is complete, return here and press the enter key.
|
||||
EOM
|
||||
@@ -73,13 +89,13 @@ COMMAND="./gradlew :eclipse"
|
||||
|
||||
cat <<EOM
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
STEP 3: generate root project Eclipse metadata
|
||||
------------------------------------------------------------------------
|
||||
STEP 3: Generate root project Eclipse metadata
|
||||
|
||||
Unfortunately, Eclipse does not allow for importing project
|
||||
hierarchies, so we had to skip root project metadata generation in the
|
||||
during step 1. In this step we simply generate root project metadata
|
||||
so you can import it in the next step.
|
||||
Unfortunately, Eclipse does not support importing project hierarchies,
|
||||
so we had to skip root project metadata generation during step 1. In
|
||||
this step we simply generate root project metadata so that you can
|
||||
import it in the next step.
|
||||
|
||||
The command run will be:
|
||||
|
||||
@@ -93,7 +109,7 @@ read
|
||||
$COMMAND || exit
|
||||
|
||||
cat <<EOM
|
||||
-----------------------------------------------------------------------
|
||||
------------------------------------------------------------------------
|
||||
STEP 4: Import root project into Eclipse/STS
|
||||
|
||||
Follow the project import steps listed in step 2 above to import the
|
||||
@@ -105,14 +121,14 @@ EOM
|
||||
read
|
||||
|
||||
cat <<EOM
|
||||
-----------------------------------------------------------------------
|
||||
------------------------------------------------------------------------
|
||||
STEP 5: Enable Git support for all projects
|
||||
|
||||
- In the Eclipse/STS Package Explorer, select all spring* projects.
|
||||
- Right-click to open the context menu and select Team > Share Project...
|
||||
- In the Share Project dialog that appears, select Git and press Next
|
||||
- Check "Use or create repository in parent folder of project"
|
||||
- Click Finish
|
||||
- In the Share Project dialog that appears, select Git and press Next.
|
||||
- Check "Use or create repository in parent folder of project".
|
||||
- Click Finish.
|
||||
|
||||
When complete, you'll have Git support enabled for all projects.
|
||||
|
||||
|
||||
+7
-7
@@ -1,21 +1,21 @@
|
||||
The following has been tested against Intellij IDEA 12.0
|
||||
The following has been tested against Intellij IDEA 13.1
|
||||
|
||||
## Steps
|
||||
|
||||
_Within your locally cloned spring-framework working directory:_
|
||||
|
||||
1. Generate IDEA metadata with `./gradlew :spring-oxm:compileTestJava cleanIdea idea`
|
||||
2. Import into IDEA as usual
|
||||
3. Set the Project JDK as appropriate
|
||||
4. Add git support
|
||||
1. Pre-compile `spring-oxm` with `./gradlew cleanIdea :spring-oxm:compileTestJava`
|
||||
2. Import into IDEA (File->import project->import from external model->Gradle)
|
||||
3. Set the Project JDK as appropriate (1.8+)
|
||||
4. Exclude the `spring-aspects` module (Go to File->Project Structure->Modules)
|
||||
5. Code away
|
||||
|
||||
## Known issues
|
||||
|
||||
1. Those steps don't work currently for Intellij IDEA 13+
|
||||
1. `spring-oxm` should be pre-compiled since it's using repackaged dependencies (see *RepackJar tasks)
|
||||
2. `spring-aspects` does not compile out of the box due to references to aspect types unknown to IDEA.
|
||||
See http://youtrack.jetbrains.com/issue/IDEA-64446 for details. In the meantime, the 'spring-aspects'
|
||||
module has been excluded from the overall project to avoid compilation errors.
|
||||
should be excluded from the overall project to avoid compilation errors.
|
||||
3. While all JUnit tests pass from the command line with Gradle, many will fail when run from IDEA.
|
||||
Resolving this is a work in progress. If attempting to run all JUnit tests from within IDEA, you will
|
||||
likely need to set the following VM options to avoid out of memory errors:
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ include "spring-tx"
|
||||
include "spring-web"
|
||||
include "spring-webmvc"
|
||||
include "spring-webmvc-portlet"
|
||||
include "spring-webmvc-tiles3"
|
||||
include "spring-webmvc-tiles2"
|
||||
include "spring-websocket"
|
||||
include "spring-framework-bom"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -240,7 +240,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
setArgumentNamesFromStringArray(tokens);
|
||||
}
|
||||
|
||||
public void setArgumentNamesFromStringArray(String[] args) {
|
||||
public void setArgumentNamesFromStringArray(String... args) {
|
||||
this.argumentNames = new String[args.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
this.argumentNames[i] = StringUtils.trimWhitespace(args[i]);
|
||||
|
||||
+59
-54
@@ -29,7 +29,6 @@ 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;
|
||||
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
|
||||
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
||||
import org.aspectj.weaver.tools.ContextBasedMatcher;
|
||||
@@ -108,6 +107,8 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private transient ClassLoader pointcutClassLoader;
|
||||
|
||||
private transient PointcutExpression pointcutExpression;
|
||||
|
||||
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
@@ -185,20 +186,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
throw new IllegalStateException("Must set property 'expression' before attempting to match");
|
||||
}
|
||||
if (this.pointcutExpression == null) {
|
||||
this.pointcutExpression = buildPointcutExpression();
|
||||
this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
private PointcutExpression buildPointcutExpression() {
|
||||
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
return buildPointcutExpression(cl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
@@ -252,23 +246,22 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
public boolean matches(Class<?> targetClass) {
|
||||
checkReadyToMatch();
|
||||
try {
|
||||
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
|
||||
}
|
||||
catch (ReflectionWorldException rwe) {
|
||||
logger.debug("PointcutExpression matching rejected target class", rwe);
|
||||
try {
|
||||
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
|
||||
return getFallbackPointcutExpression(targetClass).couldMatchJoinPointsInType(targetClass);
|
||||
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
|
||||
}
|
||||
catch (BCException bce) {
|
||||
logger.debug("Fallback PointcutExpression matching rejected target class", bce);
|
||||
return false;
|
||||
catch (ReflectionWorldException ex) {
|
||||
logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
|
||||
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
|
||||
PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
|
||||
if (fallbackExpression != null) {
|
||||
return fallbackExpression.couldMatchJoinPointsInType(targetClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (BCException ex) {
|
||||
logger.debug("PointcutExpression matching rejected target class", ex);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -365,12 +358,19 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
|
||||
/**
|
||||
* Get a new pointcut expression based on a target class's loader, rather
|
||||
* than the default.
|
||||
* Get a new pointcut expression based on a target class's loader rather than the default.
|
||||
*/
|
||||
private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
|
||||
ClassLoader classLoader = targetClass.getClassLoader();
|
||||
return (classLoader != null ? buildPointcutExpression(classLoader) : this.pointcutExpression);
|
||||
try {
|
||||
ClassLoader classLoader = targetClass.getClassLoader();
|
||||
if (classLoader != null && classLoader != this.pointcutClassLoader) {
|
||||
return buildPointcutExpression(classLoader);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Failed to create fallback PointcutExpression", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
|
||||
@@ -396,46 +396,51 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
if (shadowMatch == null) {
|
||||
synchronized (this.shadowMatchCache) {
|
||||
// Not found - now check again with full lock...
|
||||
PointcutExpression fallbackExpression = null;
|
||||
Method methodToMatch = targetMethod;
|
||||
PointcutExpression fallbackPointcutExpression = null;
|
||||
shadowMatch = this.shadowMatchCache.get(methodToMatch);
|
||||
shadowMatch = this.shadowMatchCache.get(targetMethod);
|
||||
if (shadowMatch == null) {
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(targetMethod);
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex) {
|
||||
catch (ReflectionWorldException ex) {
|
||||
// Failed to introspect target method, probably because it has been loaded
|
||||
// in a special ClassLoader. Let's try the original method instead...
|
||||
// in a special ClassLoader. Let's try the declaring ClassLoader instead...
|
||||
try {
|
||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex2) {
|
||||
if (targetMethod == originalMethod) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(originalMethod);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex3) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's simply consider this method as non-matching.
|
||||
methodToMatch = originalMethod;
|
||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
try {
|
||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex4) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shadowMatch.maybeMatches() && fallbackPointcutExpression != null) {
|
||||
if (shadowMatch == null) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
}
|
||||
else if (shadowMatch.maybeMatches() && fallbackExpression != null) {
|
||||
shadowMatch = new DefensiveShadowMatch(shadowMatch,
|
||||
fallbackPointcutExpression.matchesMethodExecution(methodToMatch));
|
||||
fallbackExpression.matchesMethodExecution(methodToMatch));
|
||||
}
|
||||
this.shadowMatchCache.put(targetMethod, shadowMatch);
|
||||
}
|
||||
|
||||
+11
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,24 +40,24 @@ public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdv
|
||||
this.pointcut.setExpression(expression);
|
||||
}
|
||||
|
||||
public String getExpression() {
|
||||
return this.pointcut.getExpression();
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.pointcut.setLocation(location);
|
||||
}
|
||||
|
||||
public void setParameterTypes(Class<?>[] types) {
|
||||
this.pointcut.setParameterTypes(types);
|
||||
}
|
||||
|
||||
public void setParameterNames(String[] names) {
|
||||
this.pointcut.setParameterNames(names);
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return this.pointcut.getLocation();
|
||||
}
|
||||
|
||||
public String getExpression() {
|
||||
return this.pointcut.getExpression();
|
||||
public void setParameterTypes(Class<?>[] types) {
|
||||
this.pointcut.setParameterTypes(types);
|
||||
}
|
||||
|
||||
public void setParameterNames(String... names) {
|
||||
this.pointcut.setParameterNames(names);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* migrate to {@code ShadowMatch.getVariablesInvolvedInRuntimeTest()}
|
||||
* or some similar operation.
|
||||
*
|
||||
* <p>See <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=151593"/>.
|
||||
* <p>See <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=151593"/>Bug 151593</a>
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @author Ramnivas Laddad
|
||||
|
||||
+3
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,8 +19,7 @@ package org.springframework.aop.aspectj.annotation;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.annotation.OrderUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -110,10 +109,7 @@ public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInst
|
||||
if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {
|
||||
return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();
|
||||
}
|
||||
Order order = AnnotationUtils.findAnnotation(type, Order.class);
|
||||
if (order != null) {
|
||||
return order.value();
|
||||
}
|
||||
return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE);
|
||||
}
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
+3
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,7 @@ package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import org.springframework.aop.aspectj.SimpleAspectInstanceFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.annotation.OrderUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link MetadataAwareAspectInstanceFactory} that
|
||||
@@ -51,20 +50,9 @@ public class SimpleMetadataAwareAspectInstanceFactory extends SimpleAspectInstan
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine a fallback order for the case that the aspect instance
|
||||
* does not express an instance-specific order through implementing
|
||||
* the {@link org.springframework.core.Ordered} interface.
|
||||
* <p>The default implementation simply returns {@code Ordered.LOWEST_PRECEDENCE}.
|
||||
* @param aspectClass the aspect class
|
||||
*/
|
||||
@Override
|
||||
protected int getOrderForAspectClass(Class<?> aspectClass) {
|
||||
Order order = AnnotationUtils.findAnnotation(aspectClass, Order.class);
|
||||
if (order != null) {
|
||||
return order.value();
|
||||
}
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
return OrderUtils.getOrder(aspectClass, Ordered.LOWEST_PRECEDENCE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,7 @@ package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import org.springframework.aop.aspectj.SingletonAspectInstanceFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.annotation.OrderUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link MetadataAwareAspectInstanceFactory} that is backed
|
||||
@@ -53,19 +52,9 @@ public class SingletonMetadataAwareAspectInstanceFactory extends SingletonAspect
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the aspect class carries an
|
||||
* {@link org.springframework.core.annotation.Order} annotation,
|
||||
* falling back to {@code Ordered.LOWEST_PRECEDENCE}.
|
||||
* @see org.springframework.core.annotation.Order
|
||||
*/
|
||||
@Override
|
||||
protected int getOrderForAspectClass(Class<?> aspectClass) {
|
||||
Order order = AnnotationUtils.findAnnotation(aspectClass, Order.class);
|
||||
if (order != null) {
|
||||
return order.value();
|
||||
}
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
return OrderUtils.getOrder(aspectClass, Ordered.LOWEST_PRECEDENCE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+39
-45
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,10 +21,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Base class for {@link BeanPostProcessor} implementations that apply a
|
||||
@@ -34,21 +31,12 @@ import org.springframework.util.ClassUtils;
|
||||
* @since 3.2
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
|
||||
implements BeanPostProcessor, BeanClassLoaderAware, Ordered {
|
||||
public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSupport implements BeanPostProcessor {
|
||||
|
||||
protected Advisor advisor;
|
||||
|
||||
protected boolean beforeExistingAdvisors = false;
|
||||
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
/**
|
||||
* This should run after all other post-processors, so that it can just add
|
||||
* an advisor to existing proxies rather than double-proxy.
|
||||
*/
|
||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||
|
||||
private final Map<Class<?>, Boolean> eligibleBeans = new ConcurrentHashMap<Class<?>, Boolean>(64);
|
||||
|
||||
|
||||
@@ -65,20 +53,6 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
|
||||
this.beforeExistingAdvisors = beforeExistingAdvisors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader beanClassLoader) {
|
||||
this.beanClassLoader = beanClassLoader;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
@@ -91,9 +65,11 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
|
||||
// Ignore AOP infrastructure such as scoped proxies.
|
||||
return bean;
|
||||
}
|
||||
if (isEligible(bean, beanName)) {
|
||||
if (bean instanceof Advised) {
|
||||
Advised advised = (Advised) bean;
|
||||
|
||||
if (bean instanceof Advised) {
|
||||
Advised advised = (Advised) bean;
|
||||
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
|
||||
// Add our local Advisor to the existing proxy's Advisor chain...
|
||||
if (this.beforeExistingAdvisors) {
|
||||
advised.addAdvisor(0, this.advisor);
|
||||
}
|
||||
@@ -102,32 +78,50 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
else {
|
||||
ProxyFactory proxyFactory = new ProxyFactory(bean);
|
||||
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
|
||||
proxyFactory.copyFrom(this);
|
||||
proxyFactory.addAdvisor(this.advisor);
|
||||
return proxyFactory.getProxy(this.beanClassLoader);
|
||||
}
|
||||
|
||||
if (isEligible(bean, beanName)) {
|
||||
ProxyFactory proxyFactory = new ProxyFactory();
|
||||
proxyFactory.copyFrom(this);
|
||||
proxyFactory.setTarget(bean);
|
||||
if (!proxyFactory.isProxyTargetClass()) {
|
||||
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
|
||||
}
|
||||
proxyFactory.addAdvisor(this.advisor);
|
||||
return proxyFactory.getProxy(getProxyClassLoader());
|
||||
}
|
||||
else {
|
||||
// No async proxy needed.
|
||||
return bean;
|
||||
}
|
||||
|
||||
// No async proxy needed.
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given bean is eligible for advising with this
|
||||
* post-processor's {@link Advisor}.
|
||||
* <p>Implements caching of {@code canApply} results per bean target class.
|
||||
* <p>Delegates to {@link #isEligible(Class)} for target class checking.
|
||||
* Can be overridden e.g. to specifically exclude certain beans by name.
|
||||
* <p>Note: Only called for regular bean instances but not for existing
|
||||
* proxy instances which implement {@link Advised} and allow for adding
|
||||
* the local {@link Advisor} to the existing proxy's {@link Advisor} chain.
|
||||
* For the latter, {@link #isEligible(Class)} is being called directly,
|
||||
* with the actual target class behind the existing proxy (as determined
|
||||
* by {@link AopUtils#getTargetClass(Object)}).
|
||||
* @param bean the bean instance
|
||||
* @param beanName the name of the bean
|
||||
* @see AopUtils#getTargetClass(Object)
|
||||
* @see AopUtils#canApply(Advisor, Class)
|
||||
* @see #isEligible(Class)
|
||||
*/
|
||||
protected boolean isEligible(Object bean, String beanName) {
|
||||
Class<?> targetClass = AopUtils.getTargetClass(bean);
|
||||
return isEligible(bean.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given class is eligible for advising with this
|
||||
* post-processor's {@link Advisor}.
|
||||
* <p>Implements caching of {@code canApply} results per bean target class.
|
||||
* @param targetClass the class to check against
|
||||
* @see AopUtils#canApply(Advisor, Class)
|
||||
*/
|
||||
protected boolean isEligible(Class<?> targetClass) {
|
||||
Boolean eligible = this.eligibleBeans.get(targetClass);
|
||||
if (eligible != null) {
|
||||
return eligible;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2014 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,10 +32,10 @@ public interface AdvisorChainFactory {
|
||||
* for the given advisor chain configuration.
|
||||
* @param config the AOP configuration in the form of an Advised object
|
||||
* @param method the proxied method
|
||||
* @param targetClass the target class
|
||||
* @param targetClass the target class (may be {@code null} to indicate a proxy without
|
||||
* target object, in which case the method's declaring class is the next best option)
|
||||
* @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
|
||||
*/
|
||||
List<Object> getInterceptorsAndDynamicInterceptionAdvice(
|
||||
Advised config, Method method, Class<?> targetClass);
|
||||
List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, Class<?> targetClass);
|
||||
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
}
|
||||
|
||||
// Validate the class, writing log messages as necessary.
|
||||
validateClassIfNecessary(proxySuperClass);
|
||||
validateClassIfNecessary(proxySuperClass, classLoader);
|
||||
|
||||
// Configure CGLIB Enhancer...
|
||||
Enhancer enhancer = createEnhancer();
|
||||
@@ -239,11 +239,11 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
* Checks to see whether the supplied {@code Class} has already been validated and
|
||||
* validates it if not.
|
||||
*/
|
||||
private void validateClassIfNecessary(Class<?> proxySuperClass) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
private void validateClassIfNecessary(Class<?> proxySuperClass, ClassLoader proxyClassLoader) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
synchronized (validatedClasses) {
|
||||
if (!validatedClasses.containsKey(proxySuperClass)) {
|
||||
doValidateClass(proxySuperClass);
|
||||
doValidateClass(proxySuperClass, proxyClassLoader);
|
||||
validatedClasses.put(proxySuperClass, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
@@ -251,19 +251,28 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for final methods on the {@code Class} and writes warnings to the log
|
||||
* for each one found.
|
||||
* 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) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
Method[] methods = proxySuperClass.getMethods();
|
||||
private void doValidateClass(Class<?> proxySuperClass, ClassLoader proxyClassLoader) {
|
||||
if (!Object.class.equals(proxySuperClass)) {
|
||||
Method[] methods = proxySuperClass.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
if (!Object.class.equals(method.getDeclaringClass()) && !Modifier.isStatic(method.getModifiers()) &&
|
||||
Modifier.isFinal(method.getModifiers())) {
|
||||
logger.warn("Unable to proxy method [" + method + "] because it is final: " +
|
||||
"All calls to this method via a proxy will be routed directly to the proxy.");
|
||||
int mod = method.getModifiers();
|
||||
if (!Modifier.isStatic(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.");
|
||||
}
|
||||
else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) && !Modifier.isPrivate(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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,7 +613,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
*/
|
||||
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
|
||||
|
||||
private AdvisedSupport advised;
|
||||
private final AdvisedSupport advised;
|
||||
|
||||
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
|
||||
this.advised = advised;
|
||||
@@ -622,8 +631,8 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
oldProxy = AopContext.setCurrentProxy(proxy);
|
||||
setProxyContext = true;
|
||||
}
|
||||
// May be null Get as late as possible to minimize the time we
|
||||
// "own" the target, in case it comes from a pool.
|
||||
// May be null. Get as late as possible to minimize the time we
|
||||
// "own" the target, in case it comes from a pool...
|
||||
target = getTarget();
|
||||
if (target != null) {
|
||||
targetClass = target.getClass();
|
||||
@@ -689,13 +698,13 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
|
||||
private final MethodProxy methodProxy;
|
||||
|
||||
private boolean protectedMethod;
|
||||
private final boolean publicMethod;
|
||||
|
||||
public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
|
||||
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
|
||||
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
|
||||
this.methodProxy = methodProxy;
|
||||
this.protectedMethod = Modifier.isProtected(method.getModifiers());
|
||||
this.publicMethod = Modifier.isPublic(method.getModifiers());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -704,11 +713,11 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
*/
|
||||
@Override
|
||||
protected Object invokeJoinpoint() throws Throwable {
|
||||
if (this.protectedMethod) {
|
||||
return super.invokeJoinpoint();
|
||||
if (this.publicMethod) {
|
||||
return this.methodProxy.invoke(this.target, this.arguments);
|
||||
}
|
||||
else {
|
||||
return this.methodProxy.invoke(this.target, this.arguments);
|
||||
return super.invokeJoinpoint();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -829,8 +838,8 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
// 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 cannot
|
||||
// use a Dispatcher because the target can not then be released.
|
||||
// correct one is already configured. If the target is not static, then
|
||||
// cannot use a dispatcher because the target cannot be released.
|
||||
if (exposeProxy || !isStatic) {
|
||||
return INVOKE_TARGET;
|
||||
}
|
||||
|
||||
+11
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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,19 +50,21 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
|
||||
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
|
||||
Advised config, Method method, Class<?> targetClass) {
|
||||
|
||||
// This is somewhat tricky... we have to process introductions first,
|
||||
// This is somewhat tricky... We have to process introductions first,
|
||||
// but we need to preserve order in the ultimate list.
|
||||
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
|
||||
boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
|
||||
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
|
||||
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
|
||||
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
|
||||
|
||||
for (Advisor advisor : config.getAdvisors()) {
|
||||
if (advisor instanceof PointcutAdvisor) {
|
||||
// Add it conditionally.
|
||||
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
|
||||
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
|
||||
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
|
||||
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
|
||||
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
|
||||
if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
|
||||
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
|
||||
if (mm.isRuntime()) {
|
||||
// Creating a new object instance in the getInterceptors() method
|
||||
// isn't a problem as we normally cache created chains.
|
||||
@@ -78,7 +80,7 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
|
||||
}
|
||||
else if (advisor instanceof IntroductionAdvisor) {
|
||||
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
|
||||
if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {
|
||||
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
|
||||
Interceptor[] interceptors = registry.getInterceptors(advisor);
|
||||
interceptorList.addAll(Arrays.asList(interceptors));
|
||||
}
|
||||
@@ -88,18 +90,19 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
|
||||
interceptorList.addAll(Arrays.asList(interceptors));
|
||||
}
|
||||
}
|
||||
|
||||
return interceptorList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the Advisors contain matching introductions.
|
||||
*/
|
||||
private static boolean hasMatchingIntroductions(Advised config, Class<?> targetClass) {
|
||||
private static boolean hasMatchingIntroductions(Advised config, Class<?> actualClass) {
|
||||
for (int i = 0; i < config.getAdvisors().length; i++) {
|
||||
Advisor advisor = config.getAdvisors()[i];
|
||||
if (advisor instanceof IntroductionAdvisor) {
|
||||
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
|
||||
if (ia.getClassFilter().matches(targetClass)) {
|
||||
if (ia.getClassFilter().matches(actualClass)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,21 +21,18 @@ import java.io.Serializable;
|
||||
import org.springframework.aop.SpringProxy;
|
||||
|
||||
/**
|
||||
* Default {@link AopProxyFactory} implementation,
|
||||
* creating either a CGLIB proxy or a JDK dynamic proxy.
|
||||
* Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy
|
||||
* or a JDK dynamic proxy.
|
||||
*
|
||||
* <p>Creates a CGLIB proxy if one the following is true
|
||||
* for a given {@link AdvisedSupport} instance:
|
||||
* <p>Creates a CGLIB proxy if one the following is true for a given
|
||||
* {@link AdvisedSupport} instance:
|
||||
* <ul>
|
||||
* <li>the "optimize" flag is set
|
||||
* <li>the "proxyTargetClass" flag is set
|
||||
* <li>the {@code optimize} flag is set
|
||||
* <li>the {@code proxyTargetClass} flag is set
|
||||
* <li>no proxy interfaces have been specified
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note that the CGLIB library classes have to be present on
|
||||
* the class path if an actual CGLIB proxy needs to be created.
|
||||
*
|
||||
* <p>In general, specify "proxyTargetClass" to enforce a CGLIB proxy,
|
||||
* <p>In general, specify {@code proxyTargetClass} to enforce a CGLIB proxy,
|
||||
* or specify one or more interfaces to use a JDK dynamic proxy.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -75,7 +75,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
|
||||
*/
|
||||
|
||||
/** We use a static Log to avoid serialization issues */
|
||||
private static Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);
|
||||
private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);
|
||||
|
||||
/** Config used to configure this proxy */
|
||||
private final AdvisedSupport advised;
|
||||
@@ -215,8 +215,10 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
|
||||
// is type-compatible. Note that we can't help if the target sets
|
||||
// a reference to itself in another returned object.
|
||||
retVal = proxy;
|
||||
} else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
|
||||
throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
|
||||
}
|
||||
else 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;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,7 +19,6 @@ package org.springframework.aop.framework;
|
||||
import org.aopalliance.intercept.Interceptor;
|
||||
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -47,9 +46,8 @@ public class ProxyFactory extends ProxyCreatorSupport {
|
||||
* @param target the target object to be proxied
|
||||
*/
|
||||
public ProxyFactory(Object target) {
|
||||
Assert.notNull(target, "Target object must not be null");
|
||||
setInterfaces(ClassUtils.getAllInterfaces(target));
|
||||
setTarget(target);
|
||||
setInterfaces(ClassUtils.getAllInterfaces(target));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -154,7 +154,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
* @see org.aopalliance.aop.Advice
|
||||
* @see org.springframework.aop.target.SingletonTargetSource
|
||||
*/
|
||||
public void setInterceptorNames(String[] interceptorNames) {
|
||||
public void setInterceptorNames(String... interceptorNames) {
|
||||
this.interceptorNames = interceptorNames;
|
||||
}
|
||||
|
||||
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.framework;
|
||||
|
||||
import org.springframework.beans.factory.Aware;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Base class with common functionality for proxy processors, in particular
|
||||
* ClassLoader management and the {@link #evaluateProxyInterfaces} algorithm.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
* @see AbstractAdvisingBeanPostProcessor
|
||||
* @see org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanClassLoaderAware, AopInfrastructureBean {
|
||||
|
||||
/**
|
||||
* This should run after all other processors, so that it can just add
|
||||
* an advisor to existing proxies rather than double-proxy.
|
||||
*/
|
||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||
|
||||
private ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
private boolean classLoaderConfigured = false;
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param order the ordering value
|
||||
*/
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ClassLoader to generate the proxy class in.
|
||||
* <p>Default is the bean ClassLoader, i.e. the ClassLoader used by the containing
|
||||
* {@link org.springframework.beans.factory.BeanFactory} for loading all bean classes.
|
||||
* This can be overridden here for specific proxies.
|
||||
*/
|
||||
public void setProxyClassLoader(ClassLoader classLoader) {
|
||||
this.proxyClassLoader = classLoader;
|
||||
this.classLoaderConfigured = (classLoader != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured proxy ClassLoader for this processor.
|
||||
*/
|
||||
protected ClassLoader getProxyClassLoader() {
|
||||
return this.proxyClassLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
if (!this.classLoaderConfigured) {
|
||||
this.proxyClassLoader = classLoader;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check the interfaces on the given bean class and apply them to the {@link ProxyFactory},
|
||||
* if appropriate.
|
||||
* <p>Calls {@link #isConfigurationCallbackInterface} and {@link #isInternalLanguageInterface}
|
||||
* to filter for reasonable proxy interfaces, falling back to a target-class proxy otherwise.
|
||||
* @param beanClass the class of the bean
|
||||
* @param proxyFactory the ProxyFactory for the bean
|
||||
*/
|
||||
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
|
||||
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
|
||||
boolean hasReasonableProxyInterface = false;
|
||||
for (Class<?> ifc : targetInterfaces) {
|
||||
if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
|
||||
ifc.getMethods().length > 0) {
|
||||
hasReasonableProxyInterface = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasReasonableProxyInterface) {
|
||||
// Must allow for introductions; can't just set interfaces to the target's interfaces only.
|
||||
for (Class<?> ifc : targetInterfaces) {
|
||||
proxyFactory.addInterface(ifc);
|
||||
}
|
||||
}
|
||||
else {
|
||||
proxyFactory.setProxyTargetClass(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given interface is just a container callback and
|
||||
* therefore not to be considered as a reasonable proxy interface.
|
||||
* <p>If no reasonable proxy interface is found for a given bean, it will get
|
||||
* proxied with its full target class, assuming that as the user's intention.
|
||||
* @param ifc the interface to check
|
||||
* @return whether the given interface is just a container callback
|
||||
*/
|
||||
protected boolean isConfigurationCallbackInterface(Class<?> ifc) {
|
||||
return (ifc.equals(InitializingBean.class) || ifc.equals(DisposableBean.class) ||
|
||||
ObjectUtils.containsElement(ifc.getInterfaces(), Aware.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given interface is a well-known internal language interface
|
||||
* and therefore not to be considered as a reasonable proxy interface.
|
||||
* <p>If no reasonable proxy interface is found for a given bean, it will get
|
||||
* proxied with its full target class, assuming that as the user's intention.
|
||||
* @param ifc the interface to check
|
||||
* @return whether the given interface is an internal language interface
|
||||
*/
|
||||
protected boolean isInternalLanguageInterface(Class<?> ifc) {
|
||||
return ifc.getName().equals("groovy.lang.GroovyObject");
|
||||
}
|
||||
|
||||
}
|
||||
+7
-97
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -33,25 +33,18 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.framework.AopInfrastructureBean;
|
||||
import org.springframework.aop.framework.ProxyConfig;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.framework.ProxyProcessorSupport;
|
||||
import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
|
||||
import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
|
||||
import org.springframework.aop.target.SingletonTargetSource;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.factory.Aware;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
|
||||
@@ -94,9 +87,8 @@ import org.springframework.util.ObjectUtils;
|
||||
* @see DefaultAdvisorAutoProxyCreator
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
implements SmartInstantiationAwareBeanPostProcessor, BeanClassLoaderAware, BeanFactoryAware,
|
||||
Ordered, AopInfrastructureBean {
|
||||
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
|
||||
|
||||
/**
|
||||
* Convenience constant for subclasses: Return value for "do not proxy".
|
||||
@@ -115,9 +107,6 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** Default value is same as non-ordered */
|
||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||
|
||||
/** Default is global AdvisorAdapterRegistry */
|
||||
private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
|
||||
|
||||
@@ -134,10 +123,6 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
|
||||
private TargetSourceCreator[] customTargetSourceCreators;
|
||||
|
||||
private ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
private boolean classLoaderConfigured = false;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<Object, Boolean>(64);
|
||||
@@ -151,21 +136,6 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<Object, Class<?>>(16);
|
||||
|
||||
|
||||
/**
|
||||
* Set the ordering which will apply to this class's implementation
|
||||
* of Ordered, used when applying multiple BeanPostProcessors.
|
||||
* <p>Default value is {@code Integer.MAX_VALUE}, meaning that it's non-ordered.
|
||||
* @param order ordering value
|
||||
*/
|
||||
public final void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the proxy should be frozen, preventing advice
|
||||
* from being added to it once it is created.
|
||||
@@ -205,7 +175,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
* Ordering is significant: The TargetSource returned from the first matching
|
||||
* TargetSourceCreator (that is, the first that returns non-null) will be used.
|
||||
*/
|
||||
public void setCustomTargetSourceCreators(TargetSourceCreator[] targetSourceCreators) {
|
||||
public void setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators) {
|
||||
this.customTargetSourceCreators = targetSourceCreators;
|
||||
}
|
||||
|
||||
@@ -216,7 +186,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
* This is perfectly valid, if "specific" interceptors such as matching
|
||||
* Advisors are all we want.
|
||||
*/
|
||||
public void setInterceptorNames(String[] interceptorNames) {
|
||||
public void setInterceptorNames(String... interceptorNames) {
|
||||
this.interceptorNames = interceptorNames;
|
||||
}
|
||||
|
||||
@@ -228,24 +198,6 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
this.applyCommonInterceptorsFirst = applyCommonInterceptorsFirst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ClassLoader to generate the proxy class in.
|
||||
* <p>Default is the bean ClassLoader, i.e. the ClassLoader used by the
|
||||
* containing BeanFactory for loading all bean classes. This can be
|
||||
* overridden here for specific proxies.
|
||||
*/
|
||||
public void setProxyClassLoader(ClassLoader classLoader) {
|
||||
this.proxyClassLoader = classLoader;
|
||||
this.classLoaderConfigured = (classLoader != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
if (!this.classLoaderConfigured) {
|
||||
this.proxyClassLoader = classLoader;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
@@ -466,7 +418,6 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
|
||||
|
||||
ProxyFactory proxyFactory = new ProxyFactory();
|
||||
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
|
||||
proxyFactory.copyFrom(this);
|
||||
|
||||
if (!proxyFactory.isProxyTargetClass()) {
|
||||
@@ -491,7 +442,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
proxyFactory.setPreFiltered(true);
|
||||
}
|
||||
|
||||
return proxyFactory.getProxy(this.proxyClassLoader);
|
||||
return proxyFactory.getProxy(getProxyClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -508,47 +459,6 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
AutoProxyUtils.shouldProxyTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the interfaces on the given bean class and apply them to the ProxyFactory,
|
||||
* if appropriate.
|
||||
* <p>Calls {@link #isConfigurationCallbackInterface} to filter for reasonable
|
||||
* proxy interfaces, falling back to a target-class proxy otherwise.
|
||||
* @param beanClass the class of the bean
|
||||
* @param proxyFactory the ProxyFactory for the bean
|
||||
*/
|
||||
private void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
|
||||
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
|
||||
boolean hasReasonableProxyInterface = false;
|
||||
for (Class<?> ifc : targetInterfaces) {
|
||||
if (!isConfigurationCallbackInterface(ifc) && ifc.getMethods().length > 0) {
|
||||
hasReasonableProxyInterface = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasReasonableProxyInterface) {
|
||||
// Must allow for introductions; can't just set interfaces to the target's interfaces only.
|
||||
for (Class<?> ifc : targetInterfaces) {
|
||||
proxyFactory.addInterface(ifc);
|
||||
}
|
||||
}
|
||||
else {
|
||||
proxyFactory.setProxyTargetClass(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given interface is just a container callback and
|
||||
* therefore not to be considered as a reasonable proxy interface.
|
||||
* <p>If no reasonable proxy interface is found for a given bean, it will get
|
||||
* proxied with its full target class, assuming that as the user's intention.
|
||||
* @param ifc the interface to check
|
||||
* @return whether the given interface is just a container callback
|
||||
*/
|
||||
protected boolean isConfigurationCallbackInterface(Class<?> ifc) {
|
||||
return (ifc.equals(InitializingBean.class) || ifc.equals(DisposableBean.class) ||
|
||||
ObjectUtils.containsElement(ifc.getInterfaces(), Aware.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the Advisors returned by the subclass are pre-filtered
|
||||
* to match the bean's target class already, allowing the ClassFilter check
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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 class BeanNameAutoProxyCreator extends AbstractAutoProxyCreator {
|
||||
* @see org.springframework.beans.factory.FactoryBean
|
||||
* @see org.springframework.beans.factory.BeanFactory#FACTORY_BEAN_PREFIX
|
||||
*/
|
||||
public void setBeanNames(String[] beanNames) {
|
||||
public void setBeanNames(String... beanNames) {
|
||||
Assert.notEmpty(beanNames, "'beanNames' must not be empty");
|
||||
this.beanNames = new ArrayList<String>(beanNames.length);
|
||||
for (String mappedName : beanNames) {
|
||||
|
||||
+7
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,10 +21,10 @@ import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.support.TaskExecutorAdapter;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -41,6 +41,7 @@ import org.springframework.util.StringUtils;
|
||||
* bean to be used when executing it, e.g. through an annotation attribute.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1.2
|
||||
*/
|
||||
public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
@@ -81,13 +82,14 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
* Set the {@link BeanFactory} to be used when looking up executors by qualifier.
|
||||
*/
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine the specific executor to use when executing the given method.
|
||||
* Should preferably return an {@link AsyncListenableTaskExecutor} implementation.
|
||||
* @return the executor to use (or {@code null}, but just if no default executor has been set)
|
||||
*/
|
||||
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
|
||||
@@ -104,8 +106,8 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
else if (executorToUse == null) {
|
||||
return null;
|
||||
}
|
||||
executor = (executorToUse instanceof AsyncTaskExecutor ?
|
||||
(AsyncTaskExecutor) executorToUse : new TaskExecutorAdapter(executorToUse));
|
||||
executor = (executorToUse instanceof AsyncListenableTaskExecutor ?
|
||||
(AsyncListenableTaskExecutor) executorToUse : new TaskExecutorAdapter(executorToUse));
|
||||
this.executors.put(method, executor);
|
||||
}
|
||||
return executor;
|
||||
|
||||
+90
-25
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,13 +23,17 @@ import java.util.concurrent.Future;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* AOP Alliance {@code MethodInterceptor} that processes method invocations
|
||||
@@ -46,12 +50,18 @@ import org.springframework.util.ReflectionUtils;
|
||||
* (like Spring's {@link org.springframework.scheduling.annotation.AsyncResult}
|
||||
* or EJB 3.1's {@code javax.ejb.AsyncResult}).
|
||||
*
|
||||
* <p>When the return type is {@code java.util.concurrent.Future}, any exception thrown
|
||||
* during the execution can be accessed and managed by the caller. With {@code void}
|
||||
* return type however, such exceptions cannot be transmitted back. In that case an
|
||||
* {@link AsyncUncaughtExceptionHandler} can be registered to process such exceptions.
|
||||
*
|
||||
* <p>As of Spring 3.1.2 the {@code AnnotationAsyncExecutionInterceptor} subclass is
|
||||
* preferred for use due to its support for executor qualification in conjunction with
|
||||
* Spring's {@code @Async} annotation.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.0
|
||||
* @see org.springframework.scheduling.annotation.Async
|
||||
* @see org.springframework.scheduling.annotation.AsyncAnnotationAdvisor
|
||||
@@ -60,13 +70,36 @@ import org.springframework.util.ReflectionUtils;
|
||||
public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
|
||||
implements MethodInterceptor, Ordered {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private AsyncUncaughtExceptionHandler exceptionHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code AsyncExecutionInterceptor}.
|
||||
* @param executor the {@link Executor} (typically a Spring {@link AsyncTaskExecutor}
|
||||
* or {@link java.util.concurrent.ExecutorService}) to delegate to.
|
||||
* @param defaultExecutor the {@link Executor} (typically a Spring {@link AsyncTaskExecutor}
|
||||
* or {@link java.util.concurrent.ExecutorService}) to delegate to
|
||||
* @param exceptionHandler the {@link AsyncUncaughtExceptionHandler} to use
|
||||
*/
|
||||
public AsyncExecutionInterceptor(Executor executor) {
|
||||
super(executor);
|
||||
public AsyncExecutionInterceptor(Executor defaultExecutor, AsyncUncaughtExceptionHandler exceptionHandler) {
|
||||
super(defaultExecutor);
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance with a default {@link AsyncUncaughtExceptionHandler}.
|
||||
*/
|
||||
public AsyncExecutionInterceptor(Executor defaultExecutor) {
|
||||
this(defaultExecutor, new SimpleAsyncUncaughtExceptionHandler());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Supply the {@link AsyncUncaughtExceptionHandler} to use to handle exceptions
|
||||
* thrown by invoking asynchronous methods with a {@code void} return type.
|
||||
*/
|
||||
public void setExceptionHandler(AsyncUncaughtExceptionHandler exceptionHandler) {
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,46 +114,78 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
|
||||
public Object invoke(final MethodInvocation invocation) throws Throwable {
|
||||
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
|
||||
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
||||
final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
||||
|
||||
AsyncTaskExecutor executor = determineAsyncExecutor(specificMethod);
|
||||
AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
|
||||
if (executor == null) {
|
||||
throw new IllegalStateException(
|
||||
"No executor specified and no default executor set on AsyncExecutionInterceptor either");
|
||||
}
|
||||
|
||||
Future<?> result = executor.submit(
|
||||
new Callable<Object>() {
|
||||
@Override
|
||||
public Object call() throws Exception {
|
||||
try {
|
||||
Object result = invocation.proceed();
|
||||
if (result instanceof Future) {
|
||||
return ((Future<?>) result).get();
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
ReflectionUtils.rethrowException(ex);
|
||||
}
|
||||
return null;
|
||||
Callable<Object> task = new Callable<Object>() {
|
||||
@Override
|
||||
public Object call() throws Exception {
|
||||
try {
|
||||
Object result = invocation.proceed();
|
||||
if (result instanceof Future) {
|
||||
return ((Future<?>) result).get();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
handleError(ex, userDeclaredMethod, invocation.getArguments());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
if (Future.class.isAssignableFrom(invocation.getMethod().getReturnType())) {
|
||||
return result;
|
||||
Class<?> returnType = invocation.getMethod().getReturnType();
|
||||
if (ListenableFuture.class.isAssignableFrom(returnType)) {
|
||||
return ((AsyncListenableTaskExecutor) executor).submitListenable(task);
|
||||
}
|
||||
else if (Future.class.isAssignableFrom(returnType)) {
|
||||
return executor.submit(task);
|
||||
}
|
||||
else {
|
||||
executor.submit(task);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a fatal error thrown while asynchronously invoking the specified
|
||||
* {@link Method}.
|
||||
* <p>If the return type of the method is a {@link Future} object, the original
|
||||
* exception can be propagated by just throwing it at the higher level. However,
|
||||
* for all other cases, the exception will not be transmitted back to the client.
|
||||
* In that later case, the current {@link AsyncUncaughtExceptionHandler} will be
|
||||
* used to manage such exception.
|
||||
* @param ex the exception to handle
|
||||
* @param method the method that was invoked
|
||||
* @param params the parameters used to invoke the method
|
||||
*/
|
||||
protected void handleError(Throwable ex, Method method, Object... params) throws Exception {
|
||||
if (method.getReturnType().isAssignableFrom(Future.class)) {
|
||||
ReflectionUtils.rethrowException(ex);
|
||||
}
|
||||
else {
|
||||
// Could not transmit the exception to the caller with default executor
|
||||
try {
|
||||
this.exceptionHandler.handleUncaughtException(ex, method, params);
|
||||
}
|
||||
catch (Throwable ex2) {
|
||||
logger.error("Exception handler for async method '" + method.toGenericString() +
|
||||
"' threw unexpected exception itself", ex2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation is a no-op for compatibility in Spring 3.1.2.
|
||||
* Subclasses may override to provide support for extracting qualifier information,
|
||||
* e.g. via an annotation on the given method.
|
||||
* @return always {@code null}
|
||||
* @see #determineAsyncExecutor(Method)
|
||||
* @since 3.1.2
|
||||
* @see #determineAsyncExecutor(Method)
|
||||
*/
|
||||
@Override
|
||||
protected String getExecutorQualifier(Method method) {
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* A strategy for handling uncaught exceptions thrown from asynchronous methods.
|
||||
*
|
||||
* <p>An asynchronous method usually returns a {@link java.util.concurrent.Future}
|
||||
* instance that gives access to the underlying exception. When the method does
|
||||
* not provide that return type, this handler can be used to managed such
|
||||
* uncaught exceptions.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.1
|
||||
*/
|
||||
public interface AsyncUncaughtExceptionHandler {
|
||||
|
||||
/**
|
||||
* Handle the given uncaught exception thrown from an asynchronous method.
|
||||
* @param ex the exception thrown from the asynchronous method
|
||||
* @param method the asynchronous method
|
||||
* @param params the parameters used to invoked the method
|
||||
*/
|
||||
void handleUncaughtException(Throwable ex, Method method, Object... params);
|
||||
|
||||
}
|
||||
+2
-2
@@ -258,7 +258,7 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
return returnValue;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if(stopWatch.isRunning()) {
|
||||
if (stopWatch.isRunning()) {
|
||||
stopWatch.stop();
|
||||
}
|
||||
exitThroughException = true;
|
||||
@@ -268,7 +268,7 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
}
|
||||
finally {
|
||||
if (!exitThroughException) {
|
||||
if(stopWatch.isRunning()) {
|
||||
if (stopWatch.isRunning()) {
|
||||
stopWatch.stop();
|
||||
}
|
||||
writeToLog(logger,
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* A default {@link AsyncUncaughtExceptionHandler} that simply logs the exception.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.1
|
||||
*/
|
||||
public class SimpleAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
|
||||
|
||||
private final Log logger = LogFactory.getLog(SimpleAsyncUncaughtExceptionHandler.class);
|
||||
|
||||
@Override
|
||||
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error(String.format("Unexpected error occurred invoking async " +
|
||||
"method '%s'.", method), ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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 class NameMatchMethodPointcut extends StaticMethodMatcherPointcut impleme
|
||||
* @see #setMappedNames
|
||||
*/
|
||||
public void setMappedName(String mappedName) {
|
||||
setMappedNames(new String[] {mappedName});
|
||||
setMappedNames(mappedName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +55,7 @@ public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut impleme
|
||||
* Matching will be the union of all these; if any match,
|
||||
* the pointcut matches.
|
||||
*/
|
||||
public void setMappedNames(String[] mappedNames) {
|
||||
public void setMappedNames(String... mappedNames) {
|
||||
this.mappedNames = new LinkedList<String>();
|
||||
if (mappedNames != null) {
|
||||
this.mappedNames.addAll(Arrays.asList(mappedNames));
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -68,7 +68,7 @@ public class NameMatchMethodPointcutAdvisor extends AbstractGenericPointcutAdvis
|
||||
* the pointcut matches.
|
||||
* @see NameMatchMethodPointcut#setMappedNames
|
||||
*/
|
||||
public void setMappedNames(String[] mappedNames) {
|
||||
public void setMappedNames(String... mappedNames) {
|
||||
this.pointcut.setMappedNames(mappedNames);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -98,7 +98,7 @@ public class RegexpMethodPointcutAdvisor extends AbstractGenericPointcutAdvisor
|
||||
* @see #setPatterns
|
||||
*/
|
||||
public void setPattern(String pattern) {
|
||||
setPatterns(new String[] {pattern});
|
||||
setPatterns(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +108,7 @@ public class RegexpMethodPointcutAdvisor extends AbstractGenericPointcutAdvisor
|
||||
* patterns matches, the pointcut matches.
|
||||
* @see AbstractRegexpMethodPointcut#setPatterns
|
||||
*/
|
||||
public void setPatterns(String[] patterns) {
|
||||
public void setPatterns(String... patterns) {
|
||||
this.patterns = patterns;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,4 +4,5 @@ http\://www.springframework.org/schema/aop/spring-aop-3.0.xsd=org/springframewor
|
||||
http\://www.springframework.org/schema/aop/spring-aop-3.1.xsd=org/springframework/aop/config/spring-aop-3.1.xsd
|
||||
http\://www.springframework.org/schema/aop/spring-aop-3.2.xsd=org/springframework/aop/config/spring-aop-3.2.xsd
|
||||
http\://www.springframework.org/schema/aop/spring-aop-4.0.xsd=org/springframework/aop/config/spring-aop-4.0.xsd
|
||||
http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-4.0.xsd
|
||||
http\://www.springframework.org/schema/aop/spring-aop-4.1.xsd=org/springframework/aop/config/spring-aop-4.1.xsd
|
||||
http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-4.1.xsd
|
||||
|
||||
@@ -0,0 +1,410 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
|
||||
<xsd:schema xmlns="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
targetNamespace="http://www.springframework.org/schema/aop"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans-4.1.xsd"/>
|
||||
<xsd:import namespace="http://www.springframework.org/schema/tool" schemaLocation="http://www.springframework.org/schema/tool/spring-tool-4.1.xsd"/>
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Defines the configuration elements for the Spring Framework's AOP support.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:element name="config">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A section (compartmentalization) of AOP-specific configuration (including
|
||||
aspects, pointcuts, etc).
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="pointcut" type="pointcutType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A named pointcut definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="advisor" type="advisorType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.aop.Advisor"><![CDATA[
|
||||
A named advisor definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="aspect" type="aspectType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A named aspect definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="proxy-target-class" type="xsd:boolean" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Are class-based (CGLIB) proxies to be created? By default, standard
|
||||
Java interface-based proxies are created.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="expose-proxy" type="xsd:boolean" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicate that the proxy should be exposed by the AOP framework as a
|
||||
ThreadLocal for retrieval via the AopContext class. Off by default,
|
||||
i.e. no guarantees that AopContext access will work.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="aspectj-autoproxy">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"><![CDATA[
|
||||
Enables the use of the @AspectJ style of Spring AOP.
|
||||
|
||||
See org.springframework.context.annotation.EnableAspectJAutoProxy Javadoc
|
||||
for information on code-based alternatives to this XML element.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="include" type="includeType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicates that only @AspectJ beans with names matched by the (regex)
|
||||
pattern will be considered as defining aspects to use for Spring autoproxying.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="proxy-target-class" type="xsd:boolean" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Are class-based (CGLIB) proxies to be created? By default, standard
|
||||
Java interface-based proxies are created.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="expose-proxy" type="xsd:boolean" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicate that the proxy should be exposed by the AOP framework as a
|
||||
ThreadLocal for retrieval via the AopContext class. Off by default,
|
||||
i.e. no guarantees that AopContext access will work.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="scoped-proxy">
|
||||
<xsd:complexType>
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.aop.scope.ScopedProxyFactoryBean"><![CDATA[
|
||||
Marks a bean definition as being a scoped proxy.
|
||||
|
||||
A bean marked as such will be exposed via a proxy, with the 'real'
|
||||
bean instance being retrieved from some other source (such as a
|
||||
HttpSession) as and when required.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="proxy-target-class" type="xsd:boolean" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Are class-based (CGLIB) proxies to be created? This is the default; in order to
|
||||
switch to standard Java interface-based proxies, turn this flag to "false".
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="aspectType">
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="pointcut" type="pointcutType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A named pointcut definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="declare-parents" type="declareParentsType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Allows this aspect to introduce additional interfaces that the advised
|
||||
object will transparently implement.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="before" type="basicAdviceType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A before advice definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="after" type="basicAdviceType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
An after advice definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="after-returning" type="afterReturningAdviceType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
An after-returning advice definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="after-throwing" type="afterThrowingAdviceType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
An after-throwing advice definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="around" type="basicAdviceType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
An around advice definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="id" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The unique identifier for an aspect.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="ref" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The name of the (backing) bean that encapsulates the aspect.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="order" type="xsd:token">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.core.Ordered"><![CDATA[
|
||||
Controls the ordering of the execution of this aspect when multiple
|
||||
advice executes at a specific joinpoint.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="includeType">
|
||||
<xsd:attribute name="name" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:java.util.regex.Pattern"><![CDATA[
|
||||
The regular expression defining which beans are to be included in the
|
||||
list of @AspectJ beans; beans with names matched by the pattern will
|
||||
be included.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="pointcutType">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:exports type="org.springframework.aop.Pointcut"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="id" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The unique identifier for a pointcut.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="expression" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The pointcut expression.
|
||||
|
||||
For example : 'execution(* com.xyz.myapp.service.*.*(..))'
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="declareParentsType">
|
||||
<xsd:attribute name="types-matching" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.aop.aspectj.TypePatternClassFilter"><![CDATA[
|
||||
The AspectJ type expression that defines what types (classes) the
|
||||
introduction is restricted to.
|
||||
|
||||
An example would be 'org.springframework.beans.ITestBean+'.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="implement-interface" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:java.lang.Class"><![CDATA[
|
||||
The fully qualified name of the interface that will be introduced.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="default-impl" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:java.lang.Class"><![CDATA[
|
||||
The fully qualified name of the class that will be instantiated to serve
|
||||
as the default implementation of the introduced interface.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="delegate-ref" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A reference to the bean that will serve
|
||||
as the default implementation of the introduced interface.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref"/>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="basicAdviceType">
|
||||
<xsd:attribute name="pointcut" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The associated pointcut expression.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="pointcut-ref" type="pointcutRefType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The name of an associated pointcut definition.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.aop.Pointcut"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="method" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The name of the method that defines the logic of the advice.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="arg-names" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The comma-delimited list of advice method argument (parameter) names
|
||||
that will be matched from pointcut parameters.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="afterReturningAdviceType">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="basicAdviceType">
|
||||
<xsd:attribute name="returning" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The name of the method parameter to which the return value must
|
||||
be passed.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="afterThrowingAdviceType">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="basicAdviceType">
|
||||
<xsd:attribute name="throwing" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The name of the method parameter to which the thrown exception must
|
||||
be passed.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="advisorType">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:exports type="org.springframework.aop.Advisor"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="id" type="xsd:string"/>
|
||||
<xsd:attribute name="advice-ref" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A reference to an advice bean.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.aopalliance.aop.Advice"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="pointcut" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A pointcut expression.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="pointcut-ref" type="pointcutRefType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A reference to a pointcut definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="order" type="xsd:token">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.core.Ordered"><![CDATA[
|
||||
Controls the ordering of the execution of this advice when multiple
|
||||
advice executes at a specific joinpoint.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:simpleType name="pointcutRefType">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.aop.Pointcut"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:union memberTypes="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
|
||||
</xsd:schema>
|
||||
+6
-3
@@ -38,6 +38,7 @@ import org.aspectj.lang.annotation.DeclarePrecedence;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
@@ -402,8 +403,8 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||
|
||||
@Test
|
||||
public void testIntroductionOnTargetExcludedByTypePattern() {
|
||||
LinkedList target = new LinkedList();
|
||||
List proxy = (List) createProxy(target,
|
||||
LinkedList<Object> target = new LinkedList<Object>();
|
||||
List<?> proxy = (List<?>) createProxy(target,
|
||||
AopUtils.findAdvisorsThatCanApply(
|
||||
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
|
||||
List.class
|
||||
@@ -431,7 +432,9 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||
|
||||
// TODO: Why does this test fail? It hasn't been run before, so it maybe never actually passed...
|
||||
|
||||
public void XtestIntroductionWithArgumentBinding() {
|
||||
@Test
|
||||
@Ignore
|
||||
public void testIntroductionWithArgumentBinding() {
|
||||
TestBean target = new TestBean();
|
||||
|
||||
List<Advisor> advisors = getFixture().getAdvisors(
|
||||
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.aspectj;
|
||||
|
||||
import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
import org.springframework.beans.factory.wiring.BeanConfigurerSupport;
|
||||
|
||||
/**
|
||||
* Abstract superaspect for AspectJ aspects that can perform Dependency
|
||||
* Injection on objects, however they may be created. Define the beanCreation()
|
||||
* pointcut in subaspects.
|
||||
*
|
||||
* <p>Subaspects may also need a metadata resolution strategy, in the
|
||||
* {@code BeanWiringInfoResolver} interface. The default implementation
|
||||
* looks for a bean with the same name as the FQN. This is the default name
|
||||
* of a bean in a Spring container if the id value is not supplied explicitly.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Rod Johnson
|
||||
* @author Adrian Colyer
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
* @deprecated as of Spring 2.5.2.
|
||||
* Use AbstractDependencyInjectionAspect or its subaspects instead.
|
||||
*/
|
||||
public abstract aspect AbstractBeanConfigurerAspect extends BeanConfigurerSupport {
|
||||
|
||||
/**
|
||||
* Configured bean before initialization.
|
||||
*/
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
before(Object beanInstance) : beanInitialization(beanInstance) {
|
||||
if (preConstructionConfiguration(beanInstance)) {
|
||||
configureBean(beanInstance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configured bean after construction.
|
||||
*/
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object beanInstance) returning : beanCreation(beanInstance) {
|
||||
if (!preConstructionConfiguration(beanInstance)) {
|
||||
configureBean(beanInstance);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The initialization of a new object.
|
||||
*
|
||||
* <p>WARNING: Although this pointcut is non-abstract for backwards
|
||||
* compatibility reasons, it is meant to be overridden to select
|
||||
* initialization of any configurable bean.
|
||||
*/
|
||||
protected pointcut beanInitialization(Object beanInstance);
|
||||
|
||||
/**
|
||||
* The creation of a new object.
|
||||
*/
|
||||
protected abstract pointcut beanCreation(Object beanInstance);
|
||||
|
||||
|
||||
/**
|
||||
* Are dependencies to be injected prior to the construction of an object?
|
||||
*/
|
||||
protected boolean preConstructionConfiguration(Object beanInstance) {
|
||||
return false; // matches the default in the @Configurable annotation
|
||||
}
|
||||
|
||||
}
|
||||
+30
-27
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,26 +27,18 @@ import org.aspectj.lang.annotation.control.CodeGenerationHint;
|
||||
* @since 2.5.2
|
||||
*/
|
||||
public abstract aspect AbstractDependencyInjectionAspect {
|
||||
/**
|
||||
* Select construction join points for objects to inject dependencies
|
||||
*/
|
||||
public abstract pointcut beanConstruction(Object bean);
|
||||
|
||||
private pointcut preConstructionCondition() :
|
||||
leastSpecificSuperTypeConstruction() && preConstructionConfiguration();
|
||||
|
||||
private pointcut postConstructionCondition() :
|
||||
mostSpecificSubTypeConstruction() && !preConstructionConfiguration();
|
||||
|
||||
/**
|
||||
* Select deserialization join points for objects to inject dependencies
|
||||
* Select least specific super type that is marked for DI
|
||||
* (so that injection occurs only once with pre-construction injection).
|
||||
*/
|
||||
public abstract pointcut beanDeserialization(Object bean);
|
||||
|
||||
/**
|
||||
* Select join points in a configurable bean
|
||||
*/
|
||||
public abstract pointcut inConfigurableBean();
|
||||
|
||||
/**
|
||||
* Select join points in beans to be configured prior to construction?
|
||||
* By default, use post-construction injection matching the default in the Configurable annotation.
|
||||
*/
|
||||
public pointcut preConstructionConfiguration() : if(false);
|
||||
public abstract pointcut leastSpecificSuperTypeConstruction();
|
||||
|
||||
/**
|
||||
* Select the most-specific initialization join point
|
||||
@@ -54,24 +46,29 @@ public abstract aspect AbstractDependencyInjectionAspect {
|
||||
*/
|
||||
@CodeGenerationHint(ifNameSuffix="6f1")
|
||||
public pointcut mostSpecificSubTypeConstruction() :
|
||||
if(thisJoinPoint.getSignature().getDeclaringType() == thisJoinPoint.getThis().getClass());
|
||||
if (thisJoinPoint.getSignature().getDeclaringType() == thisJoinPoint.getThis().getClass());
|
||||
|
||||
/**
|
||||
* Select least specific super type that is marked for DI (so that injection occurs only once with pre-construction inejection
|
||||
* Select join points in beans to be configured prior to construction?
|
||||
* By default, use post-construction injection matching the default in the Configurable annotation.
|
||||
*/
|
||||
public abstract pointcut leastSpecificSuperTypeConstruction();
|
||||
public pointcut preConstructionConfiguration() : if (false);
|
||||
|
||||
/**
|
||||
* Configure the bean
|
||||
* Select construction join points for objects to inject dependencies.
|
||||
*/
|
||||
public abstract void configureBean(Object bean);
|
||||
public abstract pointcut beanConstruction(Object bean);
|
||||
|
||||
/**
|
||||
* Select deserialization join points for objects to inject dependencies.
|
||||
*/
|
||||
public abstract pointcut beanDeserialization(Object bean);
|
||||
|
||||
private pointcut preConstructionCondition() :
|
||||
leastSpecificSuperTypeConstruction() && preConstructionConfiguration();
|
||||
/**
|
||||
* Select join points in a configurable bean.
|
||||
*/
|
||||
public abstract pointcut inConfigurableBean();
|
||||
|
||||
private pointcut postConstructionCondition() :
|
||||
mostSpecificSubTypeConstruction() && !preConstructionConfiguration();
|
||||
|
||||
/**
|
||||
* Pre-construction configuration.
|
||||
@@ -100,4 +97,10 @@ public abstract aspect AbstractDependencyInjectionAspect {
|
||||
configureBean(bean);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configure the given bean.
|
||||
*/
|
||||
public abstract void configureBean(Object bean);
|
||||
|
||||
}
|
||||
|
||||
+50
-54
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,49 +20,48 @@ import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An aspect that injects dependency into any object whose type implements the {@link ConfigurableObject} interface.
|
||||
* <p>
|
||||
* This aspect supports injecting into domain objects when they are created for the first time as well as
|
||||
* upon deserialization. Subaspects need to simply provide definition for the configureBean() method. This
|
||||
* method may be implemented without relying on Spring container if so desired.
|
||||
* </p>
|
||||
* <p>
|
||||
* There are two cases that needs to be handled:
|
||||
* An aspect that injects dependency into any object whose type implements the
|
||||
* {@link ConfigurableObject} interface.
|
||||
*
|
||||
* <p>This aspect supports injecting into domain objects when they are created
|
||||
* for the first time as well as upon deserialization. Subaspects need to simply
|
||||
* provide definition for the configureBean() method. This method may be
|
||||
* implemented without relying on Spring container if so desired.
|
||||
*
|
||||
* <p>There are two cases that needs to be handled:
|
||||
* <ol>
|
||||
* <li>Normal object creation via the '{@code new}' operator: this is
|
||||
* taken care of by advising {@code initialization()} join points.</li>
|
||||
* <li>Object creation through deserialization: since no constructor is
|
||||
* invoked during deserialization, the aspect needs to advise a method that a
|
||||
* deserialization mechanism is going to invoke. Ideally, we should not
|
||||
* require user classes to implement any specific method. This implies that
|
||||
* we need to <i>introduce</i> the chosen method. We should also handle the cases
|
||||
* where the chosen method is already implemented in classes (in which case,
|
||||
* the user's implementation for that method should take precedence over the
|
||||
* introduced implementation). There are a few choices for the chosen method:
|
||||
* <ul>
|
||||
* <li>readObject(ObjectOutputStream): Java requires that the method must be
|
||||
* {@code private}</p>. Since aspects cannot introduce a private member,
|
||||
* while preserving its name, this option is ruled out.</li>
|
||||
* <li>readResolve(): Java doesn't pose any restriction on an access specifier.
|
||||
* Problem solved! There is one (minor) limitation of this approach in
|
||||
* that if a user class already has this method, that method must be
|
||||
* {@code public}. However, this shouldn't be a big burden, since
|
||||
* use cases that need classes to implement readResolve() (custom enums,
|
||||
* for example) are unlikely to be marked as @Configurable, and
|
||||
* in any case asking to make that method {@code public} should not
|
||||
* pose any undue burden.</li>
|
||||
* </ul>
|
||||
* The minor collaboration needed by user classes (i.e., that the
|
||||
* implementation of {@code readResolve()}, if any, must be
|
||||
* {@code public}) can be lifted as well if we were to use an
|
||||
* experimental feature in AspectJ - the {@code hasmethod()} PCD.</li>
|
||||
* <li>Normal object creation via the '{@code new}' operator: this is
|
||||
* taken care of by advising {@code initialization()} join points.</li>
|
||||
* <li>Object creation through deserialization: since no constructor is
|
||||
* invoked during deserialization, the aspect needs to advise a method that a
|
||||
* deserialization mechanism is going to invoke. Ideally, we should not
|
||||
* require user classes to implement any specific method. This implies that
|
||||
* we need to <i>introduce</i> the chosen method. We should also handle the cases
|
||||
* where the chosen method is already implemented in classes (in which case,
|
||||
* the user's implementation for that method should take precedence over the
|
||||
* introduced implementation). There are a few choices for the chosen method:
|
||||
* <ul>
|
||||
* <li>readObject(ObjectOutputStream): Java requires that the method must be
|
||||
* {@code private}</p>. Since aspects cannot introduce a private member,
|
||||
* while preserving its name, this option is ruled out.</li>
|
||||
* <li>readResolve(): Java doesn't pose any restriction on an access specifier.
|
||||
* Problem solved! There is one (minor) limitation of this approach in
|
||||
* that if a user class already has this method, that method must be
|
||||
* {@code public}. However, this shouldn't be a big burden, since
|
||||
* use cases that need classes to implement readResolve() (custom enums,
|
||||
* for example) are unlikely to be marked as @Configurable, and
|
||||
* in any case asking to make that method {@code public} should not
|
||||
* pose any undue burden.</li>
|
||||
* </ul>
|
||||
* The minor collaboration needed by user classes (i.e., that the implementation of
|
||||
* {@code readResolve()}, if any, must be {@code public}) can be lifted as well if we
|
||||
* were to use an experimental feature in AspectJ - the {@code hasmethod()} PCD.</li>
|
||||
* </ol>
|
||||
|
||||
* <p>
|
||||
* While having type implement the {@link ConfigurableObject} interface is certainly a valid choice, an alternative
|
||||
* is to use a 'declare parents' statement another aspect (a subaspect of this aspect would be a logical choice)
|
||||
* that declares the classes that need to be configured by supplying the {@link ConfigurableObject} interface.
|
||||
* </p>
|
||||
*
|
||||
* <p>While having type implement the {@link ConfigurableObject} interface is certainly
|
||||
* a valid choice, an alternative is to use a 'declare parents' statement another aspect
|
||||
* (a subaspect of this aspect would be a logical choice) that declares the classes that
|
||||
* need to be configured by supplying the {@link ConfigurableObject} interface.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.5.2
|
||||
@@ -72,35 +71,33 @@ public abstract aspect AbstractInterfaceDrivenDependencyInjectionAspect extends
|
||||
* Select initialization join point as object construction
|
||||
*/
|
||||
public pointcut beanConstruction(Object bean) :
|
||||
initialization(ConfigurableObject+.new(..)) && this(bean);
|
||||
initialization(ConfigurableObject+.new(..)) && this(bean);
|
||||
|
||||
/**
|
||||
* Select deserialization join point made available through ITDs for ConfigurableDeserializationSupport
|
||||
*/
|
||||
public pointcut beanDeserialization(Object bean) :
|
||||
execution(Object ConfigurableDeserializationSupport+.readResolve()) &&
|
||||
this(bean);
|
||||
execution(Object ConfigurableDeserializationSupport+.readResolve()) && this(bean);
|
||||
|
||||
public pointcut leastSpecificSuperTypeConstruction() : initialization(ConfigurableObject.new(..));
|
||||
|
||||
|
||||
|
||||
// Implementation to support re-injecting dependencies once an object is deserialized
|
||||
|
||||
/**
|
||||
* Declare any class implementing Serializable and ConfigurableObject as also implementing
|
||||
* ConfigurableDeserializationSupport. This allows us to introduce the readResolve()
|
||||
* ConfigurableDeserializationSupport. This allows us to introduce the {@code readResolve()}
|
||||
* method and select it with the beanDeserialization() pointcut.
|
||||
*
|
||||
* <p>Here is an improved version that uses the hasmethod() pointcut and lifts
|
||||
* even the minor requirement on user classes:
|
||||
*
|
||||
* <pre class="code">declare parents: ConfigurableObject+ Serializable+
|
||||
* && !hasmethod(Object readResolve() throws ObjectStreamException)
|
||||
* implements ConfigurableDeserializationSupport;
|
||||
* <pre class="code">
|
||||
* declare parents: ConfigurableObject+ Serializable+
|
||||
* && !hasmethod(Object readResolve() throws ObjectStreamException)
|
||||
* implements ConfigurableDeserializationSupport;
|
||||
* </pre>
|
||||
*/
|
||||
declare parents:
|
||||
ConfigurableObject+ && Serializable+ implements ConfigurableDeserializationSupport;
|
||||
declare parents: ConfigurableObject+ && Serializable+ implements ConfigurableDeserializationSupport;
|
||||
|
||||
/**
|
||||
* A marker interface to which the {@code readResolve()} is introduced.
|
||||
@@ -111,7 +108,6 @@ public abstract aspect AbstractInterfaceDrivenDependencyInjectionAspect extends
|
||||
/**
|
||||
* Introduce the {@code readResolve()} method so that we can advise its
|
||||
* execution to configure the object.
|
||||
*
|
||||
* <p>Note if a method with the same signature already exists in a
|
||||
* {@code Serializable} class of ConfigurableObject type,
|
||||
* that implementation will take precedence (a good thing, since we are
|
||||
|
||||
+27
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,7 +19,7 @@ package org.springframework.beans.factory.aspectj;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.aspectj.lang.annotation.control.CodeGenerationHint;
|
||||
import org.springframework.beans.BeansException;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
@@ -44,48 +44,47 @@ import org.springframework.beans.factory.wiring.BeanConfigurerSupport;
|
||||
* @see org.springframework.beans.factory.annotation.Configurable
|
||||
* @see org.springframework.beans.factory.annotation.AnnotationBeanWiringInfoResolver
|
||||
*/
|
||||
public aspect AnnotationBeanConfigurerAspect
|
||||
extends AbstractInterfaceDrivenDependencyInjectionAspect
|
||||
public aspect AnnotationBeanConfigurerAspect extends AbstractInterfaceDrivenDependencyInjectionAspect
|
||||
implements BeanFactoryAware, InitializingBean, DisposableBean {
|
||||
|
||||
private BeanConfigurerSupport beanConfigurerSupport = new BeanConfigurerSupport();
|
||||
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanConfigurerSupport.setBeanWiringInfoResolver(new AnnotationBeanWiringInfoResolver());
|
||||
this.beanConfigurerSupport.setBeanFactory(beanFactory);
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
this.beanConfigurerSupport.afterPropertiesSet();
|
||||
}
|
||||
|
||||
public void configureBean(Object bean) {
|
||||
this.beanConfigurerSupport.configureBean(bean);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
this.beanConfigurerSupport.destroy();
|
||||
}
|
||||
|
||||
|
||||
public pointcut inConfigurableBean() : @this(Configurable);
|
||||
|
||||
public pointcut preConstructionConfiguration() : preConstructionConfigurationSupport(*);
|
||||
|
||||
declare parents: @Configurable * implements ConfigurableObject;
|
||||
|
||||
public void configureBean(Object bean) {
|
||||
beanConfigurerSupport.configureBean(bean);
|
||||
}
|
||||
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
beanConfigurerSupport.setBeanFactory(beanFactory);
|
||||
beanConfigurerSupport.setBeanWiringInfoResolver(new AnnotationBeanWiringInfoResolver());
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
beanConfigurerSupport.afterPropertiesSet();
|
||||
}
|
||||
|
||||
public void destroy() throws Exception {
|
||||
beanConfigurerSupport.destroy();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* An intermediary to match preConstructionConfiguration signature (that doesn't expose the annotation object)
|
||||
*/
|
||||
@CodeGenerationHint(ifNameSuffix="bb0")
|
||||
private pointcut preConstructionConfigurationSupport(Configurable c) : @this(c) && if(c.preConstruction());
|
||||
private pointcut preConstructionConfigurationSupport(Configurable c) : @this(c) && if (c.preConstruction());
|
||||
|
||||
|
||||
declare parents: @Configurable * implements ConfigurableObject;
|
||||
|
||||
/*
|
||||
* This declaration shouldn't be needed,
|
||||
* except for an AspectJ bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=214559)
|
||||
*/
|
||||
declare parents: @Configurable Serializable+
|
||||
implements ConfigurableDeserializationSupport;
|
||||
declare parents: @Configurable Serializable+ implements ConfigurableDeserializationSupport;
|
||||
|
||||
}
|
||||
|
||||
+11
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,7 +20,9 @@ import java.lang.reflect.Method;
|
||||
|
||||
import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.cache.interceptor.CacheAspectSupport;
|
||||
import org.springframework.cache.interceptor.CacheOperationInvoker;
|
||||
import org.springframework.cache.interceptor.CacheOperationSource;
|
||||
|
||||
/**
|
||||
@@ -35,9 +37,10 @@ import org.springframework.cache.interceptor.CacheOperationSource;
|
||||
* relevant Spring cache definition will <i>not</i> be resolved.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract aspect AbstractCacheAspect extends CacheAspectSupport {
|
||||
public abstract aspect AbstractCacheAspect extends CacheAspectSupport implements DisposableBean {
|
||||
|
||||
protected AbstractCacheAspect() {
|
||||
}
|
||||
@@ -51,12 +54,17 @@ public abstract aspect AbstractCacheAspect extends CacheAspectSupport {
|
||||
setCacheOperationSources(cos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
clearMetadataCache(); // An aspect is basically a singleton
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
Object around(final Object cachedObject) : cacheMethodExecution(cachedObject) {
|
||||
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
|
||||
Invoker aspectJInvoker = new Invoker() {
|
||||
CacheOperationInvoker aspectJInvoker = new CacheOperationInvoker() {
|
||||
public Object invoke() {
|
||||
return proceed(cachedObject);
|
||||
}
|
||||
|
||||
Vendored
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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,7 +18,7 @@ package org.springframework.cache.aspectj;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.cache.annotation.AbstractCachingConfiguration;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.cache.config.CacheManagementConfigUtils;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
@@ -35,7 +35,7 @@ import org.springframework.context.annotation.Role;
|
||||
@Configuration
|
||||
public class AspectJCachingConfiguration extends AbstractCachingConfiguration {
|
||||
|
||||
@Bean(name=AnnotationConfigUtils.CACHE_ASPECT_BEAN_NAME)
|
||||
@Bean(name = CacheManagementConfigUtils.CACHE_ASPECT_BEAN_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public AnnotationCacheAspect cacheAspect() {
|
||||
AnnotationCacheAspect cacheAspect = AnnotationCacheAspect.aspectOf();
|
||||
@@ -47,4 +47,5 @@ public class AspectJCachingConfiguration extends AbstractCachingConfiguration {
|
||||
}
|
||||
return cacheAspect;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vendored
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.aspectj;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.cache.config.CacheManagementConfigUtils;
|
||||
import org.springframework.cache.jcache.config.AbstractJCacheConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
|
||||
/**
|
||||
* {@code @Configuration} class that registers the Spring infrastructure beans necessary
|
||||
* to enable AspectJ-based annotation-driven cache management for standard JSR-107
|
||||
* annotations.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.1
|
||||
* @see org.springframework.cache.annotation.EnableCaching
|
||||
* @see org.springframework.cache.annotation.CachingConfigurationSelector
|
||||
*/
|
||||
@Configuration
|
||||
public class AspectJJCacheConfiguration extends AbstractJCacheConfiguration {
|
||||
|
||||
@Bean(name = CacheManagementConfigUtils.JCACHE_ASPECT_BEAN_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public JCacheCacheAspect cacheAspect() {
|
||||
JCacheCacheAspect cacheAspect = JCacheCacheAspect.aspectOf();
|
||||
cacheAspect.setCacheOperationSource(cacheOperationSource());
|
||||
return cacheAspect;
|
||||
}
|
||||
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.cache.annotation.CachePut;
|
||||
import javax.cache.annotation.CacheRemove;
|
||||
import javax.cache.annotation.CacheRemoveAll;
|
||||
import javax.cache.annotation.CacheResult;
|
||||
|
||||
import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
|
||||
import org.springframework.cache.interceptor.CacheOperationInvoker;
|
||||
import org.springframework.cache.jcache.interceptor.JCacheAspectSupport;
|
||||
|
||||
/**
|
||||
* Concrete AspectJ cache aspect using JSR-107 standard annotations.
|
||||
*
|
||||
* <p>When using this aspect, you <i>must</i> annotate the implementation class (and/or
|
||||
* methods within that class), <i>not</i> the interface (if any) that the class
|
||||
* implements. AspectJ follows Java's rule that annotations on interfaces are <i>not</i>
|
||||
* inherited.
|
||||
*
|
||||
* <p>Any method may be annotated (regardless of visibility). Annotating non-public
|
||||
* methods directly is the only way to get caching demarcation for the execution of
|
||||
* such operations.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.1
|
||||
*/
|
||||
public aspect JCacheCacheAspect extends JCacheAspectSupport {
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
Object around(final Object cachedObject) : cacheMethodExecution(cachedObject) {
|
||||
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
|
||||
CacheOperationInvoker aspectJInvoker = new CacheOperationInvoker() {
|
||||
public Object invoke() {
|
||||
try {
|
||||
return proceed(cachedObject);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new ThrowableWrapper(ex);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
try {
|
||||
return execute(aspectJInvoker, thisJoinPoint.getTarget(), method, thisJoinPoint.getArgs());
|
||||
}
|
||||
catch (CacheOperationInvoker.ThrowableWrapper th) {
|
||||
AnyThrow.throwUnchecked(th.getOriginal());
|
||||
return null; // never reached
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition of pointcut: matched join points will have JSR-107
|
||||
* cache management applied.
|
||||
*/
|
||||
protected pointcut cacheMethodExecution(Object cachedObject) :
|
||||
(executionOfCacheResultMethod()
|
||||
|| executionOfCachePutMethod()
|
||||
|| executionOfCacheRemoveMethod()
|
||||
|| executionOfCacheRemoveAllMethod())
|
||||
&& this(cachedObject);
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the @{@link CacheResult} annotation.
|
||||
*/
|
||||
private pointcut executionOfCacheResultMethod() :
|
||||
execution(@CacheResult * *(..));
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the @{@link CachePut} annotation.
|
||||
*/
|
||||
private pointcut executionOfCachePutMethod() :
|
||||
execution(@CachePut * *(..));
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the @{@link CacheRemove} annotation.
|
||||
*/
|
||||
private pointcut executionOfCacheRemoveMethod() :
|
||||
execution(@CacheRemove * *(..));
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the @{@link CacheRemoveAll} annotation.
|
||||
*/
|
||||
private pointcut executionOfCacheRemoveAllMethod() :
|
||||
execution(@CacheRemoveAll * *(..));
|
||||
|
||||
|
||||
private static class AnyThrow {
|
||||
|
||||
private static void throwUnchecked(Throwable e) {
|
||||
AnyThrow.<RuntimeException>throwAny(e);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <E extends Throwable> void throwAny(Throwable e) throws E {
|
||||
throw (E)e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,12 +17,12 @@
|
||||
package org.springframework.scheduling.aspectj;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.scheduling.annotation.AbstractAsyncConfiguration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.config.TaskManagementConfigUtils;
|
||||
|
||||
/**
|
||||
* {@code @Configuration} class that registers the Spring infrastructure beans necessary
|
||||
@@ -37,7 +37,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
||||
@Configuration
|
||||
public class AspectJAsyncConfiguration extends AbstractAsyncConfiguration {
|
||||
|
||||
@Bean(name=AnnotationConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)
|
||||
@Bean(name = TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public AnnotationAsyncExecutionAspect asyncAdvisor() {
|
||||
AnnotationAsyncExecutionAspect asyncAspect = AnnotationAsyncExecutionAspect.aspectOf();
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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,7 +37,7 @@ import org.springframework.transaction.config.TransactionManagementConfigUtils;
|
||||
@Configuration
|
||||
public class AspectJTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
|
||||
|
||||
@Bean(name=TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME)
|
||||
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public AnnotationTransactionAspect transactionAspect() {
|
||||
AnnotationTransactionAspect txAspect = AnnotationTransactionAspect.aspectOf();
|
||||
@@ -46,4 +46,5 @@ public class AspectJTransactionManagementConfiguration extends AbstractTransacti
|
||||
}
|
||||
return txAspect;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-676
@@ -1,676 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.aspectj;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Configurable;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.mail.MailSender;
|
||||
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public abstract class AbstractBeanConfigurerTests extends TestCase {
|
||||
|
||||
protected ConfigurableApplicationContext context;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
this.context = createContext();
|
||||
}
|
||||
|
||||
protected abstract ConfigurableApplicationContext createContext();
|
||||
|
||||
public void testConfigurableWithExplicitBeanName() {
|
||||
ShouldBeConfiguredBySpring myObject = new ShouldBeConfiguredBySpring();
|
||||
assertEquals("Rod", myObject.getName());
|
||||
}
|
||||
|
||||
public void testWithoutAnnotation() {
|
||||
ShouldNotBeConfiguredBySpring myObject = new ShouldNotBeConfiguredBySpring();
|
||||
assertNull("Name should not have been set", myObject.getName());
|
||||
}
|
||||
|
||||
public void testConfigurableWithImplicitBeanName() {
|
||||
ShouldBeConfiguredBySpringUsingTypeNameAsBeanName myObject =
|
||||
new ShouldBeConfiguredBySpringUsingTypeNameAsBeanName();
|
||||
assertEquals("Rob", myObject.getName());
|
||||
}
|
||||
|
||||
public void testConfigurableUsingAutowireByType() {
|
||||
ShouldBeConfiguredBySpringUsingAutowireByType myObject =
|
||||
new ShouldBeConfiguredBySpringUsingAutowireByType();
|
||||
assertNotNull(myObject.getFriend());
|
||||
assertEquals("Ramnivas", myObject.getFriend().getName());
|
||||
}
|
||||
|
||||
public void testConfigurableUsingAutowireByName() {
|
||||
ValidAutowireByName myObject = new ValidAutowireByName();
|
||||
assertNotNull(myObject.getRamnivas());
|
||||
assertEquals("Ramnivas", myObject.getRamnivas().getName());
|
||||
}
|
||||
|
||||
public void testInvalidAutowireByName() {
|
||||
try {
|
||||
new InvalidAutowireByName();
|
||||
fail("Autowire by name cannot work");
|
||||
}
|
||||
catch (UnsatisfiedDependencyException ex) {
|
||||
// Ok
|
||||
}
|
||||
}
|
||||
|
||||
public void testNewAspectAppliesToArbitraryNonAnnotatedPojo() {
|
||||
ArbitraryExistingPojo aep = new ArbitraryExistingPojo();
|
||||
assertNotNull(aep.friend);
|
||||
assertEquals("Ramnivas", aep.friend.getName());
|
||||
}
|
||||
|
||||
public void testNewAspectThatWasNotAddedToSpringContainer() {
|
||||
try{
|
||||
new ClassThatWillNotActuallyBeWired();
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertTrue(ex.getMessage().indexOf("BeanFactory") != -1);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInjectionOnDeserialization() throws Exception {
|
||||
ShouldBeConfiguredBySpring domainObject = new ShouldBeConfiguredBySpring();
|
||||
domainObject.setName("Anonymous");
|
||||
ShouldBeConfiguredBySpring deserializedDomainObject =
|
||||
serializeAndDeserialize(domainObject);
|
||||
assertEquals("Dependency injected on deserialization","Rod",deserializedDomainObject.getName());
|
||||
}
|
||||
|
||||
public void testInjectionOnDeserializationForClassesThatContainsPublicReadResolve() throws Exception {
|
||||
ShouldBeConfiguredBySpringContainsPublicReadResolve domainObject = new ShouldBeConfiguredBySpringContainsPublicReadResolve();
|
||||
domainObject.setName("Anonymous");
|
||||
ShouldBeConfiguredBySpringContainsPublicReadResolve deserializedDomainObject =
|
||||
serializeAndDeserialize(domainObject);
|
||||
assertEquals("Dependency injected on deserialization","Rod",deserializedDomainObject.getName());
|
||||
assertEquals("User readResolve should take precedence", 1, deserializedDomainObject.readResolveInvocationCount);
|
||||
}
|
||||
|
||||
// See ShouldBeConfiguredBySpringContainsPrivateReadResolve
|
||||
// public void testInjectionOnDeserializationForClassesThatContainsPrivateReadResolve() throws Exception {
|
||||
// ShouldBeConfiguredBySpringContainsPrivateReadResolve domainObject = new ShouldBeConfiguredBySpringContainsPrivateReadResolve();
|
||||
// domainObject.setName("Anonymous");
|
||||
// ShouldBeConfiguredBySpringContainsPrivateReadResolve deserializedDomainObject =
|
||||
// serializeAndDeserialize(domainObject);
|
||||
// assertEquals("Dependency injected on deserialization","Rod",deserializedDomainObject.getName());
|
||||
// }
|
||||
|
||||
public void testNonInjectionOnDeserializationForSerializedButNotConfigured() throws Exception {
|
||||
SerializableThatShouldNotBeConfiguredBySpring domainObject = new SerializableThatShouldNotBeConfiguredBySpring();
|
||||
domainObject.setName("Anonymous");
|
||||
SerializableThatShouldNotBeConfiguredBySpring deserializedDomainObject =
|
||||
serializeAndDeserialize(domainObject);
|
||||
assertEquals("Dependency injected on deserialization","Anonymous",deserializedDomainObject.getName());
|
||||
}
|
||||
|
||||
public void testSubBeanConfiguredOnlyOnce() throws Exception {
|
||||
SubBean subBean = new SubBean();
|
||||
assertEquals("Property injected more than once", 1, subBean.setterCount);
|
||||
}
|
||||
|
||||
public void testSubBeanConfiguredOnlyOnceForPreConstruction() throws Exception {
|
||||
SubBeanPreConstruction subBean = new SubBeanPreConstruction();
|
||||
assertEquals("Property injected more than once", 1, subBean.setterCount);
|
||||
}
|
||||
|
||||
public void testSubSerializableBeanConfiguredOnlyOnce() throws Exception {
|
||||
SubSerializableBean subBean = new SubSerializableBean();
|
||||
assertEquals("Property injected more than once", 1, subBean.setterCount);
|
||||
subBean.setterCount = 0;
|
||||
|
||||
SubSerializableBean deserializedSubBean = serializeAndDeserialize(subBean);
|
||||
assertEquals("Property injected more than once", 1, deserializedSubBean.setterCount);
|
||||
}
|
||||
|
||||
public void testPreConstructionConfiguredBean() {
|
||||
PreConstructionConfiguredBean bean = new PreConstructionConfiguredBean();
|
||||
assertTrue("Injection didn't occur before construction", bean.preConstructionConfigured);
|
||||
}
|
||||
|
||||
public void testPreConstructionConfiguredBeanDeserializationReinjection() throws Exception {
|
||||
PreConstructionConfiguredBean bean = new PreConstructionConfiguredBean();
|
||||
PreConstructionConfiguredBean deserialized = serializeAndDeserialize(bean);
|
||||
assertEquals("Injection didn't occur upon deserialization", "ramnivas", deserialized.getName());
|
||||
}
|
||||
|
||||
public void testPostConstructionConfiguredBean() {
|
||||
PostConstructionConfiguredBean bean = new PostConstructionConfiguredBean();
|
||||
assertFalse("Injection occurred before construction", bean.preConstructionConfigured);
|
||||
}
|
||||
|
||||
public void testPostConstructionConfiguredBeanDeserializationReinjection() throws Exception {
|
||||
PostConstructionConfiguredBean bean = new PostConstructionConfiguredBean();
|
||||
PostConstructionConfiguredBean deserialized = serializeAndDeserialize(bean);
|
||||
assertEquals("Injection didn't occur upon deserialization", "ramnivas", deserialized.getName());
|
||||
}
|
||||
|
||||
public void testInterfaceDrivenDependencyInjection() {
|
||||
MailClientDependencyInjectionAspect.aspectOf().setMailSender(new JavaMailSenderImpl());
|
||||
Order testOrder = new Order();
|
||||
assertNotNull("Interface driven injection didn't occur for direct construction", testOrder.mailSender);
|
||||
}
|
||||
|
||||
public void testGenericInterfaceDrivenDependencyInjection() {
|
||||
PricingStrategy injectedPricingStrategy = new PricingStrategy();
|
||||
PricingStrategyDependencyInjectionAspect.aspectOf().setPricingStrategy(injectedPricingStrategy);
|
||||
LineItem testLineItem = new LineItem();
|
||||
assertSame("Generic interface driven injection didn't occur for direct construction", injectedPricingStrategy, testLineItem.pricingStrategy);
|
||||
}
|
||||
|
||||
public void testInterfaceDrivenDependencyInjectionMultipleInterfaces() {
|
||||
MailClientDependencyInjectionAspect.aspectOf().setMailSender(new JavaMailSenderImpl());
|
||||
PaymentProcessorDependencyInjectionAspect.aspectOf().setPaymentProcessor(new PaymentProcessor());
|
||||
|
||||
ShoppingCart testCart = new ShoppingCart();
|
||||
|
||||
assertNotNull("Interface driven injection didn't occur for direct construction", testCart.mailSender);
|
||||
assertNotNull("Interface driven injection didn't occur for direct construction", testCart.paymentProcessor);
|
||||
}
|
||||
|
||||
public void testInterfaceDrivenDependencyInjectionUponDeserialization() throws Exception {
|
||||
MailClientDependencyInjectionAspect.aspectOf().setMailSender(new JavaMailSenderImpl());
|
||||
Order testOrder = new Order();
|
||||
Order deserializedOrder = serializeAndDeserialize(testOrder);
|
||||
assertNotNull(deserializedOrder);
|
||||
assertNotNull("Interface driven injection didn't occur for deserialization", testOrder.mailSender);
|
||||
}
|
||||
|
||||
public void testFieldAutoWiredAnnotationInjection() {
|
||||
FieldAutoWiredServiceBean bean = new FieldAutoWiredServiceBean();
|
||||
assertNotNull(bean.testService);
|
||||
}
|
||||
|
||||
public void testMethodAutoWiredAnnotationInjection() {
|
||||
MethodAutoWiredServiceBean bean = new MethodAutoWiredServiceBean();
|
||||
assertNotNull(bean.testService);
|
||||
}
|
||||
|
||||
public void testMultiArgumentMethodAutoWiredAnnotationInjection() {
|
||||
MultiArgumentMethodAutoWiredServiceBean bean = new MultiArgumentMethodAutoWiredServiceBean();
|
||||
assertNotNull(bean.testService);
|
||||
assertNotNull(bean.paymentService);
|
||||
}
|
||||
|
||||
public void testGenericParameterConfigurableBean() {
|
||||
GenericParameterConfigurableBean bean = new GenericParameterConfigurableBean();
|
||||
assertNotNull(bean.testService);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T serializeAndDeserialize(T serializable) throws Exception {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(serializable);
|
||||
oos.close();
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
return (T)ois.readObject();
|
||||
}
|
||||
|
||||
|
||||
@Configurable("beanOne")
|
||||
@SuppressWarnings("serial")
|
||||
protected static class ShouldBeConfiguredBySpring implements Serializable {
|
||||
|
||||
private String name;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configurable("beanOne")
|
||||
@SuppressWarnings("serial")
|
||||
private static class ShouldBeConfiguredBySpringContainsPublicReadResolve implements Serializable {
|
||||
|
||||
private String name;
|
||||
|
||||
private int readResolveInvocationCount = 0;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Object readResolve() throws ObjectStreamException {
|
||||
readResolveInvocationCount++;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// Won't work until we use hasmethod() experimental pointcut in AspectJ.
|
||||
// @Configurable("beanOne")
|
||||
// private static class ShouldBeConfiguredBySpringContainsPrivateReadResolve implements Serializable {
|
||||
//
|
||||
// private String name;
|
||||
//
|
||||
// public void setName(String name) {
|
||||
// this.name = name;
|
||||
// }
|
||||
//
|
||||
// public String getName() {
|
||||
// return this.name;
|
||||
// }
|
||||
//
|
||||
// private Object readResolve() throws ObjectStreamException {
|
||||
// return this;
|
||||
// }
|
||||
// }
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class ShouldNotBeConfiguredBySpring {
|
||||
|
||||
private String name;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class SerializableThatShouldNotBeConfiguredBySpring implements Serializable {
|
||||
|
||||
private String name;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configurable
|
||||
@SuppressWarnings("unused")
|
||||
private static class ShouldBeConfiguredBySpringUsingTypeNameAsBeanName {
|
||||
|
||||
private String name;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configurable(autowire=Autowire.BY_TYPE)
|
||||
@SuppressWarnings("unused")
|
||||
private static class ShouldBeConfiguredBySpringUsingAutowireByType {
|
||||
|
||||
private TestBean friend = null;
|
||||
|
||||
public TestBean getFriend() {
|
||||
return friend;
|
||||
}
|
||||
|
||||
public void setFriend(TestBean friend) {
|
||||
this.friend = friend;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configurable(autowire=Autowire.BY_NAME)
|
||||
@SuppressWarnings("unused")
|
||||
private static class ValidAutowireByName {
|
||||
|
||||
private TestBean friend = null;
|
||||
|
||||
public TestBean getRamnivas() {
|
||||
return friend;
|
||||
}
|
||||
|
||||
public void setRamnivas(TestBean friend) {
|
||||
this.friend = friend;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configurable(autowire=Autowire.BY_NAME, dependencyCheck=true)
|
||||
@SuppressWarnings("unused")
|
||||
private static class InvalidAutowireByName {
|
||||
|
||||
private TestBean friend;
|
||||
|
||||
public TestBean getFriend() {
|
||||
return friend;
|
||||
}
|
||||
|
||||
public void setFriend(TestBean friend) {
|
||||
this.friend = friend;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class ArbitraryExistingPojo {
|
||||
|
||||
private TestBean friend;
|
||||
|
||||
public void setFriend(TestBean f) {
|
||||
this.friend = f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class CircularFactoryBean implements FactoryBean{
|
||||
|
||||
public CircularFactoryBean() {
|
||||
ValidAutowireByName autowired = new ValidAutowireByName();
|
||||
assertNull(autowired.getRamnivas());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject() throws Exception {
|
||||
return new TestBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getObjectType() {
|
||||
return TestBean.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configurable
|
||||
@SuppressWarnings("unused")
|
||||
private static class BaseBean {
|
||||
|
||||
public int setterCount;
|
||||
|
||||
private String name;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
setterCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class SubBean extends BaseBean {
|
||||
}
|
||||
|
||||
@Configurable(preConstruction=true)
|
||||
private static class SubBeanPreConstruction extends BaseBean {
|
||||
}
|
||||
|
||||
@Configurable
|
||||
@SuppressWarnings({"serial", "unused"})
|
||||
private static class BaseSerializableBean implements Serializable {
|
||||
|
||||
public int setterCount;
|
||||
|
||||
private String name;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
setterCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class SubSerializableBean extends BaseSerializableBean {
|
||||
}
|
||||
|
||||
|
||||
@Aspect
|
||||
@SuppressWarnings("unused")
|
||||
private static class WireArbitraryExistingPojo extends AbstractBeanConfigurerAspect {
|
||||
|
||||
@Pointcut("initialization(ArbitraryExistingPojo.new(..)) && this(beanInstance)")
|
||||
protected void beanCreation(Object beanInstance){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Aspect
|
||||
@SuppressWarnings("unused")
|
||||
private static class AspectThatWillNotBeUsed extends AbstractBeanConfigurerAspect {
|
||||
|
||||
@Pointcut("initialization(ClassThatWillNotActuallyBeWired.new(..)) && this(beanInstance)")
|
||||
protected void beanCreation(Object beanInstance){
|
||||
}
|
||||
}
|
||||
|
||||
private static aspect MailClientDependencyInjectionAspect extends AbstractInterfaceDrivenDependencyInjectionAspect {
|
||||
private MailSender mailSender;
|
||||
|
||||
public pointcut inConfigurableBean() : within(MailSenderClient+);
|
||||
|
||||
public void configureBean(Object bean) {
|
||||
((MailSenderClient)bean).setMailSender(this.mailSender);
|
||||
}
|
||||
|
||||
declare parents: MailSenderClient implements ConfigurableObject;
|
||||
|
||||
public void setMailSender(MailSender mailSender) {
|
||||
this.mailSender = mailSender;
|
||||
}
|
||||
}
|
||||
|
||||
private static aspect PaymentProcessorDependencyInjectionAspect extends AbstractInterfaceDrivenDependencyInjectionAspect {
|
||||
private PaymentProcessor paymentProcessor;
|
||||
|
||||
public pointcut inConfigurableBean() : within(PaymentProcessorClient+);
|
||||
|
||||
public void configureBean(Object bean) {
|
||||
((PaymentProcessorClient)bean).setPaymentProcessor(this.paymentProcessor);
|
||||
}
|
||||
|
||||
declare parents: PaymentProcessorClient implements ConfigurableObject;
|
||||
|
||||
public void setPaymentProcessor(PaymentProcessor paymentProcessor) {
|
||||
this.paymentProcessor = paymentProcessor;
|
||||
}
|
||||
}
|
||||
|
||||
private static aspect PricingStrategyDependencyInjectionAspect extends GenericInterfaceDrivenDependencyInjectionAspect<PricingStrategyClient> {
|
||||
private PricingStrategy pricingStrategy;
|
||||
|
||||
public void configure(PricingStrategyClient bean) {
|
||||
bean.setPricingStrategy(pricingStrategy);
|
||||
}
|
||||
|
||||
public void setPricingStrategy(PricingStrategy pricingStrategy) {
|
||||
this.pricingStrategy = pricingStrategy;
|
||||
}
|
||||
}
|
||||
|
||||
public static interface MailSenderClient {
|
||||
public void setMailSender(MailSender mailSender);
|
||||
}
|
||||
|
||||
public static interface PaymentProcessorClient {
|
||||
public void setPaymentProcessor(PaymentProcessor paymentProcessor);
|
||||
}
|
||||
|
||||
public static class PaymentProcessor {
|
||||
|
||||
}
|
||||
|
||||
public static interface PricingStrategyClient {
|
||||
public void setPricingStrategy(PricingStrategy pricingStrategy);
|
||||
}
|
||||
|
||||
public static class PricingStrategy {
|
||||
|
||||
}
|
||||
|
||||
public static class LineItem implements PricingStrategyClient {
|
||||
private PricingStrategy pricingStrategy;
|
||||
|
||||
@Override
|
||||
public void setPricingStrategy(PricingStrategy pricingStrategy) {
|
||||
this.pricingStrategy = pricingStrategy;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class Order implements MailSenderClient, Serializable {
|
||||
private transient MailSender mailSender;
|
||||
|
||||
@Override
|
||||
public void setMailSender(MailSender mailSender) {
|
||||
this.mailSender = mailSender;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ShoppingCart implements MailSenderClient, PaymentProcessorClient {
|
||||
private transient MailSender mailSender;
|
||||
private transient PaymentProcessor paymentProcessor;
|
||||
|
||||
@Override
|
||||
public void setMailSender(MailSender mailSender) {
|
||||
this.mailSender = mailSender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPaymentProcessor(PaymentProcessor paymentProcessor) {
|
||||
this.paymentProcessor = paymentProcessor;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClassThatWillNotActuallyBeWired {
|
||||
|
||||
}
|
||||
|
||||
@Configurable
|
||||
@SuppressWarnings("serial")
|
||||
private static class PreOrPostConstructionConfiguredBean implements Serializable {
|
||||
private transient String name;
|
||||
protected transient boolean preConstructionConfigured;
|
||||
transient int count;
|
||||
|
||||
public PreOrPostConstructionConfiguredBean() {
|
||||
preConstructionConfigured = (this.name != null);
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configurable(preConstruction=true)
|
||||
@SuppressWarnings("serial")
|
||||
public static class PreConstructionConfiguredBean extends PreOrPostConstructionConfiguredBean {
|
||||
}
|
||||
|
||||
|
||||
@Configurable(preConstruction=false)
|
||||
@SuppressWarnings("serial")
|
||||
private static class PostConstructionConfiguredBean extends PreOrPostConstructionConfiguredBean {
|
||||
}
|
||||
|
||||
@Configurable
|
||||
public static class FieldAutoWiredServiceBean {
|
||||
@Autowired transient private TestService testService;
|
||||
}
|
||||
|
||||
@Configurable
|
||||
public static class MethodAutoWiredServiceBean {
|
||||
transient private TestService testService;
|
||||
|
||||
@Autowired
|
||||
public void setTestService(TestService testService) {
|
||||
this.testService = testService;
|
||||
}
|
||||
}
|
||||
|
||||
@Configurable
|
||||
public static class MultiArgumentMethodAutoWiredServiceBean {
|
||||
transient private TestService testService;
|
||||
transient private PaymentService paymentService;
|
||||
|
||||
@Autowired
|
||||
public void setDependencies(TestService testService, PaymentService paymentService) {
|
||||
this.testService = testService;
|
||||
this.paymentService = paymentService;
|
||||
}
|
||||
}
|
||||
|
||||
@Configurable
|
||||
public static class GenericParameterConfigurableBean {
|
||||
private TestService testService;
|
||||
|
||||
public void setTestService(TestService testService) {
|
||||
this.testService = testService;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestService {
|
||||
|
||||
}
|
||||
|
||||
public static class PaymentService {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.aspectj;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Configurable;
|
||||
|
||||
@Configurable("configuredBean")
|
||||
@SuppressWarnings("serial")
|
||||
public class ShouldBeConfiguredBySpring implements Serializable {
|
||||
|
||||
private String name;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
}
|
||||
+10
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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,23 +16,22 @@
|
||||
|
||||
package org.springframework.beans.factory.aspectj;
|
||||
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class XmlBeanConfigurerTests extends AbstractBeanConfigurerTests {
|
||||
public class XmlBeanConfigurerTests {
|
||||
|
||||
@Override
|
||||
protected ConfigurableApplicationContext createContext() {
|
||||
return new ClassPathXmlApplicationContext("org/springframework/beans/factory/aspectj/beanConfigurerTests.xml");
|
||||
}
|
||||
|
||||
public void testInjectionAfterRefresh() {
|
||||
context.refresh();
|
||||
@Test
|
||||
public void testInjection() {
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/beans/factory/aspectj/beanConfigurerTests.xml");
|
||||
ShouldBeConfiguredBySpring myObject = new ShouldBeConfiguredBySpring();
|
||||
assertEquals("Rod", myObject.getName());
|
||||
Assert.assertEquals("Rod", myObject.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-56
@@ -1,64 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$WireArbitraryExistingPojo"
|
||||
factory-method="aspectOf"/>
|
||||
|
||||
<bean id="beanOne" class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$ShouldBeConfiguredBySpring"
|
||||
lazy-init="true">
|
||||
<bean id="configuredBean" class="org.springframework.beans.factory.aspectj.ShouldBeConfiguredBySpring" lazy-init="true">
|
||||
<property name="name" value="Rod"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$ShouldBeConfiguredBySpringUsingTypeNameAsBeanName"
|
||||
lazy-init="true">
|
||||
<property name="name" value="Rob"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$SubBean"
|
||||
lazy-init="true">
|
||||
<property name="name" value="Ramnivas"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$SubBeanPreConstruction"
|
||||
lazy-init="true">
|
||||
<property name="name" value="Ramnivas"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$SubSerializableBean"
|
||||
lazy-init="true">
|
||||
<property name="name" value="Ramnivas"/>
|
||||
</bean>
|
||||
|
||||
<bean id="circular" class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$CircularFactoryBean"
|
||||
autowire-candidate="false"/>
|
||||
|
||||
<!-- Used as a target for autowiring by type -->
|
||||
<bean id="ramnivas" class="org.springframework.tests.sample.beans.TestBean" depends-on="circular">
|
||||
<property name="name" value="Ramnivas"/>
|
||||
<property name="spouse" ref="circular"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$ArbitraryExistingPojo">
|
||||
<property name="friend" ref="ramnivas"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$PreConstructionConfiguredBean">
|
||||
<property name="name" value="ramnivas"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$PostConstructionConfiguredBean">
|
||||
<property name="name" value="ramnivas"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$GenericParameterConfigurableBean" scope="prototype">
|
||||
<property name="testService" ref="testService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="testService" class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$TestService"/>
|
||||
<bean id="paymentService" class="org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests$PaymentService"/>
|
||||
|
||||
</beans>
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -25,7 +25,7 @@ import org.junit.Test;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.config.AbstractAnnotationTests;
|
||||
import org.springframework.cache.config.CacheableService;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.GenericXmlApplicationContext;
|
||||
|
||||
/**
|
||||
@@ -35,7 +35,7 @@ public class AspectJAnnotationTests extends AbstractAnnotationTests {
|
||||
|
||||
|
||||
@Override
|
||||
protected ApplicationContext getApplicationContext() {
|
||||
protected ConfigurableApplicationContext getApplicationContext() {
|
||||
return new GenericXmlApplicationContext("/org/springframework/cache/config/annotation-cache-aspectj.xml");
|
||||
}
|
||||
|
||||
@@ -71,4 +71,5 @@ public class AspectJAnnotationTests extends AbstractAnnotationTests {
|
||||
assertSame(r3, primary.get(o1).get());
|
||||
assertSame(r4, secondary.get(o1).get());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vendored
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.aspectj;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||
import org.springframework.cache.config.AnnotatedJCacheableService;
|
||||
import org.springframework.cache.jcache.config.AbstractJCacheAnnotationTests;
|
||||
import org.springframework.cache.support.SimpleCacheManager;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AdviceMode;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class JCacheAspectJJavaConfigTests extends AbstractJCacheAnnotationTests {
|
||||
|
||||
@Override
|
||||
protected ApplicationContext getApplicationContext() {
|
||||
return new AnnotationConfigApplicationContext(EnableCachingConfig.class);
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableCaching(mode = AdviceMode.ASPECTJ)
|
||||
public static class EnableCachingConfig {
|
||||
|
||||
@Bean
|
||||
public CacheManager cacheManager() {
|
||||
SimpleCacheManager cm = new SimpleCacheManager();
|
||||
cm.setCaches(Arrays.asList(
|
||||
defaultCache(),
|
||||
new ConcurrentMapCache("primary"),
|
||||
new ConcurrentMapCache("secondary"),
|
||||
new ConcurrentMapCache("exception")));
|
||||
return cm;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AnnotatedJCacheableService cacheableService() {
|
||||
return new AnnotatedJCacheableService(defaultCache());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Cache defaultCache() {
|
||||
return new ConcurrentMapCache("default");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.aspectj;
|
||||
|
||||
import org.springframework.cache.jcache.config.AbstractJCacheAnnotationTests;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.GenericXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class JCacheAspectJNamespaceConfigTests extends AbstractJCacheAnnotationTests {
|
||||
|
||||
@Override
|
||||
protected ApplicationContext getApplicationContext() {
|
||||
return new GenericXmlApplicationContext(
|
||||
"/org/springframework/cache/config/annotation-jcache-aspectj.xml");
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+39
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.cache.annotation.Caching;
|
||||
* @author Costin Leau
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Cacheable("default")
|
||||
@Cacheable("testCache")
|
||||
public class AnnotatedClassCacheableService implements CacheableService<Object> {
|
||||
|
||||
private final AtomicLong counter = new AtomicLong();
|
||||
@@ -49,70 +49,94 @@ public class AnnotatedClassCacheableService implements CacheableService<Object>
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict("default")
|
||||
@CacheEvict("testCache")
|
||||
public void invalidate(Object arg1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict("default")
|
||||
@CacheEvict("testCache")
|
||||
public void evictWithException(Object arg1) {
|
||||
throw new RuntimeException("exception thrown - evict should NOT occur");
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = "default", allEntries = true)
|
||||
@CacheEvict(value = "testCache", allEntries = true)
|
||||
public void evictAll(Object arg1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = "default", beforeInvocation = true)
|
||||
@CacheEvict(value = "testCache", beforeInvocation = true)
|
||||
public void evictEarly(Object arg1) {
|
||||
throw new RuntimeException("exception thrown - evict should still occur");
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = "default", key = "#p0")
|
||||
@CacheEvict(value = "testCache", key = "#p0")
|
||||
public void evict(Object arg1, Object arg2) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = "default", key = "#p0", beforeInvocation = true)
|
||||
@CacheEvict(value = "testCache", key = "#p0", beforeInvocation = true)
|
||||
public void invalidateEarly(Object arg1, Object arg2) {
|
||||
throw new RuntimeException("exception thrown - evict should still occur");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "default", key = "#p0")
|
||||
@Cacheable(value = "testCache", key = "#p0")
|
||||
public Object key(Object arg1, Object arg2) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "default")
|
||||
@Cacheable(value = "testCache")
|
||||
public Object varArgsKey(Object... args) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "default", key = "#root.methodName + #root.caches[0].name")
|
||||
@Cacheable(value = "testCache", key = "#root.methodName + #root.caches[0].name")
|
||||
public Object name(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target")
|
||||
@Cacheable(value = "testCache", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target")
|
||||
public Object rootVars(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CachePut("default")
|
||||
@Cacheable(value = "testCache", keyGenerator = "customKyeGenerator")
|
||||
public Object customKeyGenerator(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "testCache", keyGenerator = "unknownBeanName")
|
||||
public Object unknownCustomKeyGenerator(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "testCache", cacheManager = "customCacheManager")
|
||||
public Object customCacheManager(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "testCache", cacheManager = "unknownBeanName")
|
||||
public Object unknownCustomCacheManager(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CachePut("testCache")
|
||||
public Object update(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CachePut(value = "default", condition = "#arg.equals(3)")
|
||||
@CachePut(value = "testCache", condition = "#arg.equals(3)")
|
||||
public Object conditionalUpdate(Object arg) {
|
||||
return arg;
|
||||
}
|
||||
@@ -176,4 +200,5 @@ public class AnnotatedClassCacheableService implements CacheableService<Object>
|
||||
arg1.setId(Long.MIN_VALUE);
|
||||
return arg1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vendored
+214
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javax.cache.annotation.CacheDefaults;
|
||||
import javax.cache.annotation.CacheKey;
|
||||
import javax.cache.annotation.CachePut;
|
||||
import javax.cache.annotation.CacheRemove;
|
||||
import javax.cache.annotation.CacheRemoveAll;
|
||||
import javax.cache.annotation.CacheResult;
|
||||
import javax.cache.annotation.CacheValue;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.interceptor.SimpleKeyGenerator;
|
||||
import org.springframework.cache.jcache.config.JCacheableService;
|
||||
import org.springframework.cache.jcache.support.TestableCacheKeyGenerator;
|
||||
import org.springframework.cache.jcache.support.TestableCacheResolverFactory;
|
||||
|
||||
/**
|
||||
* Repository sample with a @CacheDefaults annotation
|
||||
*
|
||||
* <p>Note: copy/pasted from its original compilation because it needs to be
|
||||
* processed by the AspectJ compiler to wave the required aspects.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@CacheDefaults(cacheName = "default")
|
||||
public class AnnotatedJCacheableService implements JCacheableService<Long> {
|
||||
|
||||
private final AtomicLong counter = new AtomicLong();
|
||||
private final AtomicLong exceptionCounter = new AtomicLong();
|
||||
private final Cache defaultCache;
|
||||
|
||||
public AnnotatedJCacheableService(Cache defaultCache) {
|
||||
this.defaultCache = defaultCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheResult
|
||||
public Long cache(String id) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheResult(exceptionCacheName = "exception", nonCachedExceptions = NullPointerException.class)
|
||||
public Long cacheWithException(@CacheKey String id, boolean matchFilter) {
|
||||
throwException(matchFilter);
|
||||
return 0L; // Never reached
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheResult(exceptionCacheName = "exception", nonCachedExceptions = NullPointerException.class)
|
||||
public Long cacheWithCheckedException(@CacheKey String id, boolean matchFilter) throws IOException {
|
||||
throwCheckedException(matchFilter);
|
||||
return 0L; // Never reached
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheResult(skipGet = true)
|
||||
public Long cacheAlwaysInvoke(String id) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheResult
|
||||
public Long cacheWithPartialKey(@CacheKey String id, boolean notUsed) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheResult(cacheResolverFactory = TestableCacheResolverFactory.class)
|
||||
public Long cacheWithCustomCacheResolver(String id) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheResult(cacheKeyGenerator = TestableCacheKeyGenerator.class)
|
||||
public Long cacheWithCustomKeyGenerator(String id, String anotherId) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CachePut
|
||||
public void put(String id, @CacheValue Object value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@CachePut(cacheFor = UnsupportedOperationException.class)
|
||||
public void putWithException(@CacheKey String id, @CacheValue Object value, boolean matchFilter) {
|
||||
throwException(matchFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CachePut(afterInvocation = false)
|
||||
public void earlyPut(String id, @CacheValue Object value) {
|
||||
Object key = SimpleKeyGenerator.generateKey(id);
|
||||
Cache.ValueWrapper valueWrapper = defaultCache.get(key);
|
||||
if (valueWrapper == null) {
|
||||
throw new AssertionError("Excepted value to be put in cache with key " + key);
|
||||
}
|
||||
Object actual = valueWrapper.get();
|
||||
if (value != actual) { // instance check on purpose
|
||||
throw new AssertionError("Wrong value set in cache with key " + key + ". " +
|
||||
"Expected=" + value + ", but got=" + actual);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@CachePut(afterInvocation = false)
|
||||
public void earlyPutWithException(@CacheKey String id, @CacheValue Object value, boolean matchFilter) {
|
||||
throwException(matchFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheRemove
|
||||
public void remove(String id) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheRemove(noEvictFor = NullPointerException.class)
|
||||
public void removeWithException(@CacheKey String id, boolean matchFilter) {
|
||||
throwException(matchFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheRemove(afterInvocation = false)
|
||||
public void earlyRemove(String id) {
|
||||
Object key = SimpleKeyGenerator.generateKey(id);
|
||||
Cache.ValueWrapper valueWrapper = defaultCache.get(key);
|
||||
if (valueWrapper != null) {
|
||||
throw new AssertionError("Value with key " + key + " expected to be already remove from cache");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheRemove(afterInvocation = false, evictFor = UnsupportedOperationException.class)
|
||||
public void earlyRemoveWithException(@CacheKey String id, boolean matchFilter) {
|
||||
throwException(matchFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheRemoveAll
|
||||
public void removeAll() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheRemoveAll(noEvictFor = NullPointerException.class)
|
||||
public void removeAllWithException(boolean matchFilter) {
|
||||
throwException(matchFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheRemoveAll(afterInvocation = false)
|
||||
public void earlyRemoveAll() {
|
||||
ConcurrentHashMap<?, ?> nativeCache = (ConcurrentHashMap<?, ?>) defaultCache.getNativeCache();
|
||||
if (!nativeCache.isEmpty()) {
|
||||
throw new AssertionError("Cache was expected to be empty");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheRemoveAll(afterInvocation = false, evictFor = UnsupportedOperationException.class)
|
||||
public void earlyRemoveAllWithException(boolean matchFilter) {
|
||||
throwException(matchFilter);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void noAnnotation() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long exceptionInvocations() {
|
||||
return exceptionCounter.get();
|
||||
}
|
||||
|
||||
private void throwException(boolean matchFilter) {
|
||||
long count = exceptionCounter.getAndIncrement();
|
||||
if (matchFilter) {
|
||||
throw new UnsupportedOperationException("Expected exception (" + count + ")");
|
||||
}
|
||||
else {
|
||||
throw new NullPointerException("Expected exception (" + count + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private void throwCheckedException(boolean matchFilter) throws IOException {
|
||||
long count = exceptionCounter.getAndIncrement();
|
||||
if (matchFilter) {
|
||||
throw new IOException("Expected exception (" + count + ")");
|
||||
}
|
||||
else {
|
||||
throw new NullPointerException("Expected exception (" + count + ")");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+10
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,14 @@ public interface CacheableService<T> {
|
||||
|
||||
T rootVars(Object arg1);
|
||||
|
||||
T customKeyGenerator(Object arg1);
|
||||
|
||||
T unknownCustomKeyGenerator(Object arg1);
|
||||
|
||||
T customCacheManager(Object arg1);
|
||||
|
||||
T unknownCustomCacheManager(Object arg1);
|
||||
|
||||
T throwChecked(Object arg1) throws Exception;
|
||||
|
||||
T throwUnchecked(Object arg1);
|
||||
@@ -74,4 +82,5 @@ public interface CacheableService<T> {
|
||||
T multiUpdate(Object arg1);
|
||||
|
||||
TestEntity putRefersToResult(TestEntity arg1);
|
||||
|
||||
}
|
||||
|
||||
+44
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,94 +35,118 @@ public class DefaultCacheableService implements CacheableService<Long> {
|
||||
private final AtomicLong nullInvocations = new AtomicLong();
|
||||
|
||||
@Override
|
||||
@Cacheable("default")
|
||||
@Cacheable("testCache")
|
||||
public Long cache(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict("default")
|
||||
@CacheEvict("testCache")
|
||||
public void invalidate(Object arg1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict("default")
|
||||
@CacheEvict("testCache")
|
||||
public void evictWithException(Object arg1) {
|
||||
throw new RuntimeException("exception thrown - evict should NOT occur");
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = "default", allEntries = true)
|
||||
@CacheEvict(value = "testCache", allEntries = true)
|
||||
public void evictAll(Object arg1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = "default", beforeInvocation = true)
|
||||
@CacheEvict(value = "testCache", beforeInvocation = true)
|
||||
public void evictEarly(Object arg1) {
|
||||
throw new RuntimeException("exception thrown - evict should still occur");
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = "default", key = "#p0")
|
||||
@CacheEvict(value = "testCache", key = "#p0")
|
||||
public void evict(Object arg1, Object arg2) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = "default", key = "#p0", beforeInvocation = true)
|
||||
@CacheEvict(value = "testCache", key = "#p0", beforeInvocation = true)
|
||||
public void invalidateEarly(Object arg1, Object arg2) {
|
||||
throw new RuntimeException("exception thrown - evict should still occur");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "default", condition = "#classField == 3")
|
||||
@Cacheable(value = "testCache", condition = "#classField == 3")
|
||||
public Long conditional(int classField) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "default", unless = "#result > 10")
|
||||
@Cacheable(value = "testCache", unless = "#result > 10")
|
||||
public Long unless(int arg) {
|
||||
return (long) arg;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "default", key = "#p0")
|
||||
@Cacheable(value = "testCache", key = "#p0")
|
||||
public Long key(Object arg1, Object arg2) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "default")
|
||||
@Cacheable(value = "testCache")
|
||||
public Long varArgsKey(Object... args) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "default", key = "#root.methodName")
|
||||
@Cacheable(value = "testCache", key = "#root.methodName")
|
||||
public Long name(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target")
|
||||
@Cacheable(value = "testCache", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target")
|
||||
public Long rootVars(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CachePut("default")
|
||||
@Cacheable(value = "testCache", keyGenerator = "customKeyGenerator")
|
||||
public Long customKeyGenerator(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "testCache", keyGenerator = "unknownBeanName")
|
||||
public Long unknownCustomKeyGenerator(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "testCache", cacheManager = "customCacheManager")
|
||||
public Long customCacheManager(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "testCache", cacheManager = "unknownBeanName")
|
||||
public Long unknownCustomCacheManager(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CachePut("testCache")
|
||||
public Long update(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CachePut(value = "default", condition = "#arg.equals(3)")
|
||||
@CachePut(value = "testCache", condition = "#arg.equals(3)")
|
||||
public Long conditionalUpdate(Object arg) {
|
||||
return Long.valueOf(arg.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable("default")
|
||||
@Cacheable("testCache")
|
||||
public Long nullValue(Object arg1) {
|
||||
nullInvocations.incrementAndGet();
|
||||
return null;
|
||||
@@ -134,13 +158,13 @@ public class DefaultCacheableService implements CacheableService<Long> {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable("default")
|
||||
@Cacheable("testCache")
|
||||
public Long throwChecked(Object arg1) throws Exception {
|
||||
throw new Exception(arg1.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable("default")
|
||||
@Cacheable("testCache")
|
||||
public Long throwUnchecked(Object arg1) {
|
||||
throw new UnsupportedOperationException(arg1.toString());
|
||||
}
|
||||
@@ -184,4 +208,5 @@ public class DefaultCacheableService implements CacheableService<Long> {
|
||||
arg1.setId(Long.MIN_VALUE);
|
||||
return arg1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.config;
|
||||
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* A custom {@link KeyGenerator} that exposes the algorithm used to compute the key
|
||||
* for convenience in tests scenario.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
final class SomeCustomKeyGenerator implements KeyGenerator {
|
||||
|
||||
@Override
|
||||
public Object generate(Object target, Method method, Object... params) {
|
||||
return generateKey(method.getName(), params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #generate(Object, java.lang.reflect.Method, Object...)
|
||||
*/
|
||||
static Object generateKey(String methodName, Object... params) {
|
||||
final StringBuilder sb = new StringBuilder(methodName);
|
||||
for (Object param : params) {
|
||||
sb.append(param);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -21,7 +21,7 @@ import org.springframework.util.ObjectUtils;
|
||||
/**
|
||||
* Simple test entity for use with caching tests.
|
||||
*
|
||||
* @author Michael Plšd
|
||||
* @author Michael Plod
|
||||
*/
|
||||
public class TestEntity {
|
||||
|
||||
@@ -53,4 +53,5 @@ public class TestEntity {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-6
@@ -1,13 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:cache="http://www.springframework.org/schema/cache"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
|
||||
|
||||
|
||||
<!--
|
||||
@@ -31,7 +28,7 @@
|
||||
<property name="caches">
|
||||
<set>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
|
||||
<property name="name" value="default"/>
|
||||
<property name="name" value="testCache"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
|
||||
<property name="name" value="primary"/>
|
||||
@@ -43,6 +40,18 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="customKeyGenerator" class="org.springframework.cache.config.SomeCustomKeyGenerator" />
|
||||
|
||||
<bean id="customCacheManager" class="org.springframework.cache.support.SimpleCacheManager">
|
||||
<property name="caches">
|
||||
<set>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
|
||||
<property name="name" value="testCache"/>
|
||||
</bean>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>
|
||||
|
||||
<bean id="service" class="org.springframework.cache.config.DefaultCacheableService"/>
|
||||
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:cache="http://www.springframework.org/schema/cache"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
|
||||
|
||||
<cache:annotation-driven mode="aspectj"/>
|
||||
|
||||
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
|
||||
<property name="caches">
|
||||
<set>
|
||||
<ref bean="defaultCache"/>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
|
||||
<property name="name" value="primary"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
|
||||
<property name="name" value="secondary"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
|
||||
<property name="name" value="exception"/>
|
||||
</bean>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="defaultCache"
|
||||
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
|
||||
<property name="name" value="default"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cacheableService" class="org.springframework.cache.config.AnnotatedJCacheableService">
|
||||
<constructor-arg ref="defaultCache"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
+15
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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,31 +16,36 @@
|
||||
|
||||
package org.springframework.context.annotation.aspectj;
|
||||
|
||||
import org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.aspectj.ShouldBeConfiguredBySpring;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.context.annotation.aspectj.EnableSpringConfigured;
|
||||
|
||||
/**
|
||||
* Tests that @EnableSpringConfigured properly registers an
|
||||
* {@link org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect}, just
|
||||
* as does {@code <context:spring-configured>}
|
||||
* {@link org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect},
|
||||
* just as does {@code <context:spring-configured>}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public class AnnotationBeanConfigurerTests extends AbstractBeanConfigurerTests {
|
||||
public class AnnotationBeanConfigurerTests {
|
||||
|
||||
@Override
|
||||
protected ConfigurableApplicationContext createContext() {
|
||||
return new AnnotationConfigApplicationContext(Config.class);
|
||||
@Test
|
||||
public void testInjection() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
|
||||
ShouldBeConfiguredBySpring myObject = new ShouldBeConfiguredBySpring();
|
||||
Assert.assertEquals("Rod", myObject.getName());
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@ImportResource("org/springframework/beans/factory/aspectj/beanConfigurerTests-beans.xml")
|
||||
@EnableSpringConfigured
|
||||
static class Config {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,7 +53,7 @@ import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||
import org.springframework.core.io.DescriptiveResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.EncodedResource;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A Groovy-based reader for Spring bean definitions: like a Groovy builder,
|
||||
@@ -108,6 +108,9 @@ import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p><b>This bean definition reader also understands XML bean definition files,
|
||||
* allowing for seamless mixing and matching with Groovy bean definition files.</b>
|
||||
*
|
||||
* <p>Typically applied to a
|
||||
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
|
||||
* or a {@link org.springframework.context.support.GenericApplicationContext},
|
||||
@@ -187,7 +190,9 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
// TRADITIONAL BEAN DEFINITION READER METHODS
|
||||
|
||||
/**
|
||||
* Load bean definitions from the specified Groovy script.
|
||||
* Load bean definitions from the specified Groovy script or XML file.
|
||||
* <p>Note that ".xml" files will be parsed as XML content; all other kinds
|
||||
* of resources will be parsed as Groovy scripts.
|
||||
* @param resource the resource descriptor for the Groovy script
|
||||
* @return the number of bean definitions found
|
||||
* @throws BeanDefinitionStoreException in case of loading or parsing errors
|
||||
@@ -197,14 +202,22 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
/**
|
||||
* Load bean definitions from the specified Groovy script.
|
||||
* Load bean definitions from the specified Groovy script or XML file.
|
||||
* <p>Note that ".xml" files will be parsed as XML content; all other kinds
|
||||
* of resources will be parsed as Groovy scripts.
|
||||
* @param encodedResource the resource descriptor for the Groovy script,
|
||||
* allowing to specify an encoding to use for parsing the file
|
||||
* @return the number of bean definitions found
|
||||
* @throws BeanDefinitionStoreException in case of loading or parsing errors
|
||||
*/
|
||||
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
|
||||
Closure beans = new Closure(this){
|
||||
// Check for XML files and redirect them to the XmlBeanDefinitionReader
|
||||
String filename = encodedResource.getResource().getFilename();
|
||||
if (StringUtils.endsWithIgnoreCase(filename, ".xml")) {
|
||||
return this.xmlBeanDefinitionReader.loadBeanDefinitions(encodedResource);
|
||||
}
|
||||
|
||||
Closure beans = new Closure(this) {
|
||||
public Object call(Object[] args) {
|
||||
invokeBeanDefiningClosure((Closure) args[0]);
|
||||
return null;
|
||||
@@ -213,7 +226,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
Binding binding = new Binding() {
|
||||
@Override
|
||||
public void setVariable(String name, Object value) {
|
||||
if (currentBeanDefinition !=null) {
|
||||
if (currentBeanDefinition != null) {
|
||||
applyPropertyToBeanDefinition(name, value);
|
||||
}
|
||||
else {
|
||||
@@ -321,17 +334,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
* @param resourcePattern the resource pattern
|
||||
*/
|
||||
public void importBeans(String resourcePattern) throws IOException {
|
||||
Resource[] resources =
|
||||
ResourcePatternUtils.getResourcePatternResolver(getResourceLoader()).getResources(resourcePattern);
|
||||
for (Resource resource : resources) {
|
||||
String filename = resource.getFilename();
|
||||
if (filename.endsWith(".groovy")) {
|
||||
loadBeanDefinitions(resource);
|
||||
}
|
||||
else if (filename.endsWith(".xml")) {
|
||||
this.xmlBeanDefinitionReader.loadBeanDefinitions(resource);
|
||||
}
|
||||
}
|
||||
loadBeanDefinitions(resourcePattern);
|
||||
}
|
||||
|
||||
|
||||
@@ -410,7 +413,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
dp.apply();
|
||||
}
|
||||
deferredProperties.clear();
|
||||
this.deferredProperties.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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 java.util.Map;
|
||||
* implementation of actual property access left to subclasses.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0
|
||||
* @see #getPropertyValue
|
||||
* @see #setPropertyValue
|
||||
@@ -35,6 +36,8 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
|
||||
|
||||
private boolean extractOldValueForEditor = false;
|
||||
|
||||
private boolean autoGrowNestedPaths = false;
|
||||
|
||||
|
||||
@Override
|
||||
public void setExtractOldValueForEditor(boolean extractOldValueForEditor) {
|
||||
@@ -46,6 +49,16 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
|
||||
return this.extractOldValueForEditor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoGrowNestedPaths(boolean autoGrowNestedPaths) {
|
||||
this.autoGrowNestedPaths = autoGrowNestedPaths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoGrowNestedPaths() {
|
||||
return this.autoGrowNestedPaths;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setPropertyValue(PropertyValue pv) throws BeansException {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,8 +29,7 @@ import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -38,6 +37,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -57,9 +57,8 @@ public abstract class BeanUtils {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(BeanUtils.class);
|
||||
|
||||
// Effectively using a WeakHashMap as a Set
|
||||
private static final Map<Class<?>, Boolean> unknownEditorTypes =
|
||||
Collections.synchronizedMap(new WeakHashMap<Class<?>, Boolean>());
|
||||
private static final Set<Class<?>> unknownEditorTypes =
|
||||
Collections.newSetFromMap(new ConcurrentReferenceHashMap<Class<?>, Boolean>(64));
|
||||
|
||||
|
||||
/**
|
||||
@@ -404,7 +403,7 @@ public abstract class BeanUtils {
|
||||
* @return the corresponding editor, or {@code null} if none found
|
||||
*/
|
||||
public static PropertyEditor findEditorByConvention(Class<?> targetType) {
|
||||
if (targetType == null || targetType.isArray() || unknownEditorTypes.containsKey(targetType)) {
|
||||
if (targetType == null || targetType.isArray() || unknownEditorTypes.contains(targetType)) {
|
||||
return null;
|
||||
}
|
||||
ClassLoader cl = targetType.getClassLoader();
|
||||
@@ -431,7 +430,7 @@ public abstract class BeanUtils {
|
||||
logger.warn("Editor class [" + editorName +
|
||||
"] does not implement [java.beans.PropertyEditor] interface");
|
||||
}
|
||||
unknownEditorTypes.put(targetType, Boolean.TRUE);
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
}
|
||||
return (PropertyEditor) instantiateClass(editorClass);
|
||||
@@ -441,7 +440,7 @@ public abstract class BeanUtils {
|
||||
logger.debug("No property editor [" + editorName + "] found for type " +
|
||||
targetType.getName() + " according to 'Editor' suffix convention");
|
||||
}
|
||||
unknownEditorTypes.put(targetType, Boolean.TRUE);
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,22 +78,6 @@ public interface BeanWrapper extends ConfigurablePropertyAccessor {
|
||||
*/
|
||||
PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;
|
||||
|
||||
/**
|
||||
* Set whether this BeanWrapper should attempt to "auto-grow" a
|
||||
* nested path that contains a {@code null} value.
|
||||
* <p>If {@code true}, a {@code null} path location will be populated
|
||||
* with a default object value and traversed instead of resulting in a
|
||||
* {@link NullValueInNestedPathException}. Turning this flag on also enables
|
||||
* auto-growth of collection elements when accessing an out-of-bounds index.
|
||||
* <p>Default is {@code false} on a plain BeanWrapper.
|
||||
*/
|
||||
void setAutoGrowNestedPaths(boolean autoGrowNestedPaths);
|
||||
|
||||
/**
|
||||
* Return whether "auto-growing" of nested paths has been activated.
|
||||
*/
|
||||
boolean isAutoGrowNestedPaths();
|
||||
|
||||
/**
|
||||
* Specify a limit for array and collection auto-growing.
|
||||
* <p>Default is unlimited on a plain BeanWrapper.
|
||||
|
||||
@@ -115,8 +115,6 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
*/
|
||||
private Map<String, BeanWrapperImpl> nestedBeanWrappers;
|
||||
|
||||
private boolean autoGrowNestedPaths = false;
|
||||
|
||||
private int autoGrowCollectionLimit = Integer.MAX_VALUE;
|
||||
|
||||
|
||||
@@ -252,25 +250,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
return (this.rootObject != null ? this.rootObject.getClass() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this BeanWrapper should attempt to "auto-grow" a nested path that contains a null value.
|
||||
* <p>If "true", a null path location will be populated with a default object value and traversed
|
||||
* instead of resulting in a {@link NullValueInNestedPathException}. Turning this flag on also
|
||||
* enables auto-growth of collection elements when accessing an out-of-bounds index.
|
||||
* <p>Default is "false" on a plain BeanWrapper.
|
||||
*/
|
||||
@Override
|
||||
public void setAutoGrowNestedPaths(boolean autoGrowNestedPaths) {
|
||||
this.autoGrowNestedPaths = autoGrowNestedPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether "auto-growing" of nested paths has been activated.
|
||||
*/
|
||||
@Override
|
||||
public boolean isAutoGrowNestedPaths() {
|
||||
return this.autoGrowNestedPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a limit for array and collection auto-growing.
|
||||
@@ -398,7 +378,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
if (pd.getReadMethod() != null || pd.getWriteMethod() != null) {
|
||||
return TypeDescriptor.nested(property(pd), tokens.keys.length);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (pd.getReadMethod() != null || pd.getWriteMethod() != null) {
|
||||
return new TypeDescriptor(property(pd));
|
||||
}
|
||||
@@ -570,7 +551,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
String canonicalName = tokens.canonicalName;
|
||||
Object propertyValue = getPropertyValue(tokens);
|
||||
if (propertyValue == null) {
|
||||
if (this.autoGrowNestedPaths) {
|
||||
if (isAutoGrowNestedPaths()) {
|
||||
propertyValue = setDefaultValue(tokens);
|
||||
}
|
||||
else {
|
||||
@@ -761,7 +742,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
|
||||
if (tokens.keys != null) {
|
||||
if (value == null) {
|
||||
if (this.autoGrowNestedPaths) {
|
||||
if (isAutoGrowNestedPaths()) {
|
||||
value = setDefaultValue(tokens.actualName);
|
||||
}
|
||||
else {
|
||||
@@ -851,7 +832,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
|
||||
private Object growArrayIfNecessary(Object array, int index, String name) {
|
||||
if (!this.autoGrowNestedPaths) {
|
||||
if (!isAutoGrowNestedPaths()) {
|
||||
return array;
|
||||
}
|
||||
int length = Array.getLength(array);
|
||||
@@ -874,7 +855,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
private void growCollectionIfNecessary(Collection<Object> collection, int index, String name,
|
||||
PropertyDescriptor pd, int nestingLevel) {
|
||||
|
||||
if (!this.autoGrowNestedPaths) {
|
||||
if (!isAutoGrowNestedPaths()) {
|
||||
return;
|
||||
}
|
||||
int size = collection.size();
|
||||
@@ -951,7 +932,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
String key = tokens.keys[tokens.keys.length - 1];
|
||||
if (propValue == null) {
|
||||
// null map value case
|
||||
if (this.autoGrowNestedPaths) {
|
||||
if (isAutoGrowNestedPaths()) {
|
||||
// TODO: cleanup, this is pretty hacky
|
||||
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
|
||||
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
|
||||
|
||||
+46
-56
@@ -20,15 +20,12 @@ import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -38,6 +35,7 @@ import org.springframework.core.SpringProperties;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -107,14 +105,22 @@ public class CachedIntrospectionResults {
|
||||
* Set of ClassLoaders that this CachedIntrospectionResults class will always
|
||||
* accept classes from, even if the classes do not qualify as cache-safe.
|
||||
*/
|
||||
static final Set<ClassLoader> acceptedClassLoaders = new HashSet<ClassLoader>();
|
||||
static final Set<ClassLoader> acceptedClassLoaders =
|
||||
Collections.newSetFromMap(new ConcurrentHashMap<ClassLoader, Boolean>(16));
|
||||
|
||||
/**
|
||||
* Map keyed by class containing CachedIntrospectionResults.
|
||||
* Needs to be a WeakHashMap with WeakReferences as values to allow
|
||||
* for proper garbage collection in case of multiple class loaders.
|
||||
* Map keyed by Class containing CachedIntrospectionResults, strongly held.
|
||||
* This variant is being used for cache-safe bean classes.
|
||||
*/
|
||||
static final Map<Class<?>, Object> classCache = new WeakHashMap<Class<?>, Object>();
|
||||
static final Map<Class<?>, CachedIntrospectionResults> strongClassCache =
|
||||
new ConcurrentHashMap<Class<?>, CachedIntrospectionResults>(64);
|
||||
|
||||
/**
|
||||
* Map keyed by Class containing CachedIntrospectionResults, softly held.
|
||||
* This variant is being used for non-cache-safe bean classes.
|
||||
*/
|
||||
static final Map<Class<?>, CachedIntrospectionResults> softClassCache =
|
||||
new ConcurrentReferenceHashMap<Class<?>, CachedIntrospectionResults>(64);
|
||||
|
||||
|
||||
/**
|
||||
@@ -131,9 +137,7 @@ public class CachedIntrospectionResults {
|
||||
*/
|
||||
public static void acceptClassLoader(ClassLoader classLoader) {
|
||||
if (classLoader != null) {
|
||||
synchronized (acceptedClassLoaders) {
|
||||
acceptedClassLoaders.add(classLoader);
|
||||
}
|
||||
acceptedClassLoaders.add(classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,20 +148,22 @@ public class CachedIntrospectionResults {
|
||||
* @param classLoader the ClassLoader to clear the cache for
|
||||
*/
|
||||
public static void clearClassLoader(ClassLoader classLoader) {
|
||||
synchronized (classCache) {
|
||||
for (Iterator<Class<?>> it = classCache.keySet().iterator(); it.hasNext();) {
|
||||
Class<?> beanClass = it.next();
|
||||
if (isUnderneathClassLoader(beanClass.getClassLoader(), classLoader)) {
|
||||
it.remove();
|
||||
}
|
||||
for (Iterator<ClassLoader> it = acceptedClassLoaders.iterator(); it.hasNext();) {
|
||||
ClassLoader registeredLoader = it.next();
|
||||
if (isUnderneathClassLoader(registeredLoader, classLoader)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
synchronized (acceptedClassLoaders) {
|
||||
for (Iterator<ClassLoader> it = acceptedClassLoaders.iterator(); it.hasNext();) {
|
||||
ClassLoader registeredLoader = it.next();
|
||||
if (isUnderneathClassLoader(registeredLoader, classLoader)) {
|
||||
it.remove();
|
||||
}
|
||||
for (Iterator<Class<?>> it = strongClassCache.keySet().iterator(); it.hasNext();) {
|
||||
Class<?> beanClass = it.next();
|
||||
if (isUnderneathClassLoader(beanClass.getClassLoader(), classLoader)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
for (Iterator<Class<?>> it = softClassCache.keySet().iterator(); it.hasNext();) {
|
||||
Class<?> beanClass = it.next();
|
||||
if (isUnderneathClassLoader(beanClass.getClassLoader(), classLoader)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,35 +176,25 @@ public class CachedIntrospectionResults {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static CachedIntrospectionResults forClass(Class<?> beanClass) throws BeansException {
|
||||
CachedIntrospectionResults results;
|
||||
Object value;
|
||||
synchronized (classCache) {
|
||||
value = classCache.get(beanClass);
|
||||
CachedIntrospectionResults results = strongClassCache.get(beanClass);
|
||||
if (results != null) {
|
||||
return results;
|
||||
}
|
||||
if (value instanceof Reference) {
|
||||
Reference<CachedIntrospectionResults> ref = (Reference<CachedIntrospectionResults>) value;
|
||||
results = ref.get();
|
||||
results = softClassCache.get(beanClass);
|
||||
if (results != null) {
|
||||
return results;
|
||||
}
|
||||
|
||||
results = new CachedIntrospectionResults(beanClass);
|
||||
if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
|
||||
isClassLoaderAccepted(beanClass.getClassLoader())) {
|
||||
strongClassCache.put(beanClass, results);
|
||||
}
|
||||
else {
|
||||
results = (CachedIntrospectionResults) value;
|
||||
}
|
||||
if (results == null) {
|
||||
if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
|
||||
isClassLoaderAccepted(beanClass.getClassLoader())) {
|
||||
results = new CachedIntrospectionResults(beanClass);
|
||||
synchronized (classCache) {
|
||||
classCache.put(beanClass, results);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Not strongly caching class [" + beanClass.getName() + "] because it is not cache-safe");
|
||||
}
|
||||
results = new CachedIntrospectionResults(beanClass);
|
||||
synchronized (classCache) {
|
||||
classCache.put(beanClass, new WeakReference<CachedIntrospectionResults>(results));
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Not strongly caching class [" + beanClass.getName() + "] because it is not cache-safe");
|
||||
}
|
||||
softClassCache.put(beanClass, results);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
@@ -211,13 +207,7 @@ public class CachedIntrospectionResults {
|
||||
* @see #acceptClassLoader
|
||||
*/
|
||||
private static boolean isClassLoaderAccepted(ClassLoader classLoader) {
|
||||
// Iterate over array copy in order to avoid synchronization for the entire
|
||||
// ClassLoader check (avoiding a synchronized acceptedClassLoaders Iterator).
|
||||
ClassLoader[] acceptedLoaderArray;
|
||||
synchronized (acceptedClassLoaders) {
|
||||
acceptedLoaderArray = acceptedClassLoaders.toArray(new ClassLoader[acceptedClassLoaders.size()]);
|
||||
}
|
||||
for (ClassLoader acceptedLoader : acceptedLoaderArray) {
|
||||
for (ClassLoader acceptedLoader : acceptedClassLoaders) {
|
||||
if (isUnderneathClassLoader(classLoader, acceptedLoader)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+17
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2014 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,6 +26,7 @@ import org.springframework.core.convert.ConversionService;
|
||||
* <p>Serves as base interface for {@link BeanWrapper}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0
|
||||
* @see BeanWrapper
|
||||
*/
|
||||
@@ -54,4 +55,19 @@ public interface ConfigurablePropertyAccessor extends PropertyAccessor, Property
|
||||
*/
|
||||
boolean isExtractOldValueForEditor();
|
||||
|
||||
/**
|
||||
* Set whether this instance should attempt to "auto-grow" a
|
||||
* nested path that contains a {@code null} value.
|
||||
* <p>If {@code true}, a {@code null} path location will be populated
|
||||
* with a default object value and traversed instead of resulting in a
|
||||
* {@link NullValueInNestedPathException}.
|
||||
* <p>Default is {@code false} on a plain instance.
|
||||
*/
|
||||
void setAutoGrowNestedPaths(boolean autoGrowNestedPaths);
|
||||
|
||||
/**
|
||||
* Return whether "auto-growing" of nested paths has been activated.
|
||||
*/
|
||||
boolean isAutoGrowNestedPaths();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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,28 +16,31 @@
|
||||
|
||||
package org.springframework.beans;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* {@link PropertyAccessor} implementation that directly accesses instance fields.
|
||||
* Allows for direct binding to fields instead of going through JavaBean setters.
|
||||
*
|
||||
* <p>This implementation just supports fields in the actual target object.
|
||||
* It is not able to traverse nested fields.
|
||||
* <p>As of Spring 4.1, this implementation supports nested field traversal.
|
||||
*
|
||||
* <p>A DirectFieldAccessor's default for the "extractOldValueForEditor" setting
|
||||
* is "true", since a field can always be read without side effects.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0
|
||||
* @see #setExtractOldValueForEditor
|
||||
* @see BeanWrapper
|
||||
@@ -46,112 +49,264 @@ import java.util.Map;
|
||||
*/
|
||||
public class DirectFieldAccessor extends AbstractPropertyAccessor {
|
||||
|
||||
private final Object target;
|
||||
private final Object rootObject;
|
||||
|
||||
private final Map<String, Field> fieldMap = new HashMap<String, Field>();
|
||||
private final Map<String, FieldAccessor> fieldMap = new HashMap<String, FieldAccessor>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new DirectFieldAccessor for the given target object.
|
||||
* @param target the target object to access
|
||||
* Create a new DirectFieldAccessor for the given root object.
|
||||
* @param rootObject the root object to access
|
||||
*/
|
||||
public DirectFieldAccessor(final Object target) {
|
||||
Assert.notNull(target, "Target object must not be null");
|
||||
this.target = target;
|
||||
ReflectionUtils.doWithFields(this.target.getClass(), new ReflectionUtils.FieldCallback() {
|
||||
@Override
|
||||
public void doWith(Field field) {
|
||||
if (fieldMap.containsKey(field.getName())) {
|
||||
// ignore superclass declarations of fields already found in a subclass
|
||||
}
|
||||
else {
|
||||
fieldMap.put(field.getName(), field);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.typeConverterDelegate = new TypeConverterDelegate(this, target);
|
||||
public DirectFieldAccessor(final Object rootObject) {
|
||||
Assert.notNull(rootObject, "Root object must not be null");
|
||||
this.rootObject = rootObject;
|
||||
this.typeConverterDelegate = new TypeConverterDelegate(this, rootObject);
|
||||
registerDefaultEditors();
|
||||
setExtractOldValueForEditor(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the root object at the top of the path of this instance.
|
||||
*/
|
||||
public final Object getRootInstance() {
|
||||
return this.rootObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class of the root object at the top of the path of this instance.
|
||||
*/
|
||||
public final Class<?> getRootClass() {
|
||||
return (this.rootObject != null ? this.rootObject.getClass() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadableProperty(String propertyName) throws BeansException {
|
||||
return this.fieldMap.containsKey(propertyName);
|
||||
return hasProperty(propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritableProperty(String propertyName) throws BeansException {
|
||||
return this.fieldMap.containsKey(propertyName);
|
||||
return hasProperty(propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getPropertyType(String propertyName) throws BeansException {
|
||||
Field field = this.fieldMap.get(propertyName);
|
||||
if (field != null) {
|
||||
return field.getType();
|
||||
public Class<?> getPropertyType(String propertyPath) throws BeansException {
|
||||
FieldAccessor fieldAccessor = getFieldAccessor(propertyPath);
|
||||
if (fieldAccessor != null) {
|
||||
return fieldAccessor.getField().getType();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException {
|
||||
Field field = this.fieldMap.get(propertyName);
|
||||
if (field != null) {
|
||||
return new TypeDescriptor(field);
|
||||
FieldAccessor fieldAccessor = getFieldAccessor(propertyName);
|
||||
if (fieldAccessor != null) {
|
||||
return new TypeDescriptor(fieldAccessor.getField());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPropertyValue(String propertyName) throws BeansException {
|
||||
Field field = this.fieldMap.get(propertyName);
|
||||
if (field == null) {
|
||||
FieldAccessor fieldAccessor = getFieldAccessor(propertyName);
|
||||
if (fieldAccessor == null) {
|
||||
throw new NotReadablePropertyException(
|
||||
this.target.getClass(), propertyName, "Field '" + propertyName + "' does not exist");
|
||||
}
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
return field.get(this.target);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new InvalidPropertyException(this.target.getClass(), propertyName, "Field is not accessible", ex);
|
||||
getRootClass(), propertyName, "Field '" + propertyName + "' does not exist");
|
||||
}
|
||||
return fieldAccessor.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPropertyValue(String propertyName, Object newValue) throws BeansException {
|
||||
Field field = this.fieldMap.get(propertyName);
|
||||
if (field == null) {
|
||||
FieldAccessor fieldAccessor = getFieldAccessor(propertyName);
|
||||
if (fieldAccessor == null) {
|
||||
throw new NotWritablePropertyException(
|
||||
this.target.getClass(), propertyName, "Field '" + propertyName + "' does not exist");
|
||||
getRootClass(), propertyName, "Field '" + propertyName + "' does not exist");
|
||||
}
|
||||
Field field = fieldAccessor.getField();
|
||||
Object oldValue = null;
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
oldValue = field.get(this.target);
|
||||
oldValue = fieldAccessor.getValue();
|
||||
Object convertedValue = this.typeConverterDelegate.convertIfNecessary(
|
||||
field.getName(), oldValue, newValue, field.getType(), new TypeDescriptor(field));
|
||||
field.set(this.target, convertedValue);
|
||||
fieldAccessor.setValue(convertedValue);
|
||||
}
|
||||
catch (ConverterNotFoundException ex) {
|
||||
PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue);
|
||||
PropertyChangeEvent pce = new PropertyChangeEvent(getRootInstance(), propertyName, oldValue, newValue);
|
||||
throw new ConversionNotSupportedException(pce, field.getType(), ex);
|
||||
}
|
||||
catch (ConversionException ex) {
|
||||
PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue);
|
||||
PropertyChangeEvent pce = new PropertyChangeEvent(getRootInstance(), propertyName, oldValue, newValue);
|
||||
throw new TypeMismatchException(pce, field.getType(), ex);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue);
|
||||
PropertyChangeEvent pce = new PropertyChangeEvent(getRootInstance(), propertyName, oldValue, newValue);
|
||||
throw new ConversionNotSupportedException(pce, field.getType(), ex);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
PropertyChangeEvent pce = new PropertyChangeEvent(this.target, propertyName, oldValue, newValue);
|
||||
PropertyChangeEvent pce = new PropertyChangeEvent(getRootInstance(), propertyName, oldValue, newValue);
|
||||
throw new TypeMismatchException(pce, field.getType(), ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new InvalidPropertyException(this.target.getClass(), propertyName, "Field is not accessible", ex);
|
||||
}
|
||||
|
||||
private boolean hasProperty(String propertyPath) {
|
||||
Assert.notNull(propertyPath, "PropertyPath must not be null");
|
||||
return getFieldAccessor(propertyPath) != null;
|
||||
}
|
||||
|
||||
private FieldAccessor getFieldAccessor(String propertyPath) {
|
||||
FieldAccessor fieldAccessor = this.fieldMap.get(propertyPath);
|
||||
if (fieldAccessor == null) {
|
||||
fieldAccessor = doGetFieldAccessor(propertyPath, getRootClass());
|
||||
this.fieldMap.put(propertyPath, fieldAccessor);
|
||||
}
|
||||
return fieldAccessor;
|
||||
}
|
||||
|
||||
private FieldAccessor doGetFieldAccessor(String propertyPath, Class<?> targetClass) {
|
||||
StringTokenizer st = new StringTokenizer(propertyPath, ".");
|
||||
FieldAccessor accessor = null;
|
||||
Class<?> parentType = targetClass;
|
||||
while (st.hasMoreTokens()) {
|
||||
String localProperty = st.nextToken();
|
||||
Field field = ReflectionUtils.findField(parentType, localProperty);
|
||||
if (field == null) {
|
||||
return null;
|
||||
}
|
||||
if (accessor == null) {
|
||||
accessor = root(propertyPath, localProperty, field);
|
||||
}
|
||||
else {
|
||||
accessor = accessor.child(localProperty, field);
|
||||
}
|
||||
parentType = field.getType();
|
||||
}
|
||||
return accessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a root {@link FieldAccessor}.
|
||||
* @param canonicalName the full expression for the field to access
|
||||
* @param actualName the name of the local (root) property
|
||||
* @param field the field accessing the property
|
||||
*/
|
||||
private FieldAccessor root(String canonicalName, String actualName, Field field) {
|
||||
return new FieldAccessor(null, canonicalName, actualName, field);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provide an easy access to a potentially hierarchical value.
|
||||
*/
|
||||
private class FieldAccessor {
|
||||
|
||||
private final List<FieldAccessor> parents;
|
||||
|
||||
private final String canonicalName;
|
||||
|
||||
private final String actualName;
|
||||
|
||||
private final Field field;
|
||||
|
||||
/**
|
||||
* Create a new FieldAccessor instance.
|
||||
* @param parent the parent accessor, if any
|
||||
* @param canonicalName the full expression for the field to access
|
||||
* @param actualName the name of the partial expression for this property
|
||||
* @param field the field accessing the property
|
||||
*/
|
||||
public FieldAccessor(FieldAccessor parent, String canonicalName, String actualName, Field field) {
|
||||
Assert.notNull(canonicalName, "Expression must no be null");
|
||||
Assert.notNull(field, "Field must no be null");
|
||||
this.parents = buildParents(parent);
|
||||
this.canonicalName = canonicalName;
|
||||
this.actualName = actualName;
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a child instance.
|
||||
* @param actualName the name of the child property
|
||||
* @param field the field accessing the child property
|
||||
*/
|
||||
public FieldAccessor child(String actualName, Field field) {
|
||||
return new FieldAccessor(this, this.canonicalName, this.actualName + "." + actualName, field);
|
||||
}
|
||||
|
||||
public Field getField() {
|
||||
return this.field;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
Object localTarget = getLocalTarget(getRootInstance());
|
||||
return getParentValue(localTarget);
|
||||
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
Object localTarget = getLocalTarget(getRootInstance());
|
||||
try {
|
||||
this.field.set(localTarget, value);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new InvalidPropertyException(localTarget.getClass(), canonicalName, "Field is not accessible", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Object getParentValue(Object target) {
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(this.field);
|
||||
return this.field.get(target);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new InvalidPropertyException(target.getClass(),
|
||||
this.canonicalName, "Field is not accessible", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Object getLocalTarget(Object rootTarget) {
|
||||
Object localTarget = rootTarget;
|
||||
for (FieldAccessor parent : parents) {
|
||||
localTarget = autoGrowIfNecessary(parent, parent.getParentValue(localTarget));
|
||||
if (localTarget == null) { // Could not traverse the graph any further
|
||||
throw new NullValueInNestedPathException(getRootClass(), parent.actualName,
|
||||
"Cannot access indexed value of property referenced in indexed property path '" +
|
||||
getField().getName() + "': returned null");
|
||||
}
|
||||
}
|
||||
return localTarget;
|
||||
}
|
||||
|
||||
private Object newValue() {
|
||||
Class<?> type = getField().getType();
|
||||
try {
|
||||
return type.newInstance();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.actualName,
|
||||
"Could not instantiate property type [" + type.getName() +
|
||||
"] to auto-grow nested property path: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Object autoGrowIfNecessary(FieldAccessor accessor, Object value) {
|
||||
if (value == null && isAutoGrowNestedPaths()) {
|
||||
Object defaultValue = accessor.newValue();
|
||||
accessor.setValue(defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private List<FieldAccessor> buildParents(FieldAccessor parent) {
|
||||
List<FieldAccessor> parents = new ArrayList<FieldAccessor>();
|
||||
if (parent != null) {
|
||||
parents.addAll(parent.parents);
|
||||
parents.add(parent);
|
||||
}
|
||||
return parents;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+40
-49
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -42,18 +42,18 @@ class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
|
||||
|
||||
private final Class<?> beanClass;
|
||||
|
||||
private final Class<?> propertyEditorClass;
|
||||
|
||||
private final Method readMethod;
|
||||
|
||||
private final Method writeMethod;
|
||||
|
||||
private final Class<?> propertyEditorClass;
|
||||
|
||||
private volatile Set<Method> ambiguousWriteMethods;
|
||||
|
||||
private Class<?> propertyType;
|
||||
|
||||
private MethodParameter writeMethodParameter;
|
||||
|
||||
private Class<?> propertyType;
|
||||
|
||||
|
||||
public GenericTypeAwarePropertyDescriptor(Class<?> beanClass, String propertyName,
|
||||
Method readMethod, Method writeMethod, Class<?> propertyEditorClass)
|
||||
@@ -78,27 +78,44 @@ class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
|
||||
this.readMethod = readMethodToUse;
|
||||
this.writeMethod = writeMethodToUse;
|
||||
|
||||
if (this.writeMethod != null && this.readMethod == null) {
|
||||
// Write method not matched against read method: potentially ambiguous through
|
||||
// several overloaded variants, in which case an arbitrary winner has been chosen
|
||||
// by the JDK's JavaBeans Introspector...
|
||||
Set<Method> ambiguousCandidates = new HashSet<Method>();
|
||||
for (Method method : beanClass.getMethods()) {
|
||||
if (method.getName().equals(writeMethodToUse.getName()) &&
|
||||
!method.equals(writeMethodToUse) && !method.isBridge()) {
|
||||
ambiguousCandidates.add(method);
|
||||
if (this.writeMethod != null) {
|
||||
if (this.readMethod == null) {
|
||||
// Write method not matched against read method: potentially ambiguous through
|
||||
// several overloaded variants, in which case an arbitrary winner has been chosen
|
||||
// by the JDK's JavaBeans Introspector...
|
||||
Set<Method> ambiguousCandidates = new HashSet<Method>();
|
||||
for (Method method : beanClass.getMethods()) {
|
||||
if (method.getName().equals(writeMethodToUse.getName()) &&
|
||||
!method.equals(writeMethodToUse) && !method.isBridge()) {
|
||||
ambiguousCandidates.add(method);
|
||||
}
|
||||
}
|
||||
if (!ambiguousCandidates.isEmpty()) {
|
||||
this.ambiguousWriteMethods = ambiguousCandidates;
|
||||
}
|
||||
}
|
||||
if (!ambiguousCandidates.isEmpty()) {
|
||||
this.ambiguousWriteMethods = ambiguousCandidates;
|
||||
}
|
||||
this.writeMethodParameter = new MethodParameter(this.writeMethod, 0);
|
||||
GenericTypeResolver.resolveParameterType(this.writeMethodParameter, this.beanClass);
|
||||
}
|
||||
|
||||
if (this.readMethod != null) {
|
||||
this.propertyType = GenericTypeResolver.resolveReturnType(this.readMethod, this.beanClass);
|
||||
}
|
||||
else if (this.writeMethodParameter != null) {
|
||||
this.propertyType = this.writeMethodParameter.getParameterType();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Class<?> getBeanClass() {
|
||||
return this.beanClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getPropertyEditorClass() {
|
||||
return this.propertyEditorClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Method getReadMethod() {
|
||||
return this.readMethod;
|
||||
@@ -120,39 +137,13 @@ class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
|
||||
return this.writeMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getPropertyEditorClass() {
|
||||
return this.propertyEditorClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Class<?> getPropertyType() {
|
||||
if (this.propertyType == null) {
|
||||
if (this.readMethod != null) {
|
||||
this.propertyType = GenericTypeResolver.resolveReturnType(this.readMethod, this.beanClass);
|
||||
}
|
||||
else {
|
||||
MethodParameter writeMethodParam = getWriteMethodParameter();
|
||||
if (writeMethodParam != null) {
|
||||
this.propertyType = writeMethodParam.getParameterType();
|
||||
}
|
||||
else {
|
||||
this.propertyType = super.getPropertyType();
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.propertyType;
|
||||
}
|
||||
|
||||
public synchronized MethodParameter getWriteMethodParameter() {
|
||||
if (this.writeMethod == null) {
|
||||
return null;
|
||||
}
|
||||
if (this.writeMethodParameter == null) {
|
||||
this.writeMethodParameter = new MethodParameter(this.writeMethod, 0);
|
||||
GenericTypeResolver.resolveParameterType(this.writeMethodParameter, this.beanClass);
|
||||
}
|
||||
public MethodParameter getWriteMethodParameter() {
|
||||
return this.writeMethodParameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getPropertyType() {
|
||||
return this.propertyType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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 class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
||||
|
||||
static {
|
||||
try {
|
||||
zoneIdClass = PropertyEditorRegistrySupport.class.getClassLoader().loadClass("java.time.ZoneId");
|
||||
zoneIdClass = ClassUtils.forName("java.time.ZoneId", PropertyEditorRegistrySupport.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Java 8 ZoneId class not available
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -172,7 +172,8 @@ final class PropertyMatches {
|
||||
char t_j = s2.charAt(j - 1);
|
||||
if (s_i == t_j) {
|
||||
cost = 0;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
cost = 1;
|
||||
}
|
||||
d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,6 +53,20 @@ class TypeConverterDelegate {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(TypeConverterDelegate.class);
|
||||
|
||||
/** Java 8's java.util.Optional.empty() instance */
|
||||
private static Object javaUtilOptionalEmpty = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> clazz = ClassUtils.forName("java.util.Optional", TypeConverterDelegate.class.getClassLoader());
|
||||
javaUtilOptionalEmpty = ClassUtils.getMethod(clazz, "empty").invoke(null);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Java 8 not available - conversion to Optional not supported then.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final PropertyEditorRegistrySupport propertyEditorRegistry;
|
||||
|
||||
private final Object targetObject;
|
||||
@@ -244,6 +258,12 @@ class TypeConverterDelegate {
|
||||
standardConversion = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// convertedValue == null
|
||||
if (javaUtilOptionalEmpty != null && requiredType.equals(javaUtilOptionalEmpty.getClass())) {
|
||||
convertedValue = javaUtilOptionalEmpty;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
|
||||
if (firstAttemptEx != null) {
|
||||
@@ -289,19 +309,19 @@ class TypeConverterDelegate {
|
||||
if (index > - 1) {
|
||||
String enumType = trimmedValue.substring(0, index);
|
||||
String fieldName = trimmedValue.substring(index + 1);
|
||||
ClassLoader loader = this.targetObject.getClass().getClassLoader();
|
||||
ClassLoader cl = this.targetObject.getClass().getClassLoader();
|
||||
try {
|
||||
Class<?> enumValueType = loader.loadClass(enumType);
|
||||
Class<?> enumValueType = ClassUtils.forName(enumType, cl);
|
||||
Field enumField = enumValueType.getField(fieldName);
|
||||
convertedValue = enumField.get(null);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
if(logger.isTraceEnabled()) {
|
||||
logger.trace("Enum class [" + enumType + "] cannot be loaded from [" + loader + "]", ex);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Enum class [" + enumType + "] cannot be loaded", ex);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if(logger.isTraceEnabled()) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Field [" + fieldName + "] isn't an enum value for type [" + enumType + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -170,8 +170,7 @@ public interface BeanFactory {
|
||||
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
|
||||
* overriding the specified default arguments (if any) in the bean definition.
|
||||
* @param name the name of the bean to retrieve
|
||||
* @param args arguments to use if creating a prototype using explicit arguments to a
|
||||
* static factory method. It is invalid to use a non-null args value in any other case.
|
||||
* @param args arguments to use if creating a prototype using explicit arguments
|
||||
* @return an instance of the bean
|
||||
* @throws NoSuchBeanDefinitionException if there is no such bean definition
|
||||
* @throws BeanDefinitionStoreException if arguments have been given but
|
||||
@@ -181,6 +180,27 @@ public interface BeanFactory {
|
||||
*/
|
||||
Object getBean(String name, Object... args) 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,
|
||||
* overriding the specified default arguments (if any) in the bean definition.
|
||||
* @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}.
|
||||
* @param args arguments to use if creating a prototype using explicit arguments to a
|
||||
* static factory method. It is invalid to use a non-null args value in any other case.
|
||||
* @return an instance of the bean
|
||||
* @throws NoSuchBeanDefinitionException if there is no such bean definition
|
||||
* @throws BeanDefinitionStoreException if arguments have been given but
|
||||
* the affected bean isn't a prototype
|
||||
* @throws BeansException if the bean could not be created
|
||||
* @since 4.1
|
||||
*/
|
||||
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
|
||||
|
||||
/**
|
||||
* Does this bean factory contain a bean definition or externally registered singleton
|
||||
* instance with the given name?
|
||||
|
||||
+1
-1
@@ -101,7 +101,7 @@ public interface ListableBeanFactory extends BeanFactory {
|
||||
* by other means than bean definitions.
|
||||
* <p>This version of {@code getBeanNamesForType} matches all kinds of beans,
|
||||
* be it singletons, prototypes, or FactoryBeans. In most implementations, the
|
||||
* result will be the same as for {@code getBeanNamesOfType(type, true, true)}.
|
||||
* result will be the same as for {@code getBeanNamesForType(type, true, true)}.
|
||||
* <p>Bean names returned by this method should always return bean names <i>in the
|
||||
* order of definition</i> in the backend configuration, as far as possible.
|
||||
* @param type the class or interface to match, or {@code null} for all bean names
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory;
|
||||
|
||||
/**
|
||||
* Callback interface triggered at the end of the singleton pre-instantiation phase
|
||||
* during {@link BeanFactory} bootstrap. This interface can be implemented by
|
||||
* singleton beans in order to perform some initialization after the regular
|
||||
* singleton instantiation algorithm, avoiding side effects with accidental early
|
||||
* initialization (e.g. from {@link ListableBeanFactory#getBeansOfType} calls).
|
||||
* In that sense, it is an alternative to {@link InitializingBean} which gets
|
||||
* triggered right at the end of a bean's local construction phase.
|
||||
*
|
||||
* <p>This callback variant is somewhat similar to
|
||||
* {@link org.springframework.context.event.ContextRefreshedEvent} but doesn't
|
||||
* require an implementation of {@link org.springframework.context.ApplicationListener},
|
||||
* with no need to filter context references across a context hierarchy etc.
|
||||
* It also implies a more minimal dependency on just the {@code beans} package
|
||||
* and is being honored by standalone {@link ListableBeanFactory} implementations,
|
||||
* not just in an {@link org.springframework.context.ApplicationContext} environment.
|
||||
*
|
||||
* <p><b>NOTE:</b> If you intend to start/manage asynchronous tasks, preferably
|
||||
* implement {@link org.springframework.context.Lifecycle} instead which offers
|
||||
* a richer model for runtime management and allows for phased startup/shutdown.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
* @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons()
|
||||
*/
|
||||
public interface SmartInitializingSingleton {
|
||||
|
||||
/**
|
||||
* Invoked right at the end of the singleton pre-instantiation phase,
|
||||
* with a guarantee that all regular singleton beans have been created
|
||||
* already. {@link ListableBeanFactory#getBeansOfType} calls within
|
||||
* this method won't trigger accidental side effects during bootstrap.
|
||||
* <p><b>NOTE:</b> This callback won't be triggered for singleton beans
|
||||
* lazily initialized on demand after {@link BeanFactory} bootstrap,
|
||||
* and not for any other bean scope either. Carefully use it for beans
|
||||
* with the intended bootstrap semantics only.
|
||||
*/
|
||||
void afterSingletonsInstantiated();
|
||||
|
||||
}
|
||||
+41
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -25,6 +25,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
@@ -44,10 +45,12 @@ import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.LookupOverride;
|
||||
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
@@ -96,6 +99,12 @@ import org.springframework.util.StringUtils;
|
||||
* thus the latter configuration will override the former for properties wired through
|
||||
* both approaches.
|
||||
*
|
||||
* <p>In addition to regular injection points as discussed above, this post-processor
|
||||
* also handles Spring's {@link Lookup @Lookup} annotation which identifies lookup
|
||||
* methods to be replaced by the container at runtime. This is essentially a type-safe
|
||||
* version of {@code getBean(Class, args)} and {@code getBean(String, args)},
|
||||
* See {@link Lookup @Lookup's javadoc} for details.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
@@ -119,6 +128,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
private final Set<String> lookupMethodsChecked =
|
||||
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(64));
|
||||
|
||||
private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache =
|
||||
new ConcurrentHashMap<Class<?>, Constructor<?>[]>(64);
|
||||
|
||||
@@ -135,9 +147,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
public AutowiredAnnotationBeanPostProcessor() {
|
||||
this.autowiredAnnotationTypes.add(Autowired.class);
|
||||
this.autowiredAnnotationTypes.add(Value.class);
|
||||
ClassLoader cl = AutowiredAnnotationBeanPostProcessor.class.getClassLoader();
|
||||
try {
|
||||
this.autowiredAnnotationTypes.add((Class<? extends Annotation>) cl.loadClass("javax.inject.Inject"));
|
||||
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
|
||||
logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -224,7 +236,28 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
|
||||
@Override
|
||||
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
|
||||
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeansException {
|
||||
if (!this.lookupMethodsChecked.contains(beanName)) {
|
||||
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
Lookup lookup = method.getAnnotation(Lookup.class);
|
||||
if (lookup != null) {
|
||||
LookupOverride override = new LookupOverride(method, lookup.value());
|
||||
try {
|
||||
RootBeanDefinition mbd = (RootBeanDefinition) beanFactory.getMergedBeanDefinition(beanName);
|
||||
mbd.getMethodOverrides().addOverride(override);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Cannot apply @Lookup to beans without corresponding bean definition");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
this.lookupMethodsChecked.add(beanName);
|
||||
}
|
||||
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
|
||||
if (candidateConstructors == null) {
|
||||
@@ -239,7 +272,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
AnnotationAttributes annotation = findAutowiredAnnotation(candidate);
|
||||
if (annotation != null) {
|
||||
if (requiredConstructor != null) {
|
||||
throw new BeanCreationException("Invalid autowire-marked constructor: " + candidate +
|
||||
throw new BeanCreationException(beanName,
|
||||
"Invalid autowire-marked constructor: " + candidate +
|
||||
". Found another constructor with 'required' Autowired annotation: " +
|
||||
requiredConstructor);
|
||||
}
|
||||
@@ -250,10 +284,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
boolean required = determineRequiredStatus(annotation);
|
||||
if (required) {
|
||||
if (!candidates.isEmpty()) {
|
||||
throw new BeanCreationException(
|
||||
throw new BeanCreationException(beanName,
|
||||
"Invalid autowire-marked constructors: " + candidates +
|
||||
". Found another constructor with 'required' Autowired annotation: " +
|
||||
requiredConstructor);
|
||||
candidate);
|
||||
}
|
||||
requiredConstructor = candidate;
|
||||
}
|
||||
|
||||
+8
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.util.ObjectUtils;
|
||||
* Spring's {@link Qualifier @Qualifier} annotation.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1.2
|
||||
* @see BeanFactoryUtils
|
||||
*/
|
||||
@@ -90,9 +91,13 @@ public class BeanFactoryAnnotationUtils {
|
||||
if (matchingBean != null) {
|
||||
return matchingBean;
|
||||
}
|
||||
else if (bf.containsBean(qualifier)) {
|
||||
// Fallback: target bean at least found by bean name - probably a manually registered singleton.
|
||||
return bf.getBean(qualifier, beanType);
|
||||
}
|
||||
else {
|
||||
throw new NoSuchBeanDefinitionException(qualifier, "No matching " + beanType.getSimpleName() +
|
||||
" bean found for qualifier '" + qualifier + "' - neither qualifier " + "match nor bean name match!");
|
||||
" bean found for qualifier '" + qualifier + "' - neither qualifier match nor bean name match!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +133,7 @@ public class BeanFactoryAnnotationUtils {
|
||||
}
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// ignore - can't compare qualifiers for a manually registered singleton object
|
||||
// Ignore - can't compare qualifiers for a manually registered singleton object
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation that indicates 'lookup' methods, to be overridden by the container
|
||||
* to redirect them back to the {@link org.springframework.beans.factory.BeanFactory}
|
||||
* for a {@code getBean} call. This is essentially an annotation-based version of the
|
||||
* XML {@code lookup-method} attribute, resulting in the same runtime arrangement.
|
||||
*
|
||||
* <p>The resolution of the target bean can either be based on the return type
|
||||
* ({@code getBean(Class)}) or on a suggested bean name ({@code getBean(String)}),
|
||||
* in both cases passing the method's arguments to the {@code getBean} call
|
||||
* for applying them as target factory method arguments or constructor arguments.
|
||||
*
|
||||
* <p>Such lookup methods can have default (stub) implementations that will simply
|
||||
* get replaced by the container, or they can be declared as abstract - for the
|
||||
* container to fill them in at runtime. In both cases, the container will generate
|
||||
* runtime subclasses of the method's containing class via CGLIB, which is why such
|
||||
* lookup methods can only work on beans that the container instantiates through
|
||||
* regular constructors (i.e. lookup methods cannot get replaced on beans returned
|
||||
* from factory methods where we can't dynamically provide a subclass for them).
|
||||
*
|
||||
* <p>Note: When used with component scanning or any other mechanism that filters
|
||||
* out abstract beans, provide stub implementations of your lookup methods to be
|
||||
* able to declare them as concrete classes.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean(Class, Object...)
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean(String, Object...)
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Lookup {
|
||||
|
||||
/**
|
||||
* This annotation attribute may suggest a target bean name to look up.
|
||||
* If not specified, the target bean will be resolved based on the
|
||||
* annotated method's return type declaration.
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
}
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -66,9 +66,9 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
||||
@SuppressWarnings("unchecked")
|
||||
public QualifierAnnotationAutowireCandidateResolver() {
|
||||
this.qualifierTypes.add(Qualifier.class);
|
||||
ClassLoader cl = QualifierAnnotationAutowireCandidateResolver.class.getClassLoader();
|
||||
try {
|
||||
this.qualifierTypes.add((Class<? extends Annotation>) cl.loadClass("javax.inject.Qualifier"));
|
||||
this.qualifierTypes.add((Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.inject.Qualifier", QualifierAnnotationAutowireCandidateResolver.class.getClassLoader()));
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - simply skip.
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -166,7 +166,7 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
* Set the names of the beans that this bean depends on being initialized.
|
||||
* The bean factory will guarantee that these beans get initialized first.
|
||||
*/
|
||||
void setDependsOn(String[] dependsOn);
|
||||
void setDependsOn(String... dependsOn);
|
||||
|
||||
/**
|
||||
* Return whether this bean is a candidate for getting autowired into some other bean.
|
||||
|
||||
-117
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.config;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.FactoryBeanNotInitializedException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.SmartFactoryBean;
|
||||
|
||||
/**
|
||||
* FactoryBean that exposes an arbitrary target bean under a different name.
|
||||
*
|
||||
* <p>Usually, the target bean will reside in a different bean definition file,
|
||||
* using this FactoryBean to link it in and expose it under a different name.
|
||||
* Effectively, this corresponds to an alias for the target bean.
|
||||
*
|
||||
* <p><b>NOTE:</b> For XML bean definition files, an {@code <alias>}
|
||||
* tag is available that effectively achieves the same.
|
||||
*
|
||||
* <p>A special capability of this FactoryBean is enabled through its configuration
|
||||
* as bean definition: The "targetBeanName" can be substituted through a placeholder,
|
||||
* in combination with Spring's {@link PropertyPlaceholderConfigurer}.
|
||||
* Thanks to Marcus Bristav for pointing this out!
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see #setTargetBeanName
|
||||
* @see PropertyPlaceholderConfigurer
|
||||
* @deprecated as of Spring 3.2, in favor of using regular bean name aliases
|
||||
* (which support placeholder parsing since Spring 2.5)
|
||||
*/
|
||||
@Deprecated
|
||||
public class BeanReferenceFactoryBean implements SmartFactoryBean<Object>, BeanFactoryAware {
|
||||
|
||||
private String targetBeanName;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the target bean.
|
||||
* <p>This property is required. The value for this property can be
|
||||
* substituted through a placeholder, in combination with Spring's
|
||||
* PropertyPlaceholderConfigurer.
|
||||
* @param targetBeanName the name of the target bean
|
||||
* @see PropertyPlaceholderConfigurer
|
||||
*/
|
||||
public void setTargetBeanName(String targetBeanName) {
|
||||
this.targetBeanName = targetBeanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
if (this.targetBeanName == null) {
|
||||
throw new IllegalArgumentException("'targetBeanName' is required");
|
||||
}
|
||||
if (!this.beanFactory.containsBean(this.targetBeanName)) {
|
||||
throw new NoSuchBeanDefinitionException(this.targetBeanName, this.beanFactory.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getObject() throws BeansException {
|
||||
if (this.beanFactory == null) {
|
||||
throw new FactoryBeanNotInitializedException();
|
||||
}
|
||||
return this.beanFactory.getBean(this.targetBeanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
if (this.beanFactory == null) {
|
||||
return null;
|
||||
}
|
||||
return this.beanFactory.getType(this.targetBeanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
if (this.beanFactory == null) {
|
||||
throw new FactoryBeanNotInitializedException();
|
||||
}
|
||||
return this.beanFactory.isSingleton(this.targetBeanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrototype() {
|
||||
if (this.beanFactory == null) {
|
||||
throw new FactoryBeanNotInitializedException();
|
||||
}
|
||||
return this.beanFactory.isPrototype(this.targetBeanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEagerInit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Factory bean for
|
||||
* <a href="http://jakarta.apache.org/commons/logging.html">commons-logging</a>
|
||||
* {@link org.apache.commons.logging.Log} instances.
|
||||
*
|
||||
* <p>Useful for sharing Log instances among multiple beans instead of using
|
||||
* one Log instance per class name, e.g. for common log topics.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 16.11.2003
|
||||
* @see org.apache.commons.logging.Log
|
||||
* @deprecated as of Spring 3.2, in favor of a bean definition that points
|
||||
* to the bean class "org.apache.commons.logging.LogFactory" and the factory
|
||||
* method "getLog", passing in the log name as constructor argument
|
||||
*/
|
||||
@Deprecated
|
||||
public class CommonsLogFactoryBean implements FactoryBean<Log>, InitializingBean {
|
||||
|
||||
private Log log;
|
||||
|
||||
|
||||
/**
|
||||
* The name of the log.
|
||||
* <p>This property is required.
|
||||
* @param logName the name of the log
|
||||
*/
|
||||
public void setLogName(String logName) {
|
||||
this.log = LogFactory.getLog(logName);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (this.log == null) {
|
||||
throw new IllegalArgumentException("'logName' is required");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Log getObject() {
|
||||
return this.log;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Log> getObjectType() {
|
||||
return (this.log != null ? this.log.getClass() : Log.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+12
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -263,18 +263,20 @@ public class DependencyDescriptor implements Serializable {
|
||||
if (this.field != null) {
|
||||
if (this.nestingLevel > 1) {
|
||||
Type type = this.field.getGenericType();
|
||||
if (type instanceof ParameterizedType) {
|
||||
Type[] args = ((ParameterizedType) type).getActualTypeArguments();
|
||||
Type arg = args[args.length - 1];
|
||||
for (int i = 2; i <= this.nestingLevel; i++) {
|
||||
if (type instanceof ParameterizedType) {
|
||||
Type[] args = ((ParameterizedType) type).getActualTypeArguments();
|
||||
type = args[args.length - 1];
|
||||
}
|
||||
}
|
||||
if (type instanceof Class) {
|
||||
return (Class<?>) type;
|
||||
}
|
||||
else if (type instanceof ParameterizedType) {
|
||||
Type arg = ((ParameterizedType) type).getRawType();
|
||||
if (arg instanceof Class) {
|
||||
return (Class<?>) arg;
|
||||
}
|
||||
else if (arg instanceof ParameterizedType) {
|
||||
arg = ((ParameterizedType) arg).getRawType();
|
||||
if (arg instanceof Class) {
|
||||
return (Class<?>) arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.config;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Factory for a Map that reads from a YAML source. YAML is a nice human-readable
|
||||
* format for configuration, and it has some useful hierarchical properties. It's
|
||||
* more or less a superset of JSON, so it has a lot of similar features. If
|
||||
* multiple resources are provided the later ones will override entries in the
|
||||
* earlier ones hierarchically - that is all entries with the same nested key of
|
||||
* type Map at any depth are merged. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* foo:
|
||||
* bar:
|
||||
* one: two
|
||||
* three: four
|
||||
* </pre>
|
||||
*
|
||||
* plus (later in the list)
|
||||
*
|
||||
* <pre class="code">
|
||||
* foo:
|
||||
* bar:
|
||||
* one: 2
|
||||
* five: six
|
||||
* </pre>
|
||||
*
|
||||
* results in an effective input of
|
||||
*
|
||||
* <pre class="code">
|
||||
* foo:
|
||||
* bar:
|
||||
* one: 2
|
||||
* three: four
|
||||
* five: six
|
||||
* </pre>
|
||||
*
|
||||
* Note that the value of "foo" in the first document is not simply replaced
|
||||
* with the value in the second, but its nested values are merged.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 4.1
|
||||
*/
|
||||
public class YamlMapFactoryBean extends YamlProcessor implements FactoryBean<Map<String, Object>>, InitializingBean {
|
||||
|
||||
private boolean singleton = true;
|
||||
|
||||
private Map<String, Object> map;
|
||||
|
||||
|
||||
/**
|
||||
* Set if a singleton should be created, or a new object on each request
|
||||
* otherwise. Default is {@code true} (a singleton).
|
||||
*/
|
||||
public void setSingleton(boolean singleton) {
|
||||
this.singleton = singleton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return this.singleton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (isSingleton()) {
|
||||
this.map = createMap();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getObject() {
|
||||
return (this.map != null ? this.map : createMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return Map.class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Template method that subclasses may override to construct the object
|
||||
* returned by this factory. The default implementation returns the
|
||||
* merged Map instance.
|
||||
* <p>Invoked lazily the first time {@link #getObject()} is invoked in
|
||||
* case of a shared singleton; else, on each {@link #getObject()} call.
|
||||
* @return the object returned by this factory
|
||||
* @see #process(java.util.Map, MatchCallback)
|
||||
*/
|
||||
protected Map<String, Object> createMap() {
|
||||
final Map<String, Object> result = new LinkedHashMap<String, Object>();
|
||||
process(new MatchCallback() {
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
merge(result, map);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private void merge(Map<String, Object> output, Map<String, Object> map) {
|
||||
for (Entry<String, Object> entry : map.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
Object existing = output.get(key);
|
||||
if (value instanceof Map && existing instanceof Map) {
|
||||
Map<String, Object> result = new LinkedHashMap<String, Object>((Map) existing);
|
||||
merge(result, (Map) value);
|
||||
output.put(key, result);
|
||||
}
|
||||
else {
|
||||
output.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+357
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base class for Yaml factories.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 4.1
|
||||
*/
|
||||
public abstract class YamlProcessor {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ResolutionMethod resolutionMethod = ResolutionMethod.OVERRIDE;
|
||||
|
||||
private Resource[] resources = new Resource[0];
|
||||
|
||||
private List<DocumentMatcher> documentMatchers = Collections.emptyList();
|
||||
|
||||
private boolean matchDefault = true;
|
||||
|
||||
|
||||
/**
|
||||
* A map of document matchers allowing callers to selectively use only
|
||||
* some of the documents in a YAML resource. In YAML documents are
|
||||
* separated by <code>---<code> lines, and each document is converted
|
||||
* to properties before the match is made. E.g.
|
||||
*
|
||||
* <pre class="code">
|
||||
* environment: dev
|
||||
* url: http://dev.bar.com
|
||||
* name: Developer Setup
|
||||
* ---
|
||||
* environment: prod
|
||||
* url:http://foo.bar.com
|
||||
* name: My Cool App
|
||||
* </pre>
|
||||
*
|
||||
* when mapped with
|
||||
* <code>documentMatchers = YamlProcessor.mapMatcher({"environment": "prod"})</code>
|
||||
* would end up as
|
||||
*
|
||||
* <pre class="code">
|
||||
* environment=prod
|
||||
* url=http://foo.bar.com
|
||||
* name=My Cool App
|
||||
* url=http://dev.bar.com
|
||||
* </pre>
|
||||
* @param matchers a map of keys to value patterns (regular expressions)
|
||||
*/
|
||||
public void setDocumentMatchers(DocumentMatcher... matchers) {
|
||||
this.documentMatchers = Collections
|
||||
.unmodifiableList(new ArrayList<DocumentMatcher>(Arrays.asList(matchers)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag indicating that a document for which all the
|
||||
* {@link #setDocumentMatchers(DocumentMatcher...) document matchers} abstain will
|
||||
* nevertheless match.
|
||||
* @param matchDefault the flag to set (default true)
|
||||
*/
|
||||
public void setMatchDefault(boolean matchDefault) {
|
||||
this.matchDefault = matchDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to use for resolving resources. Each resource will be converted to a Map, so
|
||||
* this property is used to decide which map entries to keep in the final output from
|
||||
* this factory.
|
||||
* @param resolutionMethod the resolution method to set (defaults to
|
||||
* {@link ResolutionMethod#OVERRIDE}).
|
||||
*/
|
||||
public void setResolutionMethod(ResolutionMethod resolutionMethod) {
|
||||
Assert.notNull(resolutionMethod, "ResolutionMethod must not be null");
|
||||
this.resolutionMethod = resolutionMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set locations of YAML {@link Resource resources} to be loaded.
|
||||
* @see ResolutionMethod
|
||||
*/
|
||||
public void setResources(Resource... resources) {
|
||||
this.resources = (resources == null ? null : resources.clone());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provide an opportunity for subclasses to process the Yaml parsed from the supplied
|
||||
* resources. Each resource is parsed in turn and the documents inside checked against
|
||||
* the {@link #setDocumentMatchers(DocumentMatcher...) matchers}. If a document
|
||||
* matches it is passed into the callback, along with its representation as
|
||||
* Properties. Depending on the {@link #setResolutionMethod(ResolutionMethod)} not all
|
||||
* of the documents will be parsed.
|
||||
* @param callback a callback to delegate to once matching documents are found
|
||||
*/
|
||||
protected void process(MatchCallback callback) {
|
||||
Yaml yaml = new Yaml();
|
||||
for (Resource resource : this.resources) {
|
||||
boolean found = process(callback, yaml, resource);
|
||||
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND && found) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean process(MatchCallback callback, Yaml yaml, Resource resource) {
|
||||
int count = 0;
|
||||
try {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Loading from YAML: " + resource);
|
||||
}
|
||||
for (Object object : yaml.loadAll(resource.getInputStream())) {
|
||||
if (object != null && process(asMap(object), callback)) {
|
||||
count++;
|
||||
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Loaded " + count + " document"
|
||||
+ (count > 1 ? "s" : "") + " from YAML resource: " + resource);
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
handleProcessError(resource, ex);
|
||||
}
|
||||
return (count > 0);
|
||||
}
|
||||
|
||||
private void handleProcessError(Resource resource, IOException ex) {
|
||||
if (this.resolutionMethod != ResolutionMethod.FIRST_FOUND &&
|
||||
this.resolutionMethod != ResolutionMethod.OVERRIDE_AND_IGNORE) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
if (this.logger.isWarnEnabled()) {
|
||||
this.logger.warn("Could not load map from " + resource + ": " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> asMap(Object object) {
|
||||
// YAML can have numbers as keys
|
||||
Map<String, Object> result = new LinkedHashMap<String, Object>();
|
||||
if (!(object instanceof Map)) {
|
||||
// A document can be a text literal
|
||||
result.put("document", object);
|
||||
return result;
|
||||
}
|
||||
|
||||
Map<Object, Object> map = (Map<Object, Object>) object;
|
||||
for (Entry<Object, Object> entry : map.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof Map) {
|
||||
value = asMap(value);
|
||||
}
|
||||
Object key = entry.getKey();
|
||||
if (key instanceof CharSequence) {
|
||||
result.put(key.toString(), value);
|
||||
}
|
||||
else {
|
||||
// It has to be a map key in this case
|
||||
result.put("[" + key.toString() + "]", value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean process(Map<String, Object> map, MatchCallback callback) {
|
||||
Properties properties = new Properties();
|
||||
assignProperties(properties, map, null);
|
||||
|
||||
if (this.documentMatchers.isEmpty()) {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Merging document (no matchers set)" + map);
|
||||
}
|
||||
callback.process(properties, map);
|
||||
return true;
|
||||
}
|
||||
|
||||
MatchStatus result = MatchStatus.ABSTAIN;
|
||||
for (DocumentMatcher matcher : this.documentMatchers) {
|
||||
MatchStatus match = matcher.matches(properties);
|
||||
result = MatchStatus.getMostSpecific(match, result);
|
||||
if (match == MatchStatus.FOUND) {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Matched document with document matcher: "
|
||||
+ properties);
|
||||
}
|
||||
callback.process(properties, map);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == MatchStatus.ABSTAIN && this.matchDefault) {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Matched document with default matcher: " + map);
|
||||
}
|
||||
callback.process(properties, map);
|
||||
return true;
|
||||
}
|
||||
|
||||
this.logger.debug("Unmatched document");
|
||||
return false;
|
||||
}
|
||||
|
||||
private void assignProperties(Properties properties, Map<String, Object> input, String path) {
|
||||
for (Entry<String, Object> entry : input.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (StringUtils.hasText(path)) {
|
||||
if (key.startsWith("[")) {
|
||||
key = path + key;
|
||||
}
|
||||
else {
|
||||
key = path + "." + key;
|
||||
}
|
||||
}
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof String) {
|
||||
properties.put(key, value);
|
||||
}
|
||||
else if (value instanceof Map) {
|
||||
// Need a compound key
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) value;
|
||||
assignProperties(properties, map, key);
|
||||
}
|
||||
else if (value instanceof Collection) {
|
||||
// Need a compound key
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Object> collection = (Collection<Object>) value;
|
||||
int count = 0;
|
||||
for (Object object : collection) {
|
||||
assignProperties(properties,
|
||||
Collections.singletonMap("[" + (count++) + "]", object), key);
|
||||
}
|
||||
}
|
||||
else {
|
||||
properties.put(key, value == null ? "" : value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback interface used to process properties in a resulting map.
|
||||
*/
|
||||
public interface MatchCallback {
|
||||
|
||||
/**
|
||||
* Process the properties.
|
||||
* @param properties the properties to process
|
||||
* @param map a mutable result map
|
||||
*/
|
||||
void process(Properties properties, Map<String, Object> map);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Strategy interface used to test if properties match.
|
||||
*/
|
||||
public interface DocumentMatcher {
|
||||
|
||||
/**
|
||||
* Test if the given properties match.
|
||||
* @param properties the properties to test
|
||||
* @return the status of the match.
|
||||
*/
|
||||
MatchStatus matches(Properties properties);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Status returned from {@link DocumentMatcher#matches(java.util.Properties)}
|
||||
*/
|
||||
public static enum MatchStatus {
|
||||
|
||||
/**
|
||||
* A match was found.
|
||||
*/
|
||||
FOUND,
|
||||
|
||||
/**
|
||||
* No match was found.
|
||||
*/
|
||||
NOT_FOUND,
|
||||
|
||||
/**
|
||||
* The matcher should not be considered.
|
||||
*/
|
||||
ABSTAIN;
|
||||
|
||||
/**
|
||||
* Compare two {@link MatchStatus} items, returning the most specific status.
|
||||
*/
|
||||
public static MatchStatus getMostSpecific(MatchStatus a, MatchStatus b) {
|
||||
return a.ordinal() < b.ordinal() ? a : b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to use for resolving resources.
|
||||
*/
|
||||
public static enum ResolutionMethod {
|
||||
|
||||
/**
|
||||
* Replace values from earlier in the list.
|
||||
*/
|
||||
OVERRIDE,
|
||||
|
||||
/**
|
||||
* Replace values from earlier in the list, ignoring any failures.
|
||||
*/
|
||||
OVERRIDE_AND_IGNORE,
|
||||
|
||||
/**
|
||||
* Take the first resource in the list that exists and use just that.
|
||||
*/
|
||||
FIRST_FOUND
|
||||
}
|
||||
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.config;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Factory for Java Properties that reads from a YAML source. YAML is a nice
|
||||
* human-readable format for configuration, and it has some useful hierarchical
|
||||
* properties. It's more or less a superset of JSON, so it has a lot of similar
|
||||
* features. The Properties created by this factory have nested paths for
|
||||
* hierarchical objects, so for instance this YAML
|
||||
*
|
||||
* <pre class="code">
|
||||
* environments:
|
||||
* dev:
|
||||
* url: http://dev.bar.com
|
||||
* name: Developer Setup
|
||||
* prod:
|
||||
* url: http://foo.bar.com
|
||||
* name: My Cool App
|
||||
* </pre>
|
||||
*
|
||||
* is transformed into these Properties:
|
||||
*
|
||||
* <pre class="code">
|
||||
* environments.dev.url=http://dev.bar.com
|
||||
* environments.dev.name=Developer Setup
|
||||
* environments.prod.url=http://foo.bar.com
|
||||
* environments.prod.name=My Cool App
|
||||
* </pre>
|
||||
*
|
||||
* Lists are represented as comma-separated values (useful for simple String
|
||||
* values) and also as property keys with <code>[]</code> dereferencers, for
|
||||
* example this YAML:
|
||||
*
|
||||
* <pre class="code">
|
||||
* servers:
|
||||
* - dev.bar.com
|
||||
* - foo.bar.com
|
||||
* </pre>
|
||||
*
|
||||
* becomes Java Properties like this:
|
||||
*
|
||||
* <pre class="code">
|
||||
* servers=dev.bar.com,foo.bar.com
|
||||
* servers[0]=dev.bar.com
|
||||
* servers[1]=foo.bar.com
|
||||
* </pre>
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.1
|
||||
*/
|
||||
public class YamlPropertiesFactoryBean extends YamlProcessor implements FactoryBean<Properties>, InitializingBean {
|
||||
|
||||
private boolean singleton = true;
|
||||
|
||||
private Properties properties;
|
||||
|
||||
|
||||
/**
|
||||
* Set if a singleton should be created, or a new object on each request
|
||||
* otherwise. Default is {@code true} (a singleton).
|
||||
*/
|
||||
public void setSingleton(boolean singleton) {
|
||||
this.singleton = singleton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return this.singleton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (isSingleton()) {
|
||||
this.properties = createProperties();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getObject() {
|
||||
return (this.properties != null ? this.properties : createProperties());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return Properties.class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Template method that subclasses may override to construct the object
|
||||
* returned by this factory. The default implementation returns a
|
||||
* properties with the content of all resources.
|
||||
* <p>Invoked lazily the first time {@link #getObject()} is invoked in
|
||||
* case of a shared singleton; else, on each {@link #getObject()} call.
|
||||
* @return the object returned by this factory
|
||||
* @see #process(MatchCallback) ()
|
||||
*/
|
||||
protected Properties createProperties() {
|
||||
final Properties result = new Properties();
|
||||
process(new MatchCallback() {
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
result.putAll(properties);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+4
-4
@@ -286,7 +286,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
// Use prototype bean definition, to avoid registering bean as dependent bean.
|
||||
RootBeanDefinition bd = new RootBeanDefinition(beanClass);
|
||||
bd.setScope(SCOPE_PROTOTYPE);
|
||||
bd.allowCaching = false;
|
||||
bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());
|
||||
return (T) createBean(beanClass.getName(), bd, null);
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ClassUtils.getUserClass(existingBean));
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bd.allowCaching = false;
|
||||
bd.allowCaching = ClassUtils.isCacheSafe(bd.getBeanClass(), getBeanClassLoader());
|
||||
BeanWrapper bw = new BeanWrapperImpl(existingBean);
|
||||
initBeanWrapper(bw);
|
||||
populateBean(bd.getBeanClass().getName(), bd, bw);
|
||||
@@ -315,7 +315,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
bd = new RootBeanDefinition(mbd);
|
||||
}
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bd.allowCaching = false;
|
||||
bd.allowCaching = ClassUtils.isCacheSafe(ClassUtils.getUserClass(existingBean), getBeanClassLoader());
|
||||
}
|
||||
BeanWrapper bw = new BeanWrapperImpl(existingBean);
|
||||
initBeanWrapper(bw);
|
||||
@@ -759,7 +759,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
}
|
||||
}
|
||||
});
|
||||
if (objectType.value != null) {
|
||||
if (objectType.value != null && !Object.class.equals(objectType.value)) {
|
||||
return objectType.value;
|
||||
}
|
||||
}
|
||||
|
||||
+13
-10
@@ -38,8 +38,8 @@ import org.springframework.util.StringUtils;
|
||||
/**
|
||||
* Base class for concrete, full-fledged
|
||||
* {@link org.springframework.beans.factory.config.BeanDefinition} classes,
|
||||
* factoring out common properties of {@link RootBeanDefinition} and
|
||||
* {@link ChildBeanDefinition}.
|
||||
* factoring out common properties of {@link GenericBeanDefinition},
|
||||
* {@link RootBeanDefinition} and {@link ChildBeanDefinition}.
|
||||
*
|
||||
* <p>The autowire constants match the ones defined in the
|
||||
* {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory}
|
||||
@@ -123,11 +123,14 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
public static final int DEPENDENCY_CHECK_ALL = 3;
|
||||
|
||||
/**
|
||||
* Constant that indicates the container should attempt to infer the {@link
|
||||
* #setDestroyMethodName destroy method name} for a bean as opposed to explicit
|
||||
* specification of a method name. The value {@value} is specifically designed to
|
||||
* include characters otherwise illegal in a method name, ensuring no possibility of
|
||||
* collisions with legitimately named methods having the same name.
|
||||
* Constant that indicates the container should attempt to infer the
|
||||
* {@link #setDestroyMethodName destroy method name} for a bean as opposed to
|
||||
* explicit specification of a method name. The value {@value} is specifically
|
||||
* designed to include characters otherwise illegal in a method name, ensuring
|
||||
* no possibility of collisions with legitimately named methods having the same
|
||||
* name.
|
||||
* <p>Currently, the method names detected during destroy method inference
|
||||
* are "close" and "shutdown", if present on the specific bean class.
|
||||
*/
|
||||
public static final String INFER_METHOD = "(inferred)";
|
||||
|
||||
@@ -553,7 +556,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
* of dependencies like statics (*ugh*) or database preparation on startup.
|
||||
*/
|
||||
@Override
|
||||
public void setDependsOn(String[] dependsOn) {
|
||||
public void setDependsOn(String... dependsOn) {
|
||||
this.dependsOn = dependsOn;
|
||||
}
|
||||
|
||||
@@ -644,8 +647,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
|
||||
/**
|
||||
* Specify whether to allow access to non-public constructors and methods,
|
||||
* for the case of externalized metadata pointing to those.
|
||||
* The default is {@code true}; switch this to {@false} for public access only.
|
||||
* for the case of externalized metadata pointing to those. The default is
|
||||
* {@code true}; switch this to {@code false} for public access only.
|
||||
* <p>This applies to constructor resolution, factory method resolution,
|
||||
* and also init/destroy methods. Bean property accessors have to be public
|
||||
* in any case and are not affected by this setting.
|
||||
|
||||
+7
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,7 +124,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
/** Resolution strategy for expressions in bean definition values */
|
||||
private BeanExpressionResolver beanExpressionResolver;
|
||||
|
||||
/** Spring 3.0 ConversionService to use instead of PropertyEditors */
|
||||
/** Spring ConversionService to use instead of PropertyEditors */
|
||||
private ConversionService conversionService;
|
||||
|
||||
/** Custom PropertyEditorRegistrars to apply to the beans of this factory */
|
||||
@@ -160,9 +160,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
private final Map<String, RootBeanDefinition> mergedBeanDefinitions =
|
||||
new ConcurrentHashMap<String, RootBeanDefinition>(64);
|
||||
|
||||
/**
|
||||
* Names of beans that have already been created at least once
|
||||
*/
|
||||
/** Names of beans that have already been created at least once */
|
||||
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(64));
|
||||
|
||||
/** Names of beans that are currently in creation */
|
||||
@@ -287,8 +285,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
if (dependsOn != null) {
|
||||
for (String dependsOnBean : dependsOn) {
|
||||
if (isDependent(beanName, dependsOnBean)) {
|
||||
throw new BeanCreationException("Circular depends-on relationship between '" +
|
||||
beanName + "' and '" + dependsOnBean + "'");
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
|
||||
}
|
||||
registerDependentBean(dependsOnBean, beanName);
|
||||
getBean(dependsOnBean);
|
||||
@@ -1276,7 +1274,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
// Check validity of the usage of the args parameter. This can
|
||||
// only be used for prototypes constructed via a factory method.
|
||||
if (args != null && !mbd.isPrototype()) {
|
||||
throw new BeanDefinitionStoreException(
|
||||
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
|
||||
"Can only specify arguments for the getBean method when referring to a prototype bean definition");
|
||||
}
|
||||
}
|
||||
@@ -1627,8 +1625,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
* instantiation within this class is performed by this method.
|
||||
* @param beanName the name of the bean
|
||||
* @param mbd the merged bean definition for the bean
|
||||
* @param args arguments to use if creating a prototype using explicit arguments to a
|
||||
* static factory method. This parameter must be {@code null} except in this case.
|
||||
* @param args arguments to use if creating a prototype using explicit arguments
|
||||
* @return a new instance of the bean
|
||||
* @throws BeanCreationException if the bean could not be created
|
||||
*/
|
||||
|
||||
+24
-22
@@ -25,7 +25,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanInstantiationException;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
|
||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.CallbackFilter;
|
||||
@@ -34,6 +33,7 @@ import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodInterceptor;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.cglib.proxy.NoOp;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Default object instantiation strategy for use in BeanFactories.
|
||||
@@ -89,14 +89,13 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
*/
|
||||
private static class CglibSubclassCreator {
|
||||
|
||||
private static final Class<?>[] CALLBACK_TYPES = new Class<?>[] { NoOp.class,
|
||||
LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class };
|
||||
private static final Class<?>[] CALLBACK_TYPES = new Class<?>[]
|
||||
{NoOp.class, LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class};
|
||||
|
||||
private final RootBeanDefinition beanDefinition;
|
||||
|
||||
private final BeanFactory owner;
|
||||
|
||||
|
||||
CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) {
|
||||
this.beanDefinition = beanDefinition;
|
||||
this.owner = owner;
|
||||
@@ -113,7 +112,6 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
*/
|
||||
Object instantiate(Constructor<?> ctor, Object[] args) {
|
||||
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
|
||||
|
||||
Object instance;
|
||||
if (ctor == null) {
|
||||
instance = BeanUtils.instantiate(subclass);
|
||||
@@ -123,19 +121,17 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
|
||||
instance = enhancedSubclassConstructor.newInstance(args);
|
||||
}
|
||||
catch (Exception e) {
|
||||
catch (Exception ex) {
|
||||
throw new BeanInstantiationException(this.beanDefinition.getBeanClass(), String.format(
|
||||
"Failed to invoke construcor for CGLIB enhanced subclass [%s]", subclass.getName()), e);
|
||||
"Failed to invoke constructor for CGLIB enhanced subclass [%s]", subclass.getName()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
// SPR-10785: set callbacks directly on the instance instead of in the
|
||||
// enhanced class (via the Enhancer) in order to avoid memory leaks.
|
||||
Factory factory = (Factory) instance;
|
||||
factory.setCallbacks(new Callback[] { NoOp.INSTANCE,//
|
||||
new LookupOverrideMethodInterceptor(beanDefinition, owner),//
|
||||
new ReplaceOverrideMethodInterceptor(beanDefinition, owner) });
|
||||
|
||||
factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
|
||||
new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
|
||||
new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -153,6 +149,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class providing hashCode and equals methods required by CGLIB to
|
||||
* ensure that CGLIB doesn't generate a distinct class per bean.
|
||||
@@ -162,7 +159,6 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
|
||||
private final RootBeanDefinition beanDefinition;
|
||||
|
||||
|
||||
CglibIdentitySupport(RootBeanDefinition beanDefinition) {
|
||||
this.beanDefinition = beanDefinition;
|
||||
}
|
||||
@@ -173,8 +169,8 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other.getClass().equals(this.getClass())
|
||||
&& ((CglibIdentitySupport) other).getBeanDefinition().equals(this.getBeanDefinition());
|
||||
return (getClass().equals(other.getClass()) &&
|
||||
this.beanDefinition.equals(((CglibIdentitySupport) other).beanDefinition));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -183,6 +179,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CGLIB callback for filtering method interception behavior.
|
||||
*/
|
||||
@@ -190,7 +187,6 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
|
||||
private static final Log logger = LogFactory.getLog(MethodOverrideCallbackFilter.class);
|
||||
|
||||
|
||||
MethodOverrideCallbackFilter(RootBeanDefinition beanDefinition) {
|
||||
super(beanDefinition);
|
||||
}
|
||||
@@ -210,11 +206,12 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
else if (methodOverride instanceof ReplaceOverride) {
|
||||
return METHOD_REPLACER;
|
||||
}
|
||||
throw new UnsupportedOperationException("Unexpected MethodOverride subclass: "
|
||||
+ methodOverride.getClass().getName());
|
||||
throw new UnsupportedOperationException("Unexpected MethodOverride subclass: " +
|
||||
methodOverride.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CGLIB MethodInterceptor to override methods, replacing them with an
|
||||
* implementation that returns a bean looked up in the container.
|
||||
@@ -223,7 +220,6 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
|
||||
private final BeanFactory owner;
|
||||
|
||||
|
||||
LookupOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
|
||||
super(beanDefinition);
|
||||
this.owner = owner;
|
||||
@@ -233,10 +229,17 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
|
||||
// Cast is safe, as CallbackFilter filters are used selectively.
|
||||
LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
|
||||
return this.owner.getBean(lo.getBeanName());
|
||||
Object[] argsToUse = (args.length > 0 ? args : null); // if no-arg, don't insist on args at all
|
||||
if (StringUtils.hasText(lo.getBeanName())) {
|
||||
return this.owner.getBean(lo.getBeanName(), argsToUse);
|
||||
}
|
||||
else {
|
||||
return this.owner.getBean(method.getReturnType(), argsToUse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CGLIB MethodInterceptor to override methods, replacing them with a call
|
||||
* to a generic MethodReplacer.
|
||||
@@ -245,7 +248,6 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
|
||||
private final BeanFactory owner;
|
||||
|
||||
|
||||
ReplaceOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
|
||||
super(beanDefinition);
|
||||
this.owner = owner;
|
||||
@@ -255,7 +257,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
|
||||
ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
|
||||
// TODO could cache if a singleton for minor performance optimization
|
||||
MethodReplacer mr = owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);
|
||||
MethodReplacer mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);
|
||||
return mr.reimplement(obj, method, args);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -370,7 +370,7 @@ class ConstructorResolver {
|
||||
factoryBean = this.beanFactory.getBean(factoryBeanName);
|
||||
if (factoryBean == null) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"factory-bean '" + factoryBeanName + "' returned null");
|
||||
"factory-bean '" + factoryBeanName + "' (or a BeanPostProcessor involved) returned null");
|
||||
}
|
||||
factoryClass = factoryBean.getClass();
|
||||
isStatic = false;
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.annotation.DefaultOrderProviderComparator;
|
||||
|
||||
/**
|
||||
* The default {@link Comparator} to use to order dependencies. Extends from
|
||||
* {@link DefaultOrderProviderComparator} so that the bean factory has the ability
|
||||
* to provide an {@link org.springframework.core.annotation.OrderProvider} that
|
||||
* is aware of more bean metadata, if any.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.1
|
||||
* @see org.springframework.core.annotation.OrderProviderComparator
|
||||
* @see org.springframework.core.annotation.OrderProvider
|
||||
* @see DefaultListableBeanFactory#setDependencyComparator(java.util.Comparator)
|
||||
*/
|
||||
public class DefaultDependencyComparator extends DefaultOrderProviderComparator implements Comparator<Object> {
|
||||
|
||||
/**
|
||||
* Shared default instance of DefaultDependencyComparator.
|
||||
*/
|
||||
public static final DefaultDependencyComparator INSTANCE = new DefaultDependencyComparator();
|
||||
|
||||
|
||||
private final Comparator<Object> comparator;
|
||||
|
||||
|
||||
public DefaultDependencyComparator() {
|
||||
this.comparator = AnnotationAwareOrderComparator.INSTANCE;
|
||||
}
|
||||
|
||||
public DefaultDependencyComparator(Comparator<Object> comparator) {
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int compare(Object o1, Object o2) {
|
||||
return this.comparator.compare(o1, o2);
|
||||
}
|
||||
|
||||
}
|
||||
+230
-40
@@ -32,9 +32,11 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.inject.Provider;
|
||||
@@ -54,12 +56,16 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.SmartFactoryBean;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.OrderProviderComparator;
|
||||
import org.springframework.core.annotation.OrderUtils;
|
||||
import org.springframework.lang.UsesJava8;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -93,6 +99,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @since 16 April 2001
|
||||
* @see StaticListableBeanFactory
|
||||
* @see PropertiesBeanDefinitionReader
|
||||
@@ -102,12 +109,21 @@ import org.springframework.util.StringUtils;
|
||||
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
|
||||
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
|
||||
|
||||
private static Class<?> javaUtilOptionalClass = null;
|
||||
|
||||
private static Class<?> javaxInjectProviderClass = null;
|
||||
|
||||
static {
|
||||
ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
|
||||
try {
|
||||
javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");
|
||||
javaUtilOptionalClass =
|
||||
ClassUtils.forName("java.util.Optional", DefaultListableBeanFactory.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Java 8 not available - Optional references simply not supported then.
|
||||
}
|
||||
try {
|
||||
javaxInjectProviderClass =
|
||||
ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - Provider interface simply not supported then.
|
||||
@@ -279,6 +295,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
|
||||
@Override
|
||||
public <T> T getBean(Class<T> requiredType) throws BeansException {
|
||||
return getBean(requiredType, (Object[]) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
|
||||
Assert.notNull(requiredType, "Required type must not be null");
|
||||
String[] beanNames = getBeanNamesForType(requiredType);
|
||||
if (beanNames.length > 1) {
|
||||
@@ -293,27 +314,25 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
}
|
||||
if (beanNames.length == 1) {
|
||||
return getBean(beanNames[0], requiredType);
|
||||
return getBean(beanNames[0], requiredType, args);
|
||||
}
|
||||
else if (beanNames.length > 1) {
|
||||
T primaryBean = null;
|
||||
Map<String, Object> candidates = new HashMap<String, Object>();
|
||||
for (String beanName : beanNames) {
|
||||
T beanInstance = getBean(beanName, requiredType);
|
||||
if (isPrimary(beanName, beanInstance)) {
|
||||
if (primaryBean != null) {
|
||||
throw new NoUniqueBeanDefinitionException(requiredType, beanNames.length,
|
||||
"more than one 'primary' bean found of required type: " + Arrays.asList(beanNames));
|
||||
}
|
||||
primaryBean = beanInstance;
|
||||
}
|
||||
candidates.put(beanName, getBean(beanName, requiredType, args));
|
||||
}
|
||||
if (primaryBean != null) {
|
||||
return primaryBean;
|
||||
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
|
||||
if (primaryCandidate != null) {
|
||||
return getBean(primaryCandidate, requiredType, args);
|
||||
}
|
||||
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
|
||||
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
|
||||
if (priorityCandidate != null) {
|
||||
return getBean(priorityCandidate, requiredType, args);
|
||||
}
|
||||
throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
|
||||
}
|
||||
else if (getParentBeanFactory() != null) {
|
||||
return getParentBeanFactory().getBean(requiredType);
|
||||
return getParentBeanFactory().getBean(requiredType, args);
|
||||
}
|
||||
else {
|
||||
throw new NoSuchBeanDefinitionException(requiredType);
|
||||
@@ -671,12 +690,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Pre-instantiating singletons in " + this);
|
||||
}
|
||||
|
||||
List<String> beanNames;
|
||||
synchronized (this.beanDefinitionMap) {
|
||||
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
|
||||
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
|
||||
beanNames = new ArrayList<String>(this.beanDefinitionNames);
|
||||
}
|
||||
|
||||
// Trigger initialization of all non-lazy singleton beans...
|
||||
for (String beanName : beanNames) {
|
||||
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
|
||||
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
|
||||
@@ -704,6 +726,26 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger post-initialization callback for all applicable beans...
|
||||
for (String beanName : beanNames) {
|
||||
Object singletonInstance = getSingleton(beanName);
|
||||
if (singletonInstance instanceof SmartInitializingSingleton) {
|
||||
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
|
||||
if (System.getSecurityManager() != null) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
@Override
|
||||
public Object run() {
|
||||
smartSingleton.afterSingletonsInstantiated();
|
||||
return null;
|
||||
}
|
||||
}, getAccessControlContext());
|
||||
}
|
||||
else {
|
||||
smartSingleton.afterSingletonsInstantiated();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -728,8 +770,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
}
|
||||
|
||||
BeanDefinition oldBeanDefinition;
|
||||
|
||||
synchronized (this.beanDefinitionMap) {
|
||||
BeanDefinition oldBeanDefinition = this.beanDefinitionMap.get(beanName);
|
||||
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
|
||||
if (oldBeanDefinition != null) {
|
||||
if (!this.allowBeanDefinitionOverriding) {
|
||||
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
|
||||
@@ -758,7 +802,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
this.beanDefinitionMap.put(beanName, beanDefinition);
|
||||
}
|
||||
|
||||
resetBeanDefinition(beanName);
|
||||
if (oldBeanDefinition != null || containsSingleton(beanName)) {
|
||||
resetBeanDefinition(beanName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -794,9 +840,6 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
// (e.g. the default StaticMessageSource in a StaticApplicationContext).
|
||||
destroySingleton(beanName);
|
||||
|
||||
// Remove any assumptions about by-type mappings.
|
||||
clearByTypeCache();
|
||||
|
||||
// Reset all bean definitions that have the given bean as parent (recursively).
|
||||
for (String bdName : this.beanDefinitionNames) {
|
||||
if (!beanName.equals(bdName)) {
|
||||
@@ -846,7 +889,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
|
||||
|
||||
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
|
||||
if (descriptor.getDependencyType().equals(ObjectFactory.class)) {
|
||||
if (descriptor.getDependencyType().equals(javaUtilOptionalClass)) {
|
||||
return new OptionalDependencyFactory().createOptionalDependency(descriptor, beanName);
|
||||
}
|
||||
else if (descriptor.getDependencyType().equals(ObjectFactory.class)) {
|
||||
return new DependencyObjectFactory(descriptor, beanName);
|
||||
}
|
||||
else if (descriptor.getDependencyType().equals(javaxInjectProviderClass)) {
|
||||
@@ -895,7 +941,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
|
||||
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
|
||||
if (this.dependencyComparator != null && result instanceof Object[]) {
|
||||
Arrays.sort((Object[]) result, this.dependencyComparator);
|
||||
sortArray((Object[]) result, matchingBeans);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -922,7 +968,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
|
||||
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
|
||||
if (this.dependencyComparator != null && result instanceof List) {
|
||||
Collections.sort((List<?>) result, this.dependencyComparator);
|
||||
sortList((List<?>) result, matchingBeans);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -965,7 +1011,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
return null;
|
||||
}
|
||||
if (matchingBeans.size() > 1) {
|
||||
String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor);
|
||||
String primaryBeanName = determineAutowireCandidate(matchingBeans, descriptor);
|
||||
if (primaryBeanName == null) {
|
||||
throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
|
||||
}
|
||||
@@ -983,6 +1029,34 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
}
|
||||
|
||||
private void sortArray(Object[] items, Map<String, Object> matchingBeans) {
|
||||
if (this.dependencyComparator instanceof OrderProviderComparator) {
|
||||
((OrderProviderComparator) this.dependencyComparator)
|
||||
.sortArray(items, createFactoryAwareOrderProvider(matchingBeans));
|
||||
}
|
||||
else {
|
||||
Arrays.sort(items, this.dependencyComparator);
|
||||
}
|
||||
}
|
||||
|
||||
private void sortList(List<?> items, Map<String, Object> matchingBeans) {
|
||||
if (this.dependencyComparator instanceof OrderProviderComparator) {
|
||||
((OrderProviderComparator) this.dependencyComparator)
|
||||
.sortList(items, createFactoryAwareOrderProvider(matchingBeans));
|
||||
}
|
||||
else {
|
||||
Collections.sort(items, this.dependencyComparator);
|
||||
}
|
||||
}
|
||||
|
||||
private FactoryAwareOrderProvider createFactoryAwareOrderProvider(Map<String, Object> beans) {
|
||||
IdentityHashMap<Object, String> instancesToBeanNames = new IdentityHashMap<Object, String>();
|
||||
for (Map.Entry<String, Object> entry : beans.entrySet()) {
|
||||
instancesToBeanNames.put(entry.getValue(), entry.getKey());
|
||||
}
|
||||
return new FactoryAwareOrderProvider(instancesToBeanNames, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find bean instances that match the required type.
|
||||
* Called during autowiring for the specified bean.
|
||||
@@ -1013,7 +1087,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
}
|
||||
for (String candidateName : candidateNames) {
|
||||
if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
|
||||
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
|
||||
result.put(candidateName, getBean(candidateName));
|
||||
}
|
||||
}
|
||||
@@ -1029,15 +1103,45 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the primary autowire candidate in the given set of beans.
|
||||
* Determine the autowire candidate in the given set of beans.
|
||||
* <p>Looks for {@code @Primary} and {@code @Priority} (in that order).
|
||||
* @param candidateBeans a Map of candidate names and candidate instances
|
||||
* that match the required type, as returned by {@link #findAutowireCandidates}
|
||||
* @param descriptor the target dependency to match against
|
||||
* @return the name of the primary candidate, or {@code null} if none found
|
||||
* @return the name of the autowire candidate, or {@code null} if none found
|
||||
*/
|
||||
protected String determinePrimaryCandidate(Map<String, Object> candidateBeans, DependencyDescriptor descriptor) {
|
||||
protected String determineAutowireCandidate(Map<String, Object> candidateBeans, DependencyDescriptor descriptor) {
|
||||
Class<?> requiredType = descriptor.getDependencyType();
|
||||
String primaryCandidate = determinePrimaryCandidate(candidateBeans, requiredType);
|
||||
if (primaryCandidate != null) {
|
||||
return primaryCandidate;
|
||||
}
|
||||
String priorityCandidate = determineHighestPriorityCandidate(candidateBeans, requiredType);
|
||||
if (priorityCandidate != null) {
|
||||
return priorityCandidate;
|
||||
}
|
||||
// Fallback
|
||||
for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) {
|
||||
String candidateBeanName = entry.getKey();
|
||||
Object beanInstance = entry.getValue();
|
||||
if (this.resolvableDependencies.values().contains(beanInstance) ||
|
||||
matchesBeanName(candidateBeanName, descriptor.getDependencyName())) {
|
||||
return candidateBeanName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the primary candidate in the given set of beans.
|
||||
* @param candidateBeans a Map of candidate names and candidate instances
|
||||
* that match the required type
|
||||
* @param requiredType the target dependency type to match against
|
||||
* @return the name of the primary candidate, or {@code null} if none found
|
||||
* @see #isPrimary(String, Object)
|
||||
*/
|
||||
protected String determinePrimaryCandidate(Map<String, Object> candidateBeans, Class<?> requiredType) {
|
||||
String primaryBeanName = null;
|
||||
String fallbackBeanName = null;
|
||||
for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) {
|
||||
String candidateBeanName = entry.getKey();
|
||||
Object beanInstance = entry.getValue();
|
||||
@@ -1045,11 +1149,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (primaryBeanName != null) {
|
||||
boolean candidateLocal = containsBeanDefinition(candidateBeanName);
|
||||
boolean primaryLocal = containsBeanDefinition(primaryBeanName);
|
||||
if (candidateLocal == primaryLocal) {
|
||||
throw new NoUniqueBeanDefinitionException(descriptor.getDependencyType(), candidateBeans.size(),
|
||||
if (candidateLocal && primaryLocal) {
|
||||
throw new NoUniqueBeanDefinitionException(requiredType, candidateBeans.size(),
|
||||
"more than one 'primary' bean found among candidates: " + candidateBeans.keySet());
|
||||
}
|
||||
else if (candidateLocal && !primaryLocal) {
|
||||
else if (candidateLocal) {
|
||||
primaryBeanName = candidateBeanName;
|
||||
}
|
||||
}
|
||||
@@ -1057,20 +1161,54 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
primaryBeanName = candidateBeanName;
|
||||
}
|
||||
}
|
||||
if (primaryBeanName == null &&
|
||||
(this.resolvableDependencies.values().contains(beanInstance) ||
|
||||
matchesBeanName(candidateBeanName, descriptor.getDependencyName()))) {
|
||||
fallbackBeanName = candidateBeanName;
|
||||
}
|
||||
return primaryBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the candidate with the highest priority in the given set of beans. As
|
||||
* defined by the {@link org.springframework.core.Ordered} interface, the lowest
|
||||
* value has the highest priority.
|
||||
* @param candidateBeans a Map of candidate names and candidate instances
|
||||
* that match the required type
|
||||
* @param requiredType the target dependency type to match against
|
||||
* @return the name of the candidate with the highest priority,
|
||||
* or {@code null} if none found
|
||||
* @see #getPriority(Object)
|
||||
*/
|
||||
protected String determineHighestPriorityCandidate(Map<String, Object> candidateBeans, Class<?> requiredType) {
|
||||
String highestPriorityBeanName = null;
|
||||
Integer highestPriority = null;
|
||||
for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) {
|
||||
String candidateBeanName = entry.getKey();
|
||||
Object beanInstance = entry.getValue();
|
||||
Integer candidatePriority = getPriority(beanInstance);
|
||||
if (candidatePriority != null) {
|
||||
if (highestPriorityBeanName != null) {
|
||||
if (candidatePriority.equals(highestPriority)) {
|
||||
throw new NoUniqueBeanDefinitionException(requiredType, candidateBeans.size(),
|
||||
"Multiple beans found with the same priority ('" + highestPriority + "') " +
|
||||
"among candidates: " + candidateBeans.keySet());
|
||||
}
|
||||
else if (candidatePriority < highestPriority) {
|
||||
highestPriorityBeanName = candidateBeanName;
|
||||
highestPriority = candidatePriority;
|
||||
}
|
||||
}
|
||||
else {
|
||||
highestPriorityBeanName = candidateBeanName;
|
||||
highestPriority = candidatePriority;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (primaryBeanName != null ? primaryBeanName : fallbackBeanName);
|
||||
return highestPriorityBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the bean definition for the given bean name has been
|
||||
* marked as a primary bean.
|
||||
* @param beanName the name of the bean
|
||||
* @param beanInstance the corresponding bean instance
|
||||
* @param beanInstance the corresponding bean instance (can be null)
|
||||
* @return whether the given bean qualifies as primary
|
||||
*/
|
||||
protected boolean isPrimary(String beanName, Object beanInstance) {
|
||||
@@ -1082,6 +1220,20 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
((DefaultListableBeanFactory) parentFactory).isPrimary(beanName, beanInstance));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the priority assigned for the given bean instance by
|
||||
* the {@code javax.annotation.Priority} annotation.
|
||||
* <p>If the annotation is not present, returns {@code null}.
|
||||
* @param beanInstance the bean instance to check (can be null)
|
||||
* @return the priority assigned to that bean or {@code null} if none is set
|
||||
*/
|
||||
protected Integer getPriority(Object beanInstance) {
|
||||
if (beanInstance != null) {
|
||||
return OrderUtils.getPriorityValue(beanInstance.getClass());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given candidate name matches the bean name or the aliases
|
||||
* stored in this bean definition.
|
||||
@@ -1091,6 +1243,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
(candidateName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), candidateName)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given beanName/candidateName pair indicates a self reference,
|
||||
* i.e. whether the candidate points back to the original bean or to a factory method
|
||||
* on the original bean.
|
||||
*/
|
||||
private boolean isSelfReference(String beanName, String candidateName) {
|
||||
return (beanName != null && candidateName != null &&
|
||||
(beanName.equals(candidateName) || (containsBeanDefinition(candidateName) &&
|
||||
beanName.equals(getMergedLocalBeanDefinition(candidateName).getFactoryBeanName()))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Raise a NoSuchBeanDefinitionException for an unresolvable dependency.
|
||||
*/
|
||||
@@ -1168,6 +1331,25 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Separate inner class for avoiding a hard dependency on the {@code javax.inject} API.
|
||||
*/
|
||||
@UsesJava8
|
||||
private class OptionalDependencyFactory {
|
||||
|
||||
public Object createOptionalDependency(DependencyDescriptor descriptor, String beanName) {
|
||||
DependencyDescriptor descriptorToUse = new DependencyDescriptor(descriptor) {
|
||||
@Override
|
||||
public boolean isRequired() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
descriptorToUse.increaseNestingLevel();
|
||||
return Optional.ofNullable(doResolveDependency(descriptorToUse, beanName, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializable ObjectFactory for lazy resolution of a dependency.
|
||||
*/
|
||||
@@ -1175,17 +1357,25 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
|
||||
private final DependencyDescriptor descriptor;
|
||||
|
||||
private final boolean optional;
|
||||
|
||||
private final String beanName;
|
||||
|
||||
public DependencyObjectFactory(DependencyDescriptor descriptor, String beanName) {
|
||||
this.descriptor = new DependencyDescriptor(descriptor);
|
||||
this.descriptor.increaseNestingLevel();
|
||||
this.optional = this.descriptor.getDependencyType().equals(javaUtilOptionalClass);
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject() throws BeansException {
|
||||
return doResolveDependency(this.descriptor, this.beanName, null, null);
|
||||
if (this.optional) {
|
||||
return new OptionalDependencyFactory().createOptionalDependency(this.descriptor, this.beanName);
|
||||
}
|
||||
else {
|
||||
return doResolveDependency(this.descriptor, this.beanName, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -277,7 +277,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
|
||||
@Override
|
||||
public boolean containsSingleton(String beanName) {
|
||||
return (this.singletonObjects.containsKey(beanName));
|
||||
return this.singletonObjects.containsKey(beanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -330,8 +330,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
* @see #isSingletonCurrentlyInCreation
|
||||
*/
|
||||
protected void beforeSingletonCreation(String beanName) {
|
||||
if (!this.inCreationCheckExclusions.contains(beanName) &&
|
||||
!this.singletonsCurrentlyInCreation.add(beanName)) {
|
||||
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
|
||||
throw new BeanCurrentlyInCreationException(beanName);
|
||||
}
|
||||
}
|
||||
@@ -343,8 +342,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
* @see #isSingletonCurrentlyInCreation
|
||||
*/
|
||||
protected void afterSingletonCreation(String beanName) {
|
||||
if (!this.inCreationCheckExclusions.contains(beanName) &&
|
||||
!this.singletonsCurrentlyInCreation.remove(beanName)) {
|
||||
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
|
||||
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user