mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
655 Commits
v3.1.0.RC1
...
3.1.x
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a7df66374 | |||
| 63bff1f068 | |||
| e7d2ac4427 | |||
| ae1b36dc4f | |||
| 75a84b50e3 | |||
| 72013f975c | |||
| 3a6e7b8020 | |||
| 8a93309c22 | |||
| 50ed863279 | |||
| f9bb4b3b80 | |||
| 01f31027d7 | |||
| a52396b342 | |||
| d547570bcd | |||
| a9290d80c4 | |||
| 1f52f09089 | |||
| e9616b7204 | |||
| bbd5fc6f35 | |||
| a420e84591 | |||
| b1267b95b9 | |||
| a3161632dd | |||
| e731746bb0 | |||
| f2d7d663b4 | |||
| acd268e48f | |||
| 9d77afc218 | |||
| f3d0beb955 | |||
| 245c61e278 | |||
| c374389a59 | |||
| b720804c6d | |||
| 1e888706d3 | |||
| 1bca2c01fd | |||
| 0c45f179b3 | |||
| eb492ed583 | |||
| cd8d72e3f8 | |||
| 8cf61c595e | |||
| 8422da4d3f | |||
| b93d266c75 | |||
| 57bf64364f | |||
| ebbcc4d9fb | |||
| 27f0142d9e | |||
| 8135442336 | |||
| aa388bc094 | |||
| e5783b1bfa | |||
| 7f7fbe8172 | |||
| 42ab04a299 | |||
| 5ae706ee10 | |||
| f449b5a5b3 | |||
| bdc8d798e2 | |||
| 30ad07a4e2 | |||
| 0ed1a21073 | |||
| bad2b900e9 | |||
| 9a04191c2b | |||
| a7889c9df4 | |||
| 1cd7600d8a | |||
| 418c2a8641 | |||
| 377f3eecb4 | |||
| d1efd4c3a1 | |||
| aba4be83a7 | |||
| 5bc58773fb | |||
| 39fe8eebb1 | |||
| 778693f9f8 | |||
| aa3e0be1a0 | |||
| 28c7760c79 | |||
| cc11b811ea | |||
| 8abe1f055e | |||
| 12c4f8e7f9 | |||
| b9ff29ec7e | |||
| a551cbcf9d | |||
| c207882fdc | |||
| ab21bd4266 | |||
| 2ec41af799 | |||
| eb24365556 | |||
| 3a31efaf31 | |||
| 751c429897 | |||
| f19bc572da | |||
| 81348516ff | |||
| a00e00bd47 | |||
| b0fce78abf | |||
| 90fbeb1643 | |||
| 7384c3d82f | |||
| b016c8db91 | |||
| ceb8ce0a76 | |||
| d34c392c53 | |||
| 2b4e25b6f3 | |||
| 9929810610 | |||
| 4058f693e5 | |||
| 959ab7a5db | |||
| bed2134736 | |||
| dd68fecbf2 | |||
| 667438ddb0 | |||
| f4532ad704 | |||
| 0deacb9fa1 | |||
| 0ee12563b0 | |||
| e0b29b708c | |||
| 6c36240055 | |||
| a844712908 | |||
| 03c3dc3dae | |||
| 9caf672f21 | |||
| 9d78f17176 | |||
| 245d3114a8 | |||
| 4169898842 | |||
| e491d990de | |||
| 6d6eaf8506 | |||
| a6bcda25c2 | |||
| 7702fb8513 | |||
| b17d53ffae | |||
| 7f081a5eb4 | |||
| 983e2ce64f | |||
| ea49c8b840 | |||
| 2cfd15899d | |||
| d8dc4a257a | |||
| 00ed17dca0 | |||
| 410b9f933e | |||
| a0745c0c0a | |||
| cfdd50d8ab | |||
| e3136e65f4 | |||
| ced6bb4569 | |||
| 4525527794 | |||
| 98075c33c6 | |||
| 4cee691d09 | |||
| 347737290e | |||
| a94677e7b6 | |||
| ca386c13fc | |||
| f9eacf9c1f | |||
| 88906d271b | |||
| d8166d6155 | |||
| 4fccd1799a | |||
| 9187eeff27 | |||
| 2ab55414e5 | |||
| c90e2c6f10 | |||
| 506e9f50d0 | |||
| 2564db2bfd | |||
| 13edc93f78 | |||
| 1d26c37b87 | |||
| ee8e178434 | |||
| 679e122326 | |||
| 7c1a2f37f2 | |||
| 5e318e73f8 | |||
| 682b0f2c63 | |||
| ad81ec922b | |||
| 9862fbfc01 | |||
| d7825586dc | |||
| 9338080916 | |||
| fd10e149f6 | |||
| 1dd01a7a82 | |||
| 3788635f51 | |||
| 86ef22db49 | |||
| b2fce2f254 | |||
| be2c2e9a86 | |||
| 0047200b98 | |||
| 1641e082eb | |||
| baeac9ea6b | |||
| bac05f568a | |||
| cb7d689f92 | |||
| da8e2d6736 | |||
| 6ed589d94b | |||
| e70119733a | |||
| 0824746255 | |||
| 30d0bd309c | |||
| ec2603de63 | |||
| 470c85ade0 | |||
| 01d8d64200 | |||
| 2c8b7fe093 | |||
| bbfc807b0c | |||
| c81543e1a4 | |||
| 437ce9bb0e | |||
| b79260a017 | |||
| 0f522cfe6a | |||
| da75eaedbf | |||
| 69f2496cd7 | |||
| e670975fde | |||
| 41d9d737ac | |||
| c25cbe5522 | |||
| 8c64b47473 | |||
| 229537288a | |||
| bec5463640 | |||
| 7ebfd9e6a8 | |||
| f9147d375f | |||
| 03dd7a57f0 | |||
| 43bc3f19d9 | |||
| 0cf4a2626b | |||
| a0d0b37d10 | |||
| 5a149e4600 | |||
| 25a806a54e | |||
| 33463a94e3 | |||
| a6f5d9eb93 | |||
| f11ef28a4d | |||
| 52c10c52cd | |||
| cb13353c1d | |||
| 8b09b52720 | |||
| d7fd70fa08 | |||
| fbe955ab28 | |||
| 26ee0c4842 | |||
| 19718700cf | |||
| 8599dfd74e | |||
| a3bfa754fd | |||
| 8e3a0070dc | |||
| f9cf5d1aa6 | |||
| f78bef906d | |||
| 7704d76144 | |||
| 3f48c71c77 | |||
| 576f6fd25c | |||
| 5204e11d9c | |||
| 30166981e2 | |||
| 617f0ef542 | |||
| dc400c7124 | |||
| a7e2297432 | |||
| 671f97721f | |||
| 49f728eae8 | |||
| 16da15eca1 | |||
| efabc6bf18 | |||
| 98b281ea45 | |||
| 00a69394e6 | |||
| 45f1438ef8 | |||
| e7b44e015a | |||
| 23fe1e2934 | |||
| 1f64b147b1 | |||
| 5e4f3b3108 | |||
| c87989477d | |||
| 3b4210fa6f | |||
| 79b86a7e3a | |||
| b488ae6009 | |||
| aeef8c87f6 | |||
| 556c6a79c5 | |||
| 0281158fcc | |||
| 100fa178dd | |||
| a387d13d5f | |||
| 841d9533db | |||
| 0d18deb6a4 | |||
| 42204e5098 | |||
| eed090e5f5 | |||
| 0320cc582b | |||
| a76c7ca299 | |||
| 8bab873107 | |||
| e8006bdf78 | |||
| 3f387eb9cf | |||
| 0769d53a6a | |||
| 6263c9abf9 | |||
| 1eb50297ad | |||
| 20f87ab98d | |||
| c25a1bcb60 | |||
| e8deba2915 | |||
| fa33c4b857 | |||
| 24c30eac49 | |||
| 1af7575bde | |||
| 8143d66e4c | |||
| 9e370208d0 | |||
| e66bc07c37 | |||
| c9a2dbdbfd | |||
| 2fa0e63e5a | |||
| 83ac44d1e4 | |||
| 0cf93711b9 | |||
| 8faa2e61ec | |||
| 71443efd90 | |||
| bc243b5aa7 | |||
| d36979bc80 | |||
| 5875695d99 | |||
| dcb44264ad | |||
| 9fcb578187 | |||
| 8cdfbfe864 | |||
| 9ca407d55e | |||
| 1380d053c4 | |||
| 6b76afd1ce | |||
| 2fe74a4ef0 | |||
| ee9b9d6a57 | |||
| bf8fa6e268 | |||
| c976fa329f | |||
| d22c8aca49 | |||
| 79d9f7a5f7 | |||
| 9d3cfcd8e6 | |||
| 7d72ab59ae | |||
| 40a6769309 | |||
| e30d6104f3 | |||
| 129b4b3136 | |||
| b32a365f14 | |||
| 79c9ca1a26 | |||
| 7535e24deb | |||
| 80dd32e95c | |||
| 41ade68b50 | |||
| ff862addbe | |||
| 94e3f08a44 | |||
| 1c2b1d2c85 | |||
| 58e270f7da | |||
| fc416bcb0b | |||
| e81df2ef3e | |||
| 08e2669b84 | |||
| f3651c9998 | |||
| a3484aebb3 | |||
| 6fd476e2c5 | |||
| ab98f288e9 | |||
| acaf820941 | |||
| ddf0d071ad | |||
| 2fa87a71fa | |||
| fe57f74c1a | |||
| 81861ca7a8 | |||
| 4831ca27d2 | |||
| 1bfa7013a0 | |||
| 1d9d3e6ff7 | |||
| 8e0b1c3a5f | |||
| 0a5392e37d | |||
| b787a68f20 | |||
| ef143d363e | |||
| e25f1cbca9 | |||
| 997c6c56f7 | |||
| caa50a1d41 | |||
| 6e00456e67 | |||
| a46facc2f9 | |||
| 9e21d2f741 | |||
| 9470323724 | |||
| b17d545bb7 | |||
| 1bd260adaf | |||
| 57851de88e | |||
| 1e1f8c912b | |||
| 66bc214a79 | |||
| 45ad183331 | |||
| 66012b951e | |||
| f6c7d99ba4 | |||
| e202d89c29 | |||
| 21aed042ea | |||
| f1ecd1ca2a | |||
| c1df51a3b4 | |||
| edc80ffa95 | |||
| ff44c9132c | |||
| 0db257cbe3 | |||
| 35c2869875 | |||
| c931eaa436 | |||
| 357a5193b7 | |||
| e4f2cfe39e | |||
| 4aa8b96687 | |||
| 17bbc623c1 | |||
| c55362c35e | |||
| 9a61f36d3d | |||
| 95e3f486b5 | |||
| 2a0714b41c | |||
| efd2783dd1 | |||
| 5b18fc44ce | |||
| 4f4a2e7fc7 | |||
| bf541db5b0 | |||
| d9f7fdd120 | |||
| 905d17d444 | |||
| 62e5b9da04 | |||
| f367619b0c | |||
| afa4bb3f1b | |||
| f8238f5243 | |||
| 7a170e8005 | |||
| 3ec78e2c04 | |||
| a3bb3769ba | |||
| 598b125bb2 | |||
| 9fb6e2313c | |||
| ff84419f4d | |||
| 2ffa4725cd | |||
| 025b8abfaf | |||
| 856b77bc31 | |||
| a9451d11f6 | |||
| 871336a8c8 | |||
| 81e25b91c2 | |||
| 6e5cc53fc9 | |||
| 17cf465d23 | |||
| f3f73f0e32 | |||
| 010abd06e3 | |||
| 8530828eb4 | |||
| 95683f5137 | |||
| f61410705c | |||
| 64a69f7cf8 | |||
| 90bed9718f | |||
| c7fd03be69 | |||
| 3d1fa4f6b6 | |||
| f3c3babfdf | |||
| 87a021d5c9 | |||
| 38a62f8389 | |||
| e9208981a6 | |||
| 21966990c8 | |||
| 610fa618aa | |||
| 8980ce712d | |||
| ff9ad7adc6 | |||
| 79f32c7f33 | |||
| bcd8355e61 | |||
| 9c45acd43a | |||
| 958bd49850 | |||
| 697bc43c40 | |||
| 3fdbe1081d | |||
| 4a63a5b3ba | |||
| 56d0e67581 | |||
| 96b8c46480 | |||
| b91e989ad4 | |||
| e8fc90ce3e | |||
| b0c735feae | |||
| be4e698483 | |||
| 6da6acbe54 | |||
| ab6a7e8e74 | |||
| 5a2bd97c37 | |||
| d7d1b495f2 | |||
| 92f8446eea | |||
| 66df039b03 | |||
| fe0ffec8b9 | |||
| a4b33533d3 | |||
| 66d4e45b58 | |||
| e208a2de5f | |||
| adac38f91b | |||
| affa733927 | |||
| 211f8ea854 | |||
| af38448181 | |||
| d331c5d1c9 | |||
| 3d5e245374 | |||
| 89ee5e2d80 | |||
| 86bef9030f | |||
| 0053319c62 | |||
| c39a14a130 | |||
| e9ab1a7abb | |||
| 02cd8681d4 | |||
| 41c405998e | |||
| f1168ea453 | |||
| 103c648a92 | |||
| e0252ad0b1 | |||
| 4b138e0e50 | |||
| 07ddedd7bf | |||
| 09ac195f0c | |||
| 2caca29498 | |||
| 391434e089 | |||
| 392247d674 | |||
| 1c9fe623f9 | |||
| eb31528979 | |||
| 00ff8fa2cc | |||
| cc2e558fe0 | |||
| e0231438cd | |||
| 02452a1af9 | |||
| 36d941fc99 | |||
| 88913f2b23 | |||
| e1b645368a | |||
| e158f61e93 | |||
| dfc5b482c9 | |||
| abb5fc094a | |||
| ac107d0c2a | |||
| fae32cea8e | |||
| 153d38f1c8 | |||
| 8f18337543 | |||
| 6796a775d2 | |||
| 1c45c51fe1 | |||
| 2065b788c4 | |||
| e9da854848 | |||
| 0042243a11 | |||
| 2fa9ef9f5a | |||
| d507c2b927 | |||
| 450a3d7eee | |||
| 23e58aa718 | |||
| ec1b016602 | |||
| 5ebabcf2b3 | |||
| 1141a1d610 | |||
| dd7950638d | |||
| 098342918c | |||
| 8f69e81197 | |||
| d8e640d708 | |||
| 0f75cebdff | |||
| d4123d0637 | |||
| 439b7750d4 | |||
| 48836e2ebb | |||
| 866999764d | |||
| 06d06d4aa9 | |||
| 0449f6cb84 | |||
| 34798a47ab | |||
| e648245eb3 | |||
| 2dba480d9d | |||
| 9d93b5429f | |||
| ede8482f81 | |||
| 615bb29f92 | |||
| 1c58dd9d89 | |||
| 481c8455fd | |||
| a962bd0677 | |||
| 0f1affe931 | |||
| 1adf82503b | |||
| 4242b32624 | |||
| 7ec9292e54 | |||
| 3beef9a92e | |||
| b94040f329 | |||
| 690d33e14f | |||
| 312b1aa3d6 | |||
| c472a163f1 | |||
| 6f150e4f07 | |||
| 569426dfdf | |||
| f9144ea1ea | |||
| 29e969039d | |||
| 7428b57052 | |||
| 83c83d4d15 | |||
| 34a4fba335 | |||
| 426863f790 | |||
| f74789ffbe | |||
| e0d922d352 | |||
| 5ab2bf16a5 | |||
| 3a62aa053e | |||
| a347e4d3c2 | |||
| d050a472a2 | |||
| 1a2a3dd02a | |||
| cb3524ff30 | |||
| 735ba9dcde | |||
| 5fe0804017 | |||
| 28ff473091 | |||
| df7bda5637 | |||
| c2c224958d | |||
| aedccec67e | |||
| 27471e0555 | |||
| 66b4eb16a5 | |||
| bea5016e53 | |||
| 84be348cb0 | |||
| 207b2315ed | |||
| 1a2bbe5c4d | |||
| 00133179df | |||
| 49a2aaf023 | |||
| 4bfcb79ae3 | |||
| 21f61e3680 | |||
| 53cb529162 | |||
| 9f98f77c3e | |||
| 0ef3beb462 | |||
| 33b53b7cca | |||
| 71e0a506b9 | |||
| 45a0ae3fb9 | |||
| ca4eafd4dd | |||
| f75e832e7c | |||
| dc41daa3db | |||
| 2b122816af | |||
| ffa4784628 | |||
| 0a611aa776 | |||
| 91c14bd1fe | |||
| 951514a576 | |||
| d6d169ac56 | |||
| 686ae8f7b3 | |||
| 9f3e333084 | |||
| c2eafdb2fb | |||
| 1bb6d29be2 | |||
| 6991cd9cdf | |||
| 450c75337f | |||
| fa9a7b18c6 | |||
| 2cb287a01b | |||
| e6272312a8 | |||
| b391629de1 | |||
| e7d1b5e0ee | |||
| c9b36fb4e6 | |||
| a9a068e678 | |||
| aa7fcb5431 | |||
| 81e9f6cc2c | |||
| 1843bdde35 | |||
| b55040cf02 | |||
| bba70a7f12 | |||
| 372d461bef | |||
| a09a0316b7 | |||
| 61a5ab9d34 | |||
| 3f7dccddd2 | |||
| ac52433004 | |||
| 263dd559b7 | |||
| d10f2258e8 | |||
| 1e2f49104d | |||
| f91f778fb5 | |||
| b2bc7534c2 | |||
| d35620511e | |||
| 4318ccd9d5 | |||
| 22e37aac44 | |||
| e90c7eadc2 | |||
| 93db3df35b | |||
| f50f3d2405 | |||
| 16933a511d | |||
| 68f61f3b3c | |||
| faba5941f7 | |||
| c6a0f1ef25 | |||
| 91f05c8b9d | |||
| 143db0d8de | |||
| 2c26a23c46 | |||
| a53d592f62 | |||
| 03f6d23536 | |||
| 333f9f31a7 | |||
| 3416a26136 | |||
| 549c663fba | |||
| 0113ea91a3 | |||
| ca3d774f5c | |||
| b5bcfa0ae3 | |||
| e695a21688 | |||
| 6eba6f2059 | |||
| b2ae3dbb47 | |||
| 947b5fefff | |||
| 60ee0bb8f4 | |||
| e4fada56ab | |||
| c03a950706 | |||
| 224cf11fcb | |||
| 01cc76f8e3 | |||
| e7377e3c27 | |||
| 63e235f215 | |||
| 56608d6bd6 | |||
| 1d5ca80924 | |||
| 7918810366 | |||
| 3528637d62 | |||
| 70c28a0bc5 | |||
| 9c0c87f6a7 | |||
| d1f6672a58 | |||
| 4f3cbb45f4 | |||
| 732bf58570 | |||
| a252a285e2 | |||
| f9879b762b | |||
| 06306f9149 | |||
| 83d099db98 | |||
| 42cbee883f | |||
| 7a71af2989 | |||
| 96200b690c | |||
| b7f9bf2e1c | |||
| 8abb315042 | |||
| 1533822b0a | |||
| 124662189e | |||
| 43b3b4c261 | |||
| 40798bd48f | |||
| 7b491370a3 | |||
| 4ededaf11c | |||
| b167b75453 | |||
| c0b3b7b81e | |||
| b21e1ee669 | |||
| 0b078f2ff9 | |||
| 2a39f34d33 | |||
| dc88a7c8ba | |||
| e4c88553d8 | |||
| 473eaac117 | |||
| eddb0ac3be | |||
| c3f0f31243 | |||
| b9a3d4577a | |||
| c9acaaf9d8 | |||
| d1d48ac940 | |||
| 1beb04cebf | |||
| bef75aab07 | |||
| d3f4c69f00 | |||
| 8889284517 | |||
| cd2fee035a | |||
| bba8bb6ec0 | |||
| 78fbceff82 | |||
| c290a4e68a | |||
| e8dd35ce5e | |||
| 8337f4bf20 | |||
| e6920a59fa | |||
| 1164f5a9fc | |||
| 5a6980b78b | |||
| 57fe16e14b | |||
| fd97c8d7a4 | |||
| 2980ef4c75 | |||
| 79bcefa0ce | |||
| e2d9142c5a | |||
| 0c9e3fb3bd | |||
| 36616a0c2c | |||
| 3bd9a3e3e0 | |||
| f7b9eb8fe3 | |||
| 2fdc2b5822 | |||
| 3f73f51966 | |||
| 0dfb617d8a | |||
| de5a007e46 | |||
| ca5f38c5e4 | |||
| 3c649a6c66 | |||
| 313ba395af | |||
| 5d42a6242f | |||
| dacfa6993a | |||
| 5360bd899d | |||
| e65366012d | |||
| d98316e494 | |||
| cb14697800 |
+9
-1
@@ -14,5 +14,13 @@ org.springframework.jdbc/derby.log
|
||||
org.springframework.spring-parent/.classpath
|
||||
org.springframework.spring-parent/.project
|
||||
org.springframework.test/test-output/
|
||||
spring-build
|
||||
target
|
||||
spring-build/lib/docbook
|
||||
|
||||
# ignore files and directories related to gradle build
|
||||
/.classpath
|
||||
/.project
|
||||
/.gradle
|
||||
/build
|
||||
/spring-*
|
||||
!/spring-framework-reference
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
## Spring Framework
|
||||
The Spring Framework provides a comprehensive programming and configuration model for modern
|
||||
Java-based enterprise applications - on any kind of deployment platform. A key element of Spring is
|
||||
infrastructural support at the application level: Spring focuses on the "plumbing" of enterprise
|
||||
applications so that teams can focus on application-level business logic, without unnecessary ties
|
||||
to specific deployment environments.
|
||||
|
||||
The framework also serves as the foundation for
|
||||
[Spring Integration](https://github.com/SpringSource/spring-integration),
|
||||
[Spring Batch](https://github.com/SpringSource/spring-batch) and the rest of the Spring
|
||||
[family of projects](http://springsource.org/projects). Browse the repositories under the
|
||||
[SpringSource organization](https://github.com/SpringSource) on GitHub for a full list.
|
||||
|
||||
[.NET](https://github.com/SpringSource/spring-net) and
|
||||
[Python](https://github.com/SpringSource/spring-python) variants are available as well.
|
||||
|
||||
## Downloading artifacts
|
||||
Instructions on
|
||||
[downloading Spring artifacts](https://github.com/SpringSource/spring-framework/wiki/Downloading-Spring-artifacts)
|
||||
via Maven and other build systems are available via the project wiki.
|
||||
|
||||
## Documentation
|
||||
See the current [Javadoc](http://static.springsource.org/spring-framework/docs/current/api)
|
||||
and [Reference docs](http://static.springsource.org/spring-framework/docs/current/reference).
|
||||
|
||||
## Getting support
|
||||
Check out the [Spring forums](http://forum.springsource.org) and the
|
||||
[Spring tag](http://stackoverflow.com/questions/tagged/spring) on StackOverflow.
|
||||
[Commercial support](http://springsource.com/support/springsupport) is available too.
|
||||
|
||||
## Issue Tracking
|
||||
Spring's JIRA issue tracker can be found [here](http://jira.springsource.org/browse/SPR). Think
|
||||
you've found a bug? Please consider submitting a reproduction project via the
|
||||
[spring-framework-issues](https://github.com/springsource/spring-framework-issues) repository. The
|
||||
[readme](https://github.com/springsource/spring-framework-issues#readme) provides simple
|
||||
step-by-step instructions.
|
||||
|
||||
## Building from source
|
||||
Instructions on
|
||||
[building Spring from source](https://github.com/SpringSource/spring-framework/wiki/Building-from-source)
|
||||
are available via the project wiki.
|
||||
|
||||
## Contributing
|
||||
[Pull requests](http://help.github.com/send-pull-requests) are welcome; you'll be asked to sign our
|
||||
contributor license agreement ([CLA](https://support.springsource.com/spring_committer_signup)).
|
||||
Trivial changes like typo fixes are especially appreciated (just
|
||||
[fork and edit!](https://github.com/blog/844-forking-with-the-edit-button)). For larger changes,
|
||||
please search through JIRA for similiar issues, creating a new one if necessary, and discuss your
|
||||
ideas with the Spring team.
|
||||
|
||||
## Staying in touch
|
||||
Follow [@springframework](http://twitter.com/springframework) and its
|
||||
[team members](http://twitter.com/springframework/team/members) on Twitter. In-depth articles can be
|
||||
found at the SpringSource [team blog](http://blog.springsource.org), and releases are announced via
|
||||
our [news feed](http://www.springsource.org/news-events).
|
||||
|
||||
## License
|
||||
The Spring Framework is released under version 2.0 of the
|
||||
[Apache License](http://www.apache.org/licenses/LICENSE-2.0).
|
||||
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module relativePaths="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module relativePaths="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
@@ -1,81 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="build-spring-framework" default="precommit">
|
||||
|
||||
<path id="unit.test.bundles">
|
||||
<pathelement location="../org.springframework.instrument"/>
|
||||
<pathelement location="../org.springframework.instrument.tomcat"/>
|
||||
<pathelement location="../org.springframework.core"/>
|
||||
<pathelement location="../org.springframework.expression"/>
|
||||
<pathelement location="../org.springframework.beans"/>
|
||||
<pathelement location="../org.springframework.aop"/>
|
||||
<pathelement location="../org.springframework.context"/>
|
||||
<pathelement location="../org.springframework.transaction"/>
|
||||
<pathelement location="../org.springframework.oxm"/>
|
||||
<pathelement location="../org.springframework.jms"/>
|
||||
<pathelement location="../org.springframework.jdbc"/>
|
||||
<pathelement location="../org.springframework.web"/>
|
||||
<pathelement location="../org.springframework.orm"/>
|
||||
<pathelement location="../org.springframework.context.support"/>
|
||||
<pathelement location="../org.springframework.aspects"/>
|
||||
<pathelement location="../org.springframework.web.servlet"/>
|
||||
<pathelement location="../org.springframework.web.portlet"/>
|
||||
<pathelement location="../org.springframework.test"/>
|
||||
<pathelement location="../org.springframework.web.struts"/>
|
||||
</path>
|
||||
|
||||
<path id="bundles">
|
||||
<pathelement location="../org.springframework.spring-parent"/>
|
||||
<pathelement location="../org.springframework.asm"/>
|
||||
<path refid="unit.test.bundles" />
|
||||
<pathelement location="../org.springframework.integration-tests"/>
|
||||
<pathelement location="../org.springframework.spring-library"/>
|
||||
</path>
|
||||
|
||||
<property file="${basedir}/../build.properties"/>
|
||||
<import file="${basedir}/package-top-level.xml"/>
|
||||
<import file="${basedir}/publish-top-level.xml"/>
|
||||
<import file="${basedir}/publish-documentation.xml"/>
|
||||
<import file="${basedir}/../spring-build/multi-bundle/default.xml"/>
|
||||
|
||||
<target name="precommit" depends="clean, clean-integration, test"/>
|
||||
|
||||
<presetdef name="javadoc.links">
|
||||
<javadoc>
|
||||
<link href="http://download.oracle.com/javase/6/docs/api"/>
|
||||
<link href="http://download.oracle.com/javaee/6/api"/>
|
||||
<link href="http://aopalliance.sourceforge.net/doc"/>
|
||||
<!-- Caucho Burlap/Hessian -->
|
||||
<link href="http://cglib.sourceforge.net/apidocs"/>
|
||||
<!-- EasyMock -->
|
||||
<link href="http://ehcache.sourceforge.net/apidocs"/>
|
||||
<link href="http://freemarker.sourceforge.net/docs/api/"/>
|
||||
<link href="http://docs.jboss.org/hibernate/core/3.6/javadocs/"/>
|
||||
<!-- iBATIS -->
|
||||
<!-- iText -->
|
||||
<!-- Commons Attributes -->
|
||||
<link href="http://jakarta.apache.org/commons/collections/apidocs-COLLECTIONS_3_0/"/>
|
||||
<link href="http://jakarta.apache.org/commons/dbcp/apidocs/"/>
|
||||
<link href="http://jakarta.apache.org/commons/fileupload/apidocs/"/>
|
||||
<link href="http://jakarta.apache.org/commons/httpclient/apidocs/"/>
|
||||
<link href="http://jakarta.apache.org/commons/logging/apidocs/"/>
|
||||
<link href="http://jakarta.apache.org/commons/pool/apidocs/"/>
|
||||
<!-- JasperReports -->
|
||||
<!-- JDO -->
|
||||
<!-- JMX -->
|
||||
<!-- JOTM -->
|
||||
<!-- JPA -->
|
||||
<!-- JSF -->
|
||||
<link href="http://junit.sourceforge.net/javadoc_40/"/>
|
||||
<link href="http://logging.apache.org/log4j/docs/api/"/>
|
||||
<link href="http://jakarta.apache.org/regexp/apidocs/"/>
|
||||
<link href="http://jakarta.apache.org/poi/apidocs/"/>
|
||||
<link href="http://portals.apache.org/pluto/portlet-1.0-apidocs/"/>
|
||||
<link href="http://www.quartz-scheduler.org/api/2.1.0/"/>
|
||||
<link href="http://struts.apache.org/struts-doc-1.2.9/api/"/>
|
||||
<link href="http://java.sun.com/javase/6/docs/jre/api/net/httpserver/spec/"/>
|
||||
<link href="http://tiles.apache.org/framework/apidocs/"/>
|
||||
<link href="http://velocity.apache.org/engine/devel/apidocs/"/>
|
||||
</javadoc>
|
||||
</presetdef>
|
||||
|
||||
</project>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="build-spring-framework" default="precommit">
|
||||
|
||||
<path id="unit.test.bundles">
|
||||
<pathelement location="../org.springframework.instrument"/>
|
||||
<pathelement location="../org.springframework.instrument.tomcat"/>
|
||||
<pathelement location="../org.springframework.core"/>
|
||||
<pathelement location="../org.springframework.expression"/>
|
||||
<pathelement location="../org.springframework.beans"/>
|
||||
<pathelement location="../org.springframework.aop"/>
|
||||
<pathelement location="../org.springframework.context"/>
|
||||
<pathelement location="../org.springframework.transaction"/>
|
||||
<pathelement location="../org.springframework.oxm"/>
|
||||
<pathelement location="../org.springframework.jms"/>
|
||||
<pathelement location="../org.springframework.jdbc"/>
|
||||
<pathelement location="../org.springframework.web"/>
|
||||
<pathelement location="../org.springframework.orm"/>
|
||||
<pathelement location="../org.springframework.context.support"/>
|
||||
<pathelement location="../org.springframework.aspects"/>
|
||||
<pathelement location="../org.springframework.web.servlet"/>
|
||||
<pathelement location="../org.springframework.web.portlet"/>
|
||||
<pathelement location="../org.springframework.test"/>
|
||||
<pathelement location="../org.springframework.web.struts"/>
|
||||
</path>
|
||||
|
||||
<path id="bundles">
|
||||
<pathelement location="../org.springframework.spring-parent"/>
|
||||
<pathelement location="../org.springframework.asm"/>
|
||||
<path refid="unit.test.bundles" />
|
||||
<pathelement location="../org.springframework.integration-tests"/>
|
||||
<pathelement location="../org.springframework.spring-library"/>
|
||||
</path>
|
||||
|
||||
<property file="${basedir}/../build.properties"/>
|
||||
<import file="${basedir}/package-top-level.xml"/>
|
||||
<import file="${basedir}/publish-top-level.xml"/>
|
||||
<import file="${basedir}/publish-documentation.xml"/>
|
||||
<import file="${basedir}/../spring-build/multi-bundle/default.xml"/>
|
||||
|
||||
<target name="precommit" depends="clean, clean-integration, test"/>
|
||||
|
||||
<presetdef name="javadoc.links">
|
||||
<javadoc>
|
||||
<link href="http://download.oracle.com/javase/6/docs/api"/>
|
||||
<link href="http://download.oracle.com/javaee/6/api"/>
|
||||
<link href="http://aopalliance.sourceforge.net/doc"/>
|
||||
<!-- Caucho Burlap/Hessian -->
|
||||
<link href="http://cglib.sourceforge.net/apidocs"/>
|
||||
<!-- EasyMock -->
|
||||
<link href="http://ehcache.sourceforge.net/apidocs"/>
|
||||
<link href="http://freemarker.sourceforge.net/docs/api/"/>
|
||||
<link href="http://docs.jboss.org/hibernate/core/3.6/javadocs/"/>
|
||||
<!-- iBATIS -->
|
||||
<!-- iText -->
|
||||
<!-- Commons Attributes -->
|
||||
<link href="http://jakarta.apache.org/commons/collections/apidocs-COLLECTIONS_3_0/"/>
|
||||
<link href="http://jakarta.apache.org/commons/dbcp/apidocs/"/>
|
||||
<link href="http://jakarta.apache.org/commons/fileupload/apidocs/"/>
|
||||
<link href="http://jakarta.apache.org/commons/httpclient/apidocs/"/>
|
||||
<link href="http://jakarta.apache.org/commons/logging/apidocs/"/>
|
||||
<link href="http://jakarta.apache.org/commons/pool/apidocs/"/>
|
||||
<!-- JasperReports -->
|
||||
<!-- JDO -->
|
||||
<!-- JMX -->
|
||||
<!-- JOTM -->
|
||||
<!-- JPA -->
|
||||
<!-- JSF -->
|
||||
<link href="http://junit.sourceforge.net/javadoc_40/"/>
|
||||
<link href="http://logging.apache.org/log4j/docs/api/"/>
|
||||
<link href="http://jakarta.apache.org/regexp/apidocs/"/>
|
||||
<link href="http://jakarta.apache.org/poi/apidocs/"/>
|
||||
<link href="http://portals.apache.org/pluto/portlet-1.0-apidocs/"/>
|
||||
<link href="http://www.quartz-scheduler.org/api/2.1.0/"/>
|
||||
<link href="http://struts.apache.org/struts-doc-1.2.9/api/"/>
|
||||
<link href="http://java.sun.com/javase/6/docs/jre/api/net/httpserver/spec/"/>
|
||||
<link href="http://tiles.apache.org/framework/apidocs/"/>
|
||||
<link href="http://velocity.apache.org/engine/devel/apidocs/"/>
|
||||
</javadoc>
|
||||
</presetdef>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
|
||||
<!-- Main targets -->
|
||||
<target name="publish-documentation" depends="publish-documentation.init">
|
||||
<sshexec host="static.springframework.org" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
<sshexec host="static.springsource.org" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
command="rm -rf /opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version}"/>
|
||||
<sshexec host="static.springframework.org" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
<sshexec host="static.springsource.org" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
command="mkdir /opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version}"/>
|
||||
|
||||
<scp remoteToDir="${username}@spring02.managed.contegix.com:/opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version}"
|
||||
<scp remoteToDir="${username}@static.springsource.org:/opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version}"
|
||||
keyfile="${key.file}" passphrase="${passphrase}" sftp="true" verbose="true">
|
||||
<fileset dir="${package.output.dir}">
|
||||
<include name="changelog.txt" />
|
||||
@@ -18,7 +18,7 @@
|
||||
<fileset dir="${package.docs.dir}" />
|
||||
</scp>
|
||||
|
||||
<sshexec host="static.springframework.org" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
<sshexec host="static.springsource.org" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
command="rm -f /opt/www/domains/springframework.org/www/htdocs/spring/docs/3.1.x ; ln -s /opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version} /opt/www/domains/springframework.org/www/htdocs/spring/docs/3.1.x"/>
|
||||
</target>
|
||||
|
||||
|
||||
@@ -3,6 +3,243 @@ SPRING FRAMEWORK CHANGELOG
|
||||
http://www.springsource.org
|
||||
|
||||
|
||||
Changes in version 3.1.4 (2013-01-23)
|
||||
-------------------------------------
|
||||
|
||||
* overhauled non-void JavaBean write method support (SPR-10029)
|
||||
* SpEL support for static finals on interfaces (SPR-10125)
|
||||
* BridgeMethodResolver properly handles bridge methods in interfaces (SPR-9330)
|
||||
* LocalVariableTableParameterNameDiscoverer works for bridge methods as well (SPR-9429)
|
||||
* CachedIntrospectionResults uses full WeakReference for any non-safe ClassLoader arrangement (SPR-10028)
|
||||
* CachedIntrospectionResults.clearClassLoader(null) removes cached classes for the system class loader (SPR-9189)
|
||||
* DefaultListableBeanFactory avoids wide/interleaved metadata locks to avoid deadlock potential (SPR-10020)
|
||||
* fixed CGLIB proxy class leaks through further equals/hashCode implementations in Spring AOP pointcuts (SPR-8008)
|
||||
* ConfigurationClassPostProcessor consistently uses ClassLoader, not loading core JDK classes via ASM (SPR-10058)
|
||||
* MessageSourceResourceBundle overrides JDK 1.6 containsKey method, avoiding NPE in getKeys (SPR-10136)
|
||||
* SpringBeanAutowiringInterceptor eagerly releases BeanFactory if post-construction fails (SPR-10013)
|
||||
* added "exposeAccessContext" flag JndiRmiClientInterceptor/ProxyFactoryBean (for WebLogic; SPR-9428)
|
||||
* MBeanExporter does not log warnings for manually unregistered MBeans (SPR-9451)
|
||||
* AbstractCacheManager accepts no caches defined, allowing for EHCache default cache setup (SPR-7955)
|
||||
* reintroduced "mode" and "proxy-target-class" attributes in spring-task-3.1.xsd (SPR-10177)
|
||||
* improved defensiveness of JDBC 3.0 ParameterMetaData calls for parameter type determination (SPR-10084)
|
||||
* JpaTransactionManager etc finds default EntityManagerFactory in parent context as well (SPR-10160)
|
||||
* tx timeouts for JPA translate to "javax.persistence.query.timeout" only (for EclipseLink compatibility; SPR-10068)
|
||||
* DefaultMessageListenerContainer allows for concurrent subscription consumers on WebLogic/ActiveMQ (SPR-10037)
|
||||
* DefaultMessageListenerContainer clears resources of paused tasks when shutting down after stop (SPR-10092)
|
||||
* JmsTemplate uses configured receiveTimeout if shorter than remaining transaction timeout (SPR-10109)
|
||||
* added MappingJackson2MessageConverter for JMS (SPR-10099)
|
||||
* ResourceDatabasePopulator explicitly closes its LineNumberReader (SPR-9912)
|
||||
* MimeMessageHelper encodes attachment filename if not ASCII compliant (SPR-9258)
|
||||
* FreeMarkerConfigurationFactory properly supports TemplateLoaders when recreating Configurations (SPR-9389)
|
||||
* SpringContextResourceAdapter implements equals/hashCode according to the JCA 1.5 contract (SPR-9162)
|
||||
* ContextLoader properly detects pre-refreshed WebApplicationContext (SPR-9996)
|
||||
* AbstractCachingViewResolver uses a cache limit of 1024 by default, avoiding overflow for redirect URLs (SPR-10065)
|
||||
* fixed HierarchicalUriComponents equals implementation (SPR-10088)
|
||||
* MockHttpServletRequest's getParameter(Values) returns null for null parameter name (SPR-10192)
|
||||
* MockHttpServletResponse's getHeaderNames declares Collection instead of Set for Servlet 3.0 compatibility (SPR-9885)
|
||||
* ResourcePropertySource supports JDK 5-style Properties XML (SPR-9896)
|
||||
|
||||
|
||||
Changes in version 3.1.3 (2012-10-31)
|
||||
-------------------------------------
|
||||
|
||||
* fixed cache handling for JNLP connections
|
||||
* LinkedCaseInsensitiveMap checks for uniqueness of case-insensitive keys now
|
||||
* ResourceBundleMessageSource supports "defaultEncoding", "fallbackToSystemLocale", "cacheSeconds"
|
||||
* BeanWrapper does not fall back to String constructor if ConversionService attempt failed before
|
||||
* @Import'ed configuration classes get properly registered in case of same class name
|
||||
* @Autowired-driven ObjectFactory/Provider resolution works in non-singleton beans as well
|
||||
* @Resource processing properly works with scoped beans and prototypes again
|
||||
* allow replaced-method 'arg-type' matches against element body as well as 'match' attribute
|
||||
* fixed potential race condition in concurrent calling of autowired methods on a prototype bean
|
||||
* cancel on a Future returned by a TaskScheduler works reliably
|
||||
* LoadTimeWeaverAware beans are consistently being created early for JPA weaving to work reliably
|
||||
* Spring-backed DataSources consistently implement JDBC 4.0's Wrapper interface
|
||||
* optimized ResourceDatabasePopulator to work around JDK 1.7 substring performance regression
|
||||
* deprecated SimpleJdbcTestUtils in favor of JdbcTestUtils
|
||||
* introduced "countRowsInTableWhere()" and "dropTables()" in JdbcTestUtils
|
||||
* same-named unit from persistence.xml overrides in case of conflict with default unit
|
||||
* JPA persistence.xml files may use jar-file entries relative to the unit root (as per the JPA spec)
|
||||
* added "jtaDataSource" property to JPA LocalContainerEntityManagerFactoryBean (for default units)
|
||||
* Hibernate 4 LocalSessionFactoryBuilder sets thread context ClassLoader (for JBoss 7 compatibility)
|
||||
* Jaxb2Marshaller performs proper "supports" check for scanned packages
|
||||
* media types in HTTP Accept headers can be parsed with single quotes (-> Android 2.x)
|
||||
* MediaType's include method now recognizes wildcards in media types with a suffix
|
||||
* added support for recognizing wildcards in media types with a suffix
|
||||
* UriComponentsBuilder is capable of handling opaque URIs as well
|
||||
* CookieGenerator supports "cookieHttpOnly" flag for Servlet 3.0
|
||||
* HttpComponentsHttpInvokerRequestExecutor explicitly releases connection on HttpComponents 4.2
|
||||
* improved no-match handling for @RequestMapping methods
|
||||
* dynamic return value types for @MVC methods
|
||||
* fixed issue with resolution of WebDataBinder argument
|
||||
* fixed issue with resolving Errors controller argument
|
||||
* now decoding target parameters prior to saving a FlashMap
|
||||
* prevent response updates if @ResponseStatus has a reason
|
||||
* improved regex for parsing query params
|
||||
* optimized use of AntPathStringMatcher
|
||||
* optimized use of HandlerMethod and subclasses
|
||||
* fixed issue in message conversion where producible and acceptable headers are equally specific
|
||||
* fixed NullPointerException in AbstractMessageConverterMethodProcessor
|
||||
* fixed side effect from caching in AnnotationMethodHandlerExceptionResolver
|
||||
* DispatcherPortlet uses a forward for rendering a view as resource response
|
||||
* fixed Portlet request mapping priorities in cross-controller case
|
||||
|
||||
|
||||
Changes in version 3.1.2 (2012-07-09)
|
||||
-------------------------------------
|
||||
|
||||
* removed INDEX.LIST entries from Spring jar META-INF dirs
|
||||
* fixed OSGi metadata for optional "javax.inject" package import
|
||||
* fixed AbstractResource's InputStream-based "contentLength()" implementation
|
||||
* fixed MutablePropertySources "get" implementation to correctly return null if not found
|
||||
* fixed @PropertySource placeholder resolution to apply to all specified values
|
||||
* JDBC parameter binding uses JDBC 3.0 ParameterMetaData (if available) for type determination
|
||||
* added "jtaTransactionManager" property to Hibernate 4 LocalSessionFactoryBean/Builder
|
||||
* EhCacheFactoryBean applies listeners and enabled/disabled flags to existing cache regions as well
|
||||
* added "repeatCount" bean property to Quartz SimpleTriggerFactoryBean
|
||||
* support executor qualification with @Async#value
|
||||
* ServletContextResource's getFile implementation falls back to getRealPath for non-existent files
|
||||
* fixed StandardServletMultipartResolver compatibility with Resin (only deleting actual file parts)
|
||||
* fixed RequestConditionHolder to return null when no match is found
|
||||
* fixed concurrency issue in AnnotationMethodHandlerExceptionResolver
|
||||
* fixed issue with parsing invalid Content-Type or Accept headers
|
||||
* added "defaultCharset" property to StringHttpMessageConverter
|
||||
* added Jackson 2 HttpMessageConverter and View types
|
||||
* translate IOException on EOF from Jackson to HttpMessageNotReadableException
|
||||
* fix content negotiation issue when sorting selected media types by quality value
|
||||
* raise RestClientException instead of IllegalArgumentException for unknown status codes
|
||||
* discover controllers based on type-level @RequestMapping in new @MVC support classes
|
||||
* fixed issue with suffix pattern in AnnotationMethodHandlerAdapter
|
||||
* merge rather than add URI vars in ExtendedServletRequestDataBinder
|
||||
* raise RestClientException for unknown HTTP status codes
|
||||
* fixed issue with encoded params in UriComponentsBuilder
|
||||
* XStreamMarshaller converts StreamException to Spring exception in case of unmarshalling an empty stream
|
||||
* corrected DispatcherPortlet behavior to not forward event exceptions to the render phase by default
|
||||
|
||||
|
||||
Changes in version 3.1.1 (2012-02-16)
|
||||
-------------------------------------
|
||||
|
||||
* official support for Hibernate 4.0.0/4.0.1 as well as Hibernate 4.1
|
||||
* JBossNativeJdbcExtractor is compatible with JBoss AS 7 as well
|
||||
* restored JBossLoadTimeWeaver compatibility with JBoss AS 5.1
|
||||
* Provider injection works with generically typed collections of beans as well
|
||||
* @ActiveProfiles mechanism in test context framework works with @ImportResource as well
|
||||
* context:property-placeholder's "file-encoding" attribute value is being applied correctly
|
||||
* clarified Resource's "getFilename" method to return null if resource type does not have a filename
|
||||
* Resource "contentLength()" implementations work with OSGi bundle resources and JBoss VFS resources
|
||||
* PathMatchingResourcePatternResolver preserves caching for JNLP (Java Web Start) jar connections
|
||||
* optimized converter lookup in GenericConversionService to avoid contention in JDK proxy check
|
||||
* DataBinder correctly handles ParseException from Formatter for String->String case
|
||||
* CacheNamespaceHandler actually parses cache:annotation-driven's "key-generator" attribute
|
||||
* introduced CustomSQLExceptionTranslatorRegistry/Registrar for JDBC error code translation
|
||||
* officially deprecated TopLinkJpaDialect in favor of EclipseLink and Spring's EclipseLinkJpaDialect
|
||||
* fixed LocalContainerEntityManagerFactoryBean's "packagesToScan" to avoid additional provider scan
|
||||
* LocalContainerEntityManagerFactoryBean's "persistenceUnitName" applies to "packagesToScan" as well
|
||||
* DefaultPersistenceUnitManager uses containing jar as persistence unit root URL for default unit
|
||||
* added protected "isPersistenceUnitOverrideAllowed()" method to DefaultPersistenceUnitManager
|
||||
* Hibernate synchronization properly unbinds Session even in case of afterCompletion exception
|
||||
* Hibernate exception translation covers NonUniqueObjectException to DuplicateKeyException case
|
||||
* Hibernate 4 LocalSessionFactoryBean implements PersistenceExceptionTranslator interface as well
|
||||
* Hibernate 4 LocalSessionFactoryBean does not insist on a "dataSource" reference being set
|
||||
* added "entityInterceptor" property to Hibernate 4 LocalSessionFactoryBean
|
||||
* added "getConfiguration" accessor to Hibernate 4 LocalSessionFactoryBean
|
||||
* added "durability" and "description" properties to JobDetailFactoryBean
|
||||
* fixed QuartzJobBean and MethodInvokingJobDetailFactoryBean for compatibility with Quartz 2.0/2.1
|
||||
* JMS CachingConnectionFactory never caches consumers for temporary queues and topics
|
||||
* JMS SimpleMessageListenerContainer silently falls back to lazy registration of consumers
|
||||
* added "receive-timeout" attribute to jms:listener-container element in JMS namespace
|
||||
* ServletServerHttpRequest/Response fall back on the Content-Type and encoding of the request
|
||||
* preserve quotes in MediaType parameters
|
||||
* added "normalize()" method to UriComponents
|
||||
* remove empty path segments from input to UriComponentsBuilder
|
||||
* added "fromRequestUri(request)" and "fromCurrentRequestUri()" methods to ServletUriComponentsBuilder
|
||||
* Servlet/PortletContextResource's "isReadable()" implementation returns false for directories
|
||||
* allow adding flash attributes in methods with a ModelAndView return value
|
||||
* make flash attributes available in the model of Parameterizable/UrlFilenameViewController
|
||||
* revised the FlashMapManager contract and implementation to address a flaw in its design
|
||||
* removed check for HTTP POST when resolving multipart request controller method arguments
|
||||
* fixed request mapping bug involving direct vs pattern path matches with HTTP methods
|
||||
* updated @RequestMapping and reference docs wrt differences between @MVC 3.1 and @MVC 2.5-3.0
|
||||
* improved @SessionAttributes handling to provide better support for clustered sessions
|
||||
* added property to RedirectView to disable expanding URI variables in redirect URL
|
||||
|
||||
|
||||
Changes in version 3.1 GA (2011-12-12)
|
||||
--------------------------------------
|
||||
|
||||
* SmartLifecycle beans in Lifecycle dependency graphs are only being started when isAutoStartup=true
|
||||
* ConversionService is able to work with "Collections.emptyList()" as target type (again)
|
||||
* restored DataBinder's ability to bind to an auto-growing List with unknown element type
|
||||
* added SmartValidator interface with general support for validation hints
|
||||
* added custom @Validated annotation with support for JSR-303 validation groups
|
||||
* JSR-303 SpringValidatorAdapter and MVC data binding provide support for validation groups
|
||||
* restored SpringValidatorAdapter's ability to handle bean constraints with property paths
|
||||
* added MethodValidationInterceptor/PostProcessor for Hibernate Validator 4.2 based method validation
|
||||
* fixed QuartzJobBean to work with Quartz 2.0/2.1 as well
|
||||
* @Transactional qualifiers match against transaction manager definitions in parent contexts as well
|
||||
* optimized AnnotationTransactionAspect and AnnotationCacheAspect pointcuts to avoid runtime checks
|
||||
* renamed @CacheEvict's "afterInvocation" attribute to "beforeInvocation" (for better readability)
|
||||
* added "mappingResources" property to LocalContainerEntityManagerFactoryBean (pointing to orm.xml)
|
||||
* Hibernate 4.0 variant of HibernateTransactionManager properly works with Open Session in View now
|
||||
* JmsInvokerClientInterceptor/FactoryBean always uses createConnection/createSession when on JMS 1.1
|
||||
* added out-of-the-box MappingJacksonMessageConverter impl for Spring's JMS MessageConverter facility
|
||||
* DispatcherServlet's "dispatchOptionsRequest" only sets the default 'Allow' header if actually needed
|
||||
* ResourceHttpRequestHandler sends content without content-type header if no media type found
|
||||
* ResourceHttpRequestHandler and ContentNegotiatingViewResolver use consistent mime type resolution
|
||||
* simplified support package layout in "web.method" and "web.servlet.mvc.method"
|
||||
* added "useTrailingSlashMatch" property to RequestMappingHandlerMapping
|
||||
* Portlet MVC annotation mapping allows for distributing action names across controllers
|
||||
* added String constants to MediaType
|
||||
|
||||
|
||||
Changes in version 3.1 RC2 (2011-11-28)
|
||||
---------------------------------------
|
||||
|
||||
* fixed OSGi manifest for spring-web bundle to not require Apache HttpComponents anymore
|
||||
* fixed GenericTypeResolver to consistently return null if not resolvable
|
||||
* added proper "contentLength()" implementation to ByteArrayResource
|
||||
* refined Resource "exists()" check for HTTP URLs to always return false for 404 status
|
||||
* LocaleEditor and StringToLocaleConverter do not restrict variant part through validation
|
||||
* LinkedCaseInsensitiveMap overrides putAll method as well (for IBM JDK 1.6 compatibility)
|
||||
* optimized DefaultListableBeanFactory's PropertyDescriptor caching for concurrent access
|
||||
* renamed ValueWrapperImpl to SimpleValueWrapper (for use in Cache implementations)
|
||||
* exposed EHCache 1.7's "statisticsEnabled"/"sampledStatisticsEnabled" on EhCacheFactoryBean
|
||||
* SpringValidatorAdapter accepts non-indexed set paths (for Hibernate Validator compatibility)
|
||||
* TransactionSynchronizationManager eagerly cleans up void ResourceHolders on any access
|
||||
* SimpleJdbcTestUtils executeSqlScript properly closes its LineNumberReader after use
|
||||
* JDO PersistenceManager synchronization performs close attempt after completion (if necessary)
|
||||
* JPA EntityManagerFactoryUtils silently ignores IllegalArgumentExceptions from setHint calls
|
||||
* fixed HibernateTransactionManager for Hibernate 4.0 to refer to correct openSession() method
|
||||
* added "namingStrategy" property to Hibernate 4 LocalSessionFactoryBean variant
|
||||
* HibernateJpaDialect does NOT expose underlying Session for underlying SessionFactory anymore
|
||||
* fixed MethodInvokingJobDetailFactoryBean's Quartz 2.0 support
|
||||
* added Quartz 2.1 compatibility while preserving Quartz 2.0 support
|
||||
* introduced JobDetail/CronTrigger/SimpleTriggerFactoryBean variants for Quartz 2.0/2.1 support
|
||||
* added "forwarder" property to ConnectorServerFactoryBean, accepting an MBeanServerForwarder
|
||||
* RmiClientInterceptor detects nested SocketException as connect failure as well
|
||||
* fixed StandardServlet/PortletEnvironment to check for JNDI (for Google App Engine compatibility)
|
||||
* Servlet/PortletContextResource's getFile prefers "file:" URL resolution over calling getRealPath
|
||||
* Portlet session mutex uses global session attribute to be shared among all portlets in the session
|
||||
* using original request URI in FlashMap matching logic to account for URL rewriting
|
||||
* now supporting target request with multiple parameter values in FlashMap matching logic
|
||||
* fixed issue in SimpleMappingExceptionResolver causing exception when setting "statusCodes" property
|
||||
* added ignoreDefaultModelOnRedirect attribute to <mvc:annotation-driven/>
|
||||
* added methods to UriComponentsBuilder for replacing the path or the query
|
||||
* support UriComponentsBuilder as @Controller method argument
|
||||
* added ServletUriComponentsBuilder to build a UriComponents instance starting with a ServletRequest
|
||||
* fixed issue with cache ignoring prototype-scoped controllers in RequestMappingHandlerAdapter
|
||||
* fixed issue with setting Content-Length header depending on the charset of the response
|
||||
* fixed @RequestMapping header matching to correctly process negated header conditions
|
||||
* added getObjectMapper() accessor to MappingJacksonHttpMessageConverter
|
||||
* AbstractCachingViewResolver caches unresolved view names by default ("cacheUnresolved"=true)
|
||||
* form input tag now allows type values other than "text" such as HTML5-specific types
|
||||
* form hidden tag now supports "disabled" attribute
|
||||
* fixed "formMultiSelect"/"formCheckboxes" FreeMarker macros to compare against actual field value
|
||||
* MockHttpServletRequest/Response now keep contentType field and Content-Type header in sync
|
||||
* updated Spring MVC configuration section to include MVC Java config and the MVC namespace
|
||||
|
||||
|
||||
Changes in version 3.1 RC1 (2011-10-11)
|
||||
---------------------------------------
|
||||
|
||||
@@ -15,6 +252,8 @@ Changes in version 3.1 RC1 (2011-10-11)
|
||||
* prepared Spring's DataSource and RowSet adapters for forward compatibility with JDBC 4.1
|
||||
* introduced ForkJoinPoolFactoryBean for Java 7 (alternative: add new jsr166.jar to Java 6)
|
||||
* introduced extended WritableResource interface
|
||||
* ConversionService prevents Converter from trying to convert to a subtype of its actual target type
|
||||
* CollectionCollection/MapToMapConverter preserve original Collection/Map if no converted elements
|
||||
* DefaultListableBeanFactory is only deserializable through a SerializedBeanFactoryReference
|
||||
* DefaultListableBeanFactory's getBean(name, type) attempts type conversion if necessary
|
||||
* DefaultListableBeanFactory allows for init methods to register further bean definitions (again)
|
||||
@@ -34,7 +273,6 @@ Changes in version 3.1 RC1 (2011-10-11)
|
||||
* added flash attribute support through FlashMap and FlashMapManager abstractions
|
||||
* added RedirectAttributes abstraction as supported method argument type of @RequestMapping methods
|
||||
* added "ignoreDefaultModelOnRedirect" flag to RequestMappingHandlerAdapter
|
||||
* added support for @RequestPart annotated controller method arguments
|
||||
* fixed @ExceptionHandler exception type matching (ExceptionDepthComparator)
|
||||
* ResourceHttpRequestHandler detects invalid directory traversal in given path
|
||||
* HtmlUtils properly escapes single quotes as well
|
||||
@@ -48,6 +286,8 @@ Changes in version 3.1 RC1 (2011-10-11)
|
||||
* JpaTransactionManager etc can find EntityManagerFactory by "persistenceUnitName" property now
|
||||
* HibernateJpaDialect exposes underlying Session for underlying SessionFactory
|
||||
* deprecated JpaTemplate/JpaInterceptor/JpaDaoSupport and JdoTemplate/JdoInterceptor/JdoDaoSupport
|
||||
* updated H2 error codes in sql-error-codes.xml
|
||||
* fixed NamedParameterJdbcTemplate to use correct maximum type for queryForInt/Long
|
||||
* jdbc:script's "separator" and "execution" attributes work nested with embedded-database as well
|
||||
* added "encoding" attribute to jdbc:script element
|
||||
* JavaMailSenderImpl detects and respects "mail.transport.protocol" property in existing Session
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
SPRING FRAMEWORK 3.1 RC1 (July 2011)
|
||||
------------------------------------
|
||||
SPRING FRAMEWORK 3.1.4 (January 2013)
|
||||
-------------------------------------
|
||||
http://www.springsource.org
|
||||
|
||||
1. INTRODUCTION
|
||||
|
||||
+5
-2
@@ -1,4 +1,4 @@
|
||||
version=3.1.0
|
||||
version=3.1.5
|
||||
|
||||
natural.name=spring-framework
|
||||
project.name=Spring Framework
|
||||
@@ -26,4 +26,7 @@ aj.osgi.range="[1.6.8, 2.0.0)"
|
||||
|
||||
## For trunk development / ci builds
|
||||
release.type=integration
|
||||
#build.stamp=BUILD-SNAPSHOT
|
||||
build.stamp=BUILD-SNAPSHOT
|
||||
|
||||
#bundlor
|
||||
fail.on.warnings=false
|
||||
|
||||
+4
-5
@@ -1,5 +1,4 @@
|
||||
# common dependency versions
|
||||
aspectj.version=1.6.8.RELEASE
|
||||
slf4j.version=1.5.3
|
||||
junit.version=4.9.0
|
||||
testng.version=5.12.1
|
||||
# common dependency versions
|
||||
aspectj.version=1.6.8.RELEASE
|
||||
junit.version=4.9.0
|
||||
testng.version=5.12.1
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src/main/java"/>
|
||||
<classpathentry kind="src" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.beans"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/com.jamonapi/com.springsource.com.jamonapi/2.4.0/com.springsource.com.jamonapi-2.4.0.jar" sourcepath="/IVY_CACHE/com.jamonapi/com.springsource.com.jamonapi/2.4.0/com.springsource.com.jamonapi-sources-2.4.0.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.2.0/com.springsource.net.sf.cglib-2.2.0.jar" sourcepath="/IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.1.3/com.springsource.net.sf.cglib-sources-2.1.3.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar" sourcepath="/IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-sources-1.0.0.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.3.0/com.springsource.org.apache.commons.pool-1.3.0.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.3.0/com.springsource.org.apache.commons.pool-sources-1.3.0.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar" sourcepath="/IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-sources-1.2.15.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar" sourcepath="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-sources-1.6.8.RELEASE.jar"/>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src/main/java"/>
|
||||
<classpathentry kind="src" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.beans"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/com.jamonapi/com.springsource.com.jamonapi/2.4.0/com.springsource.com.jamonapi-2.4.0.jar" sourcepath="/IVY_CACHE/com.jamonapi/com.springsource.com.jamonapi/2.4.0/com.springsource.com.jamonapi-sources-2.4.0.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.2.0/com.springsource.net.sf.cglib-2.2.0.jar" sourcepath="/IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.1.3/com.springsource.net.sf.cglib-sources-2.1.3.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar" sourcepath="/IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-sources-1.0.0.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.3.0/com.springsource.org.apache.commons.pool-1.3.0.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.3.0/com.springsource.org.apache.commons.pool-sources-1.3.0.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar" sourcepath="/IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-sources-1.2.15.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar" sourcepath="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-sources-1.6.8.RELEASE.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-2.5.1.jar" sourcepath="/IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-sources-2.5.1.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.9.0/com.springsource.org.junit-4.9.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.9.0/com.springsource.org.junit-sources-4.9.0.jar"/>
|
||||
<classpathentry kind="lib" path="/org.springframework.asm/target/artifacts/org.springframework.asm.jar" sourcepath="/org.springframework.asm/target/artifacts/org.springframework.asm-sources.jar"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.9.0/com.springsource.org.junit-4.9.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.9.0/com.springsource.org.junit-sources-4.9.0.jar"/>
|
||||
<classpathentry kind="lib" path="/org.springframework.asm/target/artifacts/org.springframework.asm.jar" sourcepath="/org.springframework.asm/target/artifacts/org.springframework.asm-sources.jar"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module relativePaths="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="module" module-name="beans" />
|
||||
<orderEntry type="module" module-name="core" />
|
||||
<orderEntry type="library" name="AOP Alliance" level="project" />
|
||||
<orderEntry type="library" name="AspectJ" level="project" />
|
||||
<orderEntry type="library" name="CGLIB" level="project" />
|
||||
<orderEntry type="library" name="Commons Logging" level="project" />
|
||||
<orderEntry type="library" name="Commons Pool" level="project" />
|
||||
<orderEntry type="library" name="EasyMock" level="project" />
|
||||
<orderEntry type="library" name="Jamon" level="project" />
|
||||
<orderEntry type="library" name="JUnit" level="project" />
|
||||
<orderEntry type="library" name="Log4j" level="project" />
|
||||
</component>
|
||||
<component name="copyright">
|
||||
<Base>
|
||||
<setting name="state" value="2" />
|
||||
</Base>
|
||||
</component>
|
||||
</module>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module relativePaths="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="module" module-name="beans" />
|
||||
<orderEntry type="module" module-name="core" />
|
||||
<orderEntry type="library" name="AOP Alliance" level="project" />
|
||||
<orderEntry type="library" name="AspectJ" level="project" />
|
||||
<orderEntry type="library" name="CGLIB" level="project" />
|
||||
<orderEntry type="library" name="Commons Logging" level="project" />
|
||||
<orderEntry type="library" name="Commons Pool" level="project" />
|
||||
<orderEntry type="library" name="EasyMock" level="project" />
|
||||
<orderEntry type="library" name="Jamon" level="project" />
|
||||
<orderEntry type="library" name="JUnit" level="project" />
|
||||
<orderEntry type="library" name="Log4j" level="project" />
|
||||
</component>
|
||||
<component name="copyright">
|
||||
<Base>
|
||||
<setting name="state" value="2" />
|
||||
</Base>
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>3.1.5.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>3.1.5.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.jamonapi</groupId>
|
||||
|
||||
+18
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* 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.
|
||||
@@ -681,6 +681,23 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
return !this.adviceMethod.equals(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof AdviceExcludingMethodMatcher)) {
|
||||
return false;
|
||||
}
|
||||
AdviceExcludingMethodMatcher otherMm = (AdviceExcludingMethodMatcher) other;
|
||||
return this.adviceMethod.equals(otherMm.adviceMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.adviceMethod.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2011 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,13 +26,13 @@ import org.springframework.beans.factory.xml.ParserContext;
|
||||
|
||||
/**
|
||||
* {@link BeanDefinitionParser} responsible for parsing the
|
||||
* <code><aop:spring-configured/></code> tag.
|
||||
* {@code <aop:spring-configured/>} tag.
|
||||
*
|
||||
* <p><b>NOTE:</b> This is essentially a duplicate of Spring 2.5's
|
||||
* {@link org.springframework.context.config.SpringConfiguredBeanDefinitionParser}
|
||||
* for the <code><context:spring-configured/></code> tag, mirrored here
|
||||
* for compatibility with Spring 2.0's <code><aop:spring-configured/></code>
|
||||
* tag (avoiding a direct dependency on the context package).
|
||||
* for the {@code <context:spring-configured/>} tag, mirrored here for compatibility with
|
||||
* Spring 2.0's {@code <aop:spring-configured/>} tag (avoiding a direct dependency on the
|
||||
* context package).
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
@@ -55,6 +55,7 @@ class SpringConfiguredBeanDefinitionParser implements BeanDefinitionParser {
|
||||
RootBeanDefinition def = new RootBeanDefinition();
|
||||
def.setBeanClassName(BEAN_CONFIGURER_ASPECT_CLASS_NAME);
|
||||
def.setFactoryMethodName("aspectOf");
|
||||
def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
def.setSource(parserContext.extractSource(element));
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(def, BEAN_CONFIGURER_ASPECT_BEAN_NAME));
|
||||
}
|
||||
|
||||
+8
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* 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.
|
||||
@@ -271,7 +271,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
|
||||
Object cacheKey = getCacheKey(beanClass, beanName);
|
||||
|
||||
if (!this.targetSourcedBeans.contains(cacheKey)) {
|
||||
if (!this.targetSourcedBeans.contains(beanName)) {
|
||||
if (this.advisedBeans.contains(cacheKey) || this.nonAdvisedBeans.contains(cacheKey)) {
|
||||
return null;
|
||||
}
|
||||
@@ -371,17 +371,18 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
|
||||
/**
|
||||
* Return whether the given bean class represents an infrastructure class
|
||||
* that should never be proxied.
|
||||
* <p>Default implementation considers Advisors, Advices and
|
||||
* AbstractAutoProxyCreators as infrastructure classes.
|
||||
* <p>The default implementation considers Advices, Advisors and
|
||||
* AopInfrastructureBeans as infrastructure classes.
|
||||
* @param beanClass the class of the bean
|
||||
* @return whether the bean represents an infrastructure class
|
||||
* @see org.aopalliance.aop.Advice
|
||||
* @see org.springframework.aop.Advisor
|
||||
* @see org.aopalliance.intercept.MethodInterceptor
|
||||
* @see org.springframework.aop.framework.AopInfrastructureBean
|
||||
* @see #shouldSkip
|
||||
*/
|
||||
protected boolean isInfrastructureClass(Class<?> beanClass) {
|
||||
boolean retVal = Advisor.class.isAssignableFrom(beanClass) ||
|
||||
Advice.class.isAssignableFrom(beanClass) ||
|
||||
boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
|
||||
Advisor.class.isAssignableFrom(beanClass) ||
|
||||
AopInfrastructureBean.class.isAssignableFrom(beanClass);
|
||||
if (retVal && logger.isTraceEnabled()) {
|
||||
logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
|
||||
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.aop.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
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.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.support.TaskExecutorAdapter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base class for asynchronous method execution aspects, such as
|
||||
* {@link org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor}
|
||||
* or {@link org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect}.
|
||||
*
|
||||
* <p>Provides support for <i>executor qualification</i> on a method-by-method basis.
|
||||
* {@code AsyncExecutionAspectSupport} objects must be constructed with a default {@code
|
||||
* Executor}, but each individual method may further qualify a specific {@code Executor}
|
||||
* bean to be used when executing it, e.g. through an annotation attribute.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1.2
|
||||
*/
|
||||
public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
|
||||
private final Map<Method, AsyncTaskExecutor> executors = new HashMap<Method, AsyncTaskExecutor>();
|
||||
|
||||
private Executor defaultExecutor;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@link AsyncExecutionAspectSupport}, using the provided default
|
||||
* executor unless individual async methods indicate via qualifier that a more
|
||||
* specific executor should be used.
|
||||
* @param defaultExecutor the executor to use when executing asynchronous methods
|
||||
*/
|
||||
public AsyncExecutionAspectSupport(Executor defaultExecutor) {
|
||||
this.setExecutor(defaultExecutor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Supply the executor to be used when executing async methods.
|
||||
* @param defaultExecutor the {@code Executor} (typically a Spring {@code
|
||||
* AsyncTaskExecutor} or {@link java.util.concurrent.ExecutorService}) to delegate to
|
||||
* unless a more specific executor has been requested via a qualifier on the async
|
||||
* method, in which case the executor will be looked up at invocation time against the
|
||||
* enclosing bean factory.
|
||||
* @see #getExecutorQualifier
|
||||
* @see #setBeanFactory(BeanFactory)
|
||||
*/
|
||||
public void setExecutor(Executor defaultExecutor) {
|
||||
this.defaultExecutor = defaultExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link BeanFactory} to be used when looking up executors by qualifier.
|
||||
*/
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine the specific executor to use when executing the given method.
|
||||
* @returns the executor to use (never {@code null})
|
||||
*/
|
||||
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
|
||||
if (!this.executors.containsKey(method)) {
|
||||
Executor executor = this.defaultExecutor;
|
||||
String qualifier = getExecutorQualifier(method);
|
||||
if (StringUtils.hasLength(qualifier)) {
|
||||
Assert.notNull(this.beanFactory,
|
||||
"BeanFactory must be set on " + this.getClass().getSimpleName() +
|
||||
" to access qualified executor [" + qualifier + "]");
|
||||
executor = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
|
||||
this.beanFactory, Executor.class, qualifier);
|
||||
}
|
||||
if (executor instanceof AsyncTaskExecutor) {
|
||||
this.executors.put(method, (AsyncTaskExecutor) executor);
|
||||
}
|
||||
else if (executor != null) {
|
||||
this.executors.put(method, new TaskExecutorAdapter(executor));
|
||||
}
|
||||
}
|
||||
return this.executors.get(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the qualifier or bean name of the executor to be used when executing the
|
||||
* given async method, typically specified in the form of an annotation attribute.
|
||||
* Returning an empty string or {@code null} indicates that no specific executor has
|
||||
* been specified and that the {@linkplain #setExecutor(Executor) default executor}
|
||||
* should be used.
|
||||
* @param method the method to inspect for executor qualifier metadata
|
||||
* @return the qualifier if specified, otherwise empty string or {@code null}
|
||||
* @see #determineAsyncExecutor(Method)
|
||||
*/
|
||||
protected abstract String getExecutorQualifier(Method method);
|
||||
|
||||
}
|
||||
+120
-103
@@ -1,103 +1,120 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.support.TaskExecutorAdapter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* AOP Alliance <code>MethodInterceptor</code> that processes method invocations
|
||||
* asynchronously, using a given {@link org.springframework.core.task.AsyncTaskExecutor}.
|
||||
* Typically used with the {@link org.springframework.context.task.Async} annotation.
|
||||
*
|
||||
* <p>In terms of target method signatures, any parameter types are supported.
|
||||
* However, the return type is constrained to either <code>void</code> or
|
||||
* <code>java.util.concurrent.Future</code>. In the latter case, the Future handle
|
||||
* returned from the proxy will be an actual asynchronous Future that can be used
|
||||
* to track the result of the asynchronous method execution. However, since the
|
||||
* target method needs to implement the same signature, it will have to return
|
||||
* a temporary Future handle that just passes the return value through
|
||||
* (like Spring's {@link org.springframework.scheduling.annotation.AsyncResult}
|
||||
* or EJB 3.1's <code>javax.ejb.AsyncResult</code>).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see org.springframework.scheduling.annotation.Async
|
||||
* @see org.springframework.scheduling.annotation.AsyncAnnotationAdvisor
|
||||
*/
|
||||
public class AsyncExecutionInterceptor implements MethodInterceptor, Ordered {
|
||||
|
||||
private final AsyncTaskExecutor asyncExecutor;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AsyncExecutionInterceptor.
|
||||
* @param asyncExecutor the Spring AsyncTaskExecutor to delegate to
|
||||
*/
|
||||
public AsyncExecutionInterceptor(AsyncTaskExecutor asyncExecutor) {
|
||||
Assert.notNull(asyncExecutor, "TaskExecutor must not be null");
|
||||
this.asyncExecutor = asyncExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new AsyncExecutionInterceptor.
|
||||
* @param asyncExecutor the <code>java.util.concurrent</code> Executor
|
||||
* to delegate to (typically a {@link java.util.concurrent.ExecutorService}
|
||||
*/
|
||||
public AsyncExecutionInterceptor(Executor asyncExecutor) {
|
||||
this.asyncExecutor = new TaskExecutorAdapter(asyncExecutor);
|
||||
}
|
||||
|
||||
|
||||
public Object invoke(final MethodInvocation invocation) throws Throwable {
|
||||
Future result = this.asyncExecutor.submit(new Callable<Object>() {
|
||||
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;
|
||||
}
|
||||
});
|
||||
if (Future.class.isAssignableFrom(invocation.getMethod().getReturnType())) {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.aop.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* AOP Alliance <code>MethodInterceptor</code> that processes method invocations
|
||||
* asynchronously, using a given {@link org.springframework.core.task.AsyncTaskExecutor}.
|
||||
* Typically used with the {@link org.springframework.scheduling.annotation.Async} annotation.
|
||||
*
|
||||
* <p>In terms of target method signatures, any parameter types are supported.
|
||||
* However, the return type is constrained to either <code>void</code> or
|
||||
* <code>java.util.concurrent.Future</code>. In the latter case, the Future handle
|
||||
* returned from the proxy will be an actual asynchronous Future that can be used
|
||||
* to track the result of the asynchronous method execution. However, since the
|
||||
* target method needs to implement the same signature, it will have to return
|
||||
* a temporary Future handle that just passes the return value through
|
||||
* (like Spring's {@link org.springframework.scheduling.annotation.AsyncResult}
|
||||
* or EJB 3.1's <code>javax.ejb.AsyncResult</code>).
|
||||
*
|
||||
* <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
|
||||
* @since 3.0
|
||||
* @see org.springframework.scheduling.annotation.Async
|
||||
* @see org.springframework.scheduling.annotation.AsyncAnnotationAdvisor
|
||||
* @see org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor
|
||||
*/
|
||||
public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
|
||||
implements MethodInterceptor, Ordered {
|
||||
|
||||
/**
|
||||
* Create a new {@code AsyncExecutionInterceptor}.
|
||||
* @param executor the {@link Executor} (typically a Spring {@link AsyncTaskExecutor}
|
||||
* or {@link java.util.concurrent.ExecutorService}) to delegate to.
|
||||
*/
|
||||
public AsyncExecutionInterceptor(Executor executor) {
|
||||
super(executor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Intercept the given method invocation, submit the actual calling of the method to
|
||||
* the correct task executor and return immediately to the caller.
|
||||
* @param invocation the method to intercept and make asynchronous
|
||||
* @return {@link Future} if the original method returns {@code Future}; {@code null}
|
||||
* otherwise.
|
||||
*/
|
||||
public Object invoke(final MethodInvocation invocation) throws Throwable {
|
||||
Future<?> result = this.determineAsyncExecutor(invocation.getMethod()).submit(
|
||||
new Callable<Object>() {
|
||||
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;
|
||||
}
|
||||
});
|
||||
if (Future.class.isAssignableFrom(invocation.getMethod().getReturnType())) {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>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
|
||||
*/
|
||||
@Override
|
||||
protected String getExecutorQualifier(Method method) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -206,6 +206,7 @@ public abstract class AopUtils {
|
||||
* @return whether the pointcut can apply on any method
|
||||
*/
|
||||
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
|
||||
Assert.notNull(pc, "Pointcut must not be null");
|
||||
if (!pc.getClassFilter().matches(targetClass)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+18
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* 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.
|
||||
@@ -56,4 +56,21 @@ public class AnnotationMethodMatcher extends StaticMethodMatcher {
|
||||
return (specificMethod != method && specificMethod.isAnnotationPresent(this.annotationType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof AnnotationMethodMatcher)) {
|
||||
return false;
|
||||
}
|
||||
AnnotationMethodMatcher otherMm = (AnnotationMethodMatcher) other;
|
||||
return this.annotationType.equals(otherMm.annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.annotationType.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Spring's proxy-based AOP framework.
|
||||
</p>
|
||||
</body>
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Spring's proxy-based AOP framework.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
+174
-174
@@ -1,174 +1,174 @@
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.MethodBeforeAdvice;
|
||||
import org.springframework.aop.ThrowsAdvice;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.core.OverridingClassLoader;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class TrickyAspectJPointcutExpressionTests {
|
||||
|
||||
@Test
|
||||
public void testManualProxyJavaWithUnconditionalPointcut() throws Exception {
|
||||
TestService target = new TestServiceImpl();
|
||||
LogUserAdvice logAdvice = new LogUserAdvice();
|
||||
testAdvice(new DefaultPointcutAdvisor(logAdvice), logAdvice, target, "TestServiceImpl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManualProxyJavaWithStaticPointcut() throws Exception {
|
||||
TestService target = new TestServiceImpl();
|
||||
LogUserAdvice logAdvice = new LogUserAdvice();
|
||||
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName()));
|
||||
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManualProxyJavaWithDynamicPointcut() throws Exception {
|
||||
TestService target = new TestServiceImpl();
|
||||
LogUserAdvice logAdvice = new LogUserAdvice();
|
||||
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName()));
|
||||
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManualProxyJavaWithDynamicPointcutAndProxyTargetClass() throws Exception {
|
||||
TestService target = new TestServiceImpl();
|
||||
LogUserAdvice logAdvice = new LogUserAdvice();
|
||||
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName()));
|
||||
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManualProxyJavaWithStaticPointcutAndTwoClassLoaders() throws Exception {
|
||||
|
||||
LogUserAdvice logAdvice = new LogUserAdvice();
|
||||
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName()));
|
||||
|
||||
// Test with default class loader first...
|
||||
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, new TestServiceImpl(), "TestServiceImpl");
|
||||
|
||||
// Then try again with a different class loader on the target...
|
||||
SimpleThrowawayClassLoader loader = new SimpleThrowawayClassLoader(new TestServiceImpl().getClass().getClassLoader());
|
||||
// Make sure the interface is loaded from the parent class loader
|
||||
loader.excludeClass(TestService.class.getName());
|
||||
loader.excludeClass(TestException.class.getName());
|
||||
TestService other = (TestService) loader.loadClass(TestServiceImpl.class.getName()).newInstance();
|
||||
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, other, "TestServiceImpl");
|
||||
|
||||
}
|
||||
|
||||
private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message)
|
||||
throws Exception {
|
||||
testAdvice(advisor, logAdvice, target, message, false);
|
||||
}
|
||||
|
||||
private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message,
|
||||
boolean proxyTargetClass) throws Exception {
|
||||
|
||||
logAdvice.reset();
|
||||
|
||||
ProxyFactory factory = new ProxyFactory(target);
|
||||
factory.setProxyTargetClass(proxyTargetClass);
|
||||
factory.addAdvisor(advisor);
|
||||
TestService bean = (TestService) factory.getProxy();
|
||||
|
||||
assertEquals(0, logAdvice.getCountThrows());
|
||||
try {
|
||||
bean.sayHello();
|
||||
fail("Expected exception");
|
||||
} catch (TestException e) {
|
||||
assertEquals(message, e.getMessage());
|
||||
}
|
||||
assertEquals(1, logAdvice.getCountThrows());
|
||||
}
|
||||
|
||||
public static class SimpleThrowawayClassLoader extends OverridingClassLoader {
|
||||
|
||||
/**
|
||||
* Create a new SimpleThrowawayClassLoader for the given class loader.
|
||||
* @param parent the ClassLoader to build a throwaway ClassLoader for
|
||||
*/
|
||||
public SimpleThrowawayClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TestException extends RuntimeException {
|
||||
|
||||
public TestException(String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public static @interface Log {
|
||||
}
|
||||
|
||||
public static interface TestService {
|
||||
public String sayHello();
|
||||
}
|
||||
|
||||
@Log
|
||||
public static class TestServiceImpl implements TestService{
|
||||
public String sayHello() {
|
||||
throw new TestException("TestServiceImpl");
|
||||
}
|
||||
}
|
||||
|
||||
public class LogUserAdvice implements MethodBeforeAdvice, ThrowsAdvice {
|
||||
|
||||
private int countBefore = 0;
|
||||
|
||||
private int countThrows = 0;
|
||||
|
||||
public void before(Method method, Object[] objects, Object o) throws Throwable {
|
||||
countBefore++;
|
||||
}
|
||||
|
||||
public void afterThrowing(Exception e) throws Throwable {
|
||||
countThrows++;
|
||||
throw e;
|
||||
}
|
||||
|
||||
public int getCountBefore() {
|
||||
return countBefore;
|
||||
}
|
||||
|
||||
public int getCountThrows() {
|
||||
return countThrows;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
countThrows = 0;
|
||||
countBefore = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.MethodBeforeAdvice;
|
||||
import org.springframework.aop.ThrowsAdvice;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.core.OverridingClassLoader;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class TrickyAspectJPointcutExpressionTests {
|
||||
|
||||
@Test
|
||||
public void testManualProxyJavaWithUnconditionalPointcut() throws Exception {
|
||||
TestService target = new TestServiceImpl();
|
||||
LogUserAdvice logAdvice = new LogUserAdvice();
|
||||
testAdvice(new DefaultPointcutAdvisor(logAdvice), logAdvice, target, "TestServiceImpl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManualProxyJavaWithStaticPointcut() throws Exception {
|
||||
TestService target = new TestServiceImpl();
|
||||
LogUserAdvice logAdvice = new LogUserAdvice();
|
||||
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName()));
|
||||
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManualProxyJavaWithDynamicPointcut() throws Exception {
|
||||
TestService target = new TestServiceImpl();
|
||||
LogUserAdvice logAdvice = new LogUserAdvice();
|
||||
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName()));
|
||||
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManualProxyJavaWithDynamicPointcutAndProxyTargetClass() throws Exception {
|
||||
TestService target = new TestServiceImpl();
|
||||
LogUserAdvice logAdvice = new LogUserAdvice();
|
||||
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName()));
|
||||
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManualProxyJavaWithStaticPointcutAndTwoClassLoaders() throws Exception {
|
||||
|
||||
LogUserAdvice logAdvice = new LogUserAdvice();
|
||||
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName()));
|
||||
|
||||
// Test with default class loader first...
|
||||
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, new TestServiceImpl(), "TestServiceImpl");
|
||||
|
||||
// Then try again with a different class loader on the target...
|
||||
SimpleThrowawayClassLoader loader = new SimpleThrowawayClassLoader(new TestServiceImpl().getClass().getClassLoader());
|
||||
// Make sure the interface is loaded from the parent class loader
|
||||
loader.excludeClass(TestService.class.getName());
|
||||
loader.excludeClass(TestException.class.getName());
|
||||
TestService other = (TestService) loader.loadClass(TestServiceImpl.class.getName()).newInstance();
|
||||
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, other, "TestServiceImpl");
|
||||
|
||||
}
|
||||
|
||||
private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message)
|
||||
throws Exception {
|
||||
testAdvice(advisor, logAdvice, target, message, false);
|
||||
}
|
||||
|
||||
private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message,
|
||||
boolean proxyTargetClass) throws Exception {
|
||||
|
||||
logAdvice.reset();
|
||||
|
||||
ProxyFactory factory = new ProxyFactory(target);
|
||||
factory.setProxyTargetClass(proxyTargetClass);
|
||||
factory.addAdvisor(advisor);
|
||||
TestService bean = (TestService) factory.getProxy();
|
||||
|
||||
assertEquals(0, logAdvice.getCountThrows());
|
||||
try {
|
||||
bean.sayHello();
|
||||
fail("Expected exception");
|
||||
} catch (TestException e) {
|
||||
assertEquals(message, e.getMessage());
|
||||
}
|
||||
assertEquals(1, logAdvice.getCountThrows());
|
||||
}
|
||||
|
||||
public static class SimpleThrowawayClassLoader extends OverridingClassLoader {
|
||||
|
||||
/**
|
||||
* Create a new SimpleThrowawayClassLoader for the given class loader.
|
||||
* @param parent the ClassLoader to build a throwaway ClassLoader for
|
||||
*/
|
||||
public SimpleThrowawayClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TestException extends RuntimeException {
|
||||
|
||||
public TestException(String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public static @interface Log {
|
||||
}
|
||||
|
||||
public static interface TestService {
|
||||
public String sayHello();
|
||||
}
|
||||
|
||||
@Log
|
||||
public static class TestServiceImpl implements TestService{
|
||||
public String sayHello() {
|
||||
throw new TestException("TestServiceImpl");
|
||||
}
|
||||
}
|
||||
|
||||
public class LogUserAdvice implements MethodBeforeAdvice, ThrowsAdvice {
|
||||
|
||||
private int countBefore = 0;
|
||||
|
||||
private int countThrows = 0;
|
||||
|
||||
public void before(Method method, Object[] objects, Object o) throws Throwable {
|
||||
countBefore++;
|
||||
}
|
||||
|
||||
public void afterThrowing(Exception e) throws Throwable {
|
||||
countThrows++;
|
||||
throw e;
|
||||
}
|
||||
|
||||
public int getCountBefore() {
|
||||
return countBefore;
|
||||
}
|
||||
|
||||
public int getCountThrows() {
|
||||
return countThrows;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
countThrows = 0;
|
||||
countBefore = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+41
-41
@@ -1,41 +1,41 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.support;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import test.beans.TestBean;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* @author Colin Sampaleanu
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Rick Evans
|
||||
*/
|
||||
public class ClassUtilsTests extends TestCase {
|
||||
|
||||
public void testGetShortNameForCglibClass() {
|
||||
TestBean tb = new TestBean();
|
||||
ProxyFactory pf = new ProxyFactory();
|
||||
pf.setTarget(tb);
|
||||
pf.setProxyTargetClass(true);
|
||||
TestBean proxy = (TestBean) pf.getProxy();
|
||||
String className = ClassUtils.getShortName(proxy.getClass());
|
||||
assertEquals("Class name did not match", "TestBean", className);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2009 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.support;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import test.beans.TestBean;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* @author Colin Sampaleanu
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Rick Evans
|
||||
*/
|
||||
public class ClassUtilsTests extends TestCase {
|
||||
|
||||
public void testGetShortNameForCglibClass() {
|
||||
TestBean tb = new TestBean();
|
||||
ProxyFactory pf = new ProxyFactory();
|
||||
pf.setTarget(tb);
|
||||
pf.setProxyTargetClass(true);
|
||||
TestBean proxy = (TestBean) pf.getProxy();
|
||||
String className = ClassUtils.getShortName(proxy.getClass());
|
||||
assertEquals("Class name did not match", "TestBean", className);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-asm</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>3.1.5.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>3.1.5.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>jarjar</id>
|
||||
<phase>process-classes</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpathref="maven.plugin.classpath" />
|
||||
<jarjar jarfile="${project.build.directory}${file.separator}${project.build.finalName}-jarjar.jar">
|
||||
<zipfileset src="${project.build.directory}/jarjar-staging/com.springsource.org.objectweb.asm.jar"/>
|
||||
<zipfileset src="${project.build.directory}/jarjar-staging/com.springsource.org.objectweb.asm.commons.jar"/>
|
||||
<rule pattern="org.objectweb.asm.**" result="org.springframework.asm.@1"/>
|
||||
</jarjar>
|
||||
<unjar src="${project.build.directory}${file.separator}${project.build.finalName}-jarjar.jar"
|
||||
dest="${project.build.outputDirectory}">
|
||||
<patternset>
|
||||
<include name="**/*.class"/>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>jarjar</id>
|
||||
<phase>process-classes</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpathref="maven.plugin.classpath" />
|
||||
<jarjar jarfile="${project.build.directory}${file.separator}${project.build.finalName}-jarjar.jar">
|
||||
<zipfileset src="${project.build.directory}/jarjar-staging/com.springsource.org.objectweb.asm.jar"/>
|
||||
<zipfileset src="${project.build.directory}/jarjar-staging/com.springsource.org.objectweb.asm.commons.jar"/>
|
||||
<rule pattern="org.objectweb.asm.**" result="org.springframework.asm.@1"/>
|
||||
</jarjar>
|
||||
<unjar src="${project.build.directory}${file.separator}${project.build.finalName}-jarjar.jar"
|
||||
dest="${project.build.outputDirectory}">
|
||||
<patternset>
|
||||
<include name="**/*.class"/>
|
||||
<exclude name="*"/>
|
||||
</patternset>
|
||||
</unjar>
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code</groupId>
|
||||
<artifactId>jarjar</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</unjar>
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code</groupId>
|
||||
<artifactId>jarjar</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar" sourcepath="/IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-sources-1.6.8.RELEASE.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.9.0/com.springsource.org.junit-4.9.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.9.0/com.springsource.org.junit-sources-4.9.0.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/org.hamcrest/com.springsource.org.hamcrest/1.1.0/com.springsource.org.hamcrest-1.1.0.jar" sourcepath="IVY_CACHE/org.hamcrest/com.springsource.org.hamcrest/1.1.0/com.springsource.org.hamcrest-sources-1.1.0.jar"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/javax.persistence/com.springsource.javax.persistence/1.0.0/com.springsource.javax.persistence-1.0.0.jar" sourcepath="/IVY_CACHE/javax.persistence/com.springsource.javax.persistence/1.0.0/com.springsource.javax.persistence-sources-1.0.0.jar"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.orm"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.aop"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
||||
@@ -1,43 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml-stylesheet type="text/xsl" href="http://ivyrep.jayasoft.org/ivy-doc.xsl"?>
|
||||
<ivy-module
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="http://incubator.apache.org/ivy/schemas/ivy.xsd"
|
||||
version="1.3">
|
||||
|
||||
<info organisation="org.springframework" module="${ant.project.name}">
|
||||
<license name="Apache 2.0" url="http://www.apache.org/licenses/LICENSE-2.0"/>
|
||||
</info>
|
||||
|
||||
<configurations>
|
||||
<include file="${spring.build.dir}/common/default-ivy-configurations.xml"/>
|
||||
<conf name="commons-logging" extends="runtime" description="JARs needed to run with Commons Logging"/>
|
||||
<conf name="aspectj" extends="runtime" description="JARs needed to run with AspectJ"/>
|
||||
<conf name="context" extends="runtime" description="JARs needed to register @Configuration classes and @Bean methods"/>
|
||||
<conf name="tx" extends="runtime" description="JARs needed to run transactional aspects"/>
|
||||
<conf name="orm" extends="runtime" description="JARs needed to compile JPA aspects"/>
|
||||
<conf name="cache" extends="runtime" description="JARs needed to compile caching aspects"/>
|
||||
</configurations>
|
||||
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
<artifact name="license" type="license" ext="txt"/>
|
||||
<artifact name="notice" type="notice" ext="txt"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile, commons-logging->compile"/>
|
||||
<dependency org="org.aspectj" name="com.springsource.org.aspectj.weaver" rev="${aspectj.version}" conf="optional, aspectj->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.beans" rev="latest.integration" conf="test->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.transaction" rev="latest.integration" conf="optional, tx->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.orm" rev="latest.integration" conf="optional, orm->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.test" rev="latest.integration" conf="test->runtime"/>
|
||||
<dependency org="org.springframework" name="org.springframework.context" rev="latest.integration" conf="context->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.context.support" rev="latest.integration" conf="optional, cache->compile"/>
|
||||
<dependency org="javax.persistence" name="com.springsource.javax.persistence" rev="1.0.0" conf="optional, orm->compile"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->compile"/>
|
||||
<dependency org="javax.mail" name="com.springsource.javax.mail" rev="1.4.0" conf="optional, test->compile"/>
|
||||
</dependencies>
|
||||
|
||||
</ivy-module>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml-stylesheet type="text/xsl" href="http://ivyrep.jayasoft.org/ivy-doc.xsl"?>
|
||||
<ivy-module
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="http://incubator.apache.org/ivy/schemas/ivy.xsd"
|
||||
version="1.3">
|
||||
|
||||
<info organisation="org.springframework" module="${ant.project.name}">
|
||||
<license name="Apache 2.0" url="http://www.apache.org/licenses/LICENSE-2.0"/>
|
||||
</info>
|
||||
|
||||
<configurations>
|
||||
<include file="${spring.build.dir}/common/default-ivy-configurations.xml"/>
|
||||
<conf name="commons-logging" extends="runtime" description="JARs needed to run with Commons Logging"/>
|
||||
<conf name="aspectj" extends="runtime" description="JARs needed to run with AspectJ"/>
|
||||
<conf name="context" extends="runtime" description="JARs needed to register @Configuration classes and @Bean methods"/>
|
||||
<conf name="tx" extends="runtime" description="JARs needed to run transactional aspects"/>
|
||||
<conf name="orm" extends="runtime" description="JARs needed to compile JPA aspects"/>
|
||||
<conf name="cache" extends="runtime" description="JARs needed to compile caching aspects"/>
|
||||
</configurations>
|
||||
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
<artifact name="license" type="license" ext="txt"/>
|
||||
<artifact name="notice" type="notice" ext="txt"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
<dependency org="net.sourceforge.cglib" name="com.springsource.net.sf.cglib" rev="2.2.0" conf="test->runtime"/>
|
||||
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile, commons-logging->compile"/>
|
||||
<dependency org="org.aspectj" name="com.springsource.org.aspectj.weaver" rev="${aspectj.version}" conf="optional, aspectj->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.beans" rev="latest.integration" conf="test->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.transaction" rev="latest.integration" conf="optional, tx->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.orm" rev="latest.integration" conf="optional, orm->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.test" rev="latest.integration" conf="test->runtime"/>
|
||||
<dependency org="org.springframework" name="org.springframework.context" rev="latest.integration" conf="context->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.context.support" rev="latest.integration" conf="optional, cache->compile"/>
|
||||
<dependency org="javax.persistence" name="com.springsource.javax.persistence" rev="1.0.0" conf="optional, orm->compile"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->compile"/>
|
||||
<dependency org="org.hamcrest" name="com.springsource.org.hamcrest" rev="1.1.0" conf="test->compile"/>
|
||||
<dependency org="javax.mail" name="com.springsource.javax.mail" rev="1.4.0" conf="optional, test->compile"/>
|
||||
</dependencies>
|
||||
|
||||
</ivy-module>
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aspects</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>3.1.5.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>3.1.5.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<dependencies>
|
||||
<!-- common logging dependency is in spring-core -->
|
||||
<dependency>
|
||||
@@ -53,7 +61,7 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
|
||||
+54
-54
@@ -1,54 +1,54 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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;
|
||||
|
||||
/**
|
||||
* Generic-based dependency injection aspect.
|
||||
* <p>
|
||||
* This aspect allows users to implement efficient, type-safe dependency injection without
|
||||
* the use of the @Configurable annotation.
|
||||
*
|
||||
* The subaspect of this aspect doesn't need to include any AOP constructs.
|
||||
* For example, here is a subaspect that configures the <code>PricingStrategyClient</code> objects.
|
||||
* <pre>
|
||||
* aspect PricingStrategyDependencyInjectionAspect
|
||||
* extends GenericInterfaceDrivenDependencyInjectionAspect<PricingStrategyClient> {
|
||||
* private PricingStrategy pricingStrategy;
|
||||
*
|
||||
* public void configure(PricingStrategyClient bean) {
|
||||
* bean.setPricingStrategy(pricingStrategy);
|
||||
* }
|
||||
*
|
||||
* public void setPricingStrategy(PricingStrategy pricingStrategy) {
|
||||
* this.pricingStrategy = pricingStrategy;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* @author Ramnivas Laddad
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public abstract aspect GenericInterfaceDrivenDependencyInjectionAspect<I> extends AbstractInterfaceDrivenDependencyInjectionAspect {
|
||||
declare parents: I implements ConfigurableObject;
|
||||
|
||||
public pointcut inConfigurableBean() : within(I+);
|
||||
|
||||
public final void configureBean(Object bean) {
|
||||
configure((I)bean);
|
||||
}
|
||||
|
||||
// Unfortunately, erasure used with generics won't allow to use the same named method
|
||||
protected abstract void configure(I bean);
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2008 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;
|
||||
|
||||
/**
|
||||
* Generic-based dependency injection aspect.
|
||||
* <p>
|
||||
* This aspect allows users to implement efficient, type-safe dependency injection without
|
||||
* the use of the @Configurable annotation.
|
||||
*
|
||||
* The subaspect of this aspect doesn't need to include any AOP constructs.
|
||||
* For example, here is a subaspect that configures the <code>PricingStrategyClient</code> objects.
|
||||
* <pre>
|
||||
* aspect PricingStrategyDependencyInjectionAspect
|
||||
* extends GenericInterfaceDrivenDependencyInjectionAspect<PricingStrategyClient> {
|
||||
* private PricingStrategy pricingStrategy;
|
||||
*
|
||||
* public void configure(PricingStrategyClient bean) {
|
||||
* bean.setPricingStrategy(pricingStrategy);
|
||||
* }
|
||||
*
|
||||
* public void setPricingStrategy(PricingStrategy pricingStrategy) {
|
||||
* this.pricingStrategy = pricingStrategy;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* @author Ramnivas Laddad
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public abstract aspect GenericInterfaceDrivenDependencyInjectionAspect<I> extends AbstractInterfaceDrivenDependencyInjectionAspect {
|
||||
declare parents: I implements ConfigurableObject;
|
||||
|
||||
public pointcut inConfigurableBean() : within(I+);
|
||||
|
||||
public final void configureBean(Object bean) {
|
||||
configure((I)bean);
|
||||
}
|
||||
|
||||
// Unfortunately, erasure used with generics won't allow to use the same named method
|
||||
protected abstract void configure(I bean);
|
||||
}
|
||||
|
||||
Vendored
+73
-80
@@ -1,80 +1,73 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.cache.interceptor.CacheAspectSupport;
|
||||
import org.springframework.cache.interceptor.CacheOperationSource;
|
||||
import org.springframework.cache.interceptor.CacheAspectSupport.Invoker;
|
||||
|
||||
/**
|
||||
* Abstract superaspect for AspectJ cache aspects. Concrete
|
||||
* subaspects will implement the <code>cacheMethodExecution()</code>
|
||||
* pointcut using a strategy such as Java 5 annotations.
|
||||
*
|
||||
* <p>Suitable for use inside or outside the Spring IoC container.
|
||||
* Set the "cacheManager" property appropriately, allowing
|
||||
* use of any cache implementation supported by Spring.
|
||||
*
|
||||
* <p><b>NB:</b> If a method implements an interface that is itself
|
||||
* cache annotated, the relevant Spring cache definition
|
||||
* will <i>not</i> be resolved.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract aspect AbstractCacheAspect extends CacheAspectSupport {
|
||||
|
||||
protected AbstractCacheAspect() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct object using the given caching metadata retrieval strategy.
|
||||
* @param cos {@link CacheOperationSource} implementation, retrieving Spring
|
||||
* cache metadata for each joinpoint.
|
||||
*/
|
||||
protected AbstractCacheAspect(CacheOperationSource... cos) {
|
||||
setCacheOperationSources(cos);
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
Object around(final Object cachedObject) : cacheMethodExecution(cachedObject) {
|
||||
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
|
||||
Invoker aspectJInvoker = new Invoker() {
|
||||
public Object invoke() {
|
||||
return proceed(cachedObject);
|
||||
}
|
||||
};
|
||||
|
||||
return execute(aspectJInvoker, thisJoinPoint.getTarget(), method, thisJoinPoint.getArgs());
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete subaspects must implement this pointcut, to identify
|
||||
* cached methods. For each selected joinpoint, {@link CacheOperationDefinition}
|
||||
* will be retrieved using Spring's {@link CacheOperationSource} interface.
|
||||
*/
|
||||
protected abstract pointcut cacheMethodExecution(Object cachedObject);
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2011 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 org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.cache.interceptor.CacheAspectSupport;
|
||||
import org.springframework.cache.interceptor.CacheOperationSource;
|
||||
|
||||
/**
|
||||
* Abstract superaspect for AspectJ cache aspects. Concrete subaspects will implement the
|
||||
* {@link #cacheMethodExecution} pointcut using a strategy such as Java 5 annotations.
|
||||
*
|
||||
* <p>Suitable for use inside or outside the Spring IoC container. Set the
|
||||
* {@link #setCacheManager cacheManager} property appropriately, allowing use of any cache
|
||||
* implementation supported by Spring.
|
||||
*
|
||||
* <p><b>NB:</b> If a method implements an interface that is itself cache annotated, the
|
||||
* relevant Spring cache definition will <i>not</i> be resolved.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract aspect AbstractCacheAspect extends CacheAspectSupport {
|
||||
|
||||
protected AbstractCacheAspect() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct object using the given caching metadata retrieval strategy.
|
||||
* @param cos {@link CacheOperationSource} implementation, retrieving Spring cache
|
||||
* metadata for each joinpoint.
|
||||
*/
|
||||
protected AbstractCacheAspect(CacheOperationSource... cos) {
|
||||
setCacheOperationSources(cos);
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
Object around(final Object cachedObject) : cacheMethodExecution(cachedObject) {
|
||||
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
|
||||
Invoker aspectJInvoker = new Invoker() {
|
||||
public Object invoke() {
|
||||
return proceed(cachedObject);
|
||||
}
|
||||
};
|
||||
|
||||
return execute(aspectJInvoker, thisJoinPoint.getTarget(), method, thisJoinPoint.getArgs());
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete subaspects must implement this pointcut, to identify cached methods.
|
||||
*/
|
||||
protected abstract pointcut cacheMethodExecution(Object cachedObject);
|
||||
|
||||
}
|
||||
|
||||
org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AnnotationCacheAspect.aj
Vendored
+116
-87
@@ -1,87 +1,116 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.annotation.AnnotationCacheOperationSource;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
|
||||
/**
|
||||
* Concrete AspectJ cache aspect using Spring's {@link Cacheable} annotation.
|
||||
*
|
||||
* <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>A {@link Cacheable} annotation on a class specifies the default caching
|
||||
* semantics for the execution of any <b>public</b> operation in the class.
|
||||
*
|
||||
* <p>A {@link Cacheable} annotation on a method within the class overrides the
|
||||
* default caching semantics given by the class annotation (if present).
|
||||
* 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 Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public aspect AnnotationCacheAspect extends AbstractCacheAspect {
|
||||
|
||||
public AnnotationCacheAspect() {
|
||||
super(new AnnotationCacheOperationSource(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the
|
||||
* {@link Cacheable} annotation, or any subtype of a type with the
|
||||
* {@link Cacheable} annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtCacheableType() :
|
||||
execution(public * ((@Cacheable *)+).*(..)) && @this(Cacheable);
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the
|
||||
* {@link CacheEvict} annotation, or any subtype of a type with the
|
||||
* {@link CacheEvict} annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtCacheEvictType() :
|
||||
execution(public * ((@CacheEvict *)+).*(..)) && @this(CacheEvict);
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the
|
||||
* Cacheable annotation.
|
||||
*/
|
||||
private pointcut executionOfCacheableMethod() :
|
||||
execution(* *(..)) && @annotation(Cacheable);
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the {@link CacheEvict} annotation.
|
||||
*/
|
||||
private pointcut executionOfCacheEvictMethod() :
|
||||
execution(* *(..)) && @annotation(CacheEvict);
|
||||
|
||||
/**
|
||||
* Definition of pointcut from super aspect - matched join points
|
||||
* will have Spring cache management applied.
|
||||
*/
|
||||
protected pointcut cacheMethodExecution(Object cachedObject) :
|
||||
(executionOfAnyPublicMethodInAtCacheableType() || executionOfAnyPublicMethodInAtCacheEvictType()
|
||||
|| executionOfCacheableMethod() || executionOfCacheEvictMethod())
|
||||
&& this(cachedObject);
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2011 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.annotation.AnnotationCacheOperationSource;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.cache.annotation.Caching;
|
||||
|
||||
/**
|
||||
* Concrete AspectJ cache aspect using Spring's @{@link Cacheable} annotation.
|
||||
*
|
||||
* <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>A {@code @Cacheable} annotation on a class specifies the default caching semantics
|
||||
* for the execution of any <b>public</b> operation in the class.
|
||||
*
|
||||
* <p>A {@code @Cacheable} annotation on a method within the class overrides the default
|
||||
* caching semantics given by the class annotation (if present). 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 Costin Leau
|
||||
* @since 3.1
|
||||
*/
|
||||
public aspect AnnotationCacheAspect extends AbstractCacheAspect {
|
||||
|
||||
public AnnotationCacheAspect() {
|
||||
super(new AnnotationCacheOperationSource(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the @{@link Cacheable}
|
||||
* annotation, or any subtype of a type with the {@code @Cacheable} annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtCacheableType() :
|
||||
execution(public * ((@Cacheable *)+).*(..)) && within(@Cacheable *);
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the @{@link CacheEvict}
|
||||
* annotation, or any subtype of a type with the {@code CacheEvict} annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtCacheEvictType() :
|
||||
execution(public * ((@CacheEvict *)+).*(..)) && within(@CacheEvict *);
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the @{@link CachePut}
|
||||
* annotation, or any subtype of a type with the {@code CachePut} annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtCachePutType() :
|
||||
execution(public * ((@CachePut *)+).*(..)) && within(@CachePut *);
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the @{@link Caching}
|
||||
* annotation, or any subtype of a type with the {@code Caching} annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtCachingType() :
|
||||
execution(public * ((@Caching *)+).*(..)) && within(@Caching *);
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the @{@link Cacheable} annotation.
|
||||
*/
|
||||
private pointcut executionOfCacheableMethod() :
|
||||
execution(@Cacheable * *(..));
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the @{@link CacheEvict} annotation.
|
||||
*/
|
||||
private pointcut executionOfCacheEvictMethod() :
|
||||
execution(@CacheEvict * *(..));
|
||||
|
||||
/**
|
||||
* 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 Caching} annotation.
|
||||
*/
|
||||
private pointcut executionOfCachingMethod() :
|
||||
execution(@Caching * *(..));
|
||||
|
||||
/**
|
||||
* Definition of pointcut from super aspect - matched join points will have Spring
|
||||
* cache management applied.
|
||||
*/
|
||||
protected pointcut cacheMethodExecution(Object cachedObject) :
|
||||
(executionOfAnyPublicMethodInAtCacheableType()
|
||||
|| executionOfAnyPublicMethodInAtCacheEvictType()
|
||||
|| executionOfAnyPublicMethodInAtCachePutType()
|
||||
|| executionOfAnyPublicMethodInAtCachingType()
|
||||
|| executionOfCacheableMethod()
|
||||
|| executionOfCacheEvictMethod()
|
||||
|| executionOfCachePutMethod()
|
||||
|| executionOfCachingMethod())
|
||||
&& this(cachedObject);
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.annotation.AbstractCachingConfiguration;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
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.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see org.springframework.cache.annotation.EnableCaching
|
||||
* @see org.springframework.cache.annotation.CachingConfigurationSelector
|
||||
*/
|
||||
@Configuration
|
||||
public class AspectJCachingConfiguration extends AbstractCachingConfiguration {
|
||||
|
||||
@Bean(name=AnnotationConfigUtils.CACHE_ASPECT_BEAN_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public AnnotationCacheAspect cacheAspect() {
|
||||
AnnotationCacheAspect cacheAspect = AnnotationCacheAspect.aspectOf();
|
||||
if (this.cacheManager != null) {
|
||||
cacheAspect.setCacheManager(this.cacheManager);
|
||||
}
|
||||
if (this.keyGenerator != null) {
|
||||
cacheAspect.setKeyGenerator(this.keyGenerator);
|
||||
}
|
||||
return cacheAspect;
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.context.annotation.aspectj;
|
||||
|
||||
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;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* Signals the current application context to apply dependency injection to
|
||||
* non-managed classes that are instantiated outside of the Spring bean factory
|
||||
* (typically classes annotated with the @
|
||||
* {@link org.springframework.beans.factory.annotation.Configurable
|
||||
* Configurable} annotation).
|
||||
*
|
||||
* <p>Similar to functionality found in Spring's
|
||||
* {@code <context:spring-configured>} XML element. Often used in conjunction
|
||||
* with {@link org.springframework.context.annotation.EnableLoadTimeWeaving
|
||||
* @EnableLoadTimeWeaving}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see org.springframework.context.annotation.EnableLoadTimeWeaving
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import(SpringConfiguredConfiguration.class)
|
||||
public @interface EnableSpringConfigured {
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.context.annotation.aspectj;
|
||||
|
||||
import org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
|
||||
/**
|
||||
* {@code @Configuration} class that registers an {@link AnnotationBeanConfigurerAspect}
|
||||
* capable of performing dependency injection services for non-Spring managed objects
|
||||
* annotated with @{@link org.springframework.beans.factory.annotation.Configurable
|
||||
* Configurable}.
|
||||
*
|
||||
* <p>This configuration class is automatically imported when using the @{@link
|
||||
* EnableSpringConfigured} annotation. See {@code @EnableSpringConfigured} Javadoc for
|
||||
* complete usage details.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see EnableSpringConfigured
|
||||
*/
|
||||
@Configuration
|
||||
public class SpringConfiguredConfiguration {
|
||||
|
||||
public static final String BEAN_CONFIGURER_ASPECT_BEAN_NAME =
|
||||
"org.springframework.context.config.internalBeanConfigurerAspect";
|
||||
|
||||
@Bean(name=BEAN_CONFIGURER_ASPECT_BEAN_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public AnnotationBeanConfigurerAspect beanConfigurerAspect() {
|
||||
return AnnotationBeanConfigurerAspect.aspectOf();
|
||||
}
|
||||
}
|
||||
+197
-197
@@ -1,197 +1,197 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Abstract aspect to enable mocking of methods picked out by a pointcut.
|
||||
* Sub-aspects must define the mockStaticsTestMethod() pointcut to
|
||||
* indicate call stacks when mocking should be triggered, and the
|
||||
* methodToMock() pointcut to pick out a method invocations to mock.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*/
|
||||
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {
|
||||
|
||||
protected abstract pointcut mockStaticsTestMethod();
|
||||
|
||||
protected abstract pointcut methodToMock();
|
||||
|
||||
private boolean recording = true;
|
||||
|
||||
static enum CallResponse { nothing, return_, throw_ };
|
||||
|
||||
// Represents a list of expected calls to static entity methods
|
||||
// Public to allow inserted code to access: is this normal??
|
||||
public class Expectations {
|
||||
|
||||
// Represents an expected call to a static entity method
|
||||
private class Call {
|
||||
private final String signature;
|
||||
private final Object[] args;
|
||||
|
||||
private Object responseObject; // return value or throwable
|
||||
private CallResponse responseType = CallResponse.nothing;
|
||||
|
||||
public Call(String name, Object[] args) {
|
||||
this.signature = name;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public boolean hasResponseSpecified() {
|
||||
return responseType != CallResponse.nothing;
|
||||
}
|
||||
|
||||
public void setReturnVal(Object retVal) {
|
||||
this.responseObject = retVal;
|
||||
responseType = CallResponse.return_;
|
||||
}
|
||||
|
||||
public void setThrow(Throwable throwable) {
|
||||
this.responseObject = throwable;
|
||||
responseType = CallResponse.throw_;
|
||||
}
|
||||
|
||||
public Object returnValue(String lastSig, Object[] args) {
|
||||
checkSignature(lastSig, args);
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
public Object throwException(String lastSig, Object[] args) {
|
||||
checkSignature(lastSig, args);
|
||||
throw (RuntimeException)responseObject;
|
||||
}
|
||||
|
||||
private void checkSignature(String lastSig, Object[] args) {
|
||||
if (!signature.equals(lastSig)) {
|
||||
throw new IllegalArgumentException("Signature doesn't match");
|
||||
}
|
||||
if (!Arrays.equals(this.args, args)) {
|
||||
throw new IllegalArgumentException("Arguments don't match");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Call> calls = new LinkedList<Call>();
|
||||
|
||||
// Calls already verified
|
||||
private int verified;
|
||||
|
||||
public void verify() {
|
||||
if (verified != calls.size()) {
|
||||
throw new IllegalStateException("Expected " + calls.size()
|
||||
+ " calls, received " + verified);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the call and provide the expected return value
|
||||
* @param lastSig
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
public Object respond(String lastSig, Object[] args) {
|
||||
Call call = nextCall();
|
||||
CallResponse responseType = call.responseType;
|
||||
if (responseType == CallResponse.return_) {
|
||||
return call.returnValue(lastSig, args);
|
||||
} else if(responseType == CallResponse.throw_) {
|
||||
return (RuntimeException)call.throwException(lastSig, args);
|
||||
} else if(responseType == CallResponse.nothing) {
|
||||
// do nothing
|
||||
}
|
||||
throw new IllegalStateException("Behavior of " + call + " not specified");
|
||||
}
|
||||
|
||||
private Call nextCall() {
|
||||
if (verified > calls.size() - 1) {
|
||||
throw new IllegalStateException("Expected " + calls.size()
|
||||
+ " calls, received " + verified);
|
||||
}
|
||||
return calls.get(verified++);
|
||||
}
|
||||
|
||||
public void expectCall(String lastSig, Object lastArgs[]) {
|
||||
Call call = new Call(lastSig, lastArgs);
|
||||
calls.add(call);
|
||||
}
|
||||
|
||||
public boolean hasCalls() {
|
||||
return !calls.isEmpty();
|
||||
}
|
||||
|
||||
public void expectReturn(Object retVal) {
|
||||
Call call = calls.get(calls.size() - 1);
|
||||
if (call.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No static method invoked before setting return value");
|
||||
}
|
||||
call.setReturnVal(retVal);
|
||||
}
|
||||
|
||||
public void expectThrow(Throwable throwable) {
|
||||
Call call = calls.get(calls.size() - 1);
|
||||
if (call.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No static method invoked before setting throwable");
|
||||
}
|
||||
call.setThrow(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private Expectations expectations = new Expectations();
|
||||
|
||||
after() returning : mockStaticsTestMethod() {
|
||||
if (recording && (expectations.hasCalls())) {
|
||||
throw new IllegalStateException(
|
||||
"Calls recorded, yet playback state never reached: Create expectations then call "
|
||||
+ this.getClass().getSimpleName() + ".playback()");
|
||||
}
|
||||
expectations.verify();
|
||||
}
|
||||
|
||||
Object around() : methodToMock() && cflowbelow(mockStaticsTestMethod()) {
|
||||
if (recording) {
|
||||
expectations.expectCall(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
|
||||
// Return value doesn't matter
|
||||
return null;
|
||||
} else {
|
||||
return expectations.respond(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
|
||||
}
|
||||
}
|
||||
|
||||
public void expectReturnInternal(Object retVal) {
|
||||
if (!recording) {
|
||||
throw new IllegalStateException("Not recording: Cannot set return value");
|
||||
}
|
||||
expectations.expectReturn(retVal);
|
||||
}
|
||||
|
||||
public void expectThrowInternal(Throwable throwable) {
|
||||
if (!recording) {
|
||||
throw new IllegalStateException("Not recording: Cannot set throwable value");
|
||||
}
|
||||
expectations.expectThrow(throwable);
|
||||
}
|
||||
|
||||
public void playbackInternal() {
|
||||
recording = false;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Abstract aspect to enable mocking of methods picked out by a pointcut.
|
||||
* Sub-aspects must define the mockStaticsTestMethod() pointcut to
|
||||
* indicate call stacks when mocking should be triggered, and the
|
||||
* methodToMock() pointcut to pick out a method invocations to mock.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*/
|
||||
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {
|
||||
|
||||
protected abstract pointcut mockStaticsTestMethod();
|
||||
|
||||
protected abstract pointcut methodToMock();
|
||||
|
||||
private boolean recording = true;
|
||||
|
||||
static enum CallResponse { nothing, return_, throw_ };
|
||||
|
||||
// Represents a list of expected calls to static entity methods
|
||||
// Public to allow inserted code to access: is this normal??
|
||||
public class Expectations {
|
||||
|
||||
// Represents an expected call to a static entity method
|
||||
private class Call {
|
||||
private final String signature;
|
||||
private final Object[] args;
|
||||
|
||||
private Object responseObject; // return value or throwable
|
||||
private CallResponse responseType = CallResponse.nothing;
|
||||
|
||||
public Call(String name, Object[] args) {
|
||||
this.signature = name;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public boolean hasResponseSpecified() {
|
||||
return responseType != CallResponse.nothing;
|
||||
}
|
||||
|
||||
public void setReturnVal(Object retVal) {
|
||||
this.responseObject = retVal;
|
||||
responseType = CallResponse.return_;
|
||||
}
|
||||
|
||||
public void setThrow(Throwable throwable) {
|
||||
this.responseObject = throwable;
|
||||
responseType = CallResponse.throw_;
|
||||
}
|
||||
|
||||
public Object returnValue(String lastSig, Object[] args) {
|
||||
checkSignature(lastSig, args);
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
public Object throwException(String lastSig, Object[] args) {
|
||||
checkSignature(lastSig, args);
|
||||
throw (RuntimeException)responseObject;
|
||||
}
|
||||
|
||||
private void checkSignature(String lastSig, Object[] args) {
|
||||
if (!signature.equals(lastSig)) {
|
||||
throw new IllegalArgumentException("Signature doesn't match");
|
||||
}
|
||||
if (!Arrays.equals(this.args, args)) {
|
||||
throw new IllegalArgumentException("Arguments don't match");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Call> calls = new LinkedList<Call>();
|
||||
|
||||
// Calls already verified
|
||||
private int verified;
|
||||
|
||||
public void verify() {
|
||||
if (verified != calls.size()) {
|
||||
throw new IllegalStateException("Expected " + calls.size()
|
||||
+ " calls, received " + verified);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the call and provide the expected return value
|
||||
* @param lastSig
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
public Object respond(String lastSig, Object[] args) {
|
||||
Call call = nextCall();
|
||||
CallResponse responseType = call.responseType;
|
||||
if (responseType == CallResponse.return_) {
|
||||
return call.returnValue(lastSig, args);
|
||||
} else if(responseType == CallResponse.throw_) {
|
||||
return (RuntimeException)call.throwException(lastSig, args);
|
||||
} else if(responseType == CallResponse.nothing) {
|
||||
// do nothing
|
||||
}
|
||||
throw new IllegalStateException("Behavior of " + call + " not specified");
|
||||
}
|
||||
|
||||
private Call nextCall() {
|
||||
if (verified > calls.size() - 1) {
|
||||
throw new IllegalStateException("Expected " + calls.size()
|
||||
+ " calls, received " + verified);
|
||||
}
|
||||
return calls.get(verified++);
|
||||
}
|
||||
|
||||
public void expectCall(String lastSig, Object lastArgs[]) {
|
||||
Call call = new Call(lastSig, lastArgs);
|
||||
calls.add(call);
|
||||
}
|
||||
|
||||
public boolean hasCalls() {
|
||||
return !calls.isEmpty();
|
||||
}
|
||||
|
||||
public void expectReturn(Object retVal) {
|
||||
Call call = calls.get(calls.size() - 1);
|
||||
if (call.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No static method invoked before setting return value");
|
||||
}
|
||||
call.setReturnVal(retVal);
|
||||
}
|
||||
|
||||
public void expectThrow(Throwable throwable) {
|
||||
Call call = calls.get(calls.size() - 1);
|
||||
if (call.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No static method invoked before setting throwable");
|
||||
}
|
||||
call.setThrow(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private Expectations expectations = new Expectations();
|
||||
|
||||
after() returning : mockStaticsTestMethod() {
|
||||
if (recording && (expectations.hasCalls())) {
|
||||
throw new IllegalStateException(
|
||||
"Calls recorded, yet playback state never reached: Create expectations then call "
|
||||
+ this.getClass().getSimpleName() + ".playback()");
|
||||
}
|
||||
expectations.verify();
|
||||
}
|
||||
|
||||
Object around() : methodToMock() && cflowbelow(mockStaticsTestMethod()) {
|
||||
if (recording) {
|
||||
expectations.expectCall(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
|
||||
// Return value doesn't matter
|
||||
return null;
|
||||
} else {
|
||||
return expectations.respond(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
|
||||
}
|
||||
}
|
||||
|
||||
public void expectReturnInternal(Object retVal) {
|
||||
if (!recording) {
|
||||
throw new IllegalStateException("Not recording: Cannot set return value");
|
||||
}
|
||||
expectations.expectReturn(retVal);
|
||||
}
|
||||
|
||||
public void expectThrowInternal(Throwable throwable) {
|
||||
if (!recording) {
|
||||
throw new IllegalStateException("Not recording: Cannot set throwable value");
|
||||
}
|
||||
expectations.expectThrow(throwable);
|
||||
}
|
||||
|
||||
public void playbackInternal() {
|
||||
recording = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+68
-68
@@ -1,68 +1,68 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
/**
|
||||
* Annotation-based aspect to use in test build to enable mocking static methods
|
||||
* on JPA-annotated <code>@Entity</code> classes, as used by Roo for finders.
|
||||
*
|
||||
* <p>Mocking will occur in the call stack of any method in a class (typically a test class)
|
||||
* that is annotated with the @MockStaticEntityMethods annotation.
|
||||
*
|
||||
* <p>Also provides static methods to simplify the programming model for
|
||||
* entering playback mode and setting expected return values.
|
||||
*
|
||||
* <p>Usage:
|
||||
* <ol>
|
||||
* <li>Annotate a test class with @MockStaticEntityMethods.
|
||||
* <li>In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode.
|
||||
* Invoke static methods on Entity classes, with each recording-mode invocation
|
||||
* being followed by an invocation to the static expectReturn() or expectThrow()
|
||||
* method on AnnotationDrivenStaticEntityMockingControl.
|
||||
* <li>Invoke the static AnnotationDrivenStaticEntityMockingControl() method.
|
||||
* <li>Call the code you wish to test that uses the static methods. Verification will
|
||||
* occur automatically.
|
||||
* </ol>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @see MockStaticEntityMethods
|
||||
*/
|
||||
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
|
||||
|
||||
/**
|
||||
* Stop recording mock calls and enter playback state
|
||||
*/
|
||||
public static void playback() {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal();
|
||||
}
|
||||
|
||||
public static void expectReturn(Object retVal) {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectReturnInternal(retVal);
|
||||
}
|
||||
|
||||
public static void expectThrow(Throwable throwable) {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectThrowInternal(throwable);
|
||||
}
|
||||
|
||||
// Only matches directly annotated @Test methods, to allow methods in
|
||||
// @MockStatics classes to invoke each other without resetting the mocking environment
|
||||
protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..));
|
||||
|
||||
protected pointcut methodToMock() : execution(public static * (@javax.persistence.Entity *).*(..));
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
/**
|
||||
* Annotation-based aspect to use in test build to enable mocking static methods
|
||||
* on JPA-annotated <code>@Entity</code> classes, as used by Roo for finders.
|
||||
*
|
||||
* <p>Mocking will occur in the call stack of any method in a class (typically a test class)
|
||||
* that is annotated with the @MockStaticEntityMethods annotation.
|
||||
*
|
||||
* <p>Also provides static methods to simplify the programming model for
|
||||
* entering playback mode and setting expected return values.
|
||||
*
|
||||
* <p>Usage:
|
||||
* <ol>
|
||||
* <li>Annotate a test class with @MockStaticEntityMethods.
|
||||
* <li>In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode.
|
||||
* Invoke static methods on Entity classes, with each recording-mode invocation
|
||||
* being followed by an invocation to the static expectReturn() or expectThrow()
|
||||
* method on AnnotationDrivenStaticEntityMockingControl.
|
||||
* <li>Invoke the static AnnotationDrivenStaticEntityMockingControl() method.
|
||||
* <li>Call the code you wish to test that uses the static methods. Verification will
|
||||
* occur automatically.
|
||||
* </ol>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @see MockStaticEntityMethods
|
||||
*/
|
||||
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
|
||||
|
||||
/**
|
||||
* Stop recording mock calls and enter playback state
|
||||
*/
|
||||
public static void playback() {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal();
|
||||
}
|
||||
|
||||
public static void expectReturn(Object retVal) {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectReturnInternal(retVal);
|
||||
}
|
||||
|
||||
public static void expectThrow(Throwable throwable) {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectThrowInternal(throwable);
|
||||
}
|
||||
|
||||
// Only matches directly annotated @Test methods, to allow methods in
|
||||
// @MockStatics classes to invoke each other without resetting the mocking environment
|
||||
protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..));
|
||||
|
||||
protected pointcut methodToMock() : execution(public static * (@javax.persistence.Entity *).*(..));
|
||||
|
||||
}
|
||||
|
||||
+34
-34
@@ -1,34 +1,34 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to indicate a test class for whose @Test methods
|
||||
* static methods on Entity classes should be mocked.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @see AbstractMethodMockingControl
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface MockStaticEntityMethods {
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to indicate a test class for whose @Test methods
|
||||
* static methods on Entity classes should be mocked.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @see AbstractMethodMockingControl
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface MockStaticEntityMethods {
|
||||
|
||||
}
|
||||
|
||||
+86
-75
@@ -1,75 +1,86 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.scheduling.aspectj;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.support.TaskExecutorAdapter;
|
||||
|
||||
/**
|
||||
* Abstract aspect that routes selected methods asynchronously.
|
||||
*
|
||||
* <p>This aspect needs to be injected with an implementation of
|
||||
* {@link Executor} to activate it for a specific thread pool.
|
||||
* Otherwise it will simply delegate all calls synchronously.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0.5
|
||||
*/
|
||||
public abstract aspect AbstractAsyncExecutionAspect {
|
||||
|
||||
private AsyncTaskExecutor asyncExecutor;
|
||||
|
||||
public void setExecutor(Executor executor) {
|
||||
if (executor instanceof AsyncTaskExecutor) {
|
||||
this.asyncExecutor = (AsyncTaskExecutor) executor;
|
||||
}
|
||||
else {
|
||||
this.asyncExecutor = new TaskExecutorAdapter(asyncExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
Object around() : asyncMethod() {
|
||||
if (this.asyncExecutor == null) {
|
||||
return proceed();
|
||||
}
|
||||
Callable<Object> callable = new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
Object result = proceed();
|
||||
if (result instanceof Future) {
|
||||
return ((Future<?>) result).get();
|
||||
}
|
||||
return null;
|
||||
}};
|
||||
Future<?> result = this.asyncExecutor.submit(callable);
|
||||
if (Future.class.isAssignableFrom(((MethodSignature) thisJoinPointStaticPart.getSignature()).getReturnType())) {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract pointcut asyncMethod();
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.scheduling.aspectj;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
|
||||
import org.springframework.aop.interceptor.AsyncExecutionAspectSupport;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
|
||||
/**
|
||||
* Abstract aspect that routes selected methods asynchronously.
|
||||
*
|
||||
* <p>This aspect needs to be injected with an implementation of
|
||||
* {@link Executor} to activate it for a specific thread pool.
|
||||
* Otherwise it will simply delegate all calls synchronously.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 3.0.5
|
||||
*/
|
||||
public abstract aspect AbstractAsyncExecutionAspect extends AsyncExecutionAspectSupport {
|
||||
|
||||
/**
|
||||
* Create an {@code AnnotationAsyncExecutionAspect} with a {@code null} default
|
||||
* executor, which should instead be set via {@code #aspectOf} and
|
||||
* {@link #setExecutor(Executor)}.
|
||||
*/
|
||||
public AbstractAsyncExecutionAspect() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply around advice to methods matching the {@link #asyncMethod()} pointcut,
|
||||
* submit the actual calling of the method to the correct task executor and return
|
||||
* immediately to the caller.
|
||||
* @return {@link Future} if the original method returns {@code Future}; {@code null}
|
||||
* otherwise.
|
||||
*/
|
||||
Object around() : asyncMethod() {
|
||||
MethodSignature methodSignature = (MethodSignature) thisJoinPointStaticPart.getSignature();
|
||||
AsyncTaskExecutor executor = determineAsyncExecutor(methodSignature.getMethod());
|
||||
if (executor == null) {
|
||||
return proceed();
|
||||
}
|
||||
Callable<Object> callable = new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
Object result = proceed();
|
||||
if (result instanceof Future) {
|
||||
return ((Future<?>) result).get();
|
||||
}
|
||||
return null;
|
||||
}};
|
||||
Future<?> result = executor.submit(callable);
|
||||
if (Future.class.isAssignableFrom(methodSignature.getReturnType())) {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of joinpoints at which async advice should be applied.
|
||||
*/
|
||||
public abstract pointcut asyncMethod();
|
||||
|
||||
}
|
||||
|
||||
+82
-54
@@ -1,54 +1,82 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.scheduling.aspectj;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
/**
|
||||
* Aspect to route methods based on the {@link Async} annotation.
|
||||
*
|
||||
* <p>This aspect routes methods marked with the {@link Async} annotation
|
||||
* as well as methods in classes marked with the same. Any method expected
|
||||
* to be routed asynchronously must return either void, {@link Future},
|
||||
* or a subtype of {@link Future}. This aspect, therefore, will produce
|
||||
* a compile-time error for methods that violate this constraint on the return type.
|
||||
* If, however, a class marked with <code>@Async</code> contains a method that
|
||||
* violates this constraint, it produces only a warning.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @since 3.0.5
|
||||
*/
|
||||
public aspect AnnotationAsyncExecutionAspect extends AbstractAsyncExecutionAspect {
|
||||
|
||||
private pointcut asyncMarkedMethod()
|
||||
: execution(@Async (void || Future+) *(..));
|
||||
|
||||
private pointcut asyncTypeMarkedMethod()
|
||||
: execution((void || Future+) (@Async *).*(..));
|
||||
|
||||
public pointcut asyncMethod() : asyncMarkedMethod() || asyncTypeMarkedMethod();
|
||||
|
||||
declare error:
|
||||
execution(@Async !(void||Future) *(..)):
|
||||
"Only methods that return void or Future may have an @Async annotation";
|
||||
|
||||
declare warning:
|
||||
execution(!(void||Future) (@Async *).*(..)):
|
||||
"Methods in a class marked with @Async that do not return void or Future will be routed synchronously";
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.scheduling.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
/**
|
||||
* Aspect to route methods based on the {@link Async} annotation.
|
||||
*
|
||||
* <p>This aspect routes methods marked with the {@link Async} annotation
|
||||
* as well as methods in classes marked with the same. Any method expected
|
||||
* to be routed asynchronously must return either {@code void}, {@link Future},
|
||||
* or a subtype of {@link Future}. This aspect, therefore, will produce
|
||||
* a compile-time error for methods that violate this constraint on the return type.
|
||||
* If, however, a class marked with {@code @Async} contains a method that violates this
|
||||
* constraint, it produces only a warning.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @author Chris Beams
|
||||
* @since 3.0.5
|
||||
*/
|
||||
public aspect AnnotationAsyncExecutionAspect extends AbstractAsyncExecutionAspect {
|
||||
|
||||
private pointcut asyncMarkedMethod()
|
||||
: execution(@Async (void || Future+) *(..));
|
||||
|
||||
private pointcut asyncTypeMarkedMethod()
|
||||
: execution((void || Future+) (@Async *).*(..));
|
||||
|
||||
public pointcut asyncMethod() : asyncMarkedMethod() || asyncTypeMarkedMethod();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>This implementation inspects the given method and its declaring class for the
|
||||
* {@code @Async} annotation, returning the qualifier value expressed by
|
||||
* {@link Async#value()}. If {@code @Async} is specified at both the method and class level, the
|
||||
* method's {@code #value} takes precedence (even if empty string, indicating that
|
||||
* the default executor should be used preferentially).
|
||||
* @return the qualifier if specified, otherwise empty string indicating that the
|
||||
* {@linkplain #setExecutor(Executor) default executor} should be used
|
||||
* @see #determineAsyncExecutor(Method)
|
||||
*/
|
||||
@Override
|
||||
protected String getExecutorQualifier(Method method) {
|
||||
// maintainer's note: changes made here should also be made in
|
||||
// AnnotationAsyncExecutionInterceptor#getExecutorQualifier
|
||||
Async async = AnnotationUtils.findAnnotation(method, Async.class);
|
||||
if (async == null) {
|
||||
async = AnnotationUtils.findAnnotation(method.getDeclaringClass(), Async.class);
|
||||
}
|
||||
return async == null ? null : async.value();
|
||||
}
|
||||
|
||||
declare error:
|
||||
execution(@Async !(void||Future) *(..)):
|
||||
"Only methods that return void or Future may have an @Async annotation";
|
||||
|
||||
declare warning:
|
||||
execution(!(void||Future) (@Async *).*(..)):
|
||||
"Methods in a class marked with @Async that do not return void or Future will " +
|
||||
"be routed synchronously";
|
||||
|
||||
}
|
||||
|
||||
+93
-93
@@ -1,93 +1,93 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.transaction.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.transaction.interceptor.TransactionAttributeSource;
|
||||
|
||||
/**
|
||||
* Abstract superaspect for AspectJ transaction aspects. Concrete
|
||||
* subaspects will implement the <code>transactionalMethodExecution()</code>
|
||||
* pointcut using a strategy such as Java 5 annotations.
|
||||
*
|
||||
* <p>Suitable for use inside or outside the Spring IoC container.
|
||||
* Set the "transactionManager" property appropriately, allowing
|
||||
* use of any transaction implementation supported by Spring.
|
||||
*
|
||||
* <p><b>NB:</b> If a method implements an interface that is itself
|
||||
* transactionally annotated, the relevant Spring transaction attribute
|
||||
* will <i>not</i> be resolved. This behavior will vary from that of Spring AOP
|
||||
* if proxying an interface (but not when proxying a class). We recommend that
|
||||
* transaction annotations should be added to classes, rather than business
|
||||
* interfaces, as they are an implementation detail rather than a contract
|
||||
* specification validation.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport {
|
||||
|
||||
/**
|
||||
* Construct object using the given transaction metadata retrieval strategy.
|
||||
* @param tas TransactionAttributeSource implementation, retrieving Spring
|
||||
* transaction metadata for each joinpoint. Write the subclass to pass in null
|
||||
* if it's intended to be configured by Setter Injection.
|
||||
*/
|
||||
protected AbstractTransactionAspect(TransactionAttributeSource tas) {
|
||||
setTransactionAttributeSource(tas);
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
before(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
TransactionInfo txInfo = createTransactionIfNecessary(method, txObject.getClass());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) throwing(Throwable t) : transactionalMethodExecution(txObject) {
|
||||
try {
|
||||
completeTransactionAfterThrowing(TransactionAspectSupport.currentTransactionInfo(), t);
|
||||
}
|
||||
catch (Throwable t2) {
|
||||
logger.error("Failed to close transaction after throwing in a transactional method", t2);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) returning() : transactionalMethodExecution(txObject) {
|
||||
commitTransactionAfterReturning(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
cleanupTransactionInfo(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete subaspects must implement this pointcut, to identify
|
||||
* transactional methods. For each selected joinpoint, TransactionMetadata
|
||||
* will be retrieved using Spring's TransactionAttributeSource interface.
|
||||
*/
|
||||
protected abstract pointcut transactionalMethodExecution(Object txObject);
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 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.transaction.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.transaction.interceptor.TransactionAttributeSource;
|
||||
|
||||
/**
|
||||
* Abstract superaspect for AspectJ transaction aspects. Concrete
|
||||
* subaspects will implement the <code>transactionalMethodExecution()</code>
|
||||
* pointcut using a strategy such as Java 5 annotations.
|
||||
*
|
||||
* <p>Suitable for use inside or outside the Spring IoC container.
|
||||
* Set the "transactionManager" property appropriately, allowing
|
||||
* use of any transaction implementation supported by Spring.
|
||||
*
|
||||
* <p><b>NB:</b> If a method implements an interface that is itself
|
||||
* transactionally annotated, the relevant Spring transaction attribute
|
||||
* will <i>not</i> be resolved. This behavior will vary from that of Spring AOP
|
||||
* if proxying an interface (but not when proxying a class). We recommend that
|
||||
* transaction annotations should be added to classes, rather than business
|
||||
* interfaces, as they are an implementation detail rather than a contract
|
||||
* specification validation.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport {
|
||||
|
||||
/**
|
||||
* Construct object using the given transaction metadata retrieval strategy.
|
||||
* @param tas TransactionAttributeSource implementation, retrieving Spring
|
||||
* transaction metadata for each joinpoint. Write the subclass to pass in null
|
||||
* if it's intended to be configured by Setter Injection.
|
||||
*/
|
||||
protected AbstractTransactionAspect(TransactionAttributeSource tas) {
|
||||
setTransactionAttributeSource(tas);
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
before(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
TransactionInfo txInfo = createTransactionIfNecessary(method, txObject.getClass());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) throwing(Throwable t) : transactionalMethodExecution(txObject) {
|
||||
try {
|
||||
completeTransactionAfterThrowing(TransactionAspectSupport.currentTransactionInfo(), t);
|
||||
}
|
||||
catch (Throwable t2) {
|
||||
logger.error("Failed to close transaction after throwing in a transactional method", t2);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) returning() : transactionalMethodExecution(txObject) {
|
||||
commitTransactionAfterReturning(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
cleanupTransactionInfo(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete subaspects must implement this pointcut, to identify
|
||||
* transactional methods. For each selected joinpoint, TransactionMetadata
|
||||
* will be retrieved using Spring's TransactionAttributeSource interface.
|
||||
*/
|
||||
protected abstract pointcut transactionalMethodExecution(Object txObject);
|
||||
|
||||
}
|
||||
|
||||
+75
-75
@@ -1,75 +1,75 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Concrete AspectJ transaction aspect using Spring's @Transactional annotation.
|
||||
*
|
||||
* <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>A @Transactional annotation on a class specifies the default transaction
|
||||
* semantics for the execution of any <b>public</b> operation in the class.
|
||||
*
|
||||
* <p>A @Transactional annotation on a method within the class overrides the
|
||||
* default transaction semantics given by the class annotation (if present).
|
||||
* Any method may be annotated (regardless of visibility).
|
||||
* Annotating non-public methods directly is the only way
|
||||
* to get transaction demarcation for the execution of such operations.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
*/
|
||||
public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {
|
||||
|
||||
public AnnotationTransactionAspect() {
|
||||
super(new AnnotationTransactionAttributeSource(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the
|
||||
* Transactional annotation, or any subtype of a type with the
|
||||
* Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
|
||||
execution(public * ((@Transactional *)+).*(..)) && @this(Transactional);
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the
|
||||
* Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfTransactionalMethod() :
|
||||
execution(* *(..)) && @annotation(Transactional);
|
||||
|
||||
/**
|
||||
* Definition of pointcut from super aspect - matched join points
|
||||
* will have Spring transaction management applied.
|
||||
*/
|
||||
protected pointcut transactionalMethodExecution(Object txObject) :
|
||||
(executionOfAnyPublicMethodInAtTransactionalType()
|
||||
|| executionOfTransactionalMethod() )
|
||||
&& this(txObject);
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 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.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Concrete AspectJ transaction aspect using Spring's @Transactional annotation.
|
||||
*
|
||||
* <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>An @Transactional annotation on a class specifies the default transaction
|
||||
* semantics for the execution of any <b>public</b> operation in the class.
|
||||
*
|
||||
* <p>An @Transactional annotation on a method within the class overrides the
|
||||
* default transaction semantics given by the class annotation (if present).
|
||||
* Any method may be annotated (regardless of visibility).
|
||||
* Annotating non-public methods directly is the only way
|
||||
* to get transaction demarcation for the execution of such operations.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
*/
|
||||
public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {
|
||||
|
||||
public AnnotationTransactionAspect() {
|
||||
super(new AnnotationTransactionAttributeSource(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the
|
||||
* Transactional annotation, or any subtype of a type with the
|
||||
* Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
|
||||
execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *);
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the
|
||||
* Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfTransactionalMethod() :
|
||||
execution(@Transactional * *(..));
|
||||
|
||||
/**
|
||||
* Definition of pointcut from super aspect - matched join points
|
||||
* will have Spring transaction management applied.
|
||||
*/
|
||||
protected pointcut transactionalMethodExecution(Object txObject) :
|
||||
(executionOfAnyPublicMethodInAtTransactionalType()
|
||||
|| executionOfTransactionalMethod() )
|
||||
&& this(txObject);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
The Spring Data Binding framework, an internal library used by Spring Web Flow.
|
||||
</p>
|
||||
</body>
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
The Spring Data Binding framework, an internal library used by Spring Web Flow.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,18 +1,19 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
AspectJ load-time weaving config file to install common Spring aspects.
|
||||
-->
|
||||
<aspectj>
|
||||
|
||||
<!--
|
||||
<weaver options="-showWeaveInfo"/>
|
||||
-->
|
||||
|
||||
<aspects>
|
||||
<aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/>
|
||||
<aspect name="org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect"/>
|
||||
<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
|
||||
</aspects>
|
||||
|
||||
</aspectj>
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
AspectJ load-time weaving config file to install common Spring aspects.
|
||||
-->
|
||||
<aspectj>
|
||||
|
||||
<!--
|
||||
<weaver options="-showWeaveInfo"/>
|
||||
-->
|
||||
|
||||
<aspects>
|
||||
<aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/>
|
||||
<aspect name="org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect"/>
|
||||
<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
|
||||
<aspect name="org.springframework.cache.aspectj.AnnotationCacheAspect"/>
|
||||
</aspects>
|
||||
|
||||
</aspectj>
|
||||
|
||||
+32
-32
@@ -1,32 +1,32 @@
|
||||
/*
|
||||
* Copyright 2002-2007 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.aspectj.autoproxy;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
*/
|
||||
public class AutoProxyWithCodeStyleAspectsTests extends TestCase {
|
||||
|
||||
public void testNoAutoproxyingOfAjcCompiledAspects() {
|
||||
new ClassPathXmlApplicationContext("org/springframework/aop/aspectj/autoproxy/ajcAutoproxyTests.xml");
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2007 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.aspectj.autoproxy;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
*/
|
||||
public class AutoProxyWithCodeStyleAspectsTests extends TestCase {
|
||||
|
||||
public void testNoAutoproxyingOfAjcCompiledAspects() {
|
||||
new ClassPathXmlApplicationContext("org/springframework/aop/aspectj/autoproxy/ajcAutoproxyTests.xml");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+36
-36
@@ -1,36 +1,36 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.aspectj.autoproxy;
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
*/
|
||||
public aspect CodeStyleAspect {
|
||||
|
||||
private String foo;
|
||||
|
||||
pointcut somePC() : call(* someMethod());
|
||||
|
||||
before() : somePC() {
|
||||
System.out.println("match");
|
||||
}
|
||||
|
||||
public void setFoo(String foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 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.aspectj.autoproxy;
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
*/
|
||||
public aspect CodeStyleAspect {
|
||||
|
||||
private String foo;
|
||||
|
||||
pointcut somePC() : call(* someMethod());
|
||||
|
||||
before() : somePC() {
|
||||
System.out.println("match");
|
||||
}
|
||||
|
||||
public void setFoo(String foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+17
-17
@@ -1,17 +1,17 @@
|
||||
<?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"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
|
||||
|
||||
<aop:aspectj-autoproxy/>
|
||||
|
||||
<bean id="myAspect" class="org.springframework.aop.aspectj.autoproxy.CodeStyleAspect"
|
||||
factory-method="aspectOf">
|
||||
<property name="foo" value="bar"/>
|
||||
</bean>
|
||||
|
||||
<bean id="otherBean" class="java.lang.Object"/>
|
||||
|
||||
</beans>
|
||||
<?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"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
|
||||
|
||||
<aop:aspectj-autoproxy/>
|
||||
|
||||
<bean id="myAspect" class="org.springframework.aop.aspectj.autoproxy.CodeStyleAspect"
|
||||
factory-method="aspectOf">
|
||||
<property name="foo" value="bar"/>
|
||||
</bean>
|
||||
|
||||
<bean id="otherBean" class="java.lang.Object"/>
|
||||
|
||||
</beans>
|
||||
|
||||
+652
-657
File diff suppressed because it is too large
Load Diff
+32
-32
@@ -1,33 +1,33 @@
|
||||
/*
|
||||
* Copyright 2002-2006 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.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class SpringConfiguredWithAutoProxyingTests extends TestCase {
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
new ClassPathXmlApplicationContext("org/springframework/beans/factory/aspectj/springConfigured.xml");
|
||||
}
|
||||
|
||||
public void testSpringConfiguredAndAutoProxyUsedTogether() {
|
||||
; // set up is sufficient to trigger failure if this is going to fail...
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2006 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.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class SpringConfiguredWithAutoProxyingTests extends TestCase {
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
new ClassPathXmlApplicationContext("org/springframework/beans/factory/aspectj/springConfigured.xml");
|
||||
}
|
||||
|
||||
public void testSpringConfiguredAndAutoProxyUsedTogether() {
|
||||
; // set up is sufficient to trigger failure if this is going to fail...
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class XmlBeanConfigurerTests extends AbstractBeanConfigurerTests {
|
||||
|
||||
@Override
|
||||
protected ConfigurableApplicationContext createContext() {
|
||||
return new ClassPathXmlApplicationContext("org/springframework/beans/factory/aspectj/beanConfigurerTests.xml");
|
||||
}
|
||||
|
||||
public void testInjectionAfterRefresh() {
|
||||
context.refresh();
|
||||
ShouldBeConfiguredBySpring myObject = new ShouldBeConfiguredBySpring();
|
||||
assertEquals("Rod", myObject.getName());
|
||||
}
|
||||
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
<?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">
|
||||
|
||||
<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">
|
||||
<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.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>
|
||||
+14
-68
@@ -1,68 +1,14 @@
|
||||
<?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">
|
||||
|
||||
<context:spring-configured/>
|
||||
|
||||
<context:annotation-config/>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$WireArbitraryExistingPojo"
|
||||
factory-method="aspectOf"/>
|
||||
|
||||
<bean id="beanOne" class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$ShouldBeConfiguredBySpring"
|
||||
lazy-init="true">
|
||||
<property name="name" value="Rod"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$ShouldBeConfiguredBySpringUsingTypeNameAsBeanName"
|
||||
lazy-init="true">
|
||||
<property name="name" value="Rob"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$SubBean"
|
||||
lazy-init="true">
|
||||
<property name="name" value="Ramnivas"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$SubBeanPreConstruction"
|
||||
lazy-init="true">
|
||||
<property name="name" value="Ramnivas"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$SubSerializableBean"
|
||||
lazy-init="true">
|
||||
<property name="name" value="Ramnivas"/>
|
||||
</bean>
|
||||
|
||||
<bean id="circular" class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$CircularFactoryBean"
|
||||
autowire-candidate="false"/>
|
||||
|
||||
<!-- Used as a target for autowiring by type -->
|
||||
<bean id="ramnivas" class="org.springframework.beans.TestBean" depends-on="circular">
|
||||
<property name="name" value="Ramnivas"/>
|
||||
<property name="spouse" ref="circular"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$ArbitraryExistingPojo">
|
||||
<property name="friend" ref="ramnivas"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$PreConstructionConfiguredBean">
|
||||
<property name="name" value="ramnivas"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$PostConstructionConfiguredBean">
|
||||
<property name="name" value="ramnivas"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$GenericParameterConfigurableBean" scope="prototype">
|
||||
<property name="testService" ref="testService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="testService" class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$TestService"/>
|
||||
<bean id="paymentService" class="org.springframework.beans.factory.aspectj.BeanConfigurerTests$PaymentService"/>
|
||||
|
||||
</beans>
|
||||
<?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">
|
||||
|
||||
<context:spring-configured/>
|
||||
|
||||
<context:annotation-config/>
|
||||
|
||||
<import resource="beanConfigurerTests-beans.xml"/>
|
||||
|
||||
</beans>
|
||||
|
||||
+14
-14
@@ -1,14 +1,14 @@
|
||||
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
|
||||
|
||||
<context:spring-configured/>
|
||||
|
||||
<aop:aspectj-autoproxy/>
|
||||
|
||||
</beans>
|
||||
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
|
||||
|
||||
<context:spring-configured/>
|
||||
|
||||
<aop:aspectj-autoproxy/>
|
||||
|
||||
</beans>
|
||||
|
||||
+595
-170
@@ -1,171 +1,596 @@
|
||||
/*
|
||||
* Copyright 2010 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 static org.junit.Assert.*;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cache.config.CacheableService;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* Abstract annotation test (containing several reusable methods).
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public abstract class AbstractAnnotationTest {
|
||||
|
||||
protected ApplicationContext ctx;
|
||||
|
||||
protected CacheableService cs;
|
||||
|
||||
protected CacheableService ccs;
|
||||
|
||||
protected abstract String getConfig();
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
ctx = new ClassPathXmlApplicationContext(getConfig());
|
||||
cs = ctx.getBean("service", CacheableService.class);
|
||||
ccs = ctx.getBean("classService", CacheableService.class);
|
||||
}
|
||||
|
||||
public void testCacheable(CacheableService service) throws Exception {
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
|
||||
Object r1 = service.cache(o1);
|
||||
Object r2 = service.cache(o1);
|
||||
Object r3 = service.cache(o1);
|
||||
|
||||
assertSame(r1, r2);
|
||||
assertSame(r1, r3);
|
||||
}
|
||||
|
||||
public void testInvalidate(CacheableService service) throws Exception {
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
|
||||
Object r1 = service.cache(o1);
|
||||
Object r2 = service.cache(o1);
|
||||
|
||||
assertSame(r1, r2);
|
||||
service.invalidate(o1);
|
||||
Object r3 = service.cache(o1);
|
||||
Object r4 = service.cache(o1);
|
||||
assertNotSame(r1, r3);
|
||||
assertSame(r3, r4);
|
||||
}
|
||||
|
||||
public void testConditionalExpression(CacheableService service) throws Exception {
|
||||
Object r1 = service.conditional(4);
|
||||
Object r2 = service.conditional(4);
|
||||
|
||||
assertNotSame(r1, r2);
|
||||
|
||||
Object r3 = service.conditional(3);
|
||||
Object r4 = service.conditional(3);
|
||||
|
||||
assertSame(r3, r4);
|
||||
}
|
||||
|
||||
public void testKeyExpression(CacheableService service) throws Exception {
|
||||
Object r1 = service.key(5, 1);
|
||||
Object r2 = service.key(5, 2);
|
||||
|
||||
assertSame(r1, r2);
|
||||
|
||||
Object r3 = service.key(1, 5);
|
||||
Object r4 = service.key(2, 5);
|
||||
|
||||
assertNotSame(r3, r4);
|
||||
}
|
||||
|
||||
public void testCheckedThrowable(CacheableService service) throws Exception {
|
||||
String arg = UUID.randomUUID().toString();
|
||||
try {
|
||||
service.throwChecked(arg);
|
||||
fail("Excepted exception");
|
||||
} catch (Exception ex) {
|
||||
assertEquals(arg, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testUncheckedThrowable(CacheableService service) throws Exception {
|
||||
try {
|
||||
service.throwUnchecked(Long.valueOf(1));
|
||||
fail("Excepted exception");
|
||||
} catch (RuntimeException ex) {
|
||||
assertTrue(ex instanceof UnsupportedOperationException);
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheable() throws Exception {
|
||||
testCacheable(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidate() throws Exception {
|
||||
testInvalidate(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConditionalExpression() throws Exception {
|
||||
testConditionalExpression(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyExpression() throws Exception {
|
||||
testKeyExpression(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassCacheCacheable() throws Exception {
|
||||
testCacheable(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassCacheInvalidate() throws Exception {
|
||||
testInvalidate(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckedException() throws Exception {
|
||||
testCheckedThrowable(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassCheckedException() throws Exception {
|
||||
testCheckedThrowable(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUncheckedException() throws Exception {
|
||||
testUncheckedThrowable(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassUncheckedException() throws Exception {
|
||||
testUncheckedThrowable(ccs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright 2010-2011 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 static org.junit.Assert.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.config.AnnotatedClassCacheableService;
|
||||
import org.springframework.cache.config.CacheableService;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Abstract annotation test (containing several reusable methods).
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public abstract class AbstractAnnotationTest {
|
||||
|
||||
protected ApplicationContext ctx;
|
||||
|
||||
protected CacheableService<?> cs;
|
||||
|
||||
protected CacheableService<?> ccs;
|
||||
|
||||
protected CacheManager cm;
|
||||
|
||||
/** @return a refreshed application context */
|
||||
protected abstract ApplicationContext getApplicationContext();
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
ctx = getApplicationContext();
|
||||
cs = ctx.getBean("service", CacheableService.class);
|
||||
ccs = ctx.getBean("classService", CacheableService.class);
|
||||
cm = ctx.getBean(CacheManager.class);
|
||||
Collection<String> cn = cm.getCacheNames();
|
||||
assertTrue(cn.contains("default"));
|
||||
}
|
||||
|
||||
public void testCacheable(CacheableService<?> service) throws Exception {
|
||||
Object o1 = new Object();
|
||||
|
||||
Object r1 = service.cache(o1);
|
||||
Object r2 = service.cache(o1);
|
||||
Object r3 = service.cache(o1);
|
||||
|
||||
assertSame(r1, r2);
|
||||
assertSame(r1, r3);
|
||||
}
|
||||
|
||||
public void testEvict(CacheableService<?> service) throws Exception {
|
||||
Object o1 = new Object();
|
||||
|
||||
Object r1 = service.cache(o1);
|
||||
Object r2 = service.cache(o1);
|
||||
|
||||
assertSame(r1, r2);
|
||||
service.invalidate(o1);
|
||||
Object r3 = service.cache(o1);
|
||||
Object r4 = service.cache(o1);
|
||||
assertNotSame(r1, r3);
|
||||
assertSame(r3, r4);
|
||||
}
|
||||
|
||||
public void testEvictEarly(CacheableService<?> service) throws Exception {
|
||||
Object o1 = new Object();
|
||||
|
||||
Object r1 = service.cache(o1);
|
||||
Object r2 = service.cache(o1);
|
||||
|
||||
assertSame(r1, r2);
|
||||
try {
|
||||
service.evictEarly(o1);
|
||||
} catch (RuntimeException ex) {
|
||||
// expected
|
||||
}
|
||||
|
||||
Object r3 = service.cache(o1);
|
||||
Object r4 = service.cache(o1);
|
||||
assertNotSame(r1, r3);
|
||||
assertSame(r3, r4);
|
||||
}
|
||||
|
||||
public void testEvictException(CacheableService<?> service) throws Exception {
|
||||
Object o1 = new Object();
|
||||
|
||||
Object r1 = service.cache(o1);
|
||||
Object r2 = service.cache(o1);
|
||||
|
||||
assertSame(r1, r2);
|
||||
try {
|
||||
service.evictWithException(o1);
|
||||
} catch (RuntimeException ex) {
|
||||
// expected
|
||||
}
|
||||
// exception occurred, eviction skipped, data should still be in the cache
|
||||
Object r3 = service.cache(o1);
|
||||
assertSame(r1, r3);
|
||||
}
|
||||
|
||||
public void testEvictWKey(CacheableService<?> service) throws Exception {
|
||||
Object o1 = new Object();
|
||||
|
||||
Object r1 = service.cache(o1);
|
||||
Object r2 = service.cache(o1);
|
||||
|
||||
assertSame(r1, r2);
|
||||
service.evict(o1, null);
|
||||
Object r3 = service.cache(o1);
|
||||
Object r4 = service.cache(o1);
|
||||
assertNotSame(r1, r3);
|
||||
assertSame(r3, r4);
|
||||
}
|
||||
|
||||
public void testEvictWKeyEarly(CacheableService<?> service) throws Exception {
|
||||
Object o1 = new Object();
|
||||
|
||||
Object r1 = service.cache(o1);
|
||||
Object r2 = service.cache(o1);
|
||||
|
||||
assertSame(r1, r2);
|
||||
|
||||
try {
|
||||
service.invalidateEarly(o1, null);
|
||||
} catch (Exception ex) {
|
||||
// expected
|
||||
}
|
||||
Object r3 = service.cache(o1);
|
||||
Object r4 = service.cache(o1);
|
||||
assertNotSame(r1, r3);
|
||||
assertSame(r3, r4);
|
||||
}
|
||||
|
||||
public void testEvictAll(CacheableService<?> service) throws Exception {
|
||||
Object o1 = new Object();
|
||||
|
||||
Object r1 = service.cache(o1);
|
||||
Object r2 = service.cache(o1);
|
||||
|
||||
Object o2 = new Object();
|
||||
Object r10 = service.cache(o2);
|
||||
|
||||
assertSame(r1, r2);
|
||||
assertNotSame(r1, r10);
|
||||
service.evictAll(new Object());
|
||||
Cache cache = cm.getCache("default");
|
||||
assertNull(cache.get(o1));
|
||||
assertNull(cache.get(o2));
|
||||
|
||||
Object r3 = service.cache(o1);
|
||||
Object r4 = service.cache(o1);
|
||||
assertNotSame(r1, r3);
|
||||
assertSame(r3, r4);
|
||||
}
|
||||
|
||||
public void testConditionalExpression(CacheableService<?> service) throws Exception {
|
||||
Object r1 = service.conditional(4);
|
||||
Object r2 = service.conditional(4);
|
||||
|
||||
assertNotSame(r1, r2);
|
||||
|
||||
Object r3 = service.conditional(3);
|
||||
Object r4 = service.conditional(3);
|
||||
|
||||
assertSame(r3, r4);
|
||||
}
|
||||
|
||||
public void testKeyExpression(CacheableService<?> service) throws Exception {
|
||||
Object r1 = service.key(5, 1);
|
||||
Object r2 = service.key(5, 2);
|
||||
|
||||
assertSame(r1, r2);
|
||||
|
||||
Object r3 = service.key(1, 5);
|
||||
Object r4 = service.key(2, 5);
|
||||
|
||||
assertNotSame(r3, r4);
|
||||
}
|
||||
|
||||
public void testNullValue(CacheableService<?> service) throws Exception {
|
||||
Object key = new Object();
|
||||
assertNull(service.nullValue(key));
|
||||
int nr = service.nullInvocations().intValue();
|
||||
assertNull(service.nullValue(key));
|
||||
assertEquals(nr, service.nullInvocations().intValue());
|
||||
assertNull(service.nullValue(new Object()));
|
||||
assertEquals(nr + 1, service.nullInvocations().intValue());
|
||||
}
|
||||
|
||||
public void testMethodName(CacheableService<?> service, String keyName) throws Exception {
|
||||
Object key = new Object();
|
||||
Object r1 = service.name(key);
|
||||
assertSame(r1, service.name(key));
|
||||
Cache cache = cm.getCache("default");
|
||||
// assert the method name is used
|
||||
assertNotNull(cache.get(keyName));
|
||||
}
|
||||
|
||||
public void testCheckedThrowable(CacheableService<?> service) throws Exception {
|
||||
String arg = UUID.randomUUID().toString();
|
||||
try {
|
||||
service.throwChecked(arg);
|
||||
fail("Excepted exception");
|
||||
} catch (Exception ex) {
|
||||
assertEquals(arg, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testUncheckedThrowable(CacheableService<?> service) throws Exception {
|
||||
try {
|
||||
service.throwUnchecked(Long.valueOf(1));
|
||||
fail("Excepted exception");
|
||||
} catch (RuntimeException ex) {
|
||||
assertTrue("Excepted different exception type and got " + ex.getClass(),
|
||||
ex instanceof UnsupportedOperationException);
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testNullArg(CacheableService<?> service) {
|
||||
Object r1 = service.cache(null);
|
||||
assertSame(r1, service.cache(null));
|
||||
}
|
||||
|
||||
public void testCacheUpdate(CacheableService<?> service) {
|
||||
Object o = new Object();
|
||||
Cache cache = cm.getCache("default");
|
||||
assertNull(cache.get(o));
|
||||
Object r1 = service.update(o);
|
||||
assertSame(r1, cache.get(o).get());
|
||||
|
||||
o = new Object();
|
||||
assertNull(cache.get(o));
|
||||
Object r2 = service.update(o);
|
||||
assertSame(r2, cache.get(o).get());
|
||||
}
|
||||
|
||||
public void testConditionalCacheUpdate(CacheableService<?> service) {
|
||||
Integer one = Integer.valueOf(1);
|
||||
Integer three = Integer.valueOf(3);
|
||||
|
||||
Cache cache = cm.getCache("default");
|
||||
assertEquals(one, Integer.valueOf(service.conditionalUpdate(one).toString()));
|
||||
assertNull(cache.get(one));
|
||||
|
||||
assertEquals(three, Integer.valueOf(service.conditionalUpdate(three).toString()));
|
||||
assertEquals(three, Integer.valueOf(cache.get(three).get().toString()));
|
||||
}
|
||||
|
||||
public void testMultiCache(CacheableService<?> service) {
|
||||
Object o1 = new Object();
|
||||
Object o2 = new Object();
|
||||
|
||||
Cache primary = cm.getCache("primary");
|
||||
Cache secondary = cm.getCache("secondary");
|
||||
|
||||
assertNull(primary.get(o1));
|
||||
assertNull(secondary.get(o1));
|
||||
Object r1 = service.multiCache(o1);
|
||||
assertSame(r1, primary.get(o1).get());
|
||||
assertSame(r1, secondary.get(o1).get());
|
||||
|
||||
Object r2 = service.multiCache(o1);
|
||||
Object r3 = service.multiCache(o1);
|
||||
|
||||
assertSame(r1, r2);
|
||||
assertSame(r1, r3);
|
||||
|
||||
assertNull(primary.get(o2));
|
||||
assertNull(secondary.get(o2));
|
||||
Object r4 = service.multiCache(o2);
|
||||
assertSame(r4, primary.get(o2).get());
|
||||
assertSame(r4, secondary.get(o2).get());
|
||||
}
|
||||
|
||||
public void testMultiEvict(CacheableService<?> service) {
|
||||
Object o1 = new Object();
|
||||
|
||||
Object r1 = service.multiCache(o1);
|
||||
Object r2 = service.multiCache(o1);
|
||||
|
||||
Cache primary = cm.getCache("primary");
|
||||
Cache secondary = cm.getCache("secondary");
|
||||
|
||||
assertSame(r1, r2);
|
||||
assertSame(r1, primary.get(o1).get());
|
||||
assertSame(r1, secondary.get(o1).get());
|
||||
|
||||
service.multiEvict(o1);
|
||||
assertNull(primary.get(o1));
|
||||
assertNull(secondary.get(o1));
|
||||
|
||||
Object r3 = service.multiCache(o1);
|
||||
Object r4 = service.multiCache(o1);
|
||||
assertNotSame(r1, r3);
|
||||
assertSame(r3, r4);
|
||||
|
||||
assertSame(r3, primary.get(o1).get());
|
||||
assertSame(r4, secondary.get(o1).get());
|
||||
}
|
||||
|
||||
public void testMultiPut(CacheableService<?> service) {
|
||||
Object o = Integer.valueOf(1);
|
||||
|
||||
Cache primary = cm.getCache("primary");
|
||||
Cache secondary = cm.getCache("secondary");
|
||||
|
||||
assertNull(primary.get(o));
|
||||
assertNull(secondary.get(o));
|
||||
Object r1 = service.multiUpdate(o);
|
||||
assertSame(r1, primary.get(o).get());
|
||||
assertSame(r1, secondary.get(o).get());
|
||||
|
||||
o = Integer.valueOf(2);
|
||||
assertNull(primary.get(o));
|
||||
assertNull(secondary.get(o));
|
||||
Object r2 = service.multiUpdate(o);
|
||||
assertSame(r2, primary.get(o).get());
|
||||
assertSame(r2, secondary.get(o).get());
|
||||
}
|
||||
|
||||
public void testMultiCacheAndEvict(CacheableService<?> service) {
|
||||
String methodName = "multiCacheAndEvict";
|
||||
|
||||
Cache primary = cm.getCache("primary");
|
||||
Cache secondary = cm.getCache("secondary");
|
||||
Object key = Integer.valueOf(1);
|
||||
|
||||
secondary.put(key, key);
|
||||
|
||||
assertNull(secondary.get(methodName));
|
||||
assertSame(key, secondary.get(key).get());
|
||||
|
||||
Object r1 = service.multiCacheAndEvict(key);
|
||||
assertSame(r1, service.multiCacheAndEvict(key));
|
||||
|
||||
// assert the method name is used
|
||||
assertSame(r1, primary.get(methodName).get());
|
||||
assertNull(secondary.get(methodName));
|
||||
assertNull(secondary.get(key));
|
||||
}
|
||||
|
||||
public void testMultiConditionalCacheAndEvict(CacheableService<?> service) {
|
||||
Cache primary = cm.getCache("primary");
|
||||
Cache secondary = cm.getCache("secondary");
|
||||
Object key = Integer.valueOf(1);
|
||||
|
||||
secondary.put(key, key);
|
||||
|
||||
assertNull(primary.get(key));
|
||||
assertSame(key, secondary.get(key).get());
|
||||
|
||||
Object r1 = service.multiConditionalCacheAndEvict(key);
|
||||
Object r3 = service.multiConditionalCacheAndEvict(key);
|
||||
|
||||
assertTrue(!r1.equals(r3));
|
||||
assertNull(primary.get(key));
|
||||
|
||||
Object key2 = Integer.valueOf(3);
|
||||
Object r2 = service.multiConditionalCacheAndEvict(key2);
|
||||
assertSame(r2, service.multiConditionalCacheAndEvict(key2));
|
||||
|
||||
// assert the method name is used
|
||||
assertSame(r2, primary.get(key2).get());
|
||||
assertNull(secondary.get(key2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheable() throws Exception {
|
||||
testCacheable(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidate() throws Exception {
|
||||
testEvict(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEarlyInvalidate() throws Exception {
|
||||
testEvictEarly(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvictWithException() throws Exception {
|
||||
testEvictException(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvictAll() throws Exception {
|
||||
testEvictAll(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidateWithKey() throws Exception {
|
||||
testEvictWKey(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEarlyInvalidateWithKey() throws Exception {
|
||||
testEvictWKeyEarly(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConditionalExpression() throws Exception {
|
||||
testConditionalExpression(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyExpression() throws Exception {
|
||||
testKeyExpression(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassCacheCacheable() throws Exception {
|
||||
testCacheable(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassCacheInvalidate() throws Exception {
|
||||
testEvict(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassEarlyInvalidate() throws Exception {
|
||||
testEvictEarly(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassEvictAll() throws Exception {
|
||||
testEvictAll(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassEvictWithException() throws Exception {
|
||||
testEvictException(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassCacheInvalidateWKey() throws Exception {
|
||||
testEvictWKey(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassEarlyInvalidateWithKey() throws Exception {
|
||||
testEvictWKeyEarly(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullValue() throws Exception {
|
||||
testNullValue(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassNullValue() throws Exception {
|
||||
Object key = new Object();
|
||||
assertNull(ccs.nullValue(key));
|
||||
int nr = ccs.nullInvocations().intValue();
|
||||
assertNull(ccs.nullValue(key));
|
||||
assertEquals(nr, ccs.nullInvocations().intValue());
|
||||
assertNull(ccs.nullValue(new Object()));
|
||||
// the check method is also cached
|
||||
assertEquals(nr, ccs.nullInvocations().intValue());
|
||||
assertEquals(nr + 1, AnnotatedClassCacheableService.nullInvocations.intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodName() throws Exception {
|
||||
testMethodName(cs, "name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassMethodName() throws Exception {
|
||||
testMethodName(ccs, "namedefault");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullArg() throws Exception {
|
||||
testNullArg(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassNullArg() throws Exception {
|
||||
testNullArg(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckedException() throws Exception {
|
||||
testCheckedThrowable(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassCheckedException() throws Exception {
|
||||
testCheckedThrowable(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUncheckedException() throws Exception {
|
||||
testUncheckedThrowable(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassUncheckedException() throws Exception {
|
||||
testUncheckedThrowable(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate() {
|
||||
testCacheUpdate(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassUpdate() {
|
||||
testCacheUpdate(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConditionalUpdate() {
|
||||
testConditionalCacheUpdate(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassConditionalUpdate() {
|
||||
testConditionalCacheUpdate(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiCache() {
|
||||
testMultiCache(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassMultiCache() {
|
||||
testMultiCache(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiEvict() {
|
||||
testMultiEvict(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassMultiEvict() {
|
||||
testMultiEvict(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiPut() {
|
||||
testMultiPut(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassMultiPut() {
|
||||
testMultiPut(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiCacheAndEvict() {
|
||||
testMultiCacheAndEvict(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassMultiCacheAndEvict() {
|
||||
testMultiCacheAndEvict(ccs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiConditionalCacheAndEvict() {
|
||||
testMultiConditionalCacheAndEvict(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassMultiConditionalCacheAndEvict() {
|
||||
testMultiConditionalCacheAndEvict(ccs);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010 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.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.GenericXmlApplicationContext;
|
||||
|
||||
|
||||
/**
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public class AspectJAnnotationTest extends AbstractAnnotationTest {
|
||||
|
||||
|
||||
@Override
|
||||
protected ApplicationContext getApplicationContext() {
|
||||
return new GenericXmlApplicationContext("/org/springframework/cache/config/annotation-cache-aspectj.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyStrategy() throws Exception {
|
||||
AnnotationCacheAspect aspect = ctx.getBean("org.springframework.cache.config.internalCacheAspect", AnnotationCacheAspect.class);
|
||||
Assert.assertSame(ctx.getBean("keyGenerator"), aspect.getKeyGenerator());
|
||||
}
|
||||
}
|
||||
+138
-56
@@ -1,56 +1,138 @@
|
||||
/*
|
||||
* Copyright 2010 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.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
|
||||
/**
|
||||
* @author Costin Leau
|
||||
*/
|
||||
@Cacheable("default")
|
||||
public class AnnotatedClassCacheableService implements CacheableService {
|
||||
|
||||
private AtomicLong counter = new AtomicLong();
|
||||
|
||||
public Object cache(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
public Object conditional(int field) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@CacheEvict("default")
|
||||
public void invalidate(Object arg1) {
|
||||
}
|
||||
|
||||
@Cacheable(value = "default", key = "#p0")
|
||||
public Object key(Object arg1, Object arg2) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
public Long throwChecked(Object arg1) throws Exception {
|
||||
throw new UnsupportedOperationException(arg1.toString());
|
||||
}
|
||||
|
||||
public Long throwUnchecked(Object arg1) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2010-2011 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.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.cache.annotation.Caching;
|
||||
|
||||
/**
|
||||
* @author Costin Leau
|
||||
*/
|
||||
@Cacheable("default")
|
||||
public class AnnotatedClassCacheableService implements CacheableService<Object> {
|
||||
|
||||
private final AtomicLong counter = new AtomicLong();
|
||||
public static final AtomicLong nullInvocations = new AtomicLong();
|
||||
|
||||
public Object cache(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
public Object conditional(int field) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@CacheEvict("default")
|
||||
public void invalidate(Object arg1) {
|
||||
}
|
||||
|
||||
@CacheEvict("default")
|
||||
public void evictWithException(Object arg1) {
|
||||
throw new RuntimeException("exception thrown - evict should NOT occur");
|
||||
}
|
||||
|
||||
@CacheEvict(value = "default", allEntries = true)
|
||||
public void evictAll(Object arg1) {
|
||||
}
|
||||
|
||||
@CacheEvict(value = "default", beforeInvocation = true)
|
||||
public void evictEarly(Object arg1) {
|
||||
throw new RuntimeException("exception thrown - evict should still occur");
|
||||
}
|
||||
|
||||
@CacheEvict(value = "default", key = "#p0")
|
||||
public void evict(Object arg1, Object arg2) {
|
||||
}
|
||||
|
||||
@CacheEvict(value = "default", key = "#p0", beforeInvocation = true)
|
||||
public void invalidateEarly(Object arg1, Object arg2) {
|
||||
throw new RuntimeException("exception thrown - evict should still occur");
|
||||
}
|
||||
|
||||
@Cacheable(value = "default", key = "#p0")
|
||||
public Object key(Object arg1, Object arg2) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Cacheable(value = "default", key = "#root.methodName + #root.caches[0].name")
|
||||
public Object name(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target")
|
||||
public Object rootVars(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@CachePut("default")
|
||||
public Object update(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@CachePut(value = "default", condition = "#arg.equals(3)")
|
||||
public Object conditionalUpdate(Object arg) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
public Object nullValue(Object arg1) {
|
||||
nullInvocations.incrementAndGet();
|
||||
return null;
|
||||
}
|
||||
|
||||
public Number nullInvocations() {
|
||||
return nullInvocations.get();
|
||||
}
|
||||
|
||||
public Long throwChecked(Object arg1) throws Exception {
|
||||
throw new UnsupportedOperationException(arg1.toString());
|
||||
}
|
||||
|
||||
public Long throwUnchecked(Object arg1) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// multi annotations
|
||||
|
||||
@Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") })
|
||||
public Object multiCache(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") })
|
||||
public Object multiEvict(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") })
|
||||
public Object multiCacheAndEvict(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") })
|
||||
public Object multiConditionalCacheAndEvict(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Caching(put = { @CachePut("primary"), @CachePut("secondary") })
|
||||
public Object multiUpdate(Object arg1) {
|
||||
return arg1;
|
||||
}
|
||||
}
|
||||
Vendored
+69
-37
@@ -1,38 +1,70 @@
|
||||
/*
|
||||
* Copyright 2010 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;
|
||||
|
||||
|
||||
/**
|
||||
* Basic service interface.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public interface CacheableService<T> {
|
||||
|
||||
T cache(Object arg1);
|
||||
|
||||
void invalidate(Object arg1);
|
||||
|
||||
T conditional(int field);
|
||||
|
||||
T key(Object arg1, Object arg2);
|
||||
|
||||
T throwChecked(Object arg1) throws Exception;
|
||||
|
||||
T throwUnchecked(Object arg1);
|
||||
/*
|
||||
* Copyright 2010-2011 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;
|
||||
|
||||
/**
|
||||
* Basic service interface.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public interface CacheableService<T> {
|
||||
|
||||
T cache(Object arg1);
|
||||
|
||||
void invalidate(Object arg1);
|
||||
|
||||
void evictEarly(Object arg1);
|
||||
|
||||
void evictAll(Object arg1);
|
||||
|
||||
void evictWithException(Object arg1);
|
||||
|
||||
void evict(Object arg1, Object arg2);
|
||||
|
||||
void invalidateEarly(Object arg1, Object arg2);
|
||||
|
||||
T conditional(int field);
|
||||
|
||||
T key(Object arg1, Object arg2);
|
||||
|
||||
T name(Object arg1);
|
||||
|
||||
T nullValue(Object arg1);
|
||||
|
||||
T update(Object arg1);
|
||||
|
||||
T conditionalUpdate(Object arg2);
|
||||
|
||||
Number nullInvocations();
|
||||
|
||||
T rootVars(Object arg1);
|
||||
|
||||
T throwChecked(Object arg1) throws Exception;
|
||||
|
||||
T throwUnchecked(Object arg1);
|
||||
|
||||
// multi annotations
|
||||
T multiCache(Object arg1);
|
||||
|
||||
T multiEvict(Object arg1);
|
||||
|
||||
T multiCacheAndEvict(Object arg1);
|
||||
|
||||
T multiConditionalCacheAndEvict(Object arg1);
|
||||
|
||||
T multiUpdate(Object arg1);
|
||||
}
|
||||
+143
-61
@@ -1,62 +1,144 @@
|
||||
/*
|
||||
* Copyright 2010 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.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
|
||||
|
||||
/**
|
||||
* Simple cacheable service
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public class DefaultCacheableService implements CacheableService<Long> {
|
||||
|
||||
private AtomicLong counter = new AtomicLong();
|
||||
|
||||
@Cacheable("default")
|
||||
public Long cache(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@CacheEvict("default")
|
||||
public void invalidate(Object arg1) {
|
||||
}
|
||||
|
||||
@Cacheable(value = "default", condition = "#classField == 3")
|
||||
public Long conditional(int classField) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Cacheable(value = "default", key = "#p0")
|
||||
public Long key(Object arg1, Object arg2) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Cacheable("default")
|
||||
public Long throwChecked(Object arg1) throws Exception {
|
||||
throw new Exception(arg1.toString());
|
||||
}
|
||||
|
||||
@Cacheable("default")
|
||||
public Long throwUnchecked(Object arg1) {
|
||||
throw new UnsupportedOperationException(arg1.toString());
|
||||
}
|
||||
/*
|
||||
* Copyright 2010-2011 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.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.cache.annotation.Caching;
|
||||
|
||||
/**
|
||||
* Simple cacheable service
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public class DefaultCacheableService implements CacheableService<Long> {
|
||||
|
||||
private final AtomicLong counter = new AtomicLong();
|
||||
private final AtomicLong nullInvocations = new AtomicLong();
|
||||
|
||||
@Cacheable("default")
|
||||
public Long cache(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@CacheEvict("default")
|
||||
public void invalidate(Object arg1) {
|
||||
}
|
||||
|
||||
@CacheEvict("default")
|
||||
public void evictWithException(Object arg1) {
|
||||
throw new RuntimeException("exception thrown - evict should NOT occur");
|
||||
}
|
||||
|
||||
@CacheEvict(value = "default", allEntries = true)
|
||||
public void evictAll(Object arg1) {
|
||||
}
|
||||
|
||||
@CacheEvict(value = "default", beforeInvocation = true)
|
||||
public void evictEarly(Object arg1) {
|
||||
throw new RuntimeException("exception thrown - evict should still occur");
|
||||
}
|
||||
|
||||
@CacheEvict(value = "default", key = "#p0")
|
||||
public void evict(Object arg1, Object arg2) {
|
||||
}
|
||||
|
||||
@CacheEvict(value = "default", key = "#p0", beforeInvocation = true)
|
||||
public void invalidateEarly(Object arg1, Object arg2) {
|
||||
throw new RuntimeException("exception thrown - evict should still occur");
|
||||
}
|
||||
|
||||
@Cacheable(value = "default", condition = "#classField == 3")
|
||||
public Long conditional(int classField) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Cacheable(value = "default", key = "#p0")
|
||||
public Long key(Object arg1, Object arg2) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Cacheable(value = "default", key = "#root.methodName")
|
||||
public Long name(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target")
|
||||
public Long rootVars(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@CachePut("default")
|
||||
public Long update(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@CachePut(value = "default", condition = "#arg.equals(3)")
|
||||
public Long conditionalUpdate(Object arg) {
|
||||
return Long.valueOf(arg.toString());
|
||||
}
|
||||
|
||||
@Cacheable("default")
|
||||
public Long nullValue(Object arg1) {
|
||||
nullInvocations.incrementAndGet();
|
||||
return null;
|
||||
}
|
||||
|
||||
public Number nullInvocations() {
|
||||
return nullInvocations.get();
|
||||
}
|
||||
|
||||
@Cacheable("default")
|
||||
public Long throwChecked(Object arg1) throws Exception {
|
||||
throw new Exception(arg1.toString());
|
||||
}
|
||||
|
||||
@Cacheable("default")
|
||||
public Long throwUnchecked(Object arg1) {
|
||||
throw new UnsupportedOperationException(arg1.toString());
|
||||
}
|
||||
|
||||
// multi annotations
|
||||
|
||||
@Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") })
|
||||
public Long multiCache(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") })
|
||||
public Long multiEvict(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") })
|
||||
public Long multiCacheAndEvict(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") })
|
||||
public Long multiConditionalCacheAndEvict(Object arg1) {
|
||||
return counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@Caching(put = { @CachePut("primary"), @CachePut("secondary") })
|
||||
public Long multiUpdate(Object arg1) {
|
||||
return Long.valueOf(arg1.toString());
|
||||
}
|
||||
}
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.DefaultKeyGenerator;
|
||||
|
||||
public class SomeKeyGenerator extends DefaultKeyGenerator {
|
||||
|
||||
}
|
||||
+45
-32
@@ -1,32 +1,45 @@
|
||||
<?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:p="http://www.springframework.org/schema/p"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
|
||||
|
||||
<bean id="annotationSource" class="org.springframework.cache.annotation.AnnotationCacheOperationSource"/>
|
||||
|
||||
<aop:config>
|
||||
<aop:advisor advice-ref="debugInterceptor" pointcut="execution(* *..CacheableService.*(..))" order="1"/>
|
||||
</aop:config>
|
||||
|
||||
<bean id="cacheAspect" class="org.springframework.cache.aspectj.AnnotationCacheAspect" factory-method="aspectOf">
|
||||
<property name="cacheManager" ref="cacheManager"/>
|
||||
<property name="cacheOperationSource" ref="annotationSource"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
|
||||
<property name="caches">
|
||||
<set>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>
|
||||
|
||||
<bean id="service" class="org.springframework.cache.config.DefaultCacheableService"/>
|
||||
<bean id="classService" class="org.springframework.cache.config.AnnotatedClassCacheableService"/>
|
||||
|
||||
</beans>
|
||||
<?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:p="http://www.springframework.org/schema/p"
|
||||
xmlns:cache="http://www.springframework.org/schema/cache"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.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">
|
||||
|
||||
|
||||
<!--
|
||||
<aop:config>
|
||||
<aop:advisor advice-ref="debugInterceptor" pointcut="execution(* *..CacheableService.*(..))" order="1"/>
|
||||
</aop:config>
|
||||
|
||||
<bean id="cacheAspect" class="org.springframework.cache.aspectj.AnnotationCacheAspect" factory-method="aspectOf">
|
||||
<property name="cacheManager" ref="cacheManager"/>
|
||||
<property name="cacheOperationSources" ref="annotationSource"/>
|
||||
</bean>
|
||||
|
||||
<bean id="annotationSource" class="org.springframework.cache.annotation.AnnotationCacheOperationSource"/>
|
||||
-->
|
||||
|
||||
<cache:annotation-driven mode="aspectj" key-generator="keyGenerator"/>
|
||||
|
||||
<bean id="keyGenerator" class="org.springframework.cache.config.SomeKeyGenerator" />
|
||||
|
||||
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
|
||||
<property name="caches">
|
||||
<set>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="primary"/>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="secondary"/>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>
|
||||
|
||||
<bean id="service" class="org.springframework.cache.config.DefaultCacheableService"/>
|
||||
<bean id="classService" class="org.springframework.cache.config.AnnotatedClassCacheableService"/>
|
||||
|
||||
</beans>
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.context.annotation.aspectj;
|
||||
|
||||
import org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
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>}
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public class AnnotationBeanConfigurerTests extends AbstractBeanConfigurerTests {
|
||||
|
||||
@Override
|
||||
protected ConfigurableApplicationContext createContext() {
|
||||
return new AnnotationConfigApplicationContext(Config.class);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ImportResource("org/springframework/beans/factory/aspectj/beanConfigurerTests-beans.xml")
|
||||
@EnableSpringConfigured
|
||||
static class Config {
|
||||
}
|
||||
}
|
||||
+146
-146
@@ -1,146 +1,146 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test for static entity mocking framework.
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
@MockStaticEntityMethods
|
||||
@RunWith(JUnit4.class)
|
||||
public class AnnotationDrivenStaticEntityMockingControlTest {
|
||||
|
||||
@Test
|
||||
public void testNoArgIntReturn() {
|
||||
int expectedCount = 13;
|
||||
Person.countPeople();
|
||||
expectReturn(expectedCount);
|
||||
playback();
|
||||
Assert.assertEquals(expectedCount, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected=PersistenceException.class)
|
||||
public void testNoArgThrows() {
|
||||
Person.countPeople();
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodMatches() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLongSeriesOfCalls() {
|
||||
long id1 = 13;
|
||||
long id2 = 24;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(id2);
|
||||
expectReturn(found2);
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person.countPeople();
|
||||
expectReturn(0);
|
||||
playback();
|
||||
|
||||
Assert.assertEquals(found1, Person.findPerson(id1));
|
||||
Assert.assertEquals(found2, Person.findPerson(id2));
|
||||
Assert.assertEquals(found1, Person.findPerson(id1));
|
||||
Assert.assertEquals(0, Person.countPeople());
|
||||
}
|
||||
|
||||
// Note delegation is used when tests are invalid and should fail, as otherwise
|
||||
// the failure will occur on the verify() method in the aspect after
|
||||
// this method returns, failing the test case
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
try {
|
||||
new Delegate().testArgMethodNoMatchExpectReturn();
|
||||
Assert.fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
new Delegate().testArgMethodNoMatchExpectThrow();
|
||||
}
|
||||
|
||||
private void called(Person found, long id) {
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReentrant() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
called(found, id);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testRejectUnexpectedCall() {
|
||||
new Delegate().rejectUnexpectedCall();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testFailTooFewCalls() {
|
||||
new Delegate().failTooFewCalls();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
// Test that verification check doesn't blow up if no replay() call happened
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverReplay() {
|
||||
new Delegate().doesntEverReplay();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverSetReturn() {
|
||||
new Delegate().doesntEverSetReturn();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test for static entity mocking framework.
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
@MockStaticEntityMethods
|
||||
@RunWith(JUnit4.class)
|
||||
public class AnnotationDrivenStaticEntityMockingControlTest {
|
||||
|
||||
@Test
|
||||
public void testNoArgIntReturn() {
|
||||
int expectedCount = 13;
|
||||
Person.countPeople();
|
||||
expectReturn(expectedCount);
|
||||
playback();
|
||||
Assert.assertEquals(expectedCount, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected=PersistenceException.class)
|
||||
public void testNoArgThrows() {
|
||||
Person.countPeople();
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodMatches() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLongSeriesOfCalls() {
|
||||
long id1 = 13;
|
||||
long id2 = 24;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(id2);
|
||||
expectReturn(found2);
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person.countPeople();
|
||||
expectReturn(0);
|
||||
playback();
|
||||
|
||||
Assert.assertEquals(found1, Person.findPerson(id1));
|
||||
Assert.assertEquals(found2, Person.findPerson(id2));
|
||||
Assert.assertEquals(found1, Person.findPerson(id1));
|
||||
Assert.assertEquals(0, Person.countPeople());
|
||||
}
|
||||
|
||||
// Note delegation is used when tests are invalid and should fail, as otherwise
|
||||
// the failure will occur on the verify() method in the aspect after
|
||||
// this method returns, failing the test case
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
try {
|
||||
new Delegate().testArgMethodNoMatchExpectReturn();
|
||||
Assert.fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
new Delegate().testArgMethodNoMatchExpectThrow();
|
||||
}
|
||||
|
||||
private void called(Person found, long id) {
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReentrant() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
called(found, id);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testRejectUnexpectedCall() {
|
||||
new Delegate().rejectUnexpectedCall();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testFailTooFewCalls() {
|
||||
new Delegate().failTooFewCalls();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
// Test that verification check doesn't blow up if no replay() call happened
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverReplay() {
|
||||
new Delegate().doesntEverReplay();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverSetReturn() {
|
||||
new Delegate().doesntEverSetReturn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+92
-92
@@ -1,92 +1,92 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl;
|
||||
import org.springframework.mock.staticmock.MockStaticEntityMethods;
|
||||
|
||||
//Used because verification failures occur after method returns,
|
||||
//so we can't test for them in the test case itself
|
||||
@MockStaticEntityMethods
|
||||
@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl
|
||||
public class Delegate {
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failTooFewCalls() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverReplay() {
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverSetReturn() {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectUnexpectedCall() {
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected=RemoteException.class)
|
||||
public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
// No calls to allow verification failure
|
||||
throw new RemoteException();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl;
|
||||
import org.springframework.mock.staticmock.MockStaticEntityMethods;
|
||||
|
||||
//Used because verification failures occur after method returns,
|
||||
//so we can't test for them in the test case itself
|
||||
@MockStaticEntityMethods
|
||||
@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl
|
||||
public class Delegate {
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failTooFewCalls() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverReplay() {
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverSetReturn() {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectUnexpectedCall() {
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected=RemoteException.class)
|
||||
public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
// No calls to allow verification failure
|
||||
throw new RemoteException();
|
||||
}
|
||||
}
|
||||
|
||||
+24
-24
@@ -1,24 +1,24 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
@Entity
|
||||
public class Person {
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
@Entity
|
||||
public class Person {
|
||||
}
|
||||
|
||||
|
||||
+100
-100
@@ -1,100 +1,100 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
privileged aspect Person_Roo_Entity {
|
||||
|
||||
@javax.persistence.PersistenceContext
|
||||
transient javax.persistence.EntityManager Person.entityManager;
|
||||
|
||||
@javax.persistence.Id
|
||||
@javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
|
||||
@javax.persistence.Column(name = "id")
|
||||
private java.lang.Long Person.id;
|
||||
|
||||
@javax.persistence.Version
|
||||
@javax.persistence.Column(name = "version")
|
||||
private java.lang.Integer Person.version;
|
||||
|
||||
public java.lang.Long Person.getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void Person.setId(java.lang.Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public java.lang.Integer Person.getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public void Person.setVersion(java.lang.Integer version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.persist() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.persist(this);
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.remove() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.remove(this);
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.flush() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.flush();
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.merge() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
Person merged = this.entityManager.merge(this);
|
||||
this.entityManager.flush();
|
||||
this.id = merged.getId();
|
||||
}
|
||||
|
||||
public static long Person.countPeople() {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return (Long) em.createQuery("select count(o) from Person o").getSingleResult();
|
||||
}
|
||||
|
||||
public static java.util.List<Person> Person.findAllPeople() {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.createQuery("select o from Person o").getResultList();
|
||||
}
|
||||
|
||||
public static Person Person.findPerson(java.lang.Long id) {
|
||||
if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Person");
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.find(Person.class, id);
|
||||
}
|
||||
|
||||
public static java.util.List<Person> Person.findPersonEntries(int firstResult, int maxResults) {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.createQuery("select o from Person o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 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.mock.staticmock;
|
||||
|
||||
privileged aspect Person_Roo_Entity {
|
||||
|
||||
@javax.persistence.PersistenceContext
|
||||
transient javax.persistence.EntityManager Person.entityManager;
|
||||
|
||||
@javax.persistence.Id
|
||||
@javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
|
||||
@javax.persistence.Column(name = "id")
|
||||
private java.lang.Long Person.id;
|
||||
|
||||
@javax.persistence.Version
|
||||
@javax.persistence.Column(name = "version")
|
||||
private java.lang.Integer Person.version;
|
||||
|
||||
public java.lang.Long Person.getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void Person.setId(java.lang.Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public java.lang.Integer Person.getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public void Person.setVersion(java.lang.Integer version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.persist() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.persist(this);
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.remove() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.remove(this);
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.flush() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.flush();
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.merge() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
Person merged = this.entityManager.merge(this);
|
||||
this.entityManager.flush();
|
||||
this.id = merged.getId();
|
||||
}
|
||||
|
||||
public static long Person.countPeople() {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return (Long) em.createQuery("select count(o) from Person o").getSingleResult();
|
||||
}
|
||||
|
||||
public static java.util.List<Person> Person.findAllPeople() {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.createQuery("select o from Person o").getResultList();
|
||||
}
|
||||
|
||||
public static Person Person.findPerson(java.lang.Long id) {
|
||||
if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Person");
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.find(Person.class, id);
|
||||
}
|
||||
|
||||
public static java.util.List<Person> Person.findPersonEntries(int firstResult, int maxResults) {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.createQuery("select o from Person o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+218
-178
@@ -1,178 +1,218 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.scheduling.aspectj;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import static junit.framework.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.AsyncResult;
|
||||
|
||||
/**
|
||||
* @author Ramnivas Laddad
|
||||
*/
|
||||
public class AnnotationAsyncExecutionAspectTests {
|
||||
|
||||
private static final long WAIT_TIME = 1000; //milli seconds
|
||||
|
||||
private CountingExecutor executor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
executor = new CountingExecutor();
|
||||
AnnotationAsyncExecutionAspect.aspectOf().setExecutor(executor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodGetsRoutedAsynchronously() {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
obj.incrementAsync();
|
||||
executor.waitForCompletion();
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodReturningFutureGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
Future<Integer> future = obj.incrementReturningAFuture();
|
||||
// No need to executor.waitForCompletion() as future.get() will have the same effect
|
||||
assertEquals(5, future.get().intValue());
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syncMethodGetsRoutedSynchronously() {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
obj.increment();
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(0, executor.submitStartCounter);
|
||||
assertEquals(0, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void voidMethodInAsyncClassGetsRoutedAsynchronously() {
|
||||
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
|
||||
obj.increment();
|
||||
executor.waitForCompletion();
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodReturningFutureInAsyncClassGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException {
|
||||
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
|
||||
Future<Integer> future = obj.incrementReturningAFuture();
|
||||
assertEquals(5, future.get().intValue());
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodReturningNonVoidNonFutureInAsyncClassGetsRoutedSynchronously() {
|
||||
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
|
||||
int returnValue = obj.return5();
|
||||
assertEquals(5, returnValue);
|
||||
assertEquals(0, executor.submitStartCounter);
|
||||
assertEquals(0, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class CountingExecutor extends SimpleAsyncTaskExecutor {
|
||||
int submitStartCounter;
|
||||
int submitCompleteCounter;
|
||||
|
||||
@Override
|
||||
public <T> Future<T> submit(Callable<T> task) {
|
||||
submitStartCounter++;
|
||||
Future<T> future = super.submit(task);
|
||||
submitCompleteCounter++;
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
public synchronized void waitForCompletion() {
|
||||
try {
|
||||
wait(WAIT_TIME);
|
||||
} catch (InterruptedException e) {
|
||||
Assert.fail("Didn't finish the async job in " + WAIT_TIME + " milliseconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class ClassWithoutAsyncAnnotation {
|
||||
int counter;
|
||||
|
||||
@Async public void incrementAsync() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
public void increment() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
@Async public Future<Integer> incrementReturningAFuture() {
|
||||
counter++;
|
||||
return new AsyncResult<Integer>(5);
|
||||
}
|
||||
|
||||
// It should be an error to attach @Async to a method that returns a non-void
|
||||
// or non-Future.
|
||||
// We need to keep this commented out, otherwise there will be a compile-time error.
|
||||
// Please uncomment and re-comment this periodically to check that the compiler
|
||||
// produces an error message due to the 'declare error' statement
|
||||
// in AnnotationAsyncExecutionAspect
|
||||
// @Async public int getInt() {
|
||||
// return 0;
|
||||
// }
|
||||
}
|
||||
|
||||
@Async
|
||||
static class ClassWithAsyncAnnotation {
|
||||
int counter;
|
||||
|
||||
public void increment() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
// Manually check that there is a warning from the 'declare warning' statement in AnnotationAsynchExecutionAspect
|
||||
public int return5() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
public Future<Integer> incrementReturningAFuture() {
|
||||
counter++;
|
||||
return new AsyncResult<Integer>(5);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.scheduling.aspectj;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.AsyncResult;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AnnotationAsyncExecutionAspect}.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*/
|
||||
public class AnnotationAsyncExecutionAspectTests {
|
||||
|
||||
private static final long WAIT_TIME = 1000; //milliseconds
|
||||
|
||||
private CountingExecutor executor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
executor = new CountingExecutor();
|
||||
AnnotationAsyncExecutionAspect.aspectOf().setExecutor(executor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodGetsRoutedAsynchronously() {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
obj.incrementAsync();
|
||||
executor.waitForCompletion();
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodReturningFutureGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
Future<Integer> future = obj.incrementReturningAFuture();
|
||||
// No need to executor.waitForCompletion() as future.get() will have the same effect
|
||||
assertEquals(5, future.get().intValue());
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syncMethodGetsRoutedSynchronously() {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
obj.increment();
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(0, executor.submitStartCounter);
|
||||
assertEquals(0, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void voidMethodInAsyncClassGetsRoutedAsynchronously() {
|
||||
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
|
||||
obj.increment();
|
||||
executor.waitForCompletion();
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodReturningFutureInAsyncClassGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException {
|
||||
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
|
||||
Future<Integer> future = obj.incrementReturningAFuture();
|
||||
assertEquals(5, future.get().intValue());
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodReturningNonVoidNonFutureInAsyncClassGetsRoutedSynchronously() {
|
||||
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
|
||||
int returnValue = obj.return5();
|
||||
assertEquals(5, returnValue);
|
||||
assertEquals(0, executor.submitStartCounter);
|
||||
assertEquals(0, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void qualifiedAsyncMethodsAreRoutedToCorrectExecutor() throws InterruptedException, ExecutionException {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
beanFactory.registerBeanDefinition("e1", new RootBeanDefinition(ThreadPoolTaskExecutor.class));
|
||||
AnnotationAsyncExecutionAspect.aspectOf().setBeanFactory(beanFactory);
|
||||
|
||||
ClassWithQualifiedAsyncMethods obj = new ClassWithQualifiedAsyncMethods();
|
||||
|
||||
Future<Thread> defaultThread = obj.defaultWork();
|
||||
assertThat(defaultThread.get(), not(Thread.currentThread()));
|
||||
assertThat(defaultThread.get().getName(), not(startsWith("e1-")));
|
||||
|
||||
Future<Thread> e1Thread = obj.e1Work();
|
||||
assertThat(e1Thread.get().getName(), startsWith("e1-"));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class CountingExecutor extends SimpleAsyncTaskExecutor {
|
||||
int submitStartCounter;
|
||||
int submitCompleteCounter;
|
||||
|
||||
@Override
|
||||
public <T> Future<T> submit(Callable<T> task) {
|
||||
submitStartCounter++;
|
||||
Future<T> future = super.submit(task);
|
||||
submitCompleteCounter++;
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
public synchronized void waitForCompletion() {
|
||||
try {
|
||||
wait(WAIT_TIME);
|
||||
} catch (InterruptedException e) {
|
||||
fail("Didn't finish the async job in " + WAIT_TIME + " milliseconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class ClassWithoutAsyncAnnotation {
|
||||
int counter;
|
||||
|
||||
@Async public void incrementAsync() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
public void increment() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
@Async public Future<Integer> incrementReturningAFuture() {
|
||||
counter++;
|
||||
return new AsyncResult<Integer>(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* It should raise an error to attach @Async to a method that returns a non-void
|
||||
* or non-Future. This method must remain commented-out, otherwise there will be a
|
||||
* compile-time error. Uncomment to manually verify that the compiler produces an
|
||||
* error message due to the 'declare error' statement in
|
||||
* {@link AnnotationAsyncExecutionAspect}.
|
||||
*/
|
||||
// @Async public int getInt() {
|
||||
// return 0;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@Async
|
||||
static class ClassWithAsyncAnnotation {
|
||||
int counter;
|
||||
|
||||
public void increment() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
// Manually check that there is a warning from the 'declare warning' statement in
|
||||
// AnnotationAsyncExecutionAspect
|
||||
public int return5() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
public Future<Integer> incrementReturningAFuture() {
|
||||
counter++;
|
||||
return new AsyncResult<Integer>(5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class ClassWithQualifiedAsyncMethods {
|
||||
@Async
|
||||
public Future<Thread> defaultWork() {
|
||||
return new AsyncResult<Thread>(Thread.currentThread());
|
||||
}
|
||||
|
||||
@Async("e1")
|
||||
public Future<Thread> e1Work() {
|
||||
return new AsyncResult<Thread>(Thread.currentThread());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+34
-34
@@ -1,34 +1,34 @@
|
||||
/*
|
||||
* Copyright 2002-2006 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.
|
||||
*
|
||||
* Created on 11 Sep 2006 by Adrian Colyer
|
||||
*/
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ClassWithPrivateAnnotatedMember {
|
||||
|
||||
public void doSomething() {
|
||||
doInTransaction();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
private void doInTransaction() {}
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2006 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.
|
||||
*
|
||||
* Created on 11 Sep 2006 by Adrian Colyer
|
||||
*/
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ClassWithPrivateAnnotatedMember {
|
||||
|
||||
public void doSomething() {
|
||||
doInTransaction();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
private void doInTransaction() {}
|
||||
}
|
||||
|
||||
+34
-34
@@ -1,34 +1,34 @@
|
||||
/*
|
||||
* Copyright 2002-2006 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.
|
||||
*
|
||||
* Created on 11 Sep 2006 by Adrian Colyer
|
||||
*/
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ClassWithProtectedAnnotatedMember {
|
||||
|
||||
public void doSomething() {
|
||||
doInTransaction();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
protected void doInTransaction() {}
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2006 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.
|
||||
*
|
||||
* Created on 11 Sep 2006 by Adrian Colyer
|
||||
*/
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ClassWithProtectedAnnotatedMember {
|
||||
|
||||
public void doSomething() {
|
||||
doInTransaction();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
protected void doInTransaction() {}
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,10 +1,10 @@
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public interface ITransactional {
|
||||
|
||||
Object echo(Throwable t) throws Throwable;
|
||||
|
||||
}
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public interface ITransactional {
|
||||
|
||||
Object echo(Throwable t) throws Throwable;
|
||||
|
||||
}
|
||||
|
||||
+19
-19
@@ -1,19 +1,19 @@
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
public class MethodAnnotationOnClassWithNoInterface {
|
||||
|
||||
@Transactional(rollbackFor=InterruptedException.class)
|
||||
public Object echo(Throwable t) throws Throwable {
|
||||
if (t != null) {
|
||||
throw t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public void noTransactionAttribute() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
public class MethodAnnotationOnClassWithNoInterface {
|
||||
|
||||
@Transactional(rollbackFor=InterruptedException.class)
|
||||
public Object echo(Throwable t) throws Throwable {
|
||||
if (t != null) {
|
||||
throw t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public void noTransactionAttribute() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+18
-18
@@ -1,18 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.transaction.CallCountingTransactionManager"/>
|
||||
|
||||
<bean class="org.springframework.transaction.aspectj.AnnotationTransactionAspect" factory-method="aspectOf">
|
||||
<property name="transactionManager" ref="transactionManager"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.transaction.aspectj.TransactionalAnnotationOnlyOnClassWithNoInterface"/>
|
||||
|
||||
<bean class="org.springframework.transaction.aspectj.ClassWithProtectedAnnotatedMember"/>
|
||||
|
||||
<bean class="org.springframework.transaction.aspectj.ClassWithPrivateAnnotatedMember"/>
|
||||
|
||||
</beans>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.transaction.CallCountingTransactionManager"/>
|
||||
|
||||
<bean class="org.springframework.transaction.aspectj.AnnotationTransactionAspect" factory-method="aspectOf">
|
||||
<property name="transactionManager" ref="transactionManager"/>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.transaction.aspectj.TransactionalAnnotationOnlyOnClassWithNoInterface"/>
|
||||
|
||||
<bean class="org.springframework.transaction.aspectj.ClassWithProtectedAnnotatedMember"/>
|
||||
|
||||
<bean class="org.springframework.transaction.aspectj.ClassWithPrivateAnnotatedMember"/>
|
||||
|
||||
</beans>
|
||||
|
||||
+261
-261
@@ -1,261 +1,261 @@
|
||||
/*
|
||||
* Copyright 2002-2007 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.transaction.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
|
||||
import org.springframework.transaction.CallCountingTransactionManager;
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*/
|
||||
public class TransactionAspectTests extends AbstractDependencyInjectionSpringContextTests {
|
||||
|
||||
private TransactionAspectSupport transactionAspect;
|
||||
|
||||
private CallCountingTransactionManager txManager;
|
||||
|
||||
private TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface;
|
||||
|
||||
private ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod;
|
||||
|
||||
private ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod;
|
||||
|
||||
private MethodAnnotationOnClassWithNoInterface methodAnnotationOnly = new MethodAnnotationOnClassWithNoInterface();
|
||||
|
||||
|
||||
public void setAnnotationOnlyOnClassWithNoInterface(
|
||||
TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface) {
|
||||
this.annotationOnlyOnClassWithNoInterface = annotationOnlyOnClassWithNoInterface;
|
||||
}
|
||||
|
||||
public void setClassWithAnnotatedProtectedMethod(ClassWithProtectedAnnotatedMember aBean) {
|
||||
this.beanWithAnnotatedProtectedMethod = aBean;
|
||||
}
|
||||
|
||||
public void setClassWithAnnotatedPrivateMethod(ClassWithPrivateAnnotatedMember aBean) {
|
||||
this.beanWithAnnotatedPrivateMethod = aBean;
|
||||
}
|
||||
|
||||
public void setTransactionAspect(TransactionAspectSupport transactionAspect) {
|
||||
this.transactionAspect = transactionAspect;
|
||||
this.txManager = (CallCountingTransactionManager) transactionAspect.getTransactionManager();
|
||||
}
|
||||
|
||||
public TransactionAspectSupport getTransactionAspect() {
|
||||
return this.transactionAspect;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getConfigPath() {
|
||||
return "TransactionAspectTests-context.xml";
|
||||
}
|
||||
|
||||
|
||||
public void testCommitOnAnnotatedClass() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
annotationOnlyOnClassWithNoInterface.echo(null);
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
public void testCommitOnAnnotatedProtectedMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
beanWithAnnotatedProtectedMethod.doInTransaction();
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
public void testCommitOnAnnotatedPrivateMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
beanWithAnnotatedPrivateMethod.doSomething();
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
public void testNoCommitOnNonAnnotatedNonPublicMethodInTransactionalType() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0,txManager.begun);
|
||||
annotationOnlyOnClassWithNoInterface.nonTransactionalMethod();
|
||||
assertEquals(0,txManager.begun);
|
||||
}
|
||||
|
||||
public void testCommitOnAnnotatedMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
methodAnnotationOnly.echo(null);
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
|
||||
public static class NotTransactional {
|
||||
public void noop() {
|
||||
}
|
||||
}
|
||||
|
||||
public void testNotTransactional() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
new NotTransactional().noop();
|
||||
assertEquals(0, txManager.begun);
|
||||
}
|
||||
|
||||
|
||||
public void testDefaultCommitOnAnnotatedClass() throws Throwable {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return annotationOnlyOnClassWithNoInterface.echo(new Exception());
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
public void testDefaultRollbackOnAnnotatedClass() throws Throwable {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return annotationOnlyOnClassWithNoInterface.echo(new RuntimeException());
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
|
||||
public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface {
|
||||
}
|
||||
|
||||
public void testDefaultCommitOnSubclassOfAnnotatedClass() throws Throwable {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return new SubclassOfClassWithTransactionalAnnotation().echo(new Exception());
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface {
|
||||
}
|
||||
|
||||
public void testDefaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return new SubclassOfClassWithTransactionalMethodAnnotation().echo(new Exception());
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
public static class ImplementsAnnotatedInterface implements ITransactional {
|
||||
public Object echo(Throwable t) throws Throwable {
|
||||
if (t != null) {
|
||||
throw t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
public void testDefaultCommitOnImplementationOfAnnotatedInterface() throws Throwable {
|
||||
// testRollback(new TransactionOperationCallback() {
|
||||
// public Object performTransactionalOperation() throws Throwable {
|
||||
// return new ImplementsAnnotatedInterface().echo(new Exception());
|
||||
// }
|
||||
// }, false);
|
||||
|
||||
final Exception ex = new Exception();
|
||||
testNotTransactional(new TransactionOperationCallback() {
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return new ImplementsAnnotatedInterface().echo(ex);
|
||||
}
|
||||
}, ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: resolution does not occur. Thus we can't make a class transactional if
|
||||
* it implements a transactionally annotated interface. This behaviour could only
|
||||
* be changed in AbstractFallbackTransactionAttributeSource in Spring proper.
|
||||
* @throws SecurityException
|
||||
* @throws NoSuchMethodException
|
||||
*/
|
||||
public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws SecurityException, NoSuchMethodException {
|
||||
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
|
||||
Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
|
||||
TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class);
|
||||
assertNull(ta);
|
||||
}
|
||||
|
||||
|
||||
public void testDefaultRollbackOnImplementationOfAnnotatedInterface() throws Throwable {
|
||||
// testRollback(new TransactionOperationCallback() {
|
||||
// public Object performTransactionalOperation() throws Throwable {
|
||||
// return new ImplementsAnnotatedInterface().echo(new RuntimeException());
|
||||
// }
|
||||
// }, true);
|
||||
|
||||
final Exception rollbackProvokingException = new RuntimeException();
|
||||
testNotTransactional(new TransactionOperationCallback() {
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return new ImplementsAnnotatedInterface().echo(rollbackProvokingException);
|
||||
}
|
||||
}, rollbackProvokingException);
|
||||
}
|
||||
|
||||
|
||||
protected void testRollback(TransactionOperationCallback toc, boolean rollback) throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
try {
|
||||
toc.performTransactionalOperation();
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
catch (Throwable caught) {
|
||||
if (caught instanceof AssertionFailedError) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (rollback) {
|
||||
assertEquals(1, txManager.rollbacks);
|
||||
}
|
||||
assertEquals(1, txManager.begun);
|
||||
}
|
||||
|
||||
protected void testNotTransactional(TransactionOperationCallback toc, Throwable expected) throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
try {
|
||||
toc.performTransactionalOperation();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
if (expected == null) {
|
||||
fail("Expected " + expected);
|
||||
}
|
||||
assertSame(expected, t);
|
||||
}
|
||||
finally {
|
||||
assertEquals(0, txManager.begun);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private interface TransactionOperationCallback {
|
||||
|
||||
Object performTransactionalOperation() throws Throwable;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2007 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.transaction.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
|
||||
import org.springframework.transaction.CallCountingTransactionManager;
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*/
|
||||
public class TransactionAspectTests extends AbstractDependencyInjectionSpringContextTests {
|
||||
|
||||
private TransactionAspectSupport transactionAspect;
|
||||
|
||||
private CallCountingTransactionManager txManager;
|
||||
|
||||
private TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface;
|
||||
|
||||
private ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod;
|
||||
|
||||
private ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod;
|
||||
|
||||
private MethodAnnotationOnClassWithNoInterface methodAnnotationOnly = new MethodAnnotationOnClassWithNoInterface();
|
||||
|
||||
|
||||
public void setAnnotationOnlyOnClassWithNoInterface(
|
||||
TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface) {
|
||||
this.annotationOnlyOnClassWithNoInterface = annotationOnlyOnClassWithNoInterface;
|
||||
}
|
||||
|
||||
public void setClassWithAnnotatedProtectedMethod(ClassWithProtectedAnnotatedMember aBean) {
|
||||
this.beanWithAnnotatedProtectedMethod = aBean;
|
||||
}
|
||||
|
||||
public void setClassWithAnnotatedPrivateMethod(ClassWithPrivateAnnotatedMember aBean) {
|
||||
this.beanWithAnnotatedPrivateMethod = aBean;
|
||||
}
|
||||
|
||||
public void setTransactionAspect(TransactionAspectSupport transactionAspect) {
|
||||
this.transactionAspect = transactionAspect;
|
||||
this.txManager = (CallCountingTransactionManager) transactionAspect.getTransactionManager();
|
||||
}
|
||||
|
||||
public TransactionAspectSupport getTransactionAspect() {
|
||||
return this.transactionAspect;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getConfigPath() {
|
||||
return "TransactionAspectTests-context.xml";
|
||||
}
|
||||
|
||||
|
||||
public void testCommitOnAnnotatedClass() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
annotationOnlyOnClassWithNoInterface.echo(null);
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
public void testCommitOnAnnotatedProtectedMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
beanWithAnnotatedProtectedMethod.doInTransaction();
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
public void testCommitOnAnnotatedPrivateMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
beanWithAnnotatedPrivateMethod.doSomething();
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
public void testNoCommitOnNonAnnotatedNonPublicMethodInTransactionalType() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0,txManager.begun);
|
||||
annotationOnlyOnClassWithNoInterface.nonTransactionalMethod();
|
||||
assertEquals(0,txManager.begun);
|
||||
}
|
||||
|
||||
public void testCommitOnAnnotatedMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
methodAnnotationOnly.echo(null);
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
|
||||
public static class NotTransactional {
|
||||
public void noop() {
|
||||
}
|
||||
}
|
||||
|
||||
public void testNotTransactional() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
new NotTransactional().noop();
|
||||
assertEquals(0, txManager.begun);
|
||||
}
|
||||
|
||||
|
||||
public void testDefaultCommitOnAnnotatedClass() throws Throwable {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return annotationOnlyOnClassWithNoInterface.echo(new Exception());
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
public void testDefaultRollbackOnAnnotatedClass() throws Throwable {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return annotationOnlyOnClassWithNoInterface.echo(new RuntimeException());
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
|
||||
public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface {
|
||||
}
|
||||
|
||||
public void testDefaultCommitOnSubclassOfAnnotatedClass() throws Throwable {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return new SubclassOfClassWithTransactionalAnnotation().echo(new Exception());
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface {
|
||||
}
|
||||
|
||||
public void testDefaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return new SubclassOfClassWithTransactionalMethodAnnotation().echo(new Exception());
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
public static class ImplementsAnnotatedInterface implements ITransactional {
|
||||
public Object echo(Throwable t) throws Throwable {
|
||||
if (t != null) {
|
||||
throw t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
public void testDefaultCommitOnImplementationOfAnnotatedInterface() throws Throwable {
|
||||
// testRollback(new TransactionOperationCallback() {
|
||||
// public Object performTransactionalOperation() throws Throwable {
|
||||
// return new ImplementsAnnotatedInterface().echo(new Exception());
|
||||
// }
|
||||
// }, false);
|
||||
|
||||
final Exception ex = new Exception();
|
||||
testNotTransactional(new TransactionOperationCallback() {
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return new ImplementsAnnotatedInterface().echo(ex);
|
||||
}
|
||||
}, ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: resolution does not occur. Thus we can't make a class transactional if
|
||||
* it implements a transactionally annotated interface. This behaviour could only
|
||||
* be changed in AbstractFallbackTransactionAttributeSource in Spring proper.
|
||||
* @throws SecurityException
|
||||
* @throws NoSuchMethodException
|
||||
*/
|
||||
public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws SecurityException, NoSuchMethodException {
|
||||
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
|
||||
Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
|
||||
TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class);
|
||||
assertNull(ta);
|
||||
}
|
||||
|
||||
|
||||
public void testDefaultRollbackOnImplementationOfAnnotatedInterface() throws Throwable {
|
||||
// testRollback(new TransactionOperationCallback() {
|
||||
// public Object performTransactionalOperation() throws Throwable {
|
||||
// return new ImplementsAnnotatedInterface().echo(new RuntimeException());
|
||||
// }
|
||||
// }, true);
|
||||
|
||||
final Exception rollbackProvokingException = new RuntimeException();
|
||||
testNotTransactional(new TransactionOperationCallback() {
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return new ImplementsAnnotatedInterface().echo(rollbackProvokingException);
|
||||
}
|
||||
}, rollbackProvokingException);
|
||||
}
|
||||
|
||||
|
||||
protected void testRollback(TransactionOperationCallback toc, boolean rollback) throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
try {
|
||||
toc.performTransactionalOperation();
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
catch (Throwable caught) {
|
||||
if (caught instanceof AssertionFailedError) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (rollback) {
|
||||
assertEquals(1, txManager.rollbacks);
|
||||
}
|
||||
assertEquals(1, txManager.begun);
|
||||
}
|
||||
|
||||
protected void testNotTransactional(TransactionOperationCallback toc, Throwable expected) throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
try {
|
||||
toc.performTransactionalOperation();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
if (expected == null) {
|
||||
fail("Expected " + expected);
|
||||
}
|
||||
assertSame(expected, t);
|
||||
}
|
||||
finally {
|
||||
assertEquals(0, txManager.begun);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private interface TransactionOperationCallback {
|
||||
|
||||
Object performTransactionalOperation() throws Throwable;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-20
@@ -1,20 +1,20 @@
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public class TransactionalAnnotationOnlyOnClassWithNoInterface {
|
||||
|
||||
public Object echo(Throwable t) throws Throwable {
|
||||
if (t != null) {
|
||||
throw t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void nonTransactionalMethod() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public class TransactionalAnnotationOnlyOnClassWithNoInterface {
|
||||
|
||||
public Object echo(Throwable t) throws Throwable {
|
||||
if (t != null) {
|
||||
throw t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void nonTransactionalMethod() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
Bundle-SymbolicName: org.springframework.aspects
|
||||
Bundle-Name: Spring Aspects
|
||||
Bundle-Vendor: SpringSource
|
||||
Bundle-ManifestVersion: 2
|
||||
Import-Template:
|
||||
javax.persistence;version="[1.0.0,3.0.0)";resolution:=optional,
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
org.aspectj.*;version=${aj.osgi.range};resolution:=optional,
|
||||
org.springframework.context.*;version=${spring.osgi.range},
|
||||
org.springframework.beans.*;version=${spring.osgi.range},
|
||||
org.springframework.cache.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.core.*;version=${spring.osgi.range},
|
||||
org.springframework.dao.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.orm.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.scheduling.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.transaction.*;version=${spring.osgi.range};resolution:=optional
|
||||
Ignored-Existing-Headers:
|
||||
Bnd-LastModified,
|
||||
Import-Package,
|
||||
Tool
|
||||
Bundle-SymbolicName: org.springframework.aspects
|
||||
Bundle-Name: Spring Aspects
|
||||
Bundle-Vendor: SpringSource
|
||||
Bundle-ManifestVersion: 2
|
||||
Import-Template:
|
||||
javax.persistence;version="[1.0.0,3.0.0)";resolution:=optional,
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
org.aspectj.*;version=${aj.osgi.range};resolution:=optional,
|
||||
org.springframework.context.*;version=${spring.osgi.range},
|
||||
org.springframework.beans.*;version=${spring.osgi.range},
|
||||
org.springframework.cache.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.core.*;version=${spring.osgi.range},
|
||||
org.springframework.dao.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.orm.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.scheduling.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.transaction.*;version=${spring.osgi.range};resolution:=optional
|
||||
Ignored-Existing-Headers:
|
||||
Bnd-LastModified,
|
||||
Import-Package,
|
||||
Tool
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module relativePaths="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="module" module-name="core" />
|
||||
<orderEntry type="library" name="CGLIB" level="project" />
|
||||
<orderEntry type="library" name="Commons Logging" level="project" />
|
||||
<orderEntry type="library" name="EasyMock" level="project" />
|
||||
<orderEntry type="library" name="javax.el" level="project" />
|
||||
<orderEntry type="library" name="javax.inject" level="project" />
|
||||
<orderEntry type="library" name="Hamcrest" level="project" />
|
||||
<orderEntry type="library" name="JUnit" level="project" />
|
||||
<orderEntry type="library" name="Log4j" level="project" />
|
||||
</component>
|
||||
<component name="copyright">
|
||||
<Base>
|
||||
<setting name="state" value="2" />
|
||||
</Base>
|
||||
</component>
|
||||
</module>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module relativePaths="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="module" module-name="core" />
|
||||
<orderEntry type="library" name="CGLIB" level="project" />
|
||||
<orderEntry type="library" name="Commons Logging" level="project" />
|
||||
<orderEntry type="library" name="EasyMock" level="project" />
|
||||
<orderEntry type="library" name="javax.el" level="project" />
|
||||
<orderEntry type="library" name="javax.inject" level="project" />
|
||||
<orderEntry type="library" name="Hamcrest" level="project" />
|
||||
<orderEntry type="library" name="JUnit" level="project" />
|
||||
<orderEntry type="library" name="Log4j" level="project" />
|
||||
</component>
|
||||
<component name="copyright">
|
||||
<Base>
|
||||
<setting name="state" value="2" />
|
||||
</Base>
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>3.1.5.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>3.1.5.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
@@ -22,13 +30,13 @@
|
||||
<groupId>javax.el</groupId>
|
||||
<artifactId>el-api</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>provided</scope>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
<version>1</version>
|
||||
<scope>provided</scope>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
|
||||
+16
-14
@@ -512,11 +512,15 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
|
||||
private Object convertForProperty(String propertyName, Object oldValue, Object newValue, PropertyDescriptor pd)
|
||||
throws TypeMismatchException {
|
||||
GenericTypeAwarePropertyDescriptor gpd = (GenericTypeAwarePropertyDescriptor) pd;
|
||||
Class<?> beanClass = gpd.getBeanClass();
|
||||
|
||||
return convertIfNecessary(propertyName, oldValue, newValue, pd.getPropertyType(), new TypeDescriptor(property(pd)));
|
||||
}
|
||||
|
||||
private Property property(PropertyDescriptor pd) {
|
||||
GenericTypeAwarePropertyDescriptor typeAware = (GenericTypeAwarePropertyDescriptor) pd;
|
||||
return new Property(typeAware.getBeanClass(), typeAware.getReadMethod(), typeAware.getWriteMethod());
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation methods
|
||||
@@ -970,7 +974,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
|
||||
oldValue = Array.get(propValue, arrayIndex);
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
|
||||
Array.set(propValue, arrayIndex, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
@@ -984,12 +989,13 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
pd.getReadMethod(), tokens.keys.length);
|
||||
List list = (List) propValue;
|
||||
int index = Integer.parseInt(key);
|
||||
int size = list.size();
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor() && index < size) {
|
||||
if (isExtractOldValueForEditor() && index < list.size()) {
|
||||
oldValue = list.get(index);
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
|
||||
int size = list.size();
|
||||
if (index >= size && index < this.autoGrowCollectionLimit) {
|
||||
for (int i = size; i < index; i++) {
|
||||
try {
|
||||
@@ -1023,7 +1029,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
Map map = (Map) propValue;
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
TypeDescriptor typeDescriptor = mapKeyType != null ? TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class);
|
||||
TypeDescriptor typeDescriptor = (mapKeyType != null ?
|
||||
TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class));
|
||||
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor()) {
|
||||
@@ -1031,8 +1038,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
// Pass full property name and old value in here, since we want full
|
||||
// conversion ability for map values.
|
||||
Object convertedMapValue = convertIfNecessary(
|
||||
propertyName, oldValue, pv.getValue(), mapValueType, TypeDescriptor.nested(property(pd), tokens.keys.length));
|
||||
Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
mapValueType, TypeDescriptor.nested(property(pd), tokens.keys.length));
|
||||
map.put(convertedMapKey, convertedMapValue);
|
||||
}
|
||||
else {
|
||||
@@ -1194,10 +1201,5 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
|
||||
public String[] keys;
|
||||
}
|
||||
|
||||
private Property property(PropertyDescriptor pd) {
|
||||
GenericTypeAwarePropertyDescriptor typeAware = (GenericTypeAwarePropertyDescriptor) pd;
|
||||
return new Property(typeAware.getBeanClass(), typeAware.getReadMethod(), typeAware.getWriteMethod());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* 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.
|
||||
@@ -22,6 +22,7 @@ import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -32,7 +33,6 @@ import java.util.WeakHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -100,9 +100,6 @@ public class CachedIntrospectionResults {
|
||||
* @param classLoader the ClassLoader to clear the cache for
|
||||
*/
|
||||
public static void clearClassLoader(ClassLoader classLoader) {
|
||||
if (classLoader == null) {
|
||||
return;
|
||||
}
|
||||
synchronized (classCache) {
|
||||
for (Iterator<Class> it = classCache.keySet().iterator(); it.hasNext();) {
|
||||
Class beanClass = it.next();
|
||||
@@ -140,20 +137,16 @@ public class CachedIntrospectionResults {
|
||||
results = (CachedIntrospectionResults) value;
|
||||
}
|
||||
if (results == null) {
|
||||
// On JDK 1.5 and higher, it is almost always safe to cache the bean class...
|
||||
// The sole exception is a custom BeanInfo class being provided in a non-safe ClassLoader.
|
||||
boolean fullyCacheable =
|
||||
ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
|
||||
isClassLoaderAccepted(beanClass.getClassLoader());
|
||||
if (fullyCacheable || !ClassUtils.isPresent(beanClass.getName() + "BeanInfo", beanClass.getClassLoader())) {
|
||||
results = new CachedIntrospectionResults(beanClass, fullyCacheable);
|
||||
if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
|
||||
isClassLoaderAccepted(beanClass.getClassLoader())) {
|
||||
results = new CachedIntrospectionResults(beanClass);
|
||||
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, true);
|
||||
results = new CachedIntrospectionResults(beanClass);
|
||||
classCache.put(beanClass, new WeakReference<CachedIntrospectionResults>(results));
|
||||
}
|
||||
}
|
||||
@@ -187,12 +180,12 @@ public class CachedIntrospectionResults {
|
||||
* @param parent the parent ClassLoader to check for
|
||||
*/
|
||||
private static boolean isUnderneathClassLoader(ClassLoader candidate, ClassLoader parent) {
|
||||
if (candidate == null) {
|
||||
return false;
|
||||
}
|
||||
if (candidate == parent) {
|
||||
return true;
|
||||
}
|
||||
if (candidate == null) {
|
||||
return false;
|
||||
}
|
||||
ClassLoader classLoaderToCheck = candidate;
|
||||
while (classLoaderToCheck != null) {
|
||||
classLoaderToCheck = classLoaderToCheck.getParent();
|
||||
@@ -216,12 +209,20 @@ public class CachedIntrospectionResults {
|
||||
* @param beanClass the bean class to analyze
|
||||
* @throws BeansException in case of introspection failure
|
||||
*/
|
||||
private CachedIntrospectionResults(Class beanClass, boolean cacheFullMetadata) throws BeansException {
|
||||
private CachedIntrospectionResults(Class beanClass) throws BeansException {
|
||||
try {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Getting BeanInfo for class [" + beanClass.getName() + "]");
|
||||
}
|
||||
this.beanInfo = new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass));
|
||||
BeanInfo originalBeanInfo = Introspector.getBeanInfo(beanClass);
|
||||
BeanInfo extendedBeanInfo = null;
|
||||
for (Method method : beanClass.getMethods()) {
|
||||
if (ExtendedBeanInfo.isCandidateWriteMethod(method)) {
|
||||
extendedBeanInfo = new ExtendedBeanInfo(originalBeanInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.beanInfo = extendedBeanInfo != null ? extendedBeanInfo : originalBeanInfo;
|
||||
|
||||
// Immediately remove class from Introspector cache, to allow for proper
|
||||
// garbage collection on class loader shutdown - we cache it here anyway,
|
||||
@@ -252,9 +253,7 @@ public class CachedIntrospectionResults {
|
||||
(pd.getPropertyEditorClass() != null ?
|
||||
"; editor [" + pd.getPropertyEditorClass().getName() + "]" : ""));
|
||||
}
|
||||
if (cacheFullMetadata) {
|
||||
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
|
||||
}
|
||||
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
|
||||
this.propertyDescriptorCache.put(pd.getName(), pd);
|
||||
}
|
||||
}
|
||||
|
||||
+579
-239
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* 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.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.beans;
|
||||
|
||||
import java.awt.Image;
|
||||
|
||||
import java.beans.BeanDescriptor;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.EventSetDescriptor;
|
||||
@@ -25,250 +26,202 @@ import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.MethodDescriptor;
|
||||
import java.beans.PropertyDescriptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.SortedSet;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import static org.springframework.beans.PropertyDescriptorUtils.*;
|
||||
|
||||
/**
|
||||
* Decorates a standard {@link BeanInfo} object (likely created created by
|
||||
* {@link Introspector#getBeanInfo(Class)}) by including non-void returning setter
|
||||
* methods in the collection of {@link #getPropertyDescriptors() property descriptors}.
|
||||
* Both regular and
|
||||
* <a href="http://download.oracle.com/javase/tutorial/javabeans/properties/indexed.html">
|
||||
* indexed properties</a> are fully supported.
|
||||
* Decorator for a standard {@link BeanInfo} object, e.g. as created by
|
||||
* {@link Introspector#getBeanInfo(Class)}, designed to discover and register static
|
||||
* and/or non-void returning setter methods. For example:
|
||||
* <pre>{@code
|
||||
* public class Bean {
|
||||
* private Foo foo;
|
||||
*
|
||||
* <p>The wrapped {@code BeanInfo} object is not modified in any way.
|
||||
* public Foo getFoo() {
|
||||
* return this.foo;
|
||||
* }
|
||||
*
|
||||
* public Bean setFoo(Foo foo) {
|
||||
* this.foo = foo;
|
||||
* return this;
|
||||
* }
|
||||
* }</pre>
|
||||
* The standard JavaBeans {@code Introspector} will discover the {@code getFoo} read
|
||||
* method, but will bypass the {@code #setFoo(Foo)} write method, because its non-void
|
||||
* returning signature does not comply with the JavaBeans specification.
|
||||
* {@code ExtendedBeanInfo}, on the other hand, will recognize and include it. This is
|
||||
* designed to allow APIs with "builder" or method-chaining style setter signatures to be
|
||||
* used within Spring {@code <beans>} XML. {@link #getPropertyDescriptors()} returns all
|
||||
* existing property descriptors from the wrapped {@code BeanInfo} as well any added for
|
||||
* non-void returning setters. Both standard ("non-indexed") and
|
||||
* <a href="http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html">
|
||||
* indexed properties</a> are fully supported.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see #ExtendedBeanInfo(BeanInfo)
|
||||
* @see CachedIntrospectionResults
|
||||
*/
|
||||
class ExtendedBeanInfo implements BeanInfo {
|
||||
|
||||
private final BeanInfo delegate;
|
||||
private final SortedSet<PropertyDescriptor> propertyDescriptors =
|
||||
new TreeSet<PropertyDescriptor>(new PropertyDescriptorComparator());
|
||||
|
||||
private final Set<PropertyDescriptor> propertyDescriptors =
|
||||
new TreeSet<PropertyDescriptor>(new PropertyDescriptorComparator());
|
||||
|
||||
|
||||
/**
|
||||
* Wrap the given delegate {@link BeanInfo} instance and find any non-void returning
|
||||
* setter methods, creating and adding a {@link PropertyDescriptor} for each.
|
||||
*
|
||||
* <p>The wrapped {@code BeanInfo} is not modified in any way by this process.
|
||||
*
|
||||
* Wrap the given {@link BeanInfo} instance; copy all its existing property descriptors
|
||||
* locally, wrapping each in a custom {@link SimpleIndexedPropertyDescriptor indexed} or
|
||||
* {@link SimpleNonIndexedPropertyDescriptor non-indexed} {@code PropertyDescriptor}
|
||||
* variant that bypasses default JDK weak/soft reference management; then search
|
||||
* through its method descriptors to find any non-void returning write methods and
|
||||
* update or create the corresponding {@link PropertyDescriptor} for each one found.
|
||||
* @param delegate the wrapped {@code BeanInfo}, which is never modified
|
||||
* @throws IntrospectionException if any problems occur creating and adding new
|
||||
* property descriptors
|
||||
* @see #getPropertyDescriptors()
|
||||
* @throws IntrospectionException if any problems occur creating and adding new {@code PropertyDescriptors}
|
||||
*/
|
||||
public ExtendedBeanInfo(BeanInfo delegate) throws IntrospectionException {
|
||||
this.delegate = delegate;
|
||||
|
||||
// PropertyDescriptor instances from the delegate object are never added directly, but always
|
||||
// copied to the local collection of #propertyDescriptors and returned by calls to
|
||||
// #getPropertyDescriptors(). this algorithm iterates through all methods (method descriptors)
|
||||
// in the wrapped BeanInfo object, copying any existing PropertyDescriptor or creating a new
|
||||
// one for any non-standard setter methods found.
|
||||
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
|
||||
this.propertyDescriptors.add(pd instanceof IndexedPropertyDescriptor ?
|
||||
new SimpleIndexedPropertyDescriptor((IndexedPropertyDescriptor) pd) :
|
||||
new SimpleNonIndexedPropertyDescriptor(pd));
|
||||
}
|
||||
|
||||
ALL_METHODS:
|
||||
for (MethodDescriptor md : delegate.getMethodDescriptors()) {
|
||||
Method method = md.getMethod();
|
||||
|
||||
// bypass non-getter java.lang.Class methods for efficiency
|
||||
if (ReflectionUtils.isObjectMethod(method) && !method.getName().startsWith("get")) {
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
|
||||
// is the method a NON-INDEXED setter? ignore return type in order to capture non-void signatures
|
||||
if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) {
|
||||
String propertyName = propertyNameFor(method);
|
||||
if(propertyName.length() == 0) {
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
|
||||
Method readMethod = pd.getReadMethod();
|
||||
Method writeMethod = pd.getWriteMethod();
|
||||
// has the setter already been found by the wrapped BeanInfo?
|
||||
if (writeMethod != null
|
||||
&& writeMethod.getName().equals(method.getName())) {
|
||||
// yes -> copy it, including corresponding getter method (if any -- may be null)
|
||||
this.addOrUpdatePropertyDescriptor(propertyName, readMethod, writeMethod);
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
// has a getter corresponding to this setter already been found by the wrapped BeanInfo?
|
||||
if (readMethod != null
|
||||
&& readMethod.getName().equals(getterMethodNameFor(propertyName))
|
||||
&& readMethod.getReturnType().equals(method.getParameterTypes()[0])) {
|
||||
this.addOrUpdatePropertyDescriptor(propertyName, readMethod, method);
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
}
|
||||
// the setter method was not found by the wrapped BeanInfo -> add a new PropertyDescriptor for it
|
||||
// no corresponding getter was detected, so the 'read method' parameter is null.
|
||||
this.addOrUpdatePropertyDescriptor(propertyName, null, method);
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
|
||||
// is the method an INDEXED setter? ignore return type in order to capture non-void signatures
|
||||
if (method.getName().startsWith("set") && method.getParameterTypes().length == 2 && method.getParameterTypes()[0].equals(int.class)) {
|
||||
String propertyName = propertyNameFor(method);
|
||||
if(propertyName.length() == 0) {
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
DELEGATE_PD:
|
||||
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
|
||||
if (!(pd instanceof IndexedPropertyDescriptor)) {
|
||||
continue DELEGATE_PD;
|
||||
}
|
||||
IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
|
||||
Method readMethod = ipd.getReadMethod();
|
||||
Method writeMethod = ipd.getWriteMethod();
|
||||
Method indexedReadMethod = ipd.getIndexedReadMethod();
|
||||
Method indexedWriteMethod = ipd.getIndexedWriteMethod();
|
||||
// has the setter already been found by the wrapped BeanInfo?
|
||||
if (indexedWriteMethod != null
|
||||
&& indexedWriteMethod.getName().equals(method.getName())) {
|
||||
// yes -> copy it, including corresponding getter method (if any -- may be null)
|
||||
this.addOrUpdatePropertyDescriptor(propertyName, readMethod, writeMethod, indexedReadMethod, indexedWriteMethod);
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
// has a getter corresponding to this setter already been found by the wrapped BeanInfo?
|
||||
if (indexedReadMethod != null
|
||||
&& indexedReadMethod.getName().equals(getterMethodNameFor(propertyName))
|
||||
&& indexedReadMethod.getReturnType().equals(method.getParameterTypes()[1])) {
|
||||
this.addOrUpdatePropertyDescriptor(propertyName, readMethod, writeMethod, indexedReadMethod, method);
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
}
|
||||
// the INDEXED setter method was not found by the wrapped BeanInfo -> add a new PropertyDescriptor
|
||||
// for it. no corresponding INDEXED getter was detected, so the 'indexed read method' parameter is null.
|
||||
this.addOrUpdatePropertyDescriptor(propertyName, null, null, null, method);
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
|
||||
// the method is not a setter, but is it a getter?
|
||||
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
|
||||
// have we already copied this read method to a property descriptor locally?
|
||||
for (PropertyDescriptor existingPD : this.propertyDescriptors) {
|
||||
if (method.equals(pd.getReadMethod())
|
||||
&& existingPD.getName().equals(pd.getName())) {
|
||||
if (existingPD.getReadMethod() == null) {
|
||||
// no -> add it now
|
||||
this.addOrUpdatePropertyDescriptor(pd.getName(), method, pd.getWriteMethod());
|
||||
}
|
||||
// yes -> do not add a duplicate
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
}
|
||||
if (method == pd.getReadMethod()
|
||||
|| (pd instanceof IndexedPropertyDescriptor && method == ((IndexedPropertyDescriptor) pd).getIndexedReadMethod())) {
|
||||
// yes -> copy it, including corresponding setter method (if any -- may be null)
|
||||
if (pd instanceof IndexedPropertyDescriptor) {
|
||||
this.addOrUpdatePropertyDescriptor(pd.getName(), pd.getReadMethod(), pd.getWriteMethod(), ((IndexedPropertyDescriptor)pd).getIndexedReadMethod(), ((IndexedPropertyDescriptor)pd).getIndexedWriteMethod());
|
||||
} else {
|
||||
this.addOrUpdatePropertyDescriptor(pd.getName(), pd.getReadMethod(), pd.getWriteMethod());
|
||||
}
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
}
|
||||
for (Method method : findCandidateWriteMethods(delegate.getMethodDescriptors())) {
|
||||
handleCandidateWriteMethod(method);
|
||||
}
|
||||
}
|
||||
|
||||
private void addOrUpdatePropertyDescriptor(String propertyName, Method readMethod, Method writeMethod) throws IntrospectionException {
|
||||
addOrUpdatePropertyDescriptor(propertyName, readMethod, writeMethod, null, null);
|
||||
}
|
||||
|
||||
private void addOrUpdatePropertyDescriptor(String propertyName, Method readMethod, Method writeMethod, Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException {
|
||||
for (PropertyDescriptor existingPD : this.propertyDescriptors) {
|
||||
if (existingPD.getName().equals(propertyName)) {
|
||||
// is there already a descriptor that captures this read method or its corresponding write method?
|
||||
if (existingPD.getReadMethod() != null) {
|
||||
if (readMethod != null && existingPD.getReadMethod().getReturnType() != readMethod.getReturnType()
|
||||
|| writeMethod != null && existingPD.getReadMethod().getReturnType() != writeMethod.getParameterTypes()[0]) {
|
||||
// no -> add a new descriptor for it below
|
||||
break;
|
||||
}
|
||||
}
|
||||
// update the existing descriptor's read method
|
||||
if (readMethod != null) {
|
||||
try {
|
||||
existingPD.setReadMethod(readMethod);
|
||||
} catch (IntrospectionException ex) {
|
||||
// there is a conflicting setter method present -> null it out and try again
|
||||
existingPD.setWriteMethod(null);
|
||||
existingPD.setReadMethod(readMethod);
|
||||
}
|
||||
}
|
||||
|
||||
// is there already a descriptor that captures this write method or its corresponding read method?
|
||||
if (existingPD.getWriteMethod() != null) {
|
||||
if (readMethod != null && existingPD.getWriteMethod().getParameterTypes()[0] != readMethod.getReturnType()
|
||||
|| writeMethod != null && existingPD.getWriteMethod().getParameterTypes()[0] != writeMethod.getParameterTypes()[0]) {
|
||||
// no -> add a new descriptor for it below
|
||||
break;
|
||||
}
|
||||
}
|
||||
// update the existing descriptor's write method
|
||||
if (writeMethod != null) {
|
||||
existingPD.setWriteMethod(writeMethod);
|
||||
}
|
||||
|
||||
// is this descriptor indexed?
|
||||
if (existingPD instanceof IndexedPropertyDescriptor) {
|
||||
IndexedPropertyDescriptor existingIPD = (IndexedPropertyDescriptor) existingPD;
|
||||
|
||||
// is there already a descriptor that captures this indexed read method or its corresponding indexed write method?
|
||||
if (existingIPD.getIndexedReadMethod() != null) {
|
||||
if (indexedReadMethod != null && existingIPD.getIndexedReadMethod().getReturnType() != indexedReadMethod.getReturnType()
|
||||
|| indexedWriteMethod != null && existingIPD.getIndexedReadMethod().getReturnType() != indexedWriteMethod.getParameterTypes()[1]) {
|
||||
// no -> add a new descriptor for it below
|
||||
break;
|
||||
}
|
||||
}
|
||||
// update the existing descriptor's indexed read method
|
||||
try {
|
||||
if (indexedReadMethod != null) {
|
||||
existingIPD.setIndexedReadMethod(indexedReadMethod);
|
||||
}
|
||||
} catch (IntrospectionException ex) {
|
||||
// there is a conflicting indexed setter method present -> null it out and try again
|
||||
existingIPD.setIndexedWriteMethod(null);
|
||||
existingIPD.setIndexedReadMethod(indexedReadMethod);
|
||||
}
|
||||
|
||||
// is there already a descriptor that captures this indexed write method or its corresponding indexed read method?
|
||||
if (existingIPD.getIndexedWriteMethod() != null) {
|
||||
if (indexedReadMethod != null && existingIPD.getIndexedWriteMethod().getParameterTypes()[1] != indexedReadMethod.getReturnType()
|
||||
|| indexedWriteMethod != null && existingIPD.getIndexedWriteMethod().getParameterTypes()[1] != indexedWriteMethod.getParameterTypes()[1]) {
|
||||
// no -> add a new descriptor for it below
|
||||
break;
|
||||
}
|
||||
}
|
||||
// update the existing descriptor's indexed write method
|
||||
if (indexedWriteMethod != null) {
|
||||
existingIPD.setIndexedWriteMethod(indexedWriteMethod);
|
||||
}
|
||||
}
|
||||
|
||||
// the descriptor has been updated -> return immediately
|
||||
return;
|
||||
private List<Method> findCandidateWriteMethods(MethodDescriptor[] methodDescriptors) {
|
||||
List<Method> matches = new ArrayList<Method>();
|
||||
for (MethodDescriptor methodDescriptor : methodDescriptors) {
|
||||
Method method = methodDescriptor.getMethod();
|
||||
if (isCandidateWriteMethod(method)) {
|
||||
matches.add(method);
|
||||
}
|
||||
}
|
||||
// sort non-void returning write methods to guard against the ill effects of
|
||||
// non-deterministic sorting of methods returned from Class#getDeclaredMethods
|
||||
// under JDK 7. See http://bugs.sun.com/view_bug.do?bug_id=7023180
|
||||
Collections.sort(matches, new Comparator<Method>() {
|
||||
public int compare(Method m1, Method m2) {
|
||||
return m2.toString().compareTo(m1.toString());
|
||||
}
|
||||
});
|
||||
return matches;
|
||||
}
|
||||
|
||||
// we haven't yet seen read or write methods for this property -> add a new descriptor
|
||||
if (indexedReadMethod == null && indexedWriteMethod == null) {
|
||||
this.propertyDescriptors.add(new PropertyDescriptor(propertyName, readMethod, writeMethod));
|
||||
} else {
|
||||
this.propertyDescriptors.add(new IndexedPropertyDescriptor(propertyName, readMethod, writeMethod, indexedReadMethod, indexedWriteMethod));
|
||||
public static boolean isCandidateWriteMethod(Method method) {
|
||||
String methodName = method.getName();
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
int nParams = parameterTypes.length;
|
||||
if (methodName.length() > 3 && methodName.startsWith("set") &&
|
||||
Modifier.isPublic(method.getModifiers()) &&
|
||||
(
|
||||
!void.class.isAssignableFrom(method.getReturnType()) ||
|
||||
Modifier.isStatic(method.getModifiers())
|
||||
) &&
|
||||
(nParams == 1 || (nParams == 2 && parameterTypes[0].equals(int.class)))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handleCandidateWriteMethod(Method method) throws IntrospectionException {
|
||||
int nParams = method.getParameterTypes().length;
|
||||
String propertyName = propertyNameFor(method);
|
||||
Class<?> propertyType = method.getParameterTypes()[nParams-1];
|
||||
PropertyDescriptor existingPD = findExistingPropertyDescriptor(propertyName, propertyType);
|
||||
if (nParams == 1) {
|
||||
if (existingPD == null) {
|
||||
this.propertyDescriptors.add(
|
||||
new SimpleNonIndexedPropertyDescriptor(propertyName, null, method));
|
||||
}
|
||||
else {
|
||||
existingPD.setWriteMethod(method);
|
||||
}
|
||||
}
|
||||
else if (nParams == 2) {
|
||||
if (existingPD == null) {
|
||||
this.propertyDescriptors.add(
|
||||
new SimpleIndexedPropertyDescriptor(
|
||||
propertyName, null, null, null, method));
|
||||
}
|
||||
else if (existingPD instanceof IndexedPropertyDescriptor) {
|
||||
((IndexedPropertyDescriptor)existingPD).setIndexedWriteMethod(method);
|
||||
}
|
||||
else {
|
||||
this.propertyDescriptors.remove(existingPD);
|
||||
this.propertyDescriptors.add(
|
||||
new SimpleIndexedPropertyDescriptor(
|
||||
propertyName, existingPD.getReadMethod(),
|
||||
existingPD.getWriteMethod(), null, method));
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
"write method must have exactly 1 or 2 parameters: " + method);
|
||||
}
|
||||
}
|
||||
|
||||
private PropertyDescriptor findExistingPropertyDescriptor(
|
||||
String propertyName, Class<?> propertyType) {
|
||||
|
||||
for (PropertyDescriptor pd : this.propertyDescriptors) {
|
||||
final Class<?> candidateType;
|
||||
final String candidateName = pd.getName();
|
||||
if (pd instanceof IndexedPropertyDescriptor) {
|
||||
IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
|
||||
candidateType = ipd.getIndexedPropertyType();
|
||||
if (candidateName.equals(propertyName) &&
|
||||
(candidateType.equals(propertyType) ||
|
||||
candidateType.equals(propertyType.getComponentType()))) {
|
||||
return pd;
|
||||
}
|
||||
}
|
||||
else {
|
||||
candidateType = pd.getPropertyType();
|
||||
if (candidateName.equals(propertyName) &&
|
||||
(candidateType.equals(propertyType) ||
|
||||
propertyType.equals(candidateType.getComponentType()))) {
|
||||
return pd;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String propertyNameFor(Method method) {
|
||||
return Introspector.decapitalize(method.getName().substring(3,method.getName().length()));
|
||||
return Introspector.decapitalize(
|
||||
method.getName().substring(3, method.getName().length()));
|
||||
}
|
||||
|
||||
private Object getterMethodNameFor(String name) {
|
||||
return "get" + StringUtils.capitalize(name);
|
||||
|
||||
/**
|
||||
* Return the set of {@link PropertyDescriptor}s from the wrapped {@link BeanInfo}
|
||||
* object as well as {@code PropertyDescriptor}s for each non-void returning setter
|
||||
* method found during construction.
|
||||
* @see #ExtendedBeanInfo(BeanInfo)
|
||||
*/
|
||||
public PropertyDescriptor[] getPropertyDescriptors() {
|
||||
return this.propertyDescriptors.toArray(
|
||||
new PropertyDescriptor[this.propertyDescriptors.size()]);
|
||||
}
|
||||
|
||||
public BeanInfo[] getAdditionalBeanInfo() {
|
||||
@@ -291,44 +244,431 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
return delegate.getEventSetDescriptors();
|
||||
}
|
||||
|
||||
public Image getIcon(int arg0) {
|
||||
return delegate.getIcon(arg0);
|
||||
public Image getIcon(int iconKind) {
|
||||
return delegate.getIcon(iconKind);
|
||||
}
|
||||
|
||||
public MethodDescriptor[] getMethodDescriptors() {
|
||||
return delegate.getMethodDescriptors();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of {@link PropertyDescriptor}s from the wrapped {@link BeanInfo}
|
||||
* object as well as {@code PropertyDescriptor}s for each non-void returning setter
|
||||
* method found during construction.
|
||||
* @see #ExtendedBeanInfo(BeanInfo)
|
||||
*/
|
||||
public PropertyDescriptor[] getPropertyDescriptors() {
|
||||
return this.propertyDescriptors.toArray(new PropertyDescriptor[this.propertyDescriptors.size()]);
|
||||
|
||||
class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
|
||||
|
||||
private Method readMethod;
|
||||
private Method writeMethod;
|
||||
private Class<?> propertyType;
|
||||
private Class<?> propertyEditorClass;
|
||||
|
||||
|
||||
public SimpleNonIndexedPropertyDescriptor(PropertyDescriptor original)
|
||||
throws IntrospectionException {
|
||||
|
||||
this(original.getName(), original.getReadMethod(), original.getWriteMethod());
|
||||
copyNonMethodProperties(original, this);
|
||||
}
|
||||
|
||||
public SimpleNonIndexedPropertyDescriptor(String propertyName,
|
||||
Method readMethod, Method writeMethod) throws IntrospectionException {
|
||||
|
||||
super(propertyName, null, null);
|
||||
this.setReadMethod(readMethod);
|
||||
this.setWriteMethod(writeMethod);
|
||||
this.propertyType = findPropertyType(readMethod, writeMethod);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sorts PropertyDescriptor instances alphanumerically to emulate the behavior of {@link java.beans.BeanInfo#getPropertyDescriptors()}.
|
||||
*
|
||||
* @see ExtendedBeanInfo#propertyDescriptors
|
||||
*/
|
||||
static class PropertyDescriptorComparator implements Comparator<PropertyDescriptor> {
|
||||
public int compare(PropertyDescriptor desc1, PropertyDescriptor desc2) {
|
||||
String left = desc1.getName();
|
||||
String right = desc2.getName();
|
||||
for (int i = 0; i < left.length(); i++) {
|
||||
if (right.length() == i) {
|
||||
return 1;
|
||||
}
|
||||
int result = left.getBytes()[i] - right.getBytes()[i];
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public Method getReadMethod() {
|
||||
return this.readMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadMethod(Method readMethod) {
|
||||
this.readMethod = readMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Method getWriteMethod() {
|
||||
return this.writeMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWriteMethod(Method writeMethod) {
|
||||
this.writeMethod = writeMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getPropertyType() {
|
||||
if (this.propertyType == null) {
|
||||
try {
|
||||
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
|
||||
} catch (IntrospectionException ex) {
|
||||
// ignore, as does PropertyDescriptor#getPropertyType
|
||||
}
|
||||
return left.length() - right.length();
|
||||
}
|
||||
return this.propertyType;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getPropertyEditorClass() {
|
||||
return this.propertyEditorClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPropertyEditorClass(Class<?> propertyEditorClass) {
|
||||
this.propertyEditorClass = propertyEditorClass;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return PropertyDescriptorUtils.equals(this, obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s[name=%s, propertyType=%s, readMethod=%s, writeMethod=%s]",
|
||||
this.getClass().getSimpleName(), this.getName(), this.getPropertyType(),
|
||||
this.readMethod, this.writeMethod);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
|
||||
|
||||
private Method readMethod;
|
||||
private Method writeMethod;
|
||||
private Class<?> propertyType;
|
||||
private Class<?> propertyEditorClass;
|
||||
|
||||
private Method indexedReadMethod;
|
||||
private Method indexedWriteMethod;
|
||||
private Class<?> indexedPropertyType;
|
||||
|
||||
|
||||
public SimpleIndexedPropertyDescriptor(IndexedPropertyDescriptor original)
|
||||
throws IntrospectionException {
|
||||
|
||||
this(original.getName(), original.getReadMethod(), original.getWriteMethod(),
|
||||
original.getIndexedReadMethod(), original.getIndexedWriteMethod());
|
||||
copyNonMethodProperties(original, this);
|
||||
}
|
||||
|
||||
public SimpleIndexedPropertyDescriptor(String propertyName,
|
||||
Method readMethod, Method writeMethod,
|
||||
Method indexedReadMethod, Method indexedWriteMethod)
|
||||
throws IntrospectionException {
|
||||
|
||||
super(propertyName, null, null, null, null);
|
||||
this.setReadMethod(readMethod);
|
||||
this.setWriteMethod(writeMethod);
|
||||
this.propertyType = findPropertyType(readMethod, writeMethod);
|
||||
|
||||
this.setIndexedReadMethod(indexedReadMethod);
|
||||
this.setIndexedWriteMethod(indexedWriteMethod);
|
||||
this.indexedPropertyType = findIndexedPropertyType(
|
||||
this.getName(), this.propertyType, indexedReadMethod, indexedWriteMethod);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Method getReadMethod() {
|
||||
return this.readMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadMethod(Method readMethod) {
|
||||
this.readMethod = readMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Method getWriteMethod() {
|
||||
return this.writeMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWriteMethod(Method writeMethod) {
|
||||
this.writeMethod = writeMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getPropertyType() {
|
||||
if (this.propertyType == null) {
|
||||
try {
|
||||
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
|
||||
} catch (IntrospectionException ex) {
|
||||
// ignore, as does IndexedPropertyDescriptor#getPropertyType
|
||||
}
|
||||
}
|
||||
return this.propertyType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Method getIndexedReadMethod() {
|
||||
return this.indexedReadMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndexedReadMethod(Method indexedReadMethod) throws IntrospectionException {
|
||||
this.indexedReadMethod = indexedReadMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Method getIndexedWriteMethod() {
|
||||
return this.indexedWriteMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndexedWriteMethod(Method indexedWriteMethod) throws IntrospectionException {
|
||||
this.indexedWriteMethod = indexedWriteMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getIndexedPropertyType() {
|
||||
if (this.indexedPropertyType == null) {
|
||||
try {
|
||||
this.indexedPropertyType = findIndexedPropertyType(
|
||||
this.getName(), this.getPropertyType(),
|
||||
this.indexedReadMethod, this.indexedWriteMethod);
|
||||
} catch (IntrospectionException ex) {
|
||||
// ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
|
||||
}
|
||||
}
|
||||
return this.indexedPropertyType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getPropertyEditorClass() {
|
||||
return this.propertyEditorClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPropertyEditorClass(Class<?> propertyEditorClass) {
|
||||
this.propertyEditorClass = propertyEditorClass;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @see java.beans.IndexedPropertyDescriptor#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj != null && obj instanceof IndexedPropertyDescriptor) {
|
||||
IndexedPropertyDescriptor other = (IndexedPropertyDescriptor) obj;
|
||||
if (!compareMethods(getIndexedReadMethod(), other.getIndexedReadMethod())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!compareMethods(getIndexedWriteMethod(), other.getIndexedWriteMethod())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getIndexedPropertyType() != other.getIndexedPropertyType()) {
|
||||
return false;
|
||||
}
|
||||
return PropertyDescriptorUtils.equals(this, obj);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s[name=%s, propertyType=%s, indexedPropertyType=%s, " +
|
||||
"readMethod=%s, writeMethod=%s, indexedReadMethod=%s, indexedWriteMethod=%s]",
|
||||
this.getClass().getSimpleName(), this.getName(), this.getPropertyType(),
|
||||
this.getIndexedPropertyType(), this.readMethod, this.writeMethod,
|
||||
this.indexedReadMethod, this.indexedWriteMethod);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PropertyDescriptorUtils {
|
||||
|
||||
/*
|
||||
* see java.beans.FeatureDescriptor#FeatureDescriptor(FeatureDescriptor)
|
||||
*/
|
||||
public static void copyNonMethodProperties(PropertyDescriptor source, PropertyDescriptor target)
|
||||
throws IntrospectionException {
|
||||
|
||||
target.setExpert(source.isExpert());
|
||||
target.setHidden(source.isHidden());
|
||||
target.setPreferred(source.isPreferred());
|
||||
target.setName(source.getName());
|
||||
target.setShortDescription(source.getShortDescription());
|
||||
target.setDisplayName(source.getDisplayName());
|
||||
|
||||
// copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
|
||||
Enumeration<String> keys = source.attributeNames();
|
||||
while (keys.hasMoreElements()) {
|
||||
String key = keys.nextElement();
|
||||
target.setValue(key, source.getValue(key));
|
||||
}
|
||||
|
||||
// see java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
|
||||
target.setPropertyEditorClass(source.getPropertyEditorClass());
|
||||
target.setBound(source.isBound());
|
||||
target.setConstrained(source.isConstrained());
|
||||
}
|
||||
|
||||
/*
|
||||
* See PropertyDescriptor#findPropertyType
|
||||
*/
|
||||
public static Class<?> findPropertyType(Method readMethod, Method writeMethod)
|
||||
throws IntrospectionException {
|
||||
|
||||
Class<?> propertyType = null;
|
||||
|
||||
if (readMethod != null) {
|
||||
Class<?>[] params = readMethod.getParameterTypes();
|
||||
if (params.length != 0) {
|
||||
throw new IntrospectionException("bad read method arg count: " + readMethod);
|
||||
}
|
||||
propertyType = readMethod.getReturnType();
|
||||
if (propertyType == Void.TYPE) {
|
||||
throw new IntrospectionException("read method "
|
||||
+ readMethod.getName() + " returns void");
|
||||
}
|
||||
}
|
||||
if (writeMethod != null) {
|
||||
Class<?> params[] = writeMethod.getParameterTypes();
|
||||
if (params.length != 1) {
|
||||
throw new IntrospectionException("bad write method arg count: " + writeMethod);
|
||||
}
|
||||
if (propertyType != null
|
||||
&& !params[0].isAssignableFrom(propertyType)) {
|
||||
throw new IntrospectionException("type mismatch between read and write methods");
|
||||
}
|
||||
propertyType = params[0];
|
||||
}
|
||||
return propertyType;
|
||||
}
|
||||
|
||||
/*
|
||||
* See IndexedPropertyDescriptor#findIndexedPropertyType
|
||||
*/
|
||||
public static Class<?> findIndexedPropertyType(String name, Class<?> propertyType,
|
||||
Method indexedReadMethod, Method indexedWriteMethod)
|
||||
throws IntrospectionException {
|
||||
|
||||
Class<?> indexedPropertyType = null;
|
||||
|
||||
if (indexedReadMethod != null) {
|
||||
Class<?> params[] = indexedReadMethod.getParameterTypes();
|
||||
if (params.length != 1) {
|
||||
throw new IntrospectionException(
|
||||
"bad indexed read method arg count");
|
||||
}
|
||||
if (params[0] != Integer.TYPE) {
|
||||
throw new IntrospectionException(
|
||||
"non int index to indexed read method");
|
||||
}
|
||||
indexedPropertyType = indexedReadMethod.getReturnType();
|
||||
if (indexedPropertyType == Void.TYPE) {
|
||||
throw new IntrospectionException(
|
||||
"indexed read method returns void");
|
||||
}
|
||||
}
|
||||
if (indexedWriteMethod != null) {
|
||||
Class<?> params[] = indexedWriteMethod.getParameterTypes();
|
||||
if (params.length != 2) {
|
||||
throw new IntrospectionException(
|
||||
"bad indexed write method arg count");
|
||||
}
|
||||
if (params[0] != Integer.TYPE) {
|
||||
throw new IntrospectionException(
|
||||
"non int index to indexed write method");
|
||||
}
|
||||
if (indexedPropertyType != null && indexedPropertyType != params[1]) {
|
||||
throw new IntrospectionException(
|
||||
"type mismatch between indexed read and indexed write methods: " + name);
|
||||
}
|
||||
indexedPropertyType = params[1];
|
||||
}
|
||||
if (propertyType != null
|
||||
&& (!propertyType.isArray() ||
|
||||
propertyType.getComponentType() != indexedPropertyType)) {
|
||||
throw new IntrospectionException(
|
||||
"type mismatch between indexed and non-indexed methods: " + name);
|
||||
}
|
||||
return indexedPropertyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the given {@link PropertyDescriptor} against the given {@link Object} and
|
||||
* return {@code true} if they are objects are equivalent, i.e. both are {@code
|
||||
* PropertyDescriptor}s whose read method, write method, property types, property
|
||||
* editor and flags are equivalent.
|
||||
*
|
||||
* @see PropertyDescriptor#equals(Object)
|
||||
*/
|
||||
public static boolean equals(PropertyDescriptor pd1, Object obj) {
|
||||
if (pd1 == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && obj instanceof PropertyDescriptor) {
|
||||
PropertyDescriptor pd2 = (PropertyDescriptor) obj;
|
||||
if (!compareMethods(pd1.getReadMethod(), pd2.getReadMethod())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!compareMethods(pd1.getWriteMethod(), pd2.getWriteMethod())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pd1.getPropertyType() == pd2.getPropertyType()
|
||||
&& pd1.getPropertyEditorClass() == pd2.getPropertyEditorClass()
|
||||
&& pd1.isBound() == pd2.isBound()
|
||||
&& pd1.isConstrained() == pd2.isConstrained()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* see PropertyDescriptor#compareMethods
|
||||
*/
|
||||
public static boolean compareMethods(Method a, Method b) {
|
||||
if ((a == null) != (b == null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a != null && b != null) {
|
||||
if (!a.equals(b)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sorts PropertyDescriptor instances alpha-numerically to emulate the behavior of
|
||||
* {@link java.beans.BeanInfo#getPropertyDescriptors()}.
|
||||
*
|
||||
* @see ExtendedBeanInfo#propertyDescriptors
|
||||
*/
|
||||
class PropertyDescriptorComparator implements Comparator<PropertyDescriptor> {
|
||||
|
||||
public int compare(PropertyDescriptor desc1, PropertyDescriptor desc2) {
|
||||
String left = desc1.getName();
|
||||
String right = desc2.getName();
|
||||
for (int i = 0; i < left.length(); i++) {
|
||||
if (right.length() == i) {
|
||||
return 1;
|
||||
}
|
||||
int result = left.getBytes()[i] - right.getBytes()[i];
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return left.length() - right.length();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
|
||||
}
|
||||
|
||||
public Class<?> getBeanClass() {
|
||||
return beanClass;
|
||||
return this.beanClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+36
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* 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.
|
||||
@@ -44,6 +44,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Dave Syer
|
||||
* @since 2.0
|
||||
* @see BeanWrapperImpl
|
||||
* @see SimpleTypeConverter
|
||||
@@ -131,6 +132,8 @@ class TypeConverterDelegate {
|
||||
// Custom editor for this type?
|
||||
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
|
||||
|
||||
ConversionFailedException firstAttemptEx = null;
|
||||
|
||||
// No custom editor but custom ConversionService specified?
|
||||
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
|
||||
if (editor == null && conversionService != null && convertedValue != null && typeDescriptor != null) {
|
||||
@@ -139,8 +142,10 @@ class TypeConverterDelegate {
|
||||
if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) {
|
||||
try {
|
||||
return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc);
|
||||
} catch (ConversionFailedException e) {
|
||||
}
|
||||
catch (ConversionFailedException ex) {
|
||||
// fallback to default conversion logic below
|
||||
firstAttemptEx = ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,11 +159,13 @@ class TypeConverterDelegate {
|
||||
}
|
||||
}
|
||||
if (editor == null) {
|
||||
editor = findDefaultEditor(requiredType, typeDescriptor);
|
||||
editor = findDefaultEditor(requiredType);
|
||||
}
|
||||
convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
|
||||
}
|
||||
|
||||
boolean standardConversion = false;
|
||||
|
||||
if (requiredType != null) {
|
||||
// Try to apply some standard type conversion rules if appropriate.
|
||||
|
||||
@@ -174,21 +181,24 @@ class TypeConverterDelegate {
|
||||
// Convert elements to target type, if determined.
|
||||
convertedValue = convertToTypedCollection(
|
||||
(Collection) convertedValue, propertyName, requiredType, typeDescriptor);
|
||||
standardConversion = true;
|
||||
}
|
||||
else if (convertedValue instanceof Map) {
|
||||
// Convert keys and values to respective target type, if determined.
|
||||
convertedValue = convertToTypedMap(
|
||||
(Map) convertedValue, propertyName, requiredType, typeDescriptor);
|
||||
standardConversion = true;
|
||||
}
|
||||
if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
|
||||
convertedValue = Array.get(convertedValue, 0);
|
||||
standardConversion = true;
|
||||
}
|
||||
if (String.class.equals(requiredType) && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
|
||||
// We can stringify any primitive value...
|
||||
return (T) convertedValue.toString();
|
||||
}
|
||||
else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
|
||||
if (!requiredType.isInterface() && !requiredType.isEnum()) {
|
||||
if (firstAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
|
||||
try {
|
||||
Constructor strCtor = requiredType.getConstructor(String.class);
|
||||
return (T) BeanUtils.instantiateClass(strCtor, convertedValue);
|
||||
@@ -210,12 +220,15 @@ class TypeConverterDelegate {
|
||||
// It's an empty enum identifier: reset the enum value to null.
|
||||
return null;
|
||||
}
|
||||
|
||||
convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
|
||||
standardConversion = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
|
||||
if (firstAttemptEx != null) {
|
||||
throw firstAttemptEx;
|
||||
}
|
||||
// Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Cannot convert value of type [").append(ClassUtils.getDescriptiveType(newValue));
|
||||
@@ -236,6 +249,14 @@ class TypeConverterDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
if (firstAttemptEx != null) {
|
||||
if (editor == null && !standardConversion && requiredType != null && !Object.class.equals(requiredType)) {
|
||||
throw firstAttemptEx;
|
||||
}
|
||||
logger.debug("Original ConversionService attempt failed - ignored since " +
|
||||
"PropertyEditor based conversion eventually succeeded", firstAttemptEx);
|
||||
}
|
||||
|
||||
return (T) convertedValue;
|
||||
}
|
||||
|
||||
@@ -288,16 +309,11 @@ class TypeConverterDelegate {
|
||||
/**
|
||||
* Find a default editor for the given type.
|
||||
* @param requiredType the type to find an editor for
|
||||
* @param descriptor the JavaBeans descriptor for the property
|
||||
* @return the corresponding editor, or <code>null</code> if none
|
||||
*/
|
||||
protected PropertyEditor findDefaultEditor(Class requiredType, TypeDescriptor typeDescriptor) {
|
||||
private PropertyEditor findDefaultEditor(Class requiredType) {
|
||||
PropertyEditor editor = null;
|
||||
//if (typeDescriptor instanceof PropertyTypeDescriptor) {
|
||||
//PropertyDescriptor pd = ((PropertyTypeDescriptor) typeDescriptor).getPropertyDescriptor();
|
||||
//editor = pd.createPropertyEditor(this.targetObject);
|
||||
//}
|
||||
if (editor == null && requiredType != null) {
|
||||
if (requiredType != null) {
|
||||
// No custom editor -> check BeanWrapperImpl's default editors.
|
||||
editor = this.propertyEditorRegistry.getDefaultEditor(requiredType);
|
||||
if (editor == null && !String.class.equals(requiredType)) {
|
||||
@@ -319,7 +335,7 @@ class TypeConverterDelegate {
|
||||
* @return the new value, possibly the result of type conversion
|
||||
* @throws IllegalArgumentException if type conversion failed
|
||||
*/
|
||||
protected Object doConvertValue(Object oldValue, Object newValue, Class<?> requiredType, PropertyEditor editor) {
|
||||
private Object doConvertValue(Object oldValue, Object newValue, Class<?> requiredType, PropertyEditor editor) {
|
||||
Object convertedValue = newValue;
|
||||
boolean sharedEditor = false;
|
||||
|
||||
@@ -406,7 +422,7 @@ class TypeConverterDelegate {
|
||||
* @param editor the PropertyEditor to use
|
||||
* @return the converted value
|
||||
*/
|
||||
protected Object doConvertTextValue(Object oldValue, String newTextValue, PropertyEditor editor) {
|
||||
private Object doConvertTextValue(Object oldValue, String newTextValue, PropertyEditor editor) {
|
||||
try {
|
||||
editor.setValue(oldValue);
|
||||
}
|
||||
@@ -420,7 +436,7 @@ class TypeConverterDelegate {
|
||||
return editor.getValue();
|
||||
}
|
||||
|
||||
protected Object convertToTypedArray(Object input, String propertyName, Class<?> componentType) {
|
||||
private Object convertToTypedArray(Object input, String propertyName, Class<?> componentType) {
|
||||
if (input instanceof Collection) {
|
||||
// Convert Collection elements to array elements.
|
||||
Collection coll = (Collection) input;
|
||||
@@ -459,7 +475,7 @@ class TypeConverterDelegate {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Collection convertToTypedCollection(
|
||||
private Collection convertToTypedCollection(
|
||||
Collection original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
|
||||
|
||||
if (!Collection.class.isAssignableFrom(requiredType)) {
|
||||
@@ -524,7 +540,7 @@ class TypeConverterDelegate {
|
||||
Object element = it.next();
|
||||
String indexedPropertyName = buildIndexedPropertyName(propertyName, i);
|
||||
Object convertedElement = convertIfNecessary(indexedPropertyName, null, element,
|
||||
(elementType != null ? elementType.getType() : null) , typeDescriptor.getElementTypeDescriptor());
|
||||
(elementType != null ? elementType.getType() : null) , elementType);
|
||||
try {
|
||||
convertedCopy.add(convertedElement);
|
||||
}
|
||||
@@ -541,7 +557,7 @@ class TypeConverterDelegate {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Map convertToTypedMap(
|
||||
private Map convertToTypedMap(
|
||||
Map original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
|
||||
|
||||
if (!Map.class.isAssignableFrom(requiredType)) {
|
||||
@@ -608,9 +624,9 @@ class TypeConverterDelegate {
|
||||
Object value = entry.getValue();
|
||||
String keyedPropertyName = buildKeyedPropertyName(propertyName, key);
|
||||
Object convertedKey = convertIfNecessary(keyedPropertyName, null, key,
|
||||
(keyType != null ? keyType.getType() : null), typeDescriptor.getMapKeyTypeDescriptor());
|
||||
(keyType != null ? keyType.getType() : null), keyType);
|
||||
Object convertedValue = convertIfNecessary(keyedPropertyName, null, value,
|
||||
(valueType!= null ? valueType.getType() : null), typeDescriptor.getMapValueTypeDescriptor());
|
||||
(valueType!= null ? valueType.getType() : null), valueType);
|
||||
try {
|
||||
convertedCopy.put(convertedKey, convertedValue);
|
||||
}
|
||||
|
||||
+3
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.beans.factory;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -37,6 +38,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 04.07.2003
|
||||
*/
|
||||
public abstract class BeanFactoryUtils {
|
||||
|
||||
+6
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.beans.factory.access;
|
||||
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
|
||||
/**
|
||||
@@ -34,7 +33,7 @@ public interface BeanFactoryReference {
|
||||
|
||||
/**
|
||||
* Return the {@link BeanFactory} instance held by this reference.
|
||||
* @throws IllegalStateException if invoked after <code>release()</code> has been called
|
||||
* @throws IllegalStateException if invoked after {@code release()} has been called
|
||||
*/
|
||||
BeanFactory getFactory();
|
||||
|
||||
@@ -42,18 +41,17 @@ public interface BeanFactoryReference {
|
||||
* Indicate that the {@link BeanFactory} instance referred to by this object is not
|
||||
* needed any longer by the client code which obtained the {@link BeanFactoryReference}.
|
||||
* <p>Depending on the actual implementation of {@link BeanFactoryLocator}, and
|
||||
* the actual type of <code>BeanFactory</code>, this may possibly not actually
|
||||
* do anything; alternately in the case of a 'closeable' <code>BeanFactory</code>
|
||||
* the actual type of {@code BeanFactory}, this may possibly not actually
|
||||
* do anything; alternately in the case of a 'closeable' {@code BeanFactory}
|
||||
* or derived class (such as {@link org.springframework.context.ApplicationContext})
|
||||
* may 'close' it, or may 'close' it once no more references remain.
|
||||
* <p>In an EJB usage scenario this would normally be called from
|
||||
* <code>ejbRemove()</code> and <code>ejbPassivate()</code>.
|
||||
* {@code ejbRemove()} and {@code ejbPassivate()}.
|
||||
* <p>This is safe to call multiple times.
|
||||
* @throws FatalBeanException if the <code>BeanFactory</code> cannot be released
|
||||
* @see BeanFactoryLocator
|
||||
* @see org.springframework.context.access.ContextBeanFactoryReference
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#close()
|
||||
*/
|
||||
void release() throws FatalBeanException;
|
||||
void release();
|
||||
|
||||
}
|
||||
|
||||
+25
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.beans.factory.annotation;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Extension of the {@link org.springframework.beans.factory.support.GenericBeanDefinition}
|
||||
@@ -32,27 +33,46 @@ import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
* which also implements the AnnotatedBeanDefinition interface).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 2.5
|
||||
* @see AnnotatedBeanDefinition#getMetadata()
|
||||
* @see org.springframework.core.type.StandardAnnotationMetadata
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
|
||||
|
||||
private final AnnotationMetadata annotationMetadata;
|
||||
private final AnnotationMetadata metadata;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AnnotatedGenericBeanDefinition for the given bean class.
|
||||
* @param beanClass the loaded bean class
|
||||
*/
|
||||
public AnnotatedGenericBeanDefinition(Class beanClass) {
|
||||
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
|
||||
setBeanClass(beanClass);
|
||||
this.annotationMetadata = new StandardAnnotationMetadata(beanClass);
|
||||
this.metadata = new StandardAnnotationMetadata(beanClass, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new AnnotatedGenericBeanDefinition for the given annotation metadata,
|
||||
* allowing for ASM-based processing and avoidance of early loading of the bean class.
|
||||
* Note that this constructor is functionally equivalent to
|
||||
* {@link org.springframework.context.annotation.ScannedGenericBeanDefinition
|
||||
* ScannedGenericBeanDefinition}, however the semantics of the latter indicate that
|
||||
* a bean was discovered specifically via component-scanning as opposed to other
|
||||
* means.
|
||||
* @param metadata the annotation metadata for the bean class in question
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
|
||||
Assert.notNull(metadata, "AnnotationMetadata must not be null");
|
||||
setBeanClassName(metadata.getClassName());
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
|
||||
public final AnnotationMetadata getMetadata() {
|
||||
return this.annotationMetadata;
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
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;
|
||||
@@ -59,10 +60,12 @@ import java.lang.annotation.Target;
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
* @see AutowiredAnnotationBeanPostProcessor
|
||||
* @see Qualifier
|
||||
* @see Value
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Autowired {
|
||||
|
||||
/**
|
||||
|
||||
+21
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package org.springframework.beans.factory.annotation;
|
||||
|
||||
import static org.springframework.core.BridgeMethodResolver.findBridgedMethod;
|
||||
import static org.springframework.core.BridgeMethodResolver.isJava6VisibilityBridgeMethodPair;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
@@ -38,6 +35,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
@@ -52,6 +50,7 @@ import org.springframework.beans.factory.config.InstantiationAwareBeanPostProces
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.Ordered;
|
||||
@@ -343,10 +342,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
}
|
||||
for (Method method : targetClass.getDeclaredMethods()) {
|
||||
Method bridgedMethod = findBridgedMethod(method);
|
||||
Annotation annotation = isJava6VisibilityBridgeMethodPair(method, bridgedMethod) ?
|
||||
findAutowiredAnnotation(bridgedMethod) :
|
||||
findAutowiredAnnotation(method);
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
Annotation annotation = BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod) ?
|
||||
findAutowiredAnnotation(bridgedMethod) : findAutowiredAnnotation(method);
|
||||
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
@@ -407,10 +405,16 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
protected boolean determineRequiredStatus(Annotation annotation) {
|
||||
try {
|
||||
Method method = ReflectionUtils.findMethod(annotation.annotationType(), this.requiredParameterName);
|
||||
if (method == null) {
|
||||
// annotations like @Inject and @Value don't have a method (attribute) named "required"
|
||||
// -> default to required status
|
||||
return true;
|
||||
}
|
||||
return (this.requiredParameterValue == (Boolean) ReflectionUtils.invokeMethod(method, annotation));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// required by default
|
||||
// an exception was thrown during reflective invocation of the required attribute
|
||||
// -> default to required status
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -421,11 +425,12 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
private void registerDependentBeans(String beanName, Set<String> autowiredBeanNames) {
|
||||
if (beanName != null) {
|
||||
for (String autowiredBeanName : autowiredBeanNames) {
|
||||
beanFactory.registerDependentBean(autowiredBeanName, beanName);
|
||||
if (this.beanFactory.containsBean(autowiredBeanName)) {
|
||||
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
"Autowiring by type from bean name '" + beanName + "' to bean named '" + autowiredBeanName +
|
||||
"'");
|
||||
logger.debug("Autowiring by type from bean name '" + beanName +
|
||||
"' to bean named '" + autowiredBeanName + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -437,11 +442,11 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
private Object resolvedCachedArgument(String beanName, Object cachedArgument) {
|
||||
if (cachedArgument instanceof DependencyDescriptor) {
|
||||
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
return beanFactory.resolveDependency(descriptor, beanName, null, typeConverter);
|
||||
TypeConverter typeConverter = this.beanFactory.getTypeConverter();
|
||||
return this.beanFactory.resolveDependency(descriptor, beanName, null, typeConverter);
|
||||
}
|
||||
else if (cachedArgument instanceof RuntimeBeanReference) {
|
||||
return beanFactory.getBean(((RuntimeBeanReference) cachedArgument).getBeanName());
|
||||
return this.beanFactory.getBean(((RuntimeBeanReference) cachedArgument).getBeanName());
|
||||
}
|
||||
else {
|
||||
return cachedArgument;
|
||||
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Convenience methods performing bean lookups related to annotations, for example
|
||||
* Spring's {@link Qualifier @Qualifier} annotation.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1.2
|
||||
* @see BeanFactoryUtils
|
||||
*/
|
||||
public class BeanFactoryAnnotationUtils {
|
||||
|
||||
/**
|
||||
* Obtain a bean of type {@code T} from the given {@code BeanFactory} declaring a
|
||||
* qualifier (e.g. via {@code <qualifier>} or {@code @Qualifier}) matching the given
|
||||
* qualifier, or having a bean name matching the given qualifier.
|
||||
* @param beanFactory the BeanFactory to get the target bean from
|
||||
* @param beanType the type of bean to retrieve
|
||||
* @param qualifier the qualifier for selecting between multiple bean matches
|
||||
* @return the matching bean of type {@code T} (never {@code null})
|
||||
* @throws NoSuchBeanDefinitionException if no matching bean of type {@code T} found
|
||||
*/
|
||||
public static <T> T qualifiedBeanOfType(BeanFactory beanFactory, Class<T> beanType, String qualifier) {
|
||||
if (beanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
// Full qualifier matching supported.
|
||||
return qualifiedBeanOfType((ConfigurableListableBeanFactory) beanFactory, beanType, qualifier);
|
||||
}
|
||||
else if (beanFactory.containsBean(qualifier)) {
|
||||
// Fallback: target bean at least found by bean name.
|
||||
return beanFactory.getBean(qualifier, beanType);
|
||||
}
|
||||
else {
|
||||
throw new NoSuchBeanDefinitionException(qualifier, "No matching " + beanType.getSimpleName() +
|
||||
" bean found for bean name '" + qualifier +
|
||||
"'! (Note: Qualifier matching not supported because given " +
|
||||
"BeanFactory does not implement ConfigurableListableBeanFactory.)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a bean of type {@code T} from the given {@code BeanFactory} declaring a qualifier
|
||||
* (e.g. {@code <qualifier>} or {@code @Qualifier}) matching the given qualifier).
|
||||
* @param bf the BeanFactory to get the target bean from
|
||||
* @param beanType the type of bean to retrieve
|
||||
* @param qualifier the qualifier for selecting between multiple bean matches
|
||||
* @return the matching bean of type {@code T} (never {@code null})
|
||||
* @throws NoSuchBeanDefinitionException if no matching bean of type {@code T} found
|
||||
*/
|
||||
private static <T> T qualifiedBeanOfType(ConfigurableListableBeanFactory bf, Class<T> beanType, String qualifier) {
|
||||
Map<String, T> candidateBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, beanType);
|
||||
T matchingBean = null;
|
||||
for (String beanName : candidateBeans.keySet()) {
|
||||
if (isQualifierMatch(qualifier, beanName, bf)) {
|
||||
if (matchingBean != null) {
|
||||
throw new NoSuchBeanDefinitionException(qualifier, "No unique " + beanType.getSimpleName() +
|
||||
" bean found for qualifier '" + qualifier + "'");
|
||||
}
|
||||
matchingBean = candidateBeans.get(beanName);
|
||||
}
|
||||
}
|
||||
if (matchingBean != null) {
|
||||
return matchingBean;
|
||||
}
|
||||
else {
|
||||
throw new NoSuchBeanDefinitionException(qualifier, "No matching " + beanType.getSimpleName() +
|
||||
" bean found for qualifier '" + qualifier + "' - neither qualifier " + "match nor bean name match!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the named bean declares a qualifier of the given name.
|
||||
* @param qualifier the qualifier to match
|
||||
* @param beanName the name of the candidate bean
|
||||
* @param bf the {@code BeanFactory} from which to retrieve the named bean
|
||||
* @return {@code true} if either the bean definition (in the XML case)
|
||||
* or the bean's factory method (in the {@code @Bean} case) defines a matching
|
||||
* qualifier value (through {@code <qualifier>} or {@code @Qualifier})
|
||||
*/
|
||||
private static boolean isQualifierMatch(String qualifier, String beanName, ConfigurableListableBeanFactory bf) {
|
||||
if (bf.containsBean(beanName)) {
|
||||
try {
|
||||
BeanDefinition bd = bf.getMergedBeanDefinition(beanName);
|
||||
if (bd instanceof AbstractBeanDefinition) {
|
||||
AbstractBeanDefinition abd = (AbstractBeanDefinition) bd;
|
||||
AutowireCandidateQualifier candidate = abd.getQualifier(Qualifier.class.getName());
|
||||
if ((candidate != null && qualifier.equals(candidate.getAttribute(AutowireCandidateQualifier.VALUE_KEY))) ||
|
||||
qualifier.equals(beanName) || ObjectUtils.containsElement(bf.getAliases(beanName), qualifier)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (bd instanceof RootBeanDefinition) {
|
||||
Method factoryMethod = ((RootBeanDefinition) bd).getResolvedFactoryMethod();
|
||||
if (factoryMethod != null) {
|
||||
Qualifier targetAnnotation = factoryMethod.getAnnotation(Qualifier.class);
|
||||
if (targetAnnotation != null && qualifier.equals(targetAnnotation.value())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// ignore - can't compare qualifiers for a manually registered singleton object
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2011 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,10 +34,10 @@ import java.lang.annotation.Target;
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface Configurable {
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* 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.
|
||||
@@ -265,7 +265,7 @@ public class InitDestroyAnnotationBeanPostProcessor
|
||||
}
|
||||
|
||||
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
|
||||
synchronized(this.initMethods) {
|
||||
synchronized (this.initMethods) {
|
||||
for (Iterator<LifecycleElement> it = this.initMethods.iterator(); it.hasNext();) {
|
||||
String methodIdentifier = it.next().getIdentifier();
|
||||
if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
|
||||
@@ -276,7 +276,7 @@ public class InitDestroyAnnotationBeanPostProcessor
|
||||
}
|
||||
}
|
||||
}
|
||||
synchronized(this.destroyMethods) {
|
||||
synchronized (this.destroyMethods) {
|
||||
for (Iterator<LifecycleElement> it = this.destroyMethods.iterator(); it.hasNext();) {
|
||||
String methodIdentifier = it.next().getIdentifier();
|
||||
if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) {
|
||||
|
||||
+32
-23
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* 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.
|
||||
@@ -54,17 +54,22 @@ public class InjectionMetadata {
|
||||
|
||||
|
||||
public InjectionMetadata(Class targetClass, Collection<InjectedElement> elements) {
|
||||
this.injectedElements = Collections.synchronizedSet(new LinkedHashSet<InjectedElement>());
|
||||
for (InjectedElement element : elements) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found injected element on class [" + targetClass.getName() + "]: " + element);
|
||||
if (!elements.isEmpty()) {
|
||||
this.injectedElements = Collections.synchronizedSet(new LinkedHashSet<InjectedElement>(elements.size()));
|
||||
for (InjectedElement element : elements) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found injected element on class [" + targetClass.getName() + "]: " + element);
|
||||
}
|
||||
this.injectedElements.add(element);
|
||||
}
|
||||
this.injectedElements.add(element);
|
||||
}
|
||||
else {
|
||||
this.injectedElements = Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
|
||||
synchronized(this.injectedElements) {
|
||||
synchronized (this.injectedElements) {
|
||||
for (Iterator<InjectedElement> it = this.injectedElements.iterator(); it.hasNext();) {
|
||||
Member member = it.next().getMember();
|
||||
if (!beanDefinition.isExternallyManagedConfigMember(member)) {
|
||||
@@ -170,26 +175,30 @@ public class InjectionMetadata {
|
||||
* affected property as processed for other processors to ignore it.
|
||||
*/
|
||||
protected boolean checkPropertySkipping(PropertyValues pvs) {
|
||||
if (this.skip == null) {
|
||||
if (pvs != null) {
|
||||
synchronized (pvs) {
|
||||
if (this.skip == null) {
|
||||
if (this.pd != null) {
|
||||
if (pvs.contains(this.pd.getName())) {
|
||||
// Explicit value provided as part of the bean definition.
|
||||
this.skip = true;
|
||||
return true;
|
||||
}
|
||||
else if (pvs instanceof MutablePropertyValues) {
|
||||
((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.skip != null) {
|
||||
return this.skip;
|
||||
}
|
||||
if (pvs == null) {
|
||||
this.skip = false;
|
||||
return false;
|
||||
}
|
||||
synchronized (pvs) {
|
||||
if (this.skip != null) {
|
||||
return this.skip;
|
||||
}
|
||||
if (this.pd != null) {
|
||||
if (pvs.contains(this.pd.getName())) {
|
||||
// Explicit value provided as part of the bean definition.
|
||||
this.skip = true;
|
||||
return true;
|
||||
}
|
||||
else if (pvs instanceof MutablePropertyValues) {
|
||||
((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());
|
||||
}
|
||||
}
|
||||
this.skip = false;
|
||||
return false;
|
||||
}
|
||||
return this.skip;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,9 +31,10 @@ import java.lang.annotation.Target;
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see Autowired
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface Qualifier {
|
||||
|
||||
+55
-53
@@ -1,59 +1,61 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation at the field or method/constructor parameter level
|
||||
* that indicates a default value expression for the affected argument.
|
||||
*
|
||||
* <p>Typically used for expression-driven dependency injection. Also supported
|
||||
* for dynamic resolution of handler method parameters, e.g. in Spring MVC.
|
||||
*
|
||||
* <p>A common use case is to assign default field values using
|
||||
* "#{systemProperties.myProp}" style expressions.
|
||||
*
|
||||
* <p>Note that actual processing of the {@code @Value} annotation is performed
|
||||
/*
|
||||
* Copyright 2002-2011 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;
|
||||
|
||||
/**
|
||||
* Annotation at the field or method/constructor parameter level
|
||||
* that indicates a default value expression for the affected argument.
|
||||
*
|
||||
* <p>Typically used for expression-driven dependency injection. Also supported
|
||||
* for dynamic resolution of handler method parameters, e.g. in Spring MVC.
|
||||
*
|
||||
* <p>A common use case is to assign default field values using
|
||||
* "#{systemProperties.myProp}" style expressions.
|
||||
*
|
||||
* <p>Note that actual processing of the {@code @Value} annotation is performed
|
||||
* by a {@link org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* BeanPostProcessor} which in turn means that you <em>cannot</em> use
|
||||
* {@code @Value} within
|
||||
* BeanPostProcessor} which in turn means that you <em>cannot</em> use
|
||||
* {@code @Value} within
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* BeanPostProcessor} or {@link BeanFactoryPostProcessor} types. Please
|
||||
* consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
|
||||
* class (which, by default, checks for the presence of this annotation).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see AutowiredAnnotationBeanPostProcessor
|
||||
* @see Value
|
||||
* @see org.springframework.beans.factory.config.BeanExpressionResolver
|
||||
* @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
|
||||
public @interface Value {
|
||||
|
||||
/**
|
||||
* The actual value expression: e.g. "#{systemProperties.myProp}".
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
||||
* @see Autowired
|
||||
* @see org.springframework.beans.factory.config.BeanExpressionResolver
|
||||
* @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Value {
|
||||
|
||||
/**
|
||||
* The actual value expression: e.g. "#{systemProperties.myProp}".
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
||||
|
||||
+84
-84
@@ -1,84 +1,84 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.util.Assert;
|
||||
|
||||
/**
|
||||
* Context object for evaluating an expression within a bean definition.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BeanExpressionContext {
|
||||
|
||||
private final ConfigurableBeanFactory beanFactory;
|
||||
|
||||
private final Scope scope;
|
||||
|
||||
|
||||
public BeanExpressionContext(ConfigurableBeanFactory beanFactory, Scope scope) {
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
||||
this.beanFactory = beanFactory;
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public final ConfigurableBeanFactory getBeanFactory() {
|
||||
return this.beanFactory;
|
||||
}
|
||||
|
||||
public final Scope getScope() {
|
||||
return this.scope;
|
||||
}
|
||||
|
||||
|
||||
public boolean containsObject(String key) {
|
||||
return (this.beanFactory.containsBean(key) ||
|
||||
(this.scope != null && this.scope.resolveContextualObject(key) != null));
|
||||
}
|
||||
|
||||
public Object getObject(String key) {
|
||||
if (this.beanFactory.containsBean(key)) {
|
||||
return this.beanFactory.getBean(key);
|
||||
}
|
||||
else if (this.scope != null){
|
||||
return this.scope.resolveContextualObject(key);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof BeanExpressionContext)) {
|
||||
return false;
|
||||
}
|
||||
BeanExpressionContext otherContext = (BeanExpressionContext) other;
|
||||
return (this.beanFactory == otherContext.beanFactory && this.scope == otherContext.scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.beanFactory.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2009 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.util.Assert;
|
||||
|
||||
/**
|
||||
* Context object for evaluating an expression within a bean definition.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BeanExpressionContext {
|
||||
|
||||
private final ConfigurableBeanFactory beanFactory;
|
||||
|
||||
private final Scope scope;
|
||||
|
||||
|
||||
public BeanExpressionContext(ConfigurableBeanFactory beanFactory, Scope scope) {
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
||||
this.beanFactory = beanFactory;
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public final ConfigurableBeanFactory getBeanFactory() {
|
||||
return this.beanFactory;
|
||||
}
|
||||
|
||||
public final Scope getScope() {
|
||||
return this.scope;
|
||||
}
|
||||
|
||||
|
||||
public boolean containsObject(String key) {
|
||||
return (this.beanFactory.containsBean(key) ||
|
||||
(this.scope != null && this.scope.resolveContextualObject(key) != null));
|
||||
}
|
||||
|
||||
public Object getObject(String key) {
|
||||
if (this.beanFactory.containsBean(key)) {
|
||||
return this.beanFactory.getBean(key);
|
||||
}
|
||||
else if (this.scope != null){
|
||||
return this.scope.resolveContextualObject(key);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof BeanExpressionContext)) {
|
||||
return false;
|
||||
}
|
||||
BeanExpressionContext otherContext = (BeanExpressionContext) other;
|
||||
return (this.beanFactory == otherContext.beanFactory && this.scope == otherContext.scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.beanFactory.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+45
-45
@@ -1,45 +1,45 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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;
|
||||
|
||||
/**
|
||||
* Strategy interface for resolving a value through evaluating it
|
||||
* as an expression, if applicable.
|
||||
*
|
||||
* <p>A raw {@link org.springframework.beans.factory.BeanFactory} does not
|
||||
* contain a default implementation of this strategy. However,
|
||||
* {@link org.springframework.context.ApplicationContext} implementations
|
||||
* will provide expression support out of the box.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface BeanExpressionResolver {
|
||||
|
||||
/**
|
||||
* Evaluate the given value as an expression, if applicable;
|
||||
* return the value as-is otherwise.
|
||||
* @param value the value to check
|
||||
* @param evalContext the evaluation context
|
||||
* @return the resolved value (potentially the given value as-is)
|
||||
* @throws BeansException if evaluation failed
|
||||
*/
|
||||
Object evaluate(String value, BeanExpressionContext evalContext) throws BeansException;
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2008 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;
|
||||
|
||||
/**
|
||||
* Strategy interface for resolving a value through evaluating it
|
||||
* as an expression, if applicable.
|
||||
*
|
||||
* <p>A raw {@link org.springframework.beans.factory.BeanFactory} does not
|
||||
* contain a default implementation of this strategy. However,
|
||||
* {@link org.springframework.context.ApplicationContext} implementations
|
||||
* will provide expression support out of the box.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface BeanExpressionResolver {
|
||||
|
||||
/**
|
||||
* Evaluate the given value as an expression, if applicable;
|
||||
* return the value as-is otherwise.
|
||||
* @param value the value to check
|
||||
* @param evalContext the evaluation context
|
||||
* @return the resolved value (potentially the given value as-is)
|
||||
* @throws BeansException if evaluation failed
|
||||
*/
|
||||
Object evaluate(String value, BeanExpressionContext evalContext) throws BeansException;
|
||||
|
||||
}
|
||||
|
||||
+71
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* 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.
|
||||
@@ -21,6 +21,7 @@ import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
@@ -56,6 +57,8 @@ public class DependencyDescriptor implements Serializable {
|
||||
|
||||
private final boolean eager;
|
||||
|
||||
private int nestingLevel = 1;
|
||||
|
||||
private transient Annotation[] fieldAnnotations;
|
||||
|
||||
|
||||
@@ -118,6 +121,24 @@ public class DependencyDescriptor implements Serializable {
|
||||
this.eager = eager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @param original the original descriptor to create a copy from
|
||||
*/
|
||||
public DependencyDescriptor(DependencyDescriptor original) {
|
||||
this.methodParameter = (original.methodParameter != null ? new MethodParameter(original.methodParameter) : null);
|
||||
this.field = original.field;
|
||||
this.declaringClass = original.declaringClass;
|
||||
this.methodName = original.methodName;
|
||||
this.parameterTypes = original.parameterTypes;
|
||||
this.parameterIndex = original.parameterIndex;
|
||||
this.fieldName = original.fieldName;
|
||||
this.required = original.required;
|
||||
this.eager = original.eager;
|
||||
this.nestingLevel = original.nestingLevel;
|
||||
this.fieldAnnotations = original.fieldAnnotations;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the wrapped MethodParameter, if any.
|
||||
@@ -153,6 +174,17 @@ public class DependencyDescriptor implements Serializable {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Increase this descriptor's nesting level.
|
||||
* @see MethodParameter#increaseNestingLevel()
|
||||
*/
|
||||
public void increaseNestingLevel() {
|
||||
this.nestingLevel++;
|
||||
if (this.methodParameter != null) {
|
||||
this.methodParameter.increaseNestingLevel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize parameter name discovery for the underlying method parameter, if any.
|
||||
* <p>This method does not actually try to retrieve the parameter name at
|
||||
@@ -178,15 +210,30 @@ public class DependencyDescriptor implements Serializable {
|
||||
* @return the declared type (never <code>null</code>)
|
||||
*/
|
||||
public Class<?> getDependencyType() {
|
||||
return (this.field != null ? this.field.getType() : this.methodParameter.getParameterType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the generic type of the wrapped parameter/field.
|
||||
* @return the generic type (never <code>null</code>)
|
||||
*/
|
||||
public Type getGenericDependencyType() {
|
||||
return (this.field != null ? this.field.getGenericType() : this.methodParameter.getGenericParameterType());
|
||||
if (this.field != null) {
|
||||
if (this.nestingLevel > 1) {
|
||||
Type type = this.field.getGenericType();
|
||||
if (type instanceof ParameterizedType) {
|
||||
Type arg = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||
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;
|
||||
}
|
||||
else {
|
||||
return this.field.getType();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return this.methodParameter.getNestedParameterType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,7 +242,7 @@ public class DependencyDescriptor implements Serializable {
|
||||
*/
|
||||
public Class<?> getCollectionType() {
|
||||
return (this.field != null ?
|
||||
GenericCollectionTypeResolver.getCollectionFieldType(this.field) :
|
||||
GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
|
||||
GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
|
||||
}
|
||||
|
||||
@@ -205,7 +252,7 @@ public class DependencyDescriptor implements Serializable {
|
||||
*/
|
||||
public Class<?> getMapKeyType() {
|
||||
return (this.field != null ?
|
||||
GenericCollectionTypeResolver.getMapKeyFieldType(this.field) :
|
||||
GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
|
||||
GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
|
||||
}
|
||||
|
||||
@@ -215,7 +262,7 @@ public class DependencyDescriptor implements Serializable {
|
||||
*/
|
||||
public Class<?> getMapValueType() {
|
||||
return (this.field != null ?
|
||||
GenericCollectionTypeResolver.getMapValueFieldType(this.field) :
|
||||
GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
|
||||
GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
|
||||
}
|
||||
|
||||
@@ -248,13 +295,18 @@ public class DependencyDescriptor implements Serializable {
|
||||
if (this.fieldName != null) {
|
||||
this.field = this.declaringClass.getDeclaredField(this.fieldName);
|
||||
}
|
||||
else if (this.methodName != null) {
|
||||
this.methodParameter = new MethodParameter(
|
||||
this.declaringClass.getDeclaredMethod(this.methodName, this.parameterTypes), this.parameterIndex);
|
||||
}
|
||||
else {
|
||||
this.methodParameter = new MethodParameter(
|
||||
this.declaringClass.getDeclaredConstructor(this.parameterTypes), this.parameterIndex);
|
||||
if (this.methodName != null) {
|
||||
this.methodParameter = new MethodParameter(
|
||||
this.declaringClass.getDeclaredMethod(this.methodName, this.parameterTypes), this.parameterIndex);
|
||||
}
|
||||
else {
|
||||
this.methodParameter = new MethodParameter(
|
||||
this.declaringClass.getDeclaredConstructor(this.parameterTypes), this.parameterIndex);
|
||||
}
|
||||
for (int i = 1; i < this.nestingLevel; i++) {
|
||||
this.methodParameter.increaseNestingLevel();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
|
||||
-202
@@ -1,202 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* A container object holding a map of attributes and optionally destruction callbacks. The callbacks will be invoked,
|
||||
* if an attribute is being removed or if the holder is cleaned out.
|
||||
*
|
||||
* @author Micha Kiener
|
||||
* @since 3.1
|
||||
*/
|
||||
public class DestructionAwareAttributeHolder implements Serializable {
|
||||
|
||||
/** The map containing the registered attributes. */
|
||||
private final Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();
|
||||
|
||||
/**
|
||||
* The optional map having any destruction callbacks registered using the
|
||||
* name of the bean as the key.
|
||||
*/
|
||||
private Map<String, Runnable> registeredDestructionCallbacks;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the map representation of the registered attributes directly. Be
|
||||
* aware to synchronize any invocations to it on the map object itself to
|
||||
* avoid concurrent modification exceptions.
|
||||
*
|
||||
* @return the attributes as a map representation
|
||||
*/
|
||||
public Map<String, Object> getAttributeMap() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attribute having the specified name, if available,
|
||||
* <code>null</code> otherwise.
|
||||
*
|
||||
* @param name
|
||||
* the name of the attribute to be returned
|
||||
* @return the attribute value or <code>null</code> if not available
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object getAttribute(String name) {
|
||||
return attributes.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given object with the specified name as an attribute to the
|
||||
* underlying map.
|
||||
*
|
||||
* @param name
|
||||
* the name of the attribute
|
||||
* @param value
|
||||
* the value to be stored
|
||||
* @return any previously object stored under the same name, if any,
|
||||
* <code>null</code> otherwise
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object setAttribute(String name, Object value) {
|
||||
return attributes.put(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the object with the given <code>name</code> from the underlying
|
||||
* scope.
|
||||
* <p>
|
||||
* Returns <code>null</code> if no object was found; otherwise returns the
|
||||
* removed <code>Object</code>.
|
||||
* <p>
|
||||
* Note that an implementation should also remove a registered destruction
|
||||
* callback for the specified object, if any. It does, however, <i>not</i>
|
||||
* need to <i>execute</i> a registered destruction callback in this case,
|
||||
* since the object will be destroyed by the caller (if appropriate).
|
||||
* <p>
|
||||
* <b>Note: This is an optional operation.</b> Implementations may throw
|
||||
* {@link UnsupportedOperationException} if they do not support explicitly
|
||||
* removing an object.
|
||||
*
|
||||
* @param name
|
||||
* the name of the object to remove
|
||||
* @return the removed object, or <code>null</code> if no object was present
|
||||
* @see #registerDestructionCallback
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object removeAttribute(String name) {
|
||||
Object value = attributes.remove(name);
|
||||
|
||||
// check for a destruction callback to be invoked
|
||||
Runnable callback = getDestructionCallback(name, true);
|
||||
if (callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the map by removing all registered attribute values and invokes
|
||||
* every destruction callback registered.
|
||||
*/
|
||||
public void clear() {
|
||||
synchronized (this) {
|
||||
// step through the attribute map and invoke destruction callbacks,
|
||||
// if any
|
||||
if (registeredDestructionCallbacks != null) {
|
||||
for (Runnable runnable : registeredDestructionCallbacks.values()) {
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
registeredDestructionCallbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// clear out the registered attribute map
|
||||
attributes.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be executed on destruction of the specified object
|
||||
* in the scope (or at destruction of the entire scope, if the scope does
|
||||
* not destroy individual objects but rather only terminates in its
|
||||
* entirety).
|
||||
* <p>
|
||||
* <b>Note: This is an optional operation.</b> This method will only be
|
||||
* called for scoped beans with actual destruction configuration
|
||||
* (DisposableBean, destroy-method, DestructionAwareBeanPostProcessor).
|
||||
* Implementations should do their best to execute a given callback at the
|
||||
* appropriate time. If such a callback is not supported by the underlying
|
||||
* runtime environment at all, the callback <i>must be ignored and a
|
||||
* corresponding warning should be logged</i>.
|
||||
* <p>
|
||||
* Note that 'destruction' refers to to automatic destruction of the object
|
||||
* as part of the scope's own lifecycle, not to the individual scoped object
|
||||
* having been explicitly removed by the application. If a scoped object
|
||||
* gets removed via this facade's {@link #removeAttribute(String)} method,
|
||||
* any registered destruction callback should be removed as well, assuming
|
||||
* that the removed object will be reused or manually destroyed.
|
||||
*
|
||||
* @param name
|
||||
* the name of the object to execute the destruction callback for
|
||||
* @param callback
|
||||
* the destruction callback to be executed. Note that the
|
||||
* passed-in Runnable will never throw an exception, so it can
|
||||
* safely be executed without an enclosing try-catch block.
|
||||
* Furthermore, the Runnable will usually be serializable,
|
||||
* provided that its target object is serializable as well.
|
||||
* @see org.springframework.beans.factory.DisposableBean
|
||||
* @see org.springframework.beans.factory.support.AbstractBeanDefinition#getDestroyMethodName()
|
||||
* @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
|
||||
*/
|
||||
public void registerDestructionCallback(String name, Runnable callback) {
|
||||
if (registeredDestructionCallbacks == null) {
|
||||
registeredDestructionCallbacks = new ConcurrentHashMap<String, Runnable>();
|
||||
}
|
||||
|
||||
registeredDestructionCallbacks.put(name, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the destruction callback, if any registered for the attribute
|
||||
* with the given name or <code>null</code> if no such callback was
|
||||
* registered.
|
||||
*
|
||||
* @param name
|
||||
* the name of the registered callback requested
|
||||
* @param remove
|
||||
* <code>true</code>, if the callback should be removed after
|
||||
* this call, <code>false</code>, if it stays
|
||||
* @return the callback, if found, <code>null</code> otherwise
|
||||
*/
|
||||
public Runnable getDestructionCallback(String name, boolean remove) {
|
||||
if (registeredDestructionCallbacks == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
return registeredDestructionCallbacks.remove(name);
|
||||
}
|
||||
|
||||
return registeredDestructionCallbacks.get(name);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* 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.
|
||||
@@ -101,7 +101,7 @@ public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBean<Object
|
||||
|
||||
/**
|
||||
* Set the name of the target bean.
|
||||
* <p>The target does not <i>have</> to be a non-singleton bean, but realisticially
|
||||
* <p>The target does not <i>have</i> to be a non-singleton bean, but realistically
|
||||
* always will be (because if the target bean were a singleton, then said singleton
|
||||
* bean could simply be injected straight into the dependent object, thus obviating
|
||||
* the need for the extra level of indirection afforded by this factory approach).
|
||||
|
||||
+95
-95
@@ -1,95 +1,95 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.Serializable;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link org.springframework.beans.factory.FactoryBean} implementation that
|
||||
* returns a value which is a JSR-330 {@link javax.inject.Provider} that in turn
|
||||
* returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}.
|
||||
*
|
||||
* <p>This is basically a JSR-330 compliant variant of Spring's good old
|
||||
* {@link ObjectFactoryCreatingFactoryBean}. It can be used for traditional
|
||||
* external dependency injection configuration that targets a property or
|
||||
* constructor argument of type <code>javax.inject.Provider</code>, as an
|
||||
* alternative to JSR-330's <code>@Inject</code> annotation-driven approach.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0.2
|
||||
* @see javax.inject.Provider
|
||||
* @see ObjectFactoryCreatingFactoryBean
|
||||
*/
|
||||
public class ProviderCreatingFactoryBean extends AbstractFactoryBean<Provider> {
|
||||
|
||||
private String targetBeanName;
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the target bean.
|
||||
* <p>The target does not <i>have</> to be a non-singleton bean, but realisticially
|
||||
* always will be (because if the target bean were a singleton, then said singleton
|
||||
* bean could simply be injected straight into the dependent object, thus obviating
|
||||
* the need for the extra level of indirection afforded by this factory approach).
|
||||
*/
|
||||
public void setTargetBeanName(String targetBeanName) {
|
||||
this.targetBeanName = targetBeanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required");
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class getObjectType() {
|
||||
return Provider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Provider createInstance() {
|
||||
return new TargetBeanProvider(getBeanFactory(), this.targetBeanName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Independent inner class - for serialization purposes.
|
||||
*/
|
||||
private static class TargetBeanProvider implements Provider, Serializable {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private final String targetBeanName;
|
||||
|
||||
public TargetBeanProvider(BeanFactory beanFactory, String targetBeanName) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.targetBeanName = targetBeanName;
|
||||
}
|
||||
|
||||
public Object get() throws BeansException {
|
||||
return this.beanFactory.getBean(this.targetBeanName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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 java.io.Serializable;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link org.springframework.beans.factory.FactoryBean} implementation that
|
||||
* returns a value which is a JSR-330 {@link javax.inject.Provider} that in turn
|
||||
* returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}.
|
||||
*
|
||||
* <p>This is basically a JSR-330 compliant variant of Spring's good old
|
||||
* {@link ObjectFactoryCreatingFactoryBean}. It can be used for traditional
|
||||
* external dependency injection configuration that targets a property or
|
||||
* constructor argument of type <code>javax.inject.Provider</code>, as an
|
||||
* alternative to JSR-330's <code>@Inject</code> annotation-driven approach.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0.2
|
||||
* @see javax.inject.Provider
|
||||
* @see ObjectFactoryCreatingFactoryBean
|
||||
*/
|
||||
public class ProviderCreatingFactoryBean extends AbstractFactoryBean<Provider> {
|
||||
|
||||
private String targetBeanName;
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the target bean.
|
||||
* <p>The target does not <i>have</i> to be a non-singleton bean, but realistically
|
||||
* always will be (because if the target bean were a singleton, then said singleton
|
||||
* bean could simply be injected straight into the dependent object, thus obviating
|
||||
* the need for the extra level of indirection afforded by this factory approach).
|
||||
*/
|
||||
public void setTargetBeanName(String targetBeanName) {
|
||||
this.targetBeanName = targetBeanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required");
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class getObjectType() {
|
||||
return Provider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Provider createInstance() {
|
||||
return new TargetBeanProvider(getBeanFactory(), this.targetBeanName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Independent inner class - for serialization purposes.
|
||||
*/
|
||||
private static class TargetBeanProvider implements Provider, Serializable {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private final String targetBeanName;
|
||||
|
||||
public TargetBeanProvider(BeanFactory beanFactory, String targetBeanName) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.targetBeanName = targetBeanName;
|
||||
}
|
||||
|
||||
public Object get() throws BeansException {
|
||||
return this.beanFactory.getBean(this.targetBeanName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+17
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* 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.
|
||||
@@ -27,7 +27,6 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
@@ -36,8 +35,8 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A {@link FactoryBean} implementation that takes an interface which must have one or more
|
||||
* methods with the signatures <code>MyType xxx()</code> or <code>MyType xxx(MyIdType id)</code>
|
||||
* (typically, <code>MyService getService()</code> or <code>MyService getService(String id)</code>)
|
||||
* methods with the signatures {@code MyType xxx()} or {@code MyType xxx(MyIdType id)}
|
||||
* (typically, {@code MyService getService()} or {@code MyService getService(String id)})
|
||||
* and creates a dynamic proxy which implements that interface, delegating to an
|
||||
* underlying {@link org.springframework.beans.factory.BeanFactory}.
|
||||
*
|
||||
@@ -51,7 +50,7 @@ import org.springframework.util.StringUtils;
|
||||
* setter or constructor injection of the target bean is preferable.</b>
|
||||
*
|
||||
* <p>On invocation of the no-arg factory method, or the single-arg factory
|
||||
* method with a String id of <code>null</code> or empty String, if exactly
|
||||
* method with a String id of {@code null} or empty String, if exactly
|
||||
* <b>one</b> bean in the factory matches the return type of the factory
|
||||
* method, that bean is returned, otherwise a
|
||||
* {@link org.springframework.beans.factory.NoSuchBeanDefinitionException}
|
||||
@@ -64,7 +63,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* <p>A factory method argument will usually be a String, but can also be an
|
||||
* int or a custom enumeration type, for example, stringified via
|
||||
* <code>toString</code>. The resulting String can be used as bean name as-is,
|
||||
* {@code toString}. The resulting String can be used as bean name as-is,
|
||||
* provided that corresponding beans are defined in the bean factory.
|
||||
* Alternatively, {@link #setServiceMappings(java.util.Properties) a custom mapping}
|
||||
* between service ids and bean names can be defined.
|
||||
@@ -99,7 +98,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
*</beans></pre>
|
||||
*
|
||||
* <p>The attendant <code>MyClientBean</code> class implementation might then
|
||||
* <p>The attendant {@code MyClientBean} class implementation might then
|
||||
* look something like this:
|
||||
*
|
||||
* <pre class="code">package a.b.c;
|
||||
@@ -151,7 +150,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
*</beans></pre>
|
||||
*
|
||||
* <p>The attendant <code>MyClientBean</code> class implementation might then
|
||||
* <p>The attendant {@code MyClientBean} class implementation might then
|
||||
* look something like this:
|
||||
*
|
||||
* <pre class="code">package a.b.c;
|
||||
@@ -202,8 +201,8 @@ public class ServiceLocatorFactoryBean implements FactoryBean<Object>, BeanFacto
|
||||
|
||||
/**
|
||||
* Set the service locator interface to use, which must have one or more methods with
|
||||
* the signatures <code>MyType xxx()</code> or <code>MyType xxx(MyIdType id)</code>
|
||||
* (typically, <code>MyService getService()</code> or <code>MyService getService(String id)</code>).
|
||||
* the signatures {@code MyType xxx()} or {@code MyType xxx(MyIdType id)}
|
||||
* (typically, {@code MyService getService()} or {@code MyService getService(String id)}).
|
||||
* See the {@link ServiceLocatorFactoryBean class-level Javadoc} for
|
||||
* information on the semantics of such methods.
|
||||
*/
|
||||
@@ -214,8 +213,8 @@ public class ServiceLocatorFactoryBean implements FactoryBean<Object>, BeanFacto
|
||||
/**
|
||||
* Set the exception class that the service locator should throw if service
|
||||
* lookup failed. The specified exception class must have a constructor
|
||||
* with one of the following parameter types: <code>(String, Throwable)</code>
|
||||
* or <code>(Throwable)</code> or <code>(String)</code>.
|
||||
* with one of the following parameter types: {@code (String, Throwable)}
|
||||
* or {@code (Throwable)} or {@code (String)}.
|
||||
* <p>If not specified, subclasses of Spring's BeansException will be thrown,
|
||||
* for example NoSuchBeanDefinitionException. As those are unchecked, the
|
||||
* caller does not need to handle them, so it might be acceptable that
|
||||
@@ -236,7 +235,7 @@ public class ServiceLocatorFactoryBean implements FactoryBean<Object>, BeanFacto
|
||||
* Set mappings between service ids (passed into the service locator)
|
||||
* and bean names (in the bean factory). Service ids that are not defined
|
||||
* here will be treated as bean names as-is.
|
||||
* <p>The empty string as service id key defines the mapping for <code>null</code> and
|
||||
* <p>The empty string as service id key defines the mapping for {@code null} and
|
||||
* empty string, and for factory methods without parameter. If not defined,
|
||||
* a single matching bean will be retrieved from the bean factory.
|
||||
* @param serviceMappings mappings between service ids and bean names,
|
||||
@@ -271,8 +270,8 @@ public class ServiceLocatorFactoryBean implements FactoryBean<Object>, BeanFacto
|
||||
* Determine the constructor to use for the given service locator exception
|
||||
* class. Only called in case of a custom service locator exception.
|
||||
* <p>The default implementation looks for a constructor with one of the
|
||||
* following parameter types: <code>(String, Throwable)</code>
|
||||
* or <code>(Throwable)</code> or <code>(String)</code>.
|
||||
* following parameter types: {@code (String, Throwable)}
|
||||
* or {@code (Throwable)} or {@code (String)}.
|
||||
* @param exceptionClass the exception class
|
||||
* @return the constructor to use
|
||||
* @see #setServiceLocatorExceptionClass
|
||||
@@ -364,12 +363,12 @@ public class ServiceLocatorFactoryBean implements FactoryBean<Object>, BeanFacto
|
||||
try {
|
||||
String beanName = tryGetBeanName(args);
|
||||
if (StringUtils.hasLength(beanName)) {
|
||||
// Service locator for a specific bean name.
|
||||
// Service locator for a specific bean name
|
||||
return beanFactory.getBean(beanName, serviceLocatorMethodReturnType);
|
||||
}
|
||||
else {
|
||||
// Service locator for a bean type.
|
||||
return BeanFactoryUtils.beanOfTypeIncludingAncestors(beanFactory, serviceLocatorMethodReturnType);
|
||||
// Service locator for a bean type
|
||||
return beanFactory.getBean(serviceLocatorMethodReturnType);
|
||||
}
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
|
||||
+38
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* 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.
|
||||
@@ -21,9 +21,6 @@ import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
@@ -31,7 +28,6 @@ import java.security.PrivilegedExceptionAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -109,6 +105,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Rob Harrop
|
||||
* @author Mark Fisher
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
* @since 13.02.2004
|
||||
* @see RootBeanDefinition
|
||||
* @see DefaultListableBeanFactory
|
||||
@@ -150,7 +147,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
|
||||
/** Cache of filtered PropertyDescriptors: bean Class -> PropertyDescriptor array */
|
||||
private final Map<Class, PropertyDescriptor[]> filteredPropertyDescriptorsCache =
|
||||
new HashMap<Class, PropertyDescriptor[]>();
|
||||
new ConcurrentHashMap<Class, PropertyDescriptor[]>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -667,22 +664,32 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
|
||||
Class<?> objectType = null;
|
||||
class Holder { Class<?> value = null; }
|
||||
final Holder objectType = new Holder();
|
||||
String factoryBeanName = mbd.getFactoryBeanName();
|
||||
String factoryMethodName = mbd.getFactoryMethodName();
|
||||
final String factoryMethodName = mbd.getFactoryMethodName();
|
||||
if (factoryBeanName != null && factoryMethodName != null) {
|
||||
// Try to obtain the FactoryBean's object type without instantiating it at all.
|
||||
BeanDefinition fbDef = getBeanDefinition(factoryBeanName);
|
||||
if (fbDef instanceof AbstractBeanDefinition) {
|
||||
Class<?> fbClass = ((AbstractBeanDefinition)fbDef).getBeanClass();
|
||||
Class<?> fbClass = ((AbstractBeanDefinition) fbDef).getBeanClass();
|
||||
if (ClassUtils.isCglibProxyClass(fbClass)) {
|
||||
// CGLIB subclass methods hide generic parameters. look at the superclass.
|
||||
fbClass = fbClass.getSuperclass();
|
||||
}
|
||||
Method m = ReflectionUtils.findMethod(fbClass, factoryMethodName);
|
||||
objectType = GenericTypeResolver.resolveReturnTypeArgument(m, FactoryBean.class);
|
||||
if (objectType != null) {
|
||||
return objectType;
|
||||
// Find the given factory method, taking into account that in the case of
|
||||
// @Bean methods, there may be parameters present.
|
||||
ReflectionUtils.doWithMethods(fbClass,
|
||||
new ReflectionUtils.MethodCallback() {
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
if (method.getName().equals(factoryMethodName) &&
|
||||
FactoryBean.class.isAssignableFrom(method.getReturnType())) {
|
||||
objectType.value = GenericTypeResolver.resolveReturnTypeArgument(method, FactoryBean.class);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (objectType.value != null) {
|
||||
return objectType.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -693,9 +700,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
|
||||
if (fb != null) {
|
||||
// Try to obtain the FactoryBean's object type from this early stage of the instance.
|
||||
objectType = getTypeForFactoryBean(fb);
|
||||
if (objectType != null) {
|
||||
return objectType;
|
||||
objectType.value = getTypeForFactoryBean(fb);
|
||||
if (objectType.value != null) {
|
||||
return objectType.value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1226,22 +1233,25 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @see #isExcludedFromDependencyCheck
|
||||
*/
|
||||
protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw) {
|
||||
synchronized (this.filteredPropertyDescriptorsCache) {
|
||||
PropertyDescriptor[] filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
|
||||
if (filtered == null) {
|
||||
List<PropertyDescriptor> pds =
|
||||
new LinkedList<PropertyDescriptor>(Arrays.asList(bw.getPropertyDescriptors()));
|
||||
for (Iterator<PropertyDescriptor> it = pds.iterator(); it.hasNext();) {
|
||||
PropertyDescriptor pd = it.next();
|
||||
if (isExcludedFromDependencyCheck(pd)) {
|
||||
it.remove();
|
||||
PropertyDescriptor[] filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
|
||||
if (filtered == null) {
|
||||
synchronized (this.filteredPropertyDescriptorsCache) {
|
||||
filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
|
||||
if (filtered == null) {
|
||||
List<PropertyDescriptor> pds =
|
||||
new LinkedList<PropertyDescriptor>(Arrays.asList(bw.getPropertyDescriptors()));
|
||||
for (Iterator<PropertyDescriptor> it = pds.iterator(); it.hasNext();) {
|
||||
PropertyDescriptor pd = it.next();
|
||||
if (isExcludedFromDependencyCheck(pd)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
filtered = pds.toArray(new PropertyDescriptor[pds.size()]);
|
||||
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
|
||||
}
|
||||
filtered = pds.toArray(new PropertyDescriptor[pds.size()]);
|
||||
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+37
-36
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* 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.
|
||||
@@ -136,8 +136,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
private TypeConverter typeConverter;
|
||||
|
||||
/** Custom PropertyEditors to apply to the beans of this factory */
|
||||
private final Map<Class, Class<? extends PropertyEditor>> customEditors =
|
||||
new HashMap<Class, Class<? extends PropertyEditor>>(4);
|
||||
private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
|
||||
new HashMap<Class<?>, Class<? extends PropertyEditor>>(4);
|
||||
|
||||
/** String resolvers to apply e.g. to annotation attribute values */
|
||||
private final List<StringValueResolver> embeddedValueResolvers = new LinkedList<StringValueResolver>();
|
||||
@@ -288,7 +288,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
|
||||
// Create bean instance.
|
||||
if (mbd.isSingleton()) {
|
||||
sharedInstance = getSingleton(beanName, new ObjectFactory() {
|
||||
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
|
||||
public Object getObject() throws BeansException {
|
||||
try {
|
||||
return createBean(beanName, mbd, args);
|
||||
@@ -325,7 +325,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
|
||||
}
|
||||
try {
|
||||
Object scopedInstance = scope.get(beanName, new ObjectFactory() {
|
||||
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
|
||||
public Object getObject() throws BeansException {
|
||||
beforePrototypeCreation(beanName);
|
||||
try {
|
||||
@@ -379,7 +379,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
Object beanInstance = getSingleton(beanName, false);
|
||||
if (beanInstance != null) {
|
||||
if (beanInstance instanceof FactoryBean) {
|
||||
return (BeanFactoryUtils.isFactoryDereference(name) || ((FactoryBean) beanInstance).isSingleton());
|
||||
return (BeanFactoryUtils.isFactoryDereference(name) || ((FactoryBean<?>) beanInstance).isSingleton());
|
||||
}
|
||||
else {
|
||||
return !BeanFactoryUtils.isFactoryDereference(name);
|
||||
@@ -405,7 +405,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
if (BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
return true;
|
||||
}
|
||||
FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
|
||||
FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
|
||||
return factoryBean.isSingleton();
|
||||
}
|
||||
else {
|
||||
@@ -439,17 +439,17 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
return false;
|
||||
}
|
||||
if (isFactoryBean(beanName, mbd)) {
|
||||
final FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
|
||||
final FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
|
||||
if (System.getSecurityManager() != null) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean) factoryBean).isPrototype()) ||
|
||||
return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factoryBean).isPrototype()) ||
|
||||
!factoryBean.isSingleton());
|
||||
}
|
||||
}, getAccessControlContext());
|
||||
}
|
||||
else {
|
||||
return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean) factoryBean).isPrototype()) ||
|
||||
return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factoryBean).isPrototype()) ||
|
||||
!factoryBean.isSingleton());
|
||||
}
|
||||
}
|
||||
@@ -459,25 +459,25 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException {
|
||||
public boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException {
|
||||
String beanName = transformedBeanName(name);
|
||||
Class typeToMatch = (targetType != null ? targetType : Object.class);
|
||||
Class<?> typeToMatch = (targetType != null ? targetType : Object.class);
|
||||
|
||||
// Check manually registered singletons.
|
||||
Object beanInstance = getSingleton(beanName, false);
|
||||
if (beanInstance != null) {
|
||||
if (beanInstance instanceof FactoryBean) {
|
||||
if (!BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
Class type = getTypeForFactoryBean((FactoryBean) beanInstance);
|
||||
return (type != null && typeToMatch.isAssignableFrom(type));
|
||||
Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);
|
||||
return (type != null && ClassUtils.isAssignable(typeToMatch, type));
|
||||
}
|
||||
else {
|
||||
return typeToMatch.isAssignableFrom(beanInstance.getClass()) ;
|
||||
return ClassUtils.isAssignableValue(typeToMatch, beanInstance);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return !BeanFactoryUtils.isFactoryDereference(name) &&
|
||||
typeToMatch.isAssignableFrom(beanInstance.getClass());
|
||||
ClassUtils.isAssignableValue(typeToMatch, beanInstance);
|
||||
}
|
||||
}
|
||||
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
|
||||
@@ -501,13 +501,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
|
||||
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
|
||||
Class targetClass = predictBeanType(dbd.getBeanName(), tbd, FactoryBean.class, typeToMatch);
|
||||
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, FactoryBean.class, typeToMatch);
|
||||
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
|
||||
return typeToMatch.isAssignableFrom(targetClass);
|
||||
}
|
||||
}
|
||||
|
||||
Class beanClass = predictBeanType(beanName, mbd, FactoryBean.class, typeToMatch);
|
||||
Class<?> beanClass = predictBeanType(beanName, mbd, FactoryBean.class, typeToMatch);
|
||||
if (beanClass == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -516,7 +516,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
if (FactoryBean.class.isAssignableFrom(beanClass)) {
|
||||
if (!BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
|
||||
Class type = getTypeForFactoryBean(beanName, mbd);
|
||||
Class<?> type = getTypeForFactoryBean(beanName, mbd);
|
||||
return (type != null && typeToMatch.isAssignableFrom(type));
|
||||
}
|
||||
else {
|
||||
@@ -537,7 +537,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
Object beanInstance = getSingleton(beanName, false);
|
||||
if (beanInstance != null) {
|
||||
if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
return getTypeForFactoryBean((FactoryBean) beanInstance);
|
||||
return getTypeForFactoryBean((FactoryBean<?>) beanInstance);
|
||||
}
|
||||
else {
|
||||
return beanInstance.getClass();
|
||||
@@ -563,13 +563,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
|
||||
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
|
||||
Class targetClass = predictBeanType(dbd.getBeanName(), tbd);
|
||||
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd);
|
||||
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
|
||||
return targetClass;
|
||||
}
|
||||
}
|
||||
|
||||
Class beanClass = predictBeanType(beanName, mbd);
|
||||
Class<?> beanClass = predictBeanType(beanName, mbd);
|
||||
|
||||
// Check bean class whether we're dealing with a FactoryBean.
|
||||
if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
|
||||
@@ -707,7 +707,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
/**
|
||||
* Return the map of custom editors, with Classes as keys and PropertyEditor classes as values.
|
||||
*/
|
||||
public Map<Class, Class<? extends PropertyEditor>> getCustomEditors() {
|
||||
public Map<Class<?>, Class<? extends PropertyEditor>> getCustomEditors() {
|
||||
return this.customEditors;
|
||||
}
|
||||
|
||||
@@ -950,7 +950,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
protected final boolean isPrototypeCurrentlyInCreation(String beanName) {
|
||||
Object curVal = this.prototypesCurrentlyInCreation.get();
|
||||
return (curVal != null &&
|
||||
(curVal.equals(beanName) || (curVal instanceof Set && ((Set) curVal).contains(beanName))));
|
||||
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
|
||||
}
|
||||
|
||||
public boolean isCurrentlyInCreation(String beanName) {
|
||||
@@ -1069,8 +1069,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
}
|
||||
}
|
||||
if (!this.customEditors.isEmpty()) {
|
||||
for (Map.Entry<Class, Class<? extends PropertyEditor>> entry : this.customEditors.entrySet()) {
|
||||
Class requiredType = entry.getKey();
|
||||
for (Map.Entry<Class<?>, Class<? extends PropertyEditor>> entry : this.customEditors.entrySet()) {
|
||||
Class<?> requiredType = entry.getKey();
|
||||
Class<? extends PropertyEditor> editorClass = entry.getValue();
|
||||
registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass));
|
||||
}
|
||||
@@ -1237,15 +1237,15 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
* @return the resolved bean class (or <code>null</code> if none)
|
||||
* @throws CannotLoadBeanClassException if we failed to load the class
|
||||
*/
|
||||
protected Class resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class... typesToMatch)
|
||||
protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
|
||||
throws CannotLoadBeanClassException {
|
||||
try {
|
||||
if (mbd.hasBeanClass()) {
|
||||
return mbd.getBeanClass();
|
||||
}
|
||||
if (System.getSecurityManager() != null) {
|
||||
return AccessController.doPrivileged(new PrivilegedExceptionAction<Class>() {
|
||||
public Class run() throws Exception {
|
||||
return AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
|
||||
public Class<?> run() throws Exception {
|
||||
return doResolveBeanClass(mbd, typesToMatch);
|
||||
}
|
||||
}, getAccessControlContext());
|
||||
@@ -1266,7 +1266,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
}
|
||||
}
|
||||
|
||||
private Class doResolveBeanClass(RootBeanDefinition mbd, Class... typesToMatch) throws ClassNotFoundException {
|
||||
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch) throws ClassNotFoundException {
|
||||
if (!ObjectUtils.isEmpty(typesToMatch)) {
|
||||
ClassLoader tempClassLoader = getTempClassLoader();
|
||||
if (tempClassLoader != null) {
|
||||
@@ -1315,7 +1315,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
* (also signals that the returned <code>Class</code> will never be exposed to application code)
|
||||
* @return the type of the bean, or <code>null</code> if not predictable
|
||||
*/
|
||||
protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class... typesToMatch) {
|
||||
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
|
||||
if (mbd.getFactoryMethodName() != null) {
|
||||
return null;
|
||||
}
|
||||
@@ -1328,8 +1328,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
* @param mbd the corresponding bean definition
|
||||
*/
|
||||
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
|
||||
Class beanClass = predictBeanType(beanName, mbd, FactoryBean.class);
|
||||
return (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass));
|
||||
Class<?> predictedType = predictBeanType(beanName, mbd, FactoryBean.class);
|
||||
return (predictedType != null && FactoryBean.class.isAssignableFrom(predictedType)) ||
|
||||
(mbd.hasBeanClass() && FactoryBean.class.isAssignableFrom(mbd.getBeanClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1347,12 +1348,12 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
* @see #getBean(String)
|
||||
*/
|
||||
protected Class getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
|
||||
protected Class<?> getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
|
||||
if (!mbd.isSingleton()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
FactoryBean factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true);
|
||||
FactoryBean<?> factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true);
|
||||
return getTypeForFactoryBean(factoryBean);
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
@@ -1432,7 +1433,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
}
|
||||
if (object == null) {
|
||||
// Return bean instance from factory.
|
||||
FactoryBean factory = (FactoryBean) beanInstance;
|
||||
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
|
||||
// Caches object obtained from FactoryBean if it is a singleton.
|
||||
if (mbd == null && containsBeanDefinition(beanName)) {
|
||||
mbd = getMergedLocalBeanDefinition(beanName);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user