mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
648 Commits
main
...
v4.3.10.RELEASE
| Author | SHA1 | Date | |
|---|---|---|---|
| 208d219a4b | |||
| c752ba5b38 | |||
| 12978b8185 | |||
| 40b4276475 | |||
| 4160ced64c | |||
| a032e86355 | |||
| 4b2bad96ce | |||
| 1513c4a952 | |||
| bb6d9fabee | |||
| bffcd33ea3 | |||
| c9ffa64140 | |||
| aa0d7a61b6 | |||
| e138d7d29f | |||
| 50f8b6b3ab | |||
| 121a3bf670 | |||
| e4031f290e | |||
| 55fa5f2b65 | |||
| 3802aca474 | |||
| a9a4d7cf78 | |||
| 17382aec6d | |||
| 8ad3c958e1 | |||
| 8d743181da | |||
| f92ab75bc9 | |||
| 092b5f7556 | |||
| d4d609318d | |||
| 501891c749 | |||
| 2b0dc8d7ff | |||
| 674e2320a8 | |||
| fee259a3c5 | |||
| 016b7d753c | |||
| a17255a2e3 | |||
| 35efdf6b51 | |||
| b35c238d27 | |||
| db1fd516ea | |||
| b7337b304e | |||
| 7cac1f1e6e | |||
| fa09cd3737 | |||
| be93ee77e4 | |||
| 8330134757 | |||
| 9cb9884533 | |||
| ac25db6d2b | |||
| 22bf9febcc | |||
| c6deeb31ec | |||
| f80b2d9a94 | |||
| 8c206bf477 | |||
| 6aeb8ef56d | |||
| 04a96ffa27 | |||
| 2677584658 | |||
| 99236759ec | |||
| e2aa117ff9 | |||
| 8deec9569c | |||
| 0f8bf10aa8 | |||
| e0a7b074ed | |||
| 4fc41eeeb9 | |||
| 81143a80c4 | |||
| 9572859a35 | |||
| 78931ee3ea | |||
| e522fec611 | |||
| a12bbde87e | |||
| 50235be746 | |||
| 1332482c40 | |||
| 799589ec1c | |||
| 16fdda00c1 | |||
| d2985613d1 | |||
| beac891ff0 | |||
| 2d1b551248 | |||
| aa8cf190d3 | |||
| d643e57318 | |||
| 84d2e5a3c8 | |||
| dab56dbb05 | |||
| 9b647021f7 | |||
| 38089d8e66 | |||
| 554c3f3d7e | |||
| ee40310c92 | |||
| 226cddadef | |||
| 5a80f4f16e | |||
| bb63ce9935 | |||
| 1b4289803b | |||
| 3d7576df7f | |||
| 8b9e9202f1 | |||
| afe11e7919 | |||
| 665e6cf6ca | |||
| fd1d8aeeb4 | |||
| 9b2f9e655e | |||
| 6c370ed28d | |||
| a2b356162e | |||
| 71f7fdd632 | |||
| c35ddf905a | |||
| d866715556 | |||
| a9a1f783c5 | |||
| 65d52a4b97 | |||
| 3c8fc46568 | |||
| 421fabb2c4 | |||
| 811d523211 | |||
| 40232f4e22 | |||
| 80fa3ac907 | |||
| 54180f90e2 | |||
| 865953f145 | |||
| 93fac8882f | |||
| a3d199f4dd | |||
| 597fe0720f | |||
| 8321f01bf8 | |||
| 7e736b69b7 | |||
| 8b054840fc | |||
| 7f3d0b3e6e | |||
| 546d7ddd07 | |||
| 95099fd709 | |||
| f65e1edd58 | |||
| 0a9f98f0df | |||
| 46cf4f9ba1 | |||
| 2b930e3858 | |||
| bde2ddbeb1 | |||
| 4eb929c105 | |||
| d0d7a88233 | |||
| f7548a87ed | |||
| e0fe7cdc44 | |||
| 8289bf0aff | |||
| 79d747410d | |||
| 70bca99da8 | |||
| 83617f382c | |||
| 21ac764e5c | |||
| c4fda0e811 | |||
| 66670cfd56 | |||
| c31bfe65aa | |||
| 22ddb35258 | |||
| d0177b0f55 | |||
| 2233ec04ff | |||
| e9ff3bb4e3 | |||
| 57c8c759ae | |||
| cfd9b3461f | |||
| d3324c8d4f | |||
| ffe9bae138 | |||
| 020e51cb96 | |||
| a78066830b | |||
| 77c771e874 | |||
| 227ac3faa4 | |||
| 98dbc17591 | |||
| e58b17a3a1 | |||
| 9de97614a0 | |||
| 015e00b5dd | |||
| 0bc59225d8 | |||
| d8acc27afb | |||
| a1e4afe338 | |||
| 3b9faee335 | |||
| 0048ff84ea | |||
| c3f131325d | |||
| b945e0f202 | |||
| ce3cf3251d | |||
| d69fb06852 | |||
| e9de3bb85b | |||
| e6a51e3d29 | |||
| c734c3a3fe | |||
| a48a956c0c | |||
| e5010a823b | |||
| 1db42081e5 | |||
| 34a0857628 | |||
| ba0484fcac | |||
| f1133a8e56 | |||
| 35e37f6b60 | |||
| f117b804a8 | |||
| 278199d467 | |||
| fd568f3e96 | |||
| 45b27a85f4 | |||
| 0f71f58616 | |||
| 9834c42b5c | |||
| 7879bdfc1d | |||
| dfa8a7c358 | |||
| 427fd9b19a | |||
| 6417ed47ab | |||
| b0ef80c3ff | |||
| 7ed4884eaa | |||
| c3cc42d4d3 | |||
| 860e2bcc2d | |||
| 06231721c3 | |||
| 4d2360e5b5 | |||
| 4f52174674 | |||
| 7d7c5c9d9c | |||
| 08b9e7b83e | |||
| e24c530705 | |||
| 5017c05c23 | |||
| 6e93834e27 | |||
| 5f90a7eee9 | |||
| eff285eb3b | |||
| da7d79b3a1 | |||
| d6216fb74a | |||
| 941f3e7166 | |||
| e80c251c7a | |||
| 56abc4a429 | |||
| dde9e27630 | |||
| 15b174a522 | |||
| 1fcb2608fb | |||
| c15d687bf0 | |||
| e038631a6d | |||
| d5daa8e3a7 | |||
| 6014ca9140 | |||
| d4010573af | |||
| e3cd5c8ef0 | |||
| dec1c93b24 | |||
| 3ef6697536 | |||
| 8207c53b9a | |||
| e3be94c961 | |||
| b40f016de2 | |||
| 28849e0987 | |||
| b386be1529 | |||
| a98a61852f | |||
| 3304efd64d | |||
| b97e7d53bc | |||
| 4af6d58d8d | |||
| e2d06eaae5 | |||
| fcfacd9f83 | |||
| bddcc669b3 | |||
| 2024b37e65 | |||
| fb3191904a | |||
| 9e4d74c502 | |||
| 9b221f58b9 | |||
| f7c3b814e3 | |||
| 155bbb8466 | |||
| 4f690eea2a | |||
| 70a1ecba7f | |||
| c8b0ff2fca | |||
| f9a4856c3b | |||
| 35b67a54d2 | |||
| 78a23be9bc | |||
| 09c5958608 | |||
| ffb295971a | |||
| 77bb7e6030 | |||
| 75daf781c2 | |||
| fcead670f0 | |||
| 801b93a078 | |||
| 4beeeb8118 | |||
| 64d4afad9f | |||
| 48f57e3bb2 | |||
| d92f69747b | |||
| 315698b50e | |||
| 6deccf123d | |||
| 391ebc8eda | |||
| 28c7f65a25 | |||
| caebe72083 | |||
| f79baec5ff | |||
| d1c0ea7d74 | |||
| 53e2d7d160 | |||
| 8c62a2f11a | |||
| 8656e30550 | |||
| 0655d73f8e | |||
| 24ebd15f9c | |||
| cce84711c6 | |||
| 7f127300f9 | |||
| 1521094c5b | |||
| 0b8134049c | |||
| 70a980db58 | |||
| 8b960099f1 | |||
| cc53d597c0 | |||
| 5982f732b4 | |||
| c5500b2332 | |||
| de611cb3a9 | |||
| 72a76367f2 | |||
| 5afc3a3a50 | |||
| 2f2ef00d1f | |||
| de7eea4498 | |||
| e9a87de965 | |||
| db7b74feac | |||
| f7d126043b | |||
| 55b44b4f86 | |||
| 523370b6f2 | |||
| 131d2c2051 | |||
| 7f05c2a18c | |||
| 8fc65ab0a5 | |||
| b6108e3b2d | |||
| 26a4aef417 | |||
| 050f2c746d | |||
| fd21e0e69a | |||
| 794580ffcd | |||
| d44bc27c9a | |||
| 243e21a3ea | |||
| 20aaa8841c | |||
| d77ab67c56 | |||
| dd2b6a0fc5 | |||
| f949461297 | |||
| 9a39a25bb5 | |||
| 4b018407c1 | |||
| 28e114b569 | |||
| 99226e0fa6 | |||
| 4a84ee07be | |||
| 505480cf63 | |||
| fa2bfdd326 | |||
| afe022853c | |||
| 41b834f76e | |||
| a88436c806 | |||
| e2d6e709c3 | |||
| bd7fee5a77 | |||
| 709d4ba6e7 | |||
| 8d55c7d60a | |||
| 9cb4de8b5e | |||
| 8662c61a17 | |||
| 935671ae32 | |||
| a5ce965d22 | |||
| 1e58c80fe7 | |||
| a92ae4ba30 | |||
| b5f2e56e38 | |||
| 594f4d56b8 | |||
| 2d83ca61e7 | |||
| 307e37a69f | |||
| 8310eb3b1f | |||
| b9c4f1fa95 | |||
| faab4f9e28 | |||
| 271b0abc45 | |||
| f0c3d50408 | |||
| f0fdff1f07 | |||
| d15df3489e | |||
| f3cc4ab09d | |||
| 442d8a68a6 | |||
| 934fffec68 | |||
| 8190e7838f | |||
| 4571975414 | |||
| 5115c61b03 | |||
| 54c7a9ee95 | |||
| 0296c7c5b6 | |||
| 84d8135cbb | |||
| dd3c370bca | |||
| 4e41f74925 | |||
| c6663f59b8 | |||
| ced7503d95 | |||
| 04af30daed | |||
| 5ccc8e341c | |||
| 71977e8f9d | |||
| 5e774e0b44 | |||
| e16d753439 | |||
| b14d189db9 | |||
| 14de29c031 | |||
| b59455b63c | |||
| 1a6dc86fed | |||
| 35b0c8b577 | |||
| 75034c3710 | |||
| 305cea28c5 | |||
| 69ba85b051 | |||
| 5700d65a53 | |||
| e707c40e0b | |||
| 9d37472f23 | |||
| eb97335c6f | |||
| 0028b29760 | |||
| 1ded1e38e8 | |||
| 149acdae7d | |||
| 5fee5f39ea | |||
| f16d453805 | |||
| 2b0293578f | |||
| 66aeeedaef | |||
| af41dd1ed6 | |||
| 17f7f1fc15 | |||
| cbc512f3be | |||
| 7ac9f92bc2 | |||
| a7ba63d425 | |||
| 5ca10b1d67 | |||
| f22a4a4e80 | |||
| b53ee13662 | |||
| 8de100b116 | |||
| ac30bcb0eb | |||
| 872d6ef55a | |||
| dd3b9c7c35 | |||
| 9755ae3cbe | |||
| bc29fb5a09 | |||
| 646a574b9c | |||
| 8f19650fd7 | |||
| f08980967b | |||
| 5285f5300a | |||
| 1608d0596d | |||
| 62631bfe33 | |||
| 7ffed858f0 | |||
| 3a1334e0d4 | |||
| 37f4f43726 | |||
| db1a84ede1 | |||
| 3d2e4c338c | |||
| b42d731fc8 | |||
| fd7045adac | |||
| e26d3505f7 | |||
| fe0249bf8f | |||
| 2ac682e125 | |||
| 9be1710dca | |||
| 7e7504f5ea | |||
| e83c11667f | |||
| 05547979de | |||
| 9e67ba83a5 | |||
| 2bb3522bbb | |||
| 8f4ec35697 | |||
| 17863dfbda | |||
| 56bb20d489 | |||
| 5baf32cd81 | |||
| 38cd1ecff4 | |||
| 77e00f1926 | |||
| ade139f2d0 | |||
| 653f35a3d8 | |||
| baa7aecf60 | |||
| d859826be6 | |||
| d759c96a98 | |||
| 7cbab0efe3 | |||
| b6b536682e | |||
| edf1df33cc | |||
| bf0df54136 | |||
| 7e80d2de79 | |||
| 144f687ee9 | |||
| 0ee8322947 | |||
| 997fb5fb48 | |||
| 2b459881bd | |||
| e18e7eca47 | |||
| 1c80d2ac2f | |||
| 62918ca779 | |||
| 3cca57a801 | |||
| 5578a2e46d | |||
| fe19cfde28 | |||
| fbad637235 | |||
| 01e9307fb7 | |||
| 5697cb6c95 | |||
| 05ff83f95a | |||
| 1e3012cb49 | |||
| 45b8cf350e | |||
| 2c2c6f8e02 | |||
| 4e3a6b9404 | |||
| 76bbccb4dc | |||
| 1c4433555a | |||
| faaced1d86 | |||
| 1a1d17e13a | |||
| 4254b6d0e2 | |||
| a211c2a955 | |||
| 196200bcc0 | |||
| c062835702 | |||
| 664ef756c2 | |||
| 9de28d640e | |||
| adb9dc7ede | |||
| f9fcd24315 | |||
| 6d95b999ad | |||
| 6731e52280 | |||
| 970358b2af | |||
| 3d68950037 | |||
| d50b2a4804 | |||
| 29a946163b | |||
| 9472025da7 | |||
| f5cd5387da | |||
| 7a8bf8e9a5 | |||
| f5ecdda400 | |||
| c2031aa651 | |||
| 8751c9931e | |||
| adbf9922f4 | |||
| b3a1e5f9e9 | |||
| 22f70f9ac9 | |||
| d2079f32d8 | |||
| f2ac416f66 | |||
| 642fbfba9f | |||
| c98cdd4f4c | |||
| d04567b99c | |||
| f2e1e1b890 | |||
| 6c764f6b8a | |||
| 49929f1e56 | |||
| acdf139137 | |||
| 3346c594e4 | |||
| 0bb2cfe440 | |||
| 11573b4ea4 | |||
| 5934959b62 | |||
| 81f6c22e51 | |||
| 78a8245f4a | |||
| 049861afb4 | |||
| 3df7083f69 | |||
| ca17edd5ac | |||
| c26bf871b7 | |||
| 15d3e8c3e1 | |||
| 66b370e103 | |||
| 2bbfbb1d50 | |||
| ace25d4987 | |||
| 59cb9a4e60 | |||
| 0dce570157 | |||
| 7ddaf49eb2 | |||
| e947363a11 | |||
| 5dbfe48d24 | |||
| 07d5f8b123 | |||
| be99603f1b | |||
| 54db496815 | |||
| fbe7ddb640 | |||
| 55c37d2a57 | |||
| 4b445531f5 | |||
| 12afc263a4 | |||
| 040d131284 | |||
| 73bbe0849a | |||
| 09a0615df0 | |||
| 669d5815c9 | |||
| bd24b97bd3 | |||
| db196ce5d8 | |||
| 4396b211ce | |||
| 367949e914 | |||
| ae2bbe7f19 | |||
| 819e14f91b | |||
| fcf3ccba98 | |||
| 558a10b54f | |||
| 43c60a02f7 | |||
| 6501bc5d32 | |||
| f3dae0c9ad | |||
| dc2cafc888 | |||
| 49fc4923be | |||
| efb5f17a60 | |||
| 086e764845 | |||
| c30290b43c | |||
| d26421fe3b | |||
| 37670924f6 | |||
| ee5143b54b | |||
| acbb2544bf | |||
| d8f7347000 | |||
| 3b91dec462 | |||
| 05f74b4218 | |||
| 8e98177fb3 | |||
| 815a3ad0de | |||
| 5075dd4dfa | |||
| ca09dcbe89 | |||
| 198a74d793 | |||
| fe404628e9 | |||
| 5a004c3b2a | |||
| 430180aa96 | |||
| e828be96f0 | |||
| 52447efb97 | |||
| d09b0fe83a | |||
| 798d8668a4 | |||
| 2a82b8fed9 | |||
| 696f687419 | |||
| 9b91b9db8c | |||
| 026473280b | |||
| a7849b2861 | |||
| 74bf659c56 | |||
| c2feedb7a2 | |||
| 0735e9ba98 | |||
| ab686732d0 | |||
| 6d86437369 | |||
| 184285ab27 | |||
| 1e8065d040 | |||
| f735d12247 | |||
| 7135bc2dc2 | |||
| 9044706796 | |||
| 5f68da3153 | |||
| 5222489a01 | |||
| 27f830f345 | |||
| 8d7db8e450 | |||
| da56758054 | |||
| 66dcc4b6db | |||
| 6eab5622c7 | |||
| af53f3d6cf | |||
| 188e5327ee | |||
| 1932a9d729 | |||
| c926ec477a | |||
| 7b11fa18a1 | |||
| e6cefdca25 | |||
| fbeff475b3 | |||
| d057099c17 | |||
| 411700d7e6 | |||
| b4e9d918f2 | |||
| 2756c364d2 | |||
| 43faabd4cc | |||
| a4a71a8904 | |||
| e23ac031ff | |||
| 79a56967a1 | |||
| 0bc0453700 | |||
| 35e247aa26 | |||
| 67ba187b6f | |||
| 67f0b1986c | |||
| 60e0177d00 | |||
| 4543a28e51 | |||
| aade2d1ec9 | |||
| 4627545a3b | |||
| e2ba7c9b8c | |||
| 6f5596ac5c | |||
| 7d1c2f191a | |||
| 4ada571384 | |||
| ad8ebbaa05 | |||
| 4854989db4 | |||
| 7c5050cf80 | |||
| 14ae8be547 | |||
| ff878ea9dc | |||
| 7021a4be44 | |||
| 5c4737c3d0 | |||
| fbf3807af1 | |||
| 703c37ec88 | |||
| 96440878bb | |||
| b5c11ffb1c | |||
| 7f5b323d50 | |||
| 67176e2b75 | |||
| 79f3cf3263 | |||
| 9ee1dc79fd | |||
| 9e2c34dfa6 | |||
| cc93c2a559 | |||
| 15c7044c4d | |||
| 0ef80d3579 | |||
| 95c2e0a996 | |||
| da3e8611e1 | |||
| 64595597f3 | |||
| 82f2983cd4 | |||
| 9451177c35 | |||
| 9ed087d5da | |||
| 77f22e9674 | |||
| 8ccfdbbcf9 | |||
| 5a92aa4e06 | |||
| 7b1010cf61 | |||
| 45b2f5bac4 | |||
| 36e1c82ef5 | |||
| 503d65d570 | |||
| fe17f8da41 | |||
| b583aa1579 | |||
| e0d81b97bb | |||
| 90752f9d87 | |||
| 3663aa675a | |||
| 1ca4b81856 | |||
| 4e7e06f549 | |||
| b2f0bdb0f4 | |||
| d98bd34200 | |||
| 940bdd878e | |||
| df556333a8 | |||
| 116f05eda6 | |||
| b187bbeca3 | |||
| 479a83b628 | |||
| 1c18100143 | |||
| 5d3c0f33f6 | |||
| afe106e254 | |||
| 69dd40ec89 | |||
| dee50d5e28 | |||
| 9e93403857 | |||
| 12bff6b3a0 | |||
| 70e666b4a3 | |||
| 29f980ec72 | |||
| 1d39d762f0 | |||
| 4d6d5e0ddd | |||
| 4ea5f070a4 | |||
| da59b4da9b | |||
| 0065a160cc | |||
| 52f46c7fea | |||
| f0a826ec0c | |||
| 5c3c0f73c1 | |||
| be0b71ce31 | |||
| f85d48dd31 | |||
| a1b58ee601 | |||
| e30429051d | |||
| 942ead75e2 | |||
| 453688f6df | |||
| 7d7a161102 | |||
| aaa223ae66 | |||
| d11c624fb0 | |||
| 275e51b19d | |||
| ab62edeeaa | |||
| 813108a928 | |||
| 3c14911401 | |||
| 4337f14627 | |||
| 92d78c10a2 | |||
| 16d5ba9b3a | |||
| 52065a736b | |||
| 11cb109114 | |||
| d7eadd41d6 |
+4
-5
@@ -88,15 +88,14 @@ present in the framework.
|
||||
1. Preserve existing formatting; i.e. do not reformat code for its own sake
|
||||
1. Search the codebase using `git grep` and other tools to discover common
|
||||
naming conventions, etc.
|
||||
1. Latin-1 (ISO-8859-1) encoding for Java sources; use `native2ascii` to convert
|
||||
if necessary
|
||||
1. UTF-8 encoding for Java sources
|
||||
|
||||
|
||||
### Add Apache license header to all new classes
|
||||
|
||||
```java
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -124,11 +123,11 @@ modified a file in 2015 whose header still reads:
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
```
|
||||
|
||||
Then be sure to update it to 2015 accordingly:
|
||||
Then be sure to update it to 2016 accordingly:
|
||||
|
||||
```java
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
```
|
||||
|
||||
### Use @since tags for newly-added public API types and methods
|
||||
|
||||
+108
-109
@@ -31,52 +31,53 @@ configure(allprojects) { project ->
|
||||
group = "org.springframework"
|
||||
version = qualifyVersionIfNecessary(version)
|
||||
|
||||
ext.aspectjVersion = "1.8.9"
|
||||
ext.caffeineVersion = "2.3.1"
|
||||
ext.aspectjVersion = "1.8.10"
|
||||
ext.caffeineVersion = "2.3.5"
|
||||
ext.eclipselinkVersion = "2.4.2"
|
||||
ext.ehcacheVersion = "2.10.2"
|
||||
ext.ehcacheVersion = "2.10.4"
|
||||
ext.ehcachejcacheVersion = "1.0.1"
|
||||
ext.ehcache3Version = "3.1.0"
|
||||
ext.ehcache3Version = "3.1.4"
|
||||
ext.ejbVersion = "3.0"
|
||||
ext.fileuploadVersion = "1.3.2"
|
||||
ext.fileuploadVersion = "1.3.3"
|
||||
ext.freemarkerVersion = "2.3.23"
|
||||
ext.groovyVersion = "2.4.7"
|
||||
ext.gsonVersion = "2.7"
|
||||
ext.guavaVersion = "19.0"
|
||||
ext.groovyVersion = "2.4.12"
|
||||
ext.gsonVersion = "2.8.1"
|
||||
ext.guavaVersion = "20.0"
|
||||
ext.hamcrestVersion = "1.3"
|
||||
ext.hibernate3Version = "3.6.10.Final"
|
||||
ext.hibernate4Version = "4.3.11.Final"
|
||||
ext.hibernate5Version = "5.2.1.Final"
|
||||
ext.hibernate5Version = "5.2.10.Final"
|
||||
ext.hibval4Version = "4.3.2.Final"
|
||||
ext.hibval5Version = "5.2.4.Final"
|
||||
ext.hibval5Version = "5.2.5.Final"
|
||||
ext.hsqldbVersion = "2.3.4"
|
||||
ext.httpasyncVersion = "4.1.2"
|
||||
ext.httpclientVersion = "4.5.2"
|
||||
ext.jackson2Version = "2.8.0.rc2"
|
||||
ext.httpasyncVersion = "4.1.3"
|
||||
ext.httpclientVersion = "4.5.3"
|
||||
ext.jackson2Version = "2.8.9"
|
||||
ext.jasperreportsVersion = "6.2.1" // our tests fail with JR-internal NPEs against 6.2.2 and higher
|
||||
ext.javamailVersion = "1.5.5"
|
||||
ext.jettyVersion = "9.3.10.v20160621"
|
||||
ext.jodaVersion = "2.9.4"
|
||||
ext.jrubyVersion = "1.7.25" // JRuby 9000 only supported through JSR-223 (StandardScriptFactory)
|
||||
ext.javamailVersion = "1.5.6"
|
||||
ext.jettyVersion = "9.3.14.v20161028" // as of 9.3.15, Jetty has hard Servlet 3.1 requirement
|
||||
ext.jetty94Version = "9.4.6.v20170531" // for spring-websocket support, optimized for Jetty 9.4
|
||||
ext.jodaVersion = "2.9.9"
|
||||
ext.jrubyVersion = "1.7.26" // JRuby 9000 primarily supported through JSR-223 (StandardScriptFactory)
|
||||
ext.jtaVersion = "1.2"
|
||||
ext.junitVersion = "4.12"
|
||||
ext.log4jVersion = "1.2.17"
|
||||
ext.nettyVersion = "4.1.1.Final"
|
||||
ext.nettyVersion = "4.1.13.Final"
|
||||
ext.okhttpVersion = "2.7.5"
|
||||
ext.okhttp3Version = "3.3.1"
|
||||
ext.okhttp3Version = "3.7.0"
|
||||
ext.openjpaVersion = "2.4.1"
|
||||
ext.poiVersion = "3.14"
|
||||
ext.reactorVersion = "2.0.8.RELEASE"
|
||||
ext.romeVersion = "1.6.0"
|
||||
ext.romeVersion = "1.7.2"
|
||||
ext.slf4jVersion = "1.7.21"
|
||||
ext.snakeyamlVersion = "1.17"
|
||||
ext.snifferVersion = "1.15"
|
||||
ext.testngVersion = "6.9.10"
|
||||
ext.tiles2Version = "2.2.2"
|
||||
ext.tiles3Version = "3.0.5"
|
||||
ext.tomcatVersion = "8.5.3"
|
||||
ext.tiles3Version = "3.0.7"
|
||||
ext.tomcatVersion = "8.5.16"
|
||||
ext.tyrusVersion = "1.3.5" // constrained by WebLogic 12.1.3 support
|
||||
ext.undertowVersion = "1.4.0.CR2"
|
||||
ext.undertowVersion = "1.3.30.Final"
|
||||
ext.xmlunitVersion = "1.6"
|
||||
ext.xstreamVersion = "1.4.9"
|
||||
|
||||
@@ -110,11 +111,13 @@ configure(allprojects) { project ->
|
||||
compileJava {
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
|
||||
compileTestJava {
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
options.encoding = 'UTF-8'
|
||||
options.compilerArgs += "-parameters"
|
||||
}
|
||||
|
||||
@@ -199,10 +202,10 @@ configure(allprojects) { project ->
|
||||
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
|
||||
"http://ehcache.org/apidocs/${ehcacheVersion}",
|
||||
"http://ehcache.org/apidocs/${ehcache3Version}",
|
||||
"http://quartz-scheduler.org/api/2.2.0/",
|
||||
"http://fasterxml.github.io/jackson-core/javadoc/2.7/",
|
||||
"http://fasterxml.github.io/jackson-databind/javadoc/2.7/",
|
||||
"http://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.7/",
|
||||
"http://quartz-scheduler.org/api/2.2.1/",
|
||||
"http://fasterxml.github.io/jackson-core/javadoc/2.8/",
|
||||
"http://fasterxml.github.io/jackson-databind/javadoc/2.8/",
|
||||
"http://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.8/",
|
||||
"http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/"
|
||||
] as String[]
|
||||
}
|
||||
@@ -214,7 +217,6 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
|
||||
configurations {
|
||||
jacoco
|
||||
}
|
||||
|
||||
dependencies {
|
||||
jacoco("org.jacoco:org.jacoco.agent:0.7.5.201505241946:runtime")
|
||||
}
|
||||
@@ -248,16 +250,16 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
|
||||
options.links(project.ext.javadocLinks)
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
|
||||
// suppress warnings due to cross-module @see and @link references;
|
||||
// note that global 'api' task does display all warnings.
|
||||
// Suppress warnings due to cross-module @see and @link references.
|
||||
// Note that global 'api' task does display all warnings.
|
||||
logging.captureStandardError LogLevel.INFO
|
||||
logging.captureStandardOutput LogLevel.INFO // suppress "## warnings" message
|
||||
logging.captureStandardOutput LogLevel.INFO // suppress "## warnings" message
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||
classifier = 'sources'
|
||||
from sourceSets.main.allSource
|
||||
// don't include or exclude anything explicitly by default. See SPR-12085.
|
||||
// Don't include or exclude anything explicitly by default. See SPR-12085.
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
@@ -273,6 +275,7 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
|
||||
|
||||
project("spring-build-src") {
|
||||
description = "Exposes gradle buildSrc for IDE support"
|
||||
|
||||
apply plugin: "groovy"
|
||||
|
||||
dependencies {
|
||||
@@ -290,8 +293,8 @@ project("spring-core") {
|
||||
// both into the spring-core jar. cglib 3.2 itself depends on asm 5.x and is therefore
|
||||
// further transformed by the JarJar task to depend on org.springframework.asm; this
|
||||
// avoids including two different copies of asm unnecessarily.
|
||||
def cglibVersion = "3.2.4"
|
||||
def objenesisVersion = "2.4"
|
||||
def cglibVersion = "3.2.5"
|
||||
def objenesisVersion = "2.6"
|
||||
|
||||
configurations {
|
||||
jarjar
|
||||
@@ -311,9 +314,9 @@ project("spring-core") {
|
||||
configurations.cglib.each { originalJar ->
|
||||
zipfileset(src: originalJar)
|
||||
}
|
||||
// repackage net.sf.cglib => org.springframework.cglib
|
||||
// Repackage net.sf.cglib => org.springframework.cglib
|
||||
rule(pattern: "net.sf.cglib.**", result: "org.springframework.cglib.@1")
|
||||
// as mentioned above, transform cglib"s internal asm dependencies from
|
||||
// As mentioned above, transform cglib"s internal asm dependencies from
|
||||
// org.objectweb.asm => org.springframework.asm. Doing this counts on the
|
||||
// the fact that Spring and cglib depend on the same version of asm!
|
||||
rule(pattern: "org.objectweb.asm.**", result: "org.springframework.asm.@1")
|
||||
@@ -334,7 +337,7 @@ project("spring-core") {
|
||||
configurations.objenesis.each { originalJar ->
|
||||
zipfileset(src: originalJar)
|
||||
}
|
||||
// repackage org.objenesis => org.springframework.objenesis
|
||||
// Repackage org.objenesis => org.springframework.objenesis
|
||||
rule(pattern: "org.objenesis.**", result: "org.springframework.objenesis.@1")
|
||||
}
|
||||
}
|
||||
@@ -351,17 +354,17 @@ project("spring-core") {
|
||||
compile("commons-logging:commons-logging:1.2")
|
||||
optional("commons-codec:commons-codec:1.10")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("net.sf.jopt-simple:jopt-simple:5.0.2")
|
||||
optional("net.sf.jopt-simple:jopt-simple:5.0.3")
|
||||
optional("log4j:log4j:${log4jVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
|
||||
testCompile("com.fasterxml.woodstox:woodstox-core:5.0.2") {
|
||||
testCompile("com.fasterxml.woodstox:woodstox-core:5.0.3") {
|
||||
exclude group: "stax", module: "stax-api"
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
// inline repackaged cglib classes directly into the spring-core jar
|
||||
// Inline repackaged cglib classes directly into spring-core jar
|
||||
dependsOn cglibRepackJar
|
||||
from(zipTree(cglibRepackJar.archivePath)) {
|
||||
include "org/springframework/cglib/**"
|
||||
@@ -390,6 +393,7 @@ project("spring-beans") {
|
||||
|
||||
project("spring-beans-groovy") {
|
||||
description "Groovy Bean Definitions"
|
||||
|
||||
merge.into = project(":spring-beans")
|
||||
apply plugin: "groovy"
|
||||
|
||||
@@ -398,8 +402,8 @@ project("spring-beans-groovy") {
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
}
|
||||
|
||||
// this module's Java and Groovy sources need to be compiled together
|
||||
compileJava.enabled=false
|
||||
// This module's Java and Groovy sources need to be compiled together.
|
||||
compileJava.enabled = false
|
||||
sourceSets {
|
||||
main {
|
||||
groovy {
|
||||
@@ -465,6 +469,7 @@ project("spring-instrument-tomcat") {
|
||||
|
||||
project("spring-context") {
|
||||
description = "Spring Context"
|
||||
|
||||
apply plugin: "groovy"
|
||||
|
||||
dependencies {
|
||||
@@ -477,14 +482,14 @@ project("spring-context") {
|
||||
optional("javax.inject:javax.inject:1")
|
||||
optional("javax.ejb:ejb-api:${ejbVersion}")
|
||||
optional("javax.enterprise.concurrent:javax.enterprise.concurrent-api:1.0")
|
||||
optional("javax.money:money-api:1.0")
|
||||
optional("javax.money:money-api:1.0.1")
|
||||
optional("org.eclipse.persistence:javax.persistence:2.0.0")
|
||||
optional("javax.validation:validation-api:1.0.0.GA")
|
||||
optional("org.hibernate:hibernate-validator:${hibval4Version}")
|
||||
optional("joda-time:joda-time:${jodaVersion}")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("org.beanshell:bsh:2.0b4")
|
||||
optional("org.beanshell:bsh:2.0b5")
|
||||
optional("org.jruby:jruby:${jrubyVersion}")
|
||||
testCompile("javax.inject:javax.inject-tck:1")
|
||||
testCompile("org.javamoney:moneta:1.1")
|
||||
@@ -494,13 +499,44 @@ project("spring-context") {
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-oxm") {
|
||||
description = "Spring Object/XML Marshalling"
|
||||
apply from: "oxm.gradle"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
optional("org.codehaus.castor:castor-xml:1.4.1") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
exclude group: "org.springframework", module: "spring-context"
|
||||
}
|
||||
optional("org.apache.xmlbeans:xmlbeans:2.6.0") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
}
|
||||
optional("com.thoughtworks.xstream:xstream:${xstreamVersion}") {
|
||||
exclude group: 'xpp3', module: 'xpp3_min'
|
||||
exclude group: 'xmlpull', module: 'xmlpull'
|
||||
}
|
||||
optional("org.jibx:jibx-run:1.2.6")
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile("org.ogce:xpp3:1.1.6")
|
||||
testCompile("org.codehaus.jettison:jettison:1.3.8") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
}
|
||||
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
|
||||
testCompile(files(genCastor.classesDir).builtBy(genCastor))
|
||||
testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
|
||||
testCompile(files(genXmlbeans.classesDir).builtBy(genXmlbeans))
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-messaging") {
|
||||
description = "Spring Messaging"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
optional(project(":spring-oxm"))
|
||||
optional("io.projectreactor:reactor-core:${reactorVersion}")
|
||||
optional("io.projectreactor:reactor-net:${reactorVersion}") {
|
||||
@@ -552,54 +588,14 @@ project("spring-tx") {
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-oxm") {
|
||||
description = "Spring Object/XML Marshalling"
|
||||
apply from: "oxm.gradle"
|
||||
|
||||
compileTestJava {
|
||||
// necessary to avoid java.lang.VerifyError on jibx compilation
|
||||
// see http://jira.codehaus.org/browse/JIBX-465
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
optional("org.codehaus.castor:castor-xml:1.4.1") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
exclude group: "org.springframework", module: "spring-context"
|
||||
}
|
||||
optional("org.apache.xmlbeans:xmlbeans:2.6.0") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
}
|
||||
optional("com.thoughtworks.xstream:xstream:${xstreamVersion}") {
|
||||
exclude group: 'xpp3', module: 'xpp3_min'
|
||||
exclude group: 'xmlpull', module: 'xmlpull'
|
||||
}
|
||||
optional("org.jibx:jibx-run:1.2.6")
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
|
||||
testCompile("xpp3:xpp3:1.1.4c")
|
||||
testCompile("org.codehaus.jettison:jettison:1.3.7") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
}
|
||||
if (compileTestJava.enabled) {
|
||||
testCompile(files(genCastor.classesDir).builtBy(genCastor))
|
||||
testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
|
||||
testCompile(files(genXmlbeans.classesDir).builtBy(genXmlbeans))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-jms") {
|
||||
description = "Spring JMS"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-aop"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-messaging"))
|
||||
compile(project(":spring-tx"))
|
||||
provided("javax.jms:jms-api:1.1-rev-1")
|
||||
@@ -621,9 +617,9 @@ project("spring-jdbc") {
|
||||
optional("javax.transaction:javax.transaction-api:${jtaVersion}")
|
||||
optional("com.mchange:c3p0:0.9.5.2")
|
||||
optional("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
optional("com.h2database:h2:1.4.192")
|
||||
optional("org.apache.derby:derby:10.12.1.1")
|
||||
optional("org.apache.derby:derbyclient:10.12.1.1")
|
||||
optional("com.h2database:h2:1.4.193")
|
||||
optional("org.apache.derby:derby:10.13.1.1")
|
||||
optional("org.apache.derby:derbyclient:10.13.1.1")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -631,9 +627,9 @@ project("spring-context-support") {
|
||||
description = "Spring Context Support"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
optional(project(":spring-jdbc")) // for Quartz support
|
||||
optional(project(":spring-tx")) // for Quartz support
|
||||
optional("javax.mail:javax.mail-api:${javamailVersion}")
|
||||
@@ -667,6 +663,7 @@ project("spring-context-support") {
|
||||
|
||||
project("spring-web") {
|
||||
description = "Spring Web"
|
||||
|
||||
apply plugin: "groovy"
|
||||
|
||||
// Re-generate Protobuf classes from *.proto files and move them in test sources
|
||||
@@ -727,6 +724,7 @@ project("spring-web") {
|
||||
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-joda:${jackson2Version}")
|
||||
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:${jackson2Version}")
|
||||
testCompile("com.fasterxml.jackson.module:jackson-module-kotlin:${jackson2Version}")
|
||||
testCompile("com.squareup.okhttp3:mockwebserver:${okhttp3Version}")
|
||||
testRuntime("com.sun.mail:javax.mail:${javamailVersion}")
|
||||
}
|
||||
}
|
||||
@@ -876,13 +874,13 @@ project("spring-webmvc") {
|
||||
testCompile("org.hibernate:hibernate-validator:${hibval4Version}")
|
||||
testCompile("org.apache.httpcomponents:httpclient:${httpclientVersion}")
|
||||
testCompile("commons-fileupload:commons-fileupload:${fileuploadVersion}")
|
||||
testCompile("commons-io:commons-io:1.3")
|
||||
testCompile("commons-io:commons-io:1.4")
|
||||
testCompile("joda-time:joda-time:${jodaVersion}")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("org.jruby:jruby:${jrubyVersion}")
|
||||
testCompile("org.python:jython-standalone:2.5.3")
|
||||
testCompile("org.mozilla:rhino:1.7.7.1")
|
||||
testCompile("org.webjars:underscorejs:1.8.3")
|
||||
testRuntime("org.jruby:jruby:${jrubyVersion}")
|
||||
testRuntime("org.python:jython-standalone:2.5.3")
|
||||
testRuntime("org.webjars:underscorejs:1.8.3")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,8 +935,8 @@ project("spring-websocket") {
|
||||
description = "Spring WebSocket"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-web"))
|
||||
optional(project(":spring-messaging"))
|
||||
optional(project(":spring-webmvc"))
|
||||
@@ -955,11 +953,11 @@ project("spring-websocket") {
|
||||
optional("org.eclipse.jetty:jetty-webapp:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet"
|
||||
}
|
||||
optional("org.eclipse.jetty.websocket:websocket-server:${jettyVersion}") {
|
||||
optional("org.eclipse.jetty.websocket:websocket-server:${jetty94Version}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet"
|
||||
}
|
||||
optional("org.eclipse.jetty.websocket:websocket-client:${jettyVersion}")
|
||||
optional("org.eclipse.jetty:jetty-client:${jettyVersion}")
|
||||
optional("org.eclipse.jetty.websocket:websocket-client:${jetty94Version}")
|
||||
optional("org.eclipse.jetty:jetty-client:${jetty94Version}")
|
||||
optional("io.undertow:undertow-core:${undertowVersion}")
|
||||
optional("io.undertow:undertow-servlet:${undertowVersion}") {
|
||||
exclude group: "org.jboss.spec.javax.servlet", module: "jboss-servlet-api_3.1_spec"
|
||||
@@ -983,11 +981,12 @@ project("spring-test") {
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
optional(project(":spring-aop"))
|
||||
optional(project(":spring-beans"))
|
||||
optional(project(":spring-context"))
|
||||
optional(project(":spring-jdbc"))
|
||||
optional(project(":spring-tx"))
|
||||
optional(project(":spring-orm"))
|
||||
optional(project(":spring-tx"))
|
||||
optional(project(":spring-web"))
|
||||
optional(project(":spring-webmvc"))
|
||||
optional(project(":spring-webmvc-portlet"))
|
||||
@@ -1008,11 +1007,11 @@ project("spring-test") {
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("org.hamcrest:hamcrest-core:${hamcrestVersion}")
|
||||
optional("xmlunit:xmlunit:${xmlunitVersion}")
|
||||
optional("net.sourceforge.htmlunit:htmlunit:2.22")
|
||||
optional("org.seleniumhq.selenium:htmlunit-driver:2.21")
|
||||
optional("net.sourceforge.htmlunit:htmlunit:2.23")
|
||||
optional("org.seleniumhq.selenium:htmlunit-driver:2.23.2")
|
||||
optional("org.seleniumhq.selenium:selenium-java:2.53.1")
|
||||
optional("org.skyscreamer:jsonassert:1.3.0")
|
||||
optional("com.jayway.jsonpath:json-path:2.2.0")
|
||||
optional("org.skyscreamer:jsonassert:1.4.0")
|
||||
optional("com.jayway.jsonpath:json-path:2.3.0")
|
||||
testCompile(project(":spring-context-support"))
|
||||
testCompile(project(":spring-oxm"))
|
||||
testCompile("javax.mail:javax.mail-api:${javamailVersion}")
|
||||
@@ -1036,7 +1035,7 @@ project("spring-test") {
|
||||
testCompile("javax.cache:cache-api:1.0.0")
|
||||
testRuntime("log4j:log4j:${log4jVersion}")
|
||||
testRuntime("org.ehcache:ehcache:${ehcache3Version}")
|
||||
testRuntime("org.terracotta:management-model:2.0.0")
|
||||
testRuntime("org.terracotta:management-model:2.3.0")
|
||||
}
|
||||
|
||||
task testNG(type: Test) {
|
||||
@@ -1181,7 +1180,7 @@ configure(rootProject) {
|
||||
// don't publish the default jar for the root project
|
||||
configurations.archives.artifacts.clear()
|
||||
|
||||
dependencies { // for integration tests
|
||||
dependencies { // for integration tests
|
||||
testCompile(project(":spring-aop"))
|
||||
testCompile(project(":spring-beans"))
|
||||
testCompile(project(":spring-context"))
|
||||
@@ -1230,11 +1229,11 @@ configure(rootProject) {
|
||||
|
||||
doFirst {
|
||||
classpath = files(
|
||||
// ensure Servlet 3.x and Hibernate 4.x have precedence on the javadoc
|
||||
// Ensure Servlet 3.x and Hibernate 4.x have precedence on the javadoc
|
||||
// classpath over their respective 2.5 and 3.x variants
|
||||
project(":spring-webmvc").sourceSets.main.compileClasspath.files.find { it =~ "servlet-api" },
|
||||
rootProject.sourceSets.test.compileClasspath.files.find { it =~ "hibernate-core" },
|
||||
// ensure the javadoc process can resolve types compiled from .aj sources
|
||||
// Ensure the javadoc process can resolve types compiled from .aj sources
|
||||
project(":spring-aspects").sourceSets.main.output
|
||||
)
|
||||
classpath += files(subprojects.collect { it.sourceSets.main.compileClasspath })
|
||||
@@ -1367,7 +1366,7 @@ configure(rootProject) {
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
description = "Generates gradlew[.bat] scripts"
|
||||
gradleVersion = "2.13"
|
||||
gradleVersion = "2.14.1"
|
||||
|
||||
doLast() {
|
||||
def gradleOpts = "-XX:MaxMetaspaceSize=1024m -Xmx1024m"
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
version=4.3.1.BUILD-SNAPSHOT
|
||||
version=4.3.10.RELEASE
|
||||
|
||||
@@ -29,8 +29,8 @@ def customizePom(pom, gradleProject) {
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name "The Apache Software License, Version 2.0"
|
||||
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
name "Apache License, Version 2.0"
|
||||
url "http://www.apache.org/licenses/LICENSE-2.0"
|
||||
distribution "repo"
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-2
@@ -1,6 +1,6 @@
|
||||
#Wed Jun 15 12:59:30 CEST 2016
|
||||
#Wed Aug 17 21:21:18 CEST 2016
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-bin.zip
|
||||
|
||||
@@ -46,7 +46,7 @@ public interface MethodInterceptor extends Interceptor {
|
||||
* after the invocation. Polite implementations would certainly
|
||||
* like to invoke {@link Joinpoint#proceed()}.
|
||||
* @param invocation the method invocation joinpoint
|
||||
* @return the result of the call to {@link Joinpoint#proceed();
|
||||
* @return the result of the call to {@link Joinpoint#proceed()};
|
||||
* might be intercepted by the interceptor
|
||||
* @throws Throwable if the interceptors or the target object
|
||||
* throws an exception
|
||||
|
||||
+44
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,7 +28,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.aspectj.weaver.BCException;
|
||||
import org.aspectj.weaver.patterns.NamePattern;
|
||||
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
|
||||
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
||||
@@ -187,13 +186,24 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
throw new IllegalStateException("Must set property 'expression' before attempting to match");
|
||||
}
|
||||
if (this.pointcutExpression == null) {
|
||||
this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
this.pointcutClassLoader = determinePointcutClassLoader();
|
||||
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the ClassLoader to use for pointcut evaluation.
|
||||
*/
|
||||
private ClassLoader determinePointcutClassLoader() {
|
||||
if (this.beanFactory instanceof ConfigurableBeanFactory) {
|
||||
return ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader();
|
||||
}
|
||||
if (this.pointcutDeclarationScope != null) {
|
||||
return this.pointcutDeclarationScope.getClassLoader();
|
||||
}
|
||||
return ClassUtils.getDefaultClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
@@ -258,7 +268,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (BCException ex) {
|
||||
catch (Throwable ex) {
|
||||
logger.debug("PointcutExpression matching rejected target class", ex);
|
||||
}
|
||||
return false;
|
||||
@@ -326,7 +336,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// No current invocation...
|
||||
// TODO: Should we really proceed here?
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not access current invocation - matching with limited context: " + ex);
|
||||
}
|
||||
@@ -413,39 +422,46 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
shadowMatch = this.shadowMatchCache.get(targetMethod);
|
||||
if (shadowMatch == null) {
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorldException ex) {
|
||||
// Failed to introspect target method, probably because it has been loaded
|
||||
// in a special ClassLoader. Let's try the declaring ClassLoader instead...
|
||||
try {
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex2) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
if (shadowMatch == null && targetMethod != originalMethod) {
|
||||
methodToMatch = originalMethod;
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorldException ex3) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's try the original method's declaring class before we give up...
|
||||
catch (ReflectionWorldException ex) {
|
||||
// Failed to introspect target method, probably because it has been loaded
|
||||
// in a special ClassLoader. Let's try the declaring ClassLoader instead...
|
||||
try {
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex4) {
|
||||
catch (ReflectionWorldException ex2) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
if (shadowMatch == null && targetMethod != originalMethod) {
|
||||
methodToMatch = originalMethod;
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorldException ex3) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's try the original method's declaring class before we give up...
|
||||
try {
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex4) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Possibly AspectJ 1.8.10 encountering an invalid signature
|
||||
logger.debug("PointcutExpression matching rejected target method", ex);
|
||||
fallbackExpression = null;
|
||||
}
|
||||
if (shadowMatch == null) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
|
||||
+18
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,8 @@ package org.springframework.aop.aspectj;
|
||||
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.support.AbstractGenericPointcutAdvisor;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
|
||||
/**
|
||||
* Spring AOP Advisor that can be used for any AspectJ pointcut expression.
|
||||
@@ -26,16 +28,11 @@ import org.springframework.aop.support.AbstractGenericPointcutAdvisor;
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor {
|
||||
public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor implements BeanFactoryAware {
|
||||
|
||||
private final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
|
||||
|
||||
@Override
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
public void setExpression(String expression) {
|
||||
this.pointcut.setExpression(expression);
|
||||
}
|
||||
@@ -52,12 +49,22 @@ public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdv
|
||||
return this.pointcut.getLocation();
|
||||
}
|
||||
|
||||
public void setParameterTypes(Class<?>[] types) {
|
||||
this.pointcut.setParameterTypes(types);
|
||||
}
|
||||
|
||||
public void setParameterNames(String... names) {
|
||||
this.pointcut.setParameterNames(names);
|
||||
}
|
||||
|
||||
public void setParameterTypes(Class<?>... types) {
|
||||
this.pointcut.setParameterTypes(types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.pointcut.setBeanFactory(beanFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,6 @@ import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.PointcutAdvisor;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* AspectJPointcutAdvisor that adapts an {@link AbstractAspectJAdvice}
|
||||
@@ -51,11 +50,11 @@ public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered {
|
||||
this.pointcut = advice.buildSafePointcut();
|
||||
}
|
||||
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPerInstance() {
|
||||
return true;
|
||||
@@ -91,12 +90,12 @@ public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered {
|
||||
return false;
|
||||
}
|
||||
AspectJPointcutAdvisor otherAdvisor = (AspectJPointcutAdvisor) other;
|
||||
return (ObjectUtils.nullSafeEquals(this.advice, otherAdvisor.advice));
|
||||
return this.advice.equals(otherAdvisor.advice);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return AspectJPointcutAdvisor.class.hashCode();
|
||||
return AspectJPointcutAdvisor.class.hashCode() * 29 + this.advice.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -55,10 +55,12 @@ public class SimpleAspectInstanceFactory implements AspectInstanceFactory {
|
||||
return this.aspectClass.newInstance();
|
||||
}
|
||||
catch (InstantiationException ex) {
|
||||
throw new AopConfigException("Unable to instantiate aspect class [" + this.aspectClass.getName() + "]", ex);
|
||||
throw new AopConfigException(
|
||||
"Unable to instantiate aspect class: " + this.aspectClass.getName(), ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new AopConfigException("Cannot access element class [" + this.aspectClass.getName() + "]", ex);
|
||||
throw new AopConfigException(
|
||||
"Could not access aspect constructor: " + this.aspectClass.getName(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,6 +27,7 @@ import org.springframework.util.StringUtils;
|
||||
* Spring AOP {@link ClassFilter} implementation using AspectJ type matching.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class TypePatternClassFilter implements ClassFilter {
|
||||
@@ -76,17 +77,21 @@ public class TypePatternClassFilter implements ClassFilter {
|
||||
* or is recognized as invalid
|
||||
*/
|
||||
public void setTypePattern(String typePattern) {
|
||||
Assert.notNull(typePattern);
|
||||
Assert.notNull(typePattern, "Type pattern must not be null");
|
||||
this.typePattern = typePattern;
|
||||
this.aspectJTypePatternMatcher =
|
||||
PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution().
|
||||
parseTypePattern(replaceBooleanOperators(typePattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the AspectJ type pattern to match.
|
||||
*/
|
||||
public String getTypePattern() {
|
||||
return typePattern;
|
||||
return this.typePattern;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Should the pointcut apply to the given interface or target class?
|
||||
* @param clazz candidate target class
|
||||
@@ -95,9 +100,7 @@ public class TypePatternClassFilter implements ClassFilter {
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(Class<?> clazz) {
|
||||
if (this.aspectJTypePatternMatcher == null) {
|
||||
throw new IllegalStateException("No 'typePattern' has been set via ctor/setter.");
|
||||
}
|
||||
Assert.state(this.aspectJTypePatternMatcher != null, "No type pattern has been set");
|
||||
return this.aspectJTypePatternMatcher.matches(clazz);
|
||||
}
|
||||
|
||||
@@ -108,9 +111,8 @@ public class TypePatternClassFilter implements ClassFilter {
|
||||
* <p>This method converts back to {@code &&} for the AspectJ pointcut parser.
|
||||
*/
|
||||
private String replaceBooleanOperators(String pcExpr) {
|
||||
pcExpr = StringUtils.replace(pcExpr," and "," && ");
|
||||
pcExpr = StringUtils.replace(pcExpr, " or ", " || ");
|
||||
pcExpr = StringUtils.replace(pcExpr, " not ", " ! ");
|
||||
return pcExpr;
|
||||
String result = StringUtils.replace(pcExpr," and "," && ");
|
||||
result = StringUtils.replace(result, " or ", " || ");
|
||||
return StringUtils.replace(result, " not ", " ! ");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-45
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,7 +38,6 @@ import org.aspectj.lang.reflect.AjType;
|
||||
import org.aspectj.lang.reflect.AjTypeSystem;
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
@@ -121,49 +120,6 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The pointcut and advice annotations both have an "argNames" member which contains a
|
||||
* comma-separated list of the argument names. We use this (if non-empty) to build the
|
||||
* formal parameters for the pointcut.
|
||||
*/
|
||||
protected AspectJExpressionPointcut createPointcutExpression(
|
||||
Method annotatedMethod, Class<?> declarationScope, String[] pointcutParameterNames) {
|
||||
|
||||
Class<?> [] pointcutParameterTypes = new Class<?>[0];
|
||||
if (pointcutParameterNames != null) {
|
||||
pointcutParameterTypes = extractPointcutParameterTypes(pointcutParameterNames,annotatedMethod);
|
||||
}
|
||||
|
||||
AspectJExpressionPointcut ajexp =
|
||||
new AspectJExpressionPointcut(declarationScope,pointcutParameterNames,pointcutParameterTypes);
|
||||
ajexp.setLocation(annotatedMethod.toString());
|
||||
return ajexp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the pointcut parameters needed by aspectj based on the given argument names
|
||||
* and the argument types that are available from the adviceMethod. Needs to take into
|
||||
* account (ignore) any JoinPoint based arguments as these are not pointcut context but
|
||||
* rather part of the advice execution context (thisJoinPoint, thisJoinPointStaticPart)
|
||||
*/
|
||||
private Class<?>[] extractPointcutParameterTypes(String[] argNames, Method adviceMethod) {
|
||||
Class<?>[] ret = new Class<?>[argNames.length];
|
||||
Class<?>[] paramTypes = adviceMethod.getParameterTypes();
|
||||
if (argNames.length > paramTypes.length) {
|
||||
throw new IllegalStateException("Expecting at least " + argNames.length +
|
||||
" arguments in the advice declaration, but only found " + paramTypes.length);
|
||||
}
|
||||
|
||||
// Make the simplifying assumption for now that all of the JoinPoint based arguments
|
||||
// come first in the advice declaration.
|
||||
int typeOffset = paramTypes.length - argNames.length;
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = paramTypes[i + typeOffset];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find and return the first AspectJ annotation on the given method
|
||||
* (there <i>should</i> only be one anyway...)
|
||||
|
||||
+6
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,7 +50,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
|
||||
private List<Pattern> includePatterns;
|
||||
|
||||
private AspectJAdvisorFactory aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory();
|
||||
private AspectJAdvisorFactory aspectJAdvisorFactory;
|
||||
|
||||
private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;
|
||||
|
||||
@@ -74,6 +74,9 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
@Override
|
||||
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
super.initBeanFactory(beanFactory);
|
||||
if (this.aspectJAdvisorFactory == null) {
|
||||
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
|
||||
}
|
||||
this.aspectJAdvisorsBuilder =
|
||||
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
|
||||
}
|
||||
@@ -130,6 +133,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
|
||||
public BeanFactoryAspectJAdvisorsBuilderAdapter(
|
||||
ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
|
||||
|
||||
super(beanFactory, advisorFactory);
|
||||
}
|
||||
|
||||
|
||||
+25
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
@@ -50,7 +50,7 @@ import org.springframework.util.ClassUtils;
|
||||
public class AspectJProxyFactory extends ProxyCreatorSupport {
|
||||
|
||||
/** Cache for singleton aspect instances */
|
||||
private static final Map<Class<?>, Object> aspectCache = new HashMap<Class<?>, Object>();
|
||||
private static final Map<Class<?>, Object> aspectCache = new ConcurrentHashMap<Class<?>, Object>();
|
||||
|
||||
private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory();
|
||||
|
||||
@@ -144,7 +144,7 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
|
||||
private MetadataAwareAspectInstanceFactory createAspectInstanceFactory(
|
||||
AspectMetadata am, Class<?> aspectClass, String aspectName) {
|
||||
|
||||
MetadataAwareAspectInstanceFactory instanceFactory = null;
|
||||
MetadataAwareAspectInstanceFactory instanceFactory;
|
||||
if (am.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
|
||||
// Create a shared aspect instance.
|
||||
Object instance = getSingletonAspectInstance(aspectClass);
|
||||
@@ -162,23 +162,29 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
|
||||
* is created if one cannot be found in the instance cache.
|
||||
*/
|
||||
private Object getSingletonAspectInstance(Class<?> aspectClass) {
|
||||
synchronized (aspectCache) {
|
||||
Object instance = aspectCache.get(aspectClass);
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
}
|
||||
try {
|
||||
instance = aspectClass.newInstance();
|
||||
aspectCache.put(aspectClass, instance);
|
||||
return instance;
|
||||
}
|
||||
catch (InstantiationException ex) {
|
||||
throw new AopConfigException("Unable to instantiate aspect class [" + aspectClass.getName() + "]", ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new AopConfigException("Cannot access aspect class [" + aspectClass.getName() + "]", ex);
|
||||
// Quick check without a lock...
|
||||
Object instance = aspectCache.get(aspectClass);
|
||||
if (instance == null) {
|
||||
synchronized (aspectCache) {
|
||||
// To be safe, check within full lock now...
|
||||
instance = aspectCache.get(aspectClass);
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
}
|
||||
try {
|
||||
instance = aspectClass.newInstance();
|
||||
aspectCache.put(aspectClass, instance);
|
||||
return instance;
|
||||
}
|
||||
catch (InstantiationException ex) {
|
||||
throw new AopConfigException("Unable to instantiate aspect class [" + aspectClass.getName() + "]", ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new AopConfigException("Cannot access aspect class [" + aspectClass.getName() + "]", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+10
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,9 +35,8 @@ import org.springframework.aop.support.ComposablePointcut;
|
||||
* Metadata for an AspectJ aspect class, with an additional Spring AOP pointcut
|
||||
* for the per clause.
|
||||
*
|
||||
* <p>Uses AspectJ 5 AJType reflection API, so is only supported on Java 5.
|
||||
* Enables us to work with different AspectJ instantiation models such as
|
||||
* "singleton", "pertarget" and "perthis".
|
||||
* <p>Uses AspectJ 5 AJType reflection API, enabling us to work with different
|
||||
* AspectJ instantiation models such as "singleton", "pertarget" and "perthis".
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -102,20 +101,22 @@ public class AspectMetadata implements Serializable {
|
||||
this.ajType = ajType;
|
||||
|
||||
switch (this.ajType.getPerClause().getKind()) {
|
||||
case SINGLETON :
|
||||
case SINGLETON:
|
||||
this.perClausePointcut = Pointcut.TRUE;
|
||||
return;
|
||||
case PERTARGET : case PERTHIS :
|
||||
case PERTARGET:
|
||||
case PERTHIS:
|
||||
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
|
||||
ajexp.setLocation("@Aspect annotation on " + aspectClass.getName());
|
||||
ajexp.setLocation(aspectClass.getName());
|
||||
ajexp.setExpression(findPerClause(aspectClass));
|
||||
ajexp.setPointcutDeclarationScope(aspectClass);
|
||||
this.perClausePointcut = ajexp;
|
||||
return;
|
||||
case PERTYPEWITHIN :
|
||||
case PERTYPEWITHIN:
|
||||
// Works with a type pattern
|
||||
this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));
|
||||
return;
|
||||
default :
|
||||
default:
|
||||
throw new AopConfigException(
|
||||
"PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass);
|
||||
}
|
||||
@@ -125,8 +126,6 @@ public class AspectMetadata implements Serializable {
|
||||
* Extract contents from String of form {@code pertarget(contents)}.
|
||||
*/
|
||||
private String findPerClause(Class<?> aspectClass) {
|
||||
// TODO when AspectJ provides this, we can remove this hack. Hence we don't
|
||||
// bother to make it elegant. Or efficient. Or robust :-)
|
||||
String str = aspectClass.getAnnotation(Aspect.class).value();
|
||||
str = str.substring(str.indexOf("(") + 1);
|
||||
str = str.substring(0, str.length() - 1);
|
||||
|
||||
+13
-2
@@ -97,8 +97,19 @@ public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInst
|
||||
|
||||
@Override
|
||||
public Object getAspectCreationMutex() {
|
||||
return (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex() : this);
|
||||
if (this.beanFactory != null) {
|
||||
if (this.beanFactory.isSingleton(name)) {
|
||||
// Rely on singleton semantics provided by the factory -> no local lock.
|
||||
return null;
|
||||
}
|
||||
else if (this.beanFactory instanceof ConfigurableBeanFactory) {
|
||||
// No singleton guarantees from the factory -> let's lock locally but
|
||||
// reuse the factory's singleton lock, just in case a lazy dependency
|
||||
// of our advice bean happens to trigger the singleton lock implicitly...
|
||||
return ((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex();
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+49
-48
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,10 +17,10 @@
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
@@ -43,12 +43,12 @@ public class BeanFactoryAspectJAdvisorsBuilder {
|
||||
|
||||
private final AspectJAdvisorFactory advisorFactory;
|
||||
|
||||
private List<String> aspectBeanNames;
|
||||
private volatile List<String> aspectBeanNames;
|
||||
|
||||
private final Map<String, List<Advisor>> advisorsCache = new HashMap<String, List<Advisor>>();
|
||||
private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<String, List<Advisor>>();
|
||||
|
||||
private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache =
|
||||
new HashMap<String, MetadataAwareAspectInstanceFactory>();
|
||||
new ConcurrentHashMap<String, MetadataAwareAspectInstanceFactory>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -56,7 +56,7 @@ public class BeanFactoryAspectJAdvisorsBuilder {
|
||||
* @param beanFactory the ListableBeanFactory to scan
|
||||
*/
|
||||
public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory) {
|
||||
this(beanFactory, new ReflectiveAspectJAdvisorFactory());
|
||||
this(beanFactory, new ReflectiveAspectJAdvisorFactory(beanFactory));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,56 +80,57 @@ public class BeanFactoryAspectJAdvisorsBuilder {
|
||||
* @see #isEligibleBean
|
||||
*/
|
||||
public List<Advisor> buildAspectJAdvisors() {
|
||||
List<String> aspectNames = null;
|
||||
List<String> aspectNames = this.aspectBeanNames;
|
||||
|
||||
synchronized (this) {
|
||||
aspectNames = this.aspectBeanNames;
|
||||
if (aspectNames == null) {
|
||||
List<Advisor> advisors = new LinkedList<Advisor>();
|
||||
aspectNames = new LinkedList<String>();
|
||||
String[] beanNames =
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
|
||||
for (String beanName : beanNames) {
|
||||
if (!isEligibleBean(beanName)) {
|
||||
continue;
|
||||
}
|
||||
// We must be careful not to instantiate beans eagerly as in this
|
||||
// case they would be cached by the Spring container but would not
|
||||
// have been weaved
|
||||
Class<?> beanType = this.beanFactory.getType(beanName);
|
||||
if (beanType == null) {
|
||||
continue;
|
||||
}
|
||||
if (this.advisorFactory.isAspect(beanType)) {
|
||||
aspectNames.add(beanName);
|
||||
AspectMetadata amd = new AspectMetadata(beanType, beanName);
|
||||
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
|
||||
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
this.advisorsCache.put(beanName, classAdvisors);
|
||||
if (aspectNames == null) {
|
||||
synchronized (this) {
|
||||
aspectNames = this.aspectBeanNames;
|
||||
if (aspectNames == null) {
|
||||
List<Advisor> advisors = new LinkedList<Advisor>();
|
||||
aspectNames = new LinkedList<String>();
|
||||
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
|
||||
this.beanFactory, Object.class, true, false);
|
||||
for (String beanName : beanNames) {
|
||||
if (!isEligibleBean(beanName)) {
|
||||
continue;
|
||||
}
|
||||
// We must be careful not to instantiate beans eagerly as in this case they
|
||||
// would be cached by the Spring container but would not have been weaved.
|
||||
Class<?> beanType = this.beanFactory.getType(beanName);
|
||||
if (beanType == null) {
|
||||
continue;
|
||||
}
|
||||
if (this.advisorFactory.isAspect(beanType)) {
|
||||
aspectNames.add(beanName);
|
||||
AspectMetadata amd = new AspectMetadata(beanType, beanName);
|
||||
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
|
||||
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
this.advisorsCache.put(beanName, classAdvisors);
|
||||
}
|
||||
else {
|
||||
this.aspectFactoryCache.put(beanName, factory);
|
||||
}
|
||||
advisors.addAll(classAdvisors);
|
||||
}
|
||||
else {
|
||||
// Per target or per this.
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
throw new IllegalArgumentException("Bean with name '" + beanName +
|
||||
"' is a singleton, but aspect instantiation model is not singleton");
|
||||
}
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
|
||||
this.aspectFactoryCache.put(beanName, factory);
|
||||
advisors.addAll(this.advisorFactory.getAdvisors(factory));
|
||||
}
|
||||
advisors.addAll(classAdvisors);
|
||||
}
|
||||
else {
|
||||
// Per target or per this.
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
throw new IllegalArgumentException("Bean with name '" + beanName +
|
||||
"' is a singleton, but aspect instantiation model is not singleton");
|
||||
}
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
|
||||
this.aspectFactoryCache.put(beanName, factory);
|
||||
advisors.addAll(this.advisorFactory.getAdvisors(factory));
|
||||
}
|
||||
}
|
||||
this.aspectBeanNames = aspectNames;
|
||||
return advisors;
|
||||
}
|
||||
this.aspectBeanNames = aspectNames;
|
||||
return advisors;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-3
@@ -48,9 +48,15 @@ public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwar
|
||||
@Override
|
||||
public Object getAspectInstance() {
|
||||
if (this.materialized == null) {
|
||||
synchronized (this.maaif.getAspectCreationMutex()) {
|
||||
if (this.materialized == null) {
|
||||
this.materialized = this.maaif.getAspectInstance();
|
||||
Object mutex = this.maaif.getAspectCreationMutex();
|
||||
if (mutex == null) {
|
||||
this.materialized = this.maaif.getAspectInstance();
|
||||
}
|
||||
else {
|
||||
synchronized (mutex) {
|
||||
if (this.materialized == null) {
|
||||
this.materialized = this.maaif.getAspectInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactor
|
||||
|
||||
/**
|
||||
* Return the best possible creation mutex for this factory.
|
||||
* @return the mutex object (never {@code null})
|
||||
* @return the mutex object (may be {@code null} for no mutex to use)
|
||||
* @since 4.3
|
||||
*/
|
||||
Object getAspectCreationMutex();
|
||||
|
||||
+28
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,6 +46,7 @@ import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
|
||||
import org.springframework.aop.aspectj.DeclareParentsAdvisor;
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.ConvertingComparator;
|
||||
@@ -95,6 +96,30 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
}
|
||||
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code ReflectiveAspectJAdvisorFactory}.
|
||||
*/
|
||||
public ReflectiveAspectJAdvisorFactory() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code ReflectiveAspectJAdvisorFactory}, propagating the given
|
||||
* {@link BeanFactory} to the created {@link AspectJExpressionPointcut} instances,
|
||||
* for bean pointcut handling as well as consistent {@link ClassLoader} resolution.
|
||||
* @param beanFactory the BeanFactory to propagate (may be {@code null}}
|
||||
* @since 4.3.6
|
||||
* @see AspectJExpressionPointcut#setBeanFactory
|
||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#getBeanClassLoader()
|
||||
*/
|
||||
public ReflectiveAspectJAdvisorFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
|
||||
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
|
||||
@@ -161,9 +186,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
}
|
||||
|
||||
if (DeclareParents.class == declareParents.defaultImpl()) {
|
||||
// This is what comes back if it wasn't set. This seems bizarre...
|
||||
// TODO this restriction possibly should be relaxed
|
||||
throw new IllegalStateException("defaultImpl must be set on DeclareParents");
|
||||
throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
|
||||
}
|
||||
|
||||
return new DeclareParentsAdvisor(
|
||||
@@ -197,6 +220,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
AspectJExpressionPointcut ajexp =
|
||||
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
|
||||
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
|
||||
ajexp.setBeanFactory(this.beanFactory);
|
||||
return ajexp;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -71,7 +71,7 @@ public abstract class AbstractInterceptorDrivenBeanDefinitionDecorator implement
|
||||
BeanDefinition interceptorDefinition = createInterceptorDefinition(node);
|
||||
|
||||
// generate name and register the interceptor
|
||||
String interceptorName = existingBeanName + "." + getInterceptorNameSuffix(interceptorDefinition);
|
||||
String interceptorName = existingBeanName + '.' + getInterceptorNameSuffix(interceptorDefinition);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(
|
||||
new BeanDefinitionHolder(interceptorDefinition, interceptorName), registry);
|
||||
|
||||
|
||||
+3
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,8 +21,8 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link AspectInstanceFactory} that locates the aspect from the
|
||||
@@ -50,9 +50,7 @@ public class SimpleBeanFactoryAwareAspectInstanceFactory implements AspectInstan
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
if (!StringUtils.hasText(this.aspectBeanName)) {
|
||||
throw new IllegalArgumentException("'aspectBeanName' is required");
|
||||
}
|
||||
Assert.notNull(this.aspectBeanName, "'aspectBeanName' is required");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,6 +43,25 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
public abstract class AopProxyUtils {
|
||||
|
||||
/**
|
||||
* Obtain the singleton target object behind the given proxy, if any.
|
||||
* @param candidate the (potential) proxy to check
|
||||
* @return the singleton target object managed in a {@link SingletonTargetSource},
|
||||
* or {@code null} in any other case (not a proxy, not an existing singleton target)
|
||||
* @since 4.3.8
|
||||
* @see Advised#getTargetSource()
|
||||
* @see SingletonTargetSource#getTarget()
|
||||
*/
|
||||
public static Object getSingletonTarget(Object candidate) {
|
||||
if (candidate instanceof Advised) {
|
||||
TargetSource targetSource = ((Advised) candidate).getTargetSource();
|
||||
if (targetSource instanceof SingletonTargetSource) {
|
||||
return ((SingletonTargetSource) targetSource).getTarget();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the ultimate target class of the given bean instance, traversing
|
||||
* not only a top-level proxy but any number of nested proxies as well —
|
||||
@@ -59,14 +78,7 @@ public abstract class AopProxyUtils {
|
||||
Class<?> result = null;
|
||||
while (current instanceof TargetClassAware) {
|
||||
result = ((TargetClassAware) current).getTargetClass();
|
||||
Object nested = null;
|
||||
if (current instanceof Advised) {
|
||||
TargetSource targetSource = ((Advised) current).getTargetSource();
|
||||
if (targetSource instanceof SingletonTargetSource) {
|
||||
nested = ((SingletonTargetSource) targetSource).getTarget();
|
||||
}
|
||||
}
|
||||
current = nested;
|
||||
current = getSingletonTarget(current);
|
||||
}
|
||||
if (result == null) {
|
||||
result = (AopUtils.isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,7 @@ import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
@@ -56,9 +57,6 @@ import org.springframework.util.ObjectUtils;
|
||||
/**
|
||||
* CGLIB-based {@link AopProxy} implementation for the Spring AOP framework.
|
||||
*
|
||||
* <p>Formerly named {@code Cglib2AopProxy}, as of Spring 3.2, this class depends on
|
||||
* Spring's own internally repackaged version of CGLIB 3.</i>.
|
||||
*
|
||||
* <p>Objects of this type should be obtained through proxy factories,
|
||||
* configured by an {@link AdvisedSupport} object. This class is internal
|
||||
* to Spring's AOP framework and need not be used directly by client code.
|
||||
@@ -214,7 +212,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
"Common causes of this problem include using a final class or a non-visible class",
|
||||
ex);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
catch (Throwable ex) {
|
||||
// TargetSource.getTarget() failed
|
||||
throw new AopConfigException("Unexpected AOP exception", ex);
|
||||
}
|
||||
@@ -241,10 +239,11 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
* validates it if not.
|
||||
*/
|
||||
private void validateClassIfNecessary(Class<?> proxySuperClass, ClassLoader proxyClassLoader) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
synchronized (validatedClasses) {
|
||||
if (!validatedClasses.containsKey(proxySuperClass)) {
|
||||
doValidateClass(proxySuperClass, proxyClassLoader);
|
||||
doValidateClass(proxySuperClass, proxyClassLoader,
|
||||
ClassUtils.getAllInterfacesForClassAsSet(proxySuperClass));
|
||||
validatedClasses.put(proxySuperClass, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
@@ -255,30 +254,35 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
* Checks for final methods on the given {@code Class}, as well as package-visible
|
||||
* methods across ClassLoaders, and writes warnings to the log for each one found.
|
||||
*/
|
||||
private void doValidateClass(Class<?> proxySuperClass, ClassLoader proxyClassLoader) {
|
||||
if (Object.class != proxySuperClass) {
|
||||
private void doValidateClass(Class<?> proxySuperClass, ClassLoader proxyClassLoader, Set<Class<?>> ifcs) {
|
||||
if (proxySuperClass != Object.class) {
|
||||
Method[] methods = proxySuperClass.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
int mod = method.getModifiers();
|
||||
if (!Modifier.isStatic(mod)) {
|
||||
if (Modifier.isFinal(mod)) {
|
||||
logger.info("Unable to proxy method [" + method + "] because it is final: " +
|
||||
"All calls to this method via a proxy will NOT be routed to the target instance.");
|
||||
if (implementsInterface(method, ifcs)) {
|
||||
logger.warn("Unable to proxy interface-implementing method [" + method + "] because " +
|
||||
"it is marked as final: Consider using interface-based JDK proxies instead!");
|
||||
}
|
||||
logger.info("Final method [" + method + "] cannot get proxied via CGLIB: " +
|
||||
"Calls to this method will NOT be routed to the target instance and " +
|
||||
"might lead to NPEs against uninitialized fields in the proxy instance.");
|
||||
}
|
||||
else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) && !Modifier.isPrivate(mod) &&
|
||||
proxyClassLoader != null && proxySuperClass.getClassLoader() != proxyClassLoader) {
|
||||
logger.info("Unable to proxy method [" + method + "] because it is package-visible " +
|
||||
"across different ClassLoaders: All calls to this method via a proxy will " +
|
||||
"NOT be routed to the target instance.");
|
||||
logger.info("Method [" + method + "] is package-visible across different ClassLoaders " +
|
||||
"and cannot get proxied via CGLIB: Declare this method as public or protected " +
|
||||
"if you need to support invocations through the proxy.");
|
||||
}
|
||||
}
|
||||
}
|
||||
doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader);
|
||||
doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader, ifcs);
|
||||
}
|
||||
}
|
||||
|
||||
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
|
||||
// Parameters used for optimisation choices...
|
||||
// Parameters used for optimization choices...
|
||||
boolean exposeProxy = this.advised.isExposeProxy();
|
||||
boolean isFrozen = this.advised.isFrozen();
|
||||
boolean isStatic = this.advised.getTargetSource().isStatic();
|
||||
@@ -317,14 +321,14 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
Callback[] callbacks;
|
||||
|
||||
// If the target is a static one and the advice chain is frozen,
|
||||
// then we can make some optimisations by sending the AOP calls
|
||||
// then we can make some optimizations by sending the AOP calls
|
||||
// direct to the target using the fixed chain for that method.
|
||||
if (isStatic && isFrozen) {
|
||||
Method[] methods = rootClass.getMethods();
|
||||
Callback[] fixedCallbacks = new Callback[methods.length];
|
||||
this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
|
||||
|
||||
// TODO: small memory optimisation here (can skip creation for methods with no advice)
|
||||
// TODO: small memory optimization here (can skip creation for methods with no advice)
|
||||
for (int x = 0; x < methods.length; x++) {
|
||||
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
|
||||
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
|
||||
@@ -345,25 +349,6 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a return value. Wraps a return of {@code this} if necessary to be the
|
||||
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
|
||||
*/
|
||||
private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) {
|
||||
// Massage return value if necessary
|
||||
if (retVal != null && retVal == target && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this". Note that we can't help
|
||||
// if the target sets a reference to itself in another returned object.
|
||||
retVal = proxy;
|
||||
}
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
|
||||
throw new AopInvocationException(
|
||||
"Null return value from advice does not match primitive return type for: " + method);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
@@ -377,6 +362,39 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the given method is declared on any of the given interfaces.
|
||||
*/
|
||||
private static boolean implementsInterface(Method method, Set<Class<?>> ifcs) {
|
||||
for (Class<?> ifc : ifcs) {
|
||||
if (ClassUtils.hasMethod(ifc, method.getName(), method.getParameterTypes())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a return value. Wraps a return of {@code this} if necessary to be the
|
||||
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
|
||||
*/
|
||||
private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) {
|
||||
// Massage return value if necessary
|
||||
if (retVal != null && retVal == target &&
|
||||
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this". Note that we can't help
|
||||
// if the target sets a reference to itself in another returned object.
|
||||
retVal = proxy;
|
||||
}
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
|
||||
throw new AopInvocationException(
|
||||
"Null return value from advice does not match primitive return type for: " + method);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializable replacement for CGLIB's NoOp interface.
|
||||
* Public to allow use elsewhere in the framework.
|
||||
@@ -822,51 +840,42 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
// Else use the AOP_PROXY.
|
||||
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method has advice and optimisations are enabled: " + method);
|
||||
logger.debug("Method has advice and optimizations are enabled: " + method);
|
||||
}
|
||||
// We know that we are optimising so we can use the FixedStaticChainInterceptors.
|
||||
// We know that we are optimizing so we can use the FixedStaticChainInterceptors.
|
||||
int index = this.fixedInterceptorMap.get(key);
|
||||
return (index + this.fixedInterceptorOffset);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Unable to apply any optimisations to advised method: " + method);
|
||||
logger.debug("Unable to apply any optimizations to advised method: " + method);
|
||||
}
|
||||
return AOP_PROXY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// See if the return type of the method is outside the class hierarchy
|
||||
// of the target type. If so we know it never needs to have return type
|
||||
// massage and can use a dispatcher.
|
||||
// If the proxy is being exposed, then must use the interceptor the
|
||||
// correct one is already configured. If the target is not static, then
|
||||
// cannot use a dispatcher because the target cannot be released.
|
||||
// See if the return type of the method is outside the class hierarchy of the target type.
|
||||
// If so we know it never needs to have return type massage and can use a dispatcher.
|
||||
// If the proxy is being exposed, then must use the interceptor the correct one is already
|
||||
// configured. If the target is not static, then we cannot use a dispatcher because the
|
||||
// target needs to be explicitly released after the invocation.
|
||||
if (exposeProxy || !isStatic) {
|
||||
return INVOKE_TARGET;
|
||||
}
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (targetClass == returnType) {
|
||||
if (returnType.isAssignableFrom(targetClass)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method " + method +
|
||||
"has return type same as target type (may return this) - using INVOKE_TARGET");
|
||||
logger.debug("Method return type is assignable from target type and " +
|
||||
"may therefore return 'this' - using INVOKE_TARGET: " + method);
|
||||
}
|
||||
return INVOKE_TARGET;
|
||||
}
|
||||
else if (returnType.isPrimitive() || !returnType.isAssignableFrom(targetClass)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method " + method +
|
||||
" has return type that ensures this cannot be returned- using DISPATCH_TARGET");
|
||||
}
|
||||
return DISPATCH_TARGET;
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method " + method +
|
||||
"has return type that is assignable from the target type (may return this) - " +
|
||||
"using INVOKE_TARGET");
|
||||
logger.debug("Method return type ensures 'this' cannot be returned - " +
|
||||
"using DISPATCH_TARGET: " + method);
|
||||
}
|
||||
return INVOKE_TARGET;
|
||||
return DISPATCH_TARGET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,8 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
|
||||
|
||||
// Massage return value if necessary.
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
|
||||
if (retVal != null && retVal == target &&
|
||||
returnType != Object.class && returnType.isInstance(proxy) &&
|
||||
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this" and the return type of the method
|
||||
// is type-compatible. Note that we can't help if the target sets
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.aop.framework;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
import org.springframework.beans.factory.Aware;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
@@ -127,6 +129,7 @@ public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanC
|
||||
*/
|
||||
protected boolean isConfigurationCallbackInterface(Class<?> ifc) {
|
||||
return (InitializingBean.class == ifc || DisposableBean.class == ifc ||
|
||||
Closeable.class == ifc || "java.lang.AutoCloseable".equals(ifc.getName()) ||
|
||||
ObjectUtils.containsElement(ifc.getInterfaces(), Aware.class));
|
||||
}
|
||||
|
||||
@@ -139,7 +142,9 @@ public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanC
|
||||
* @return whether the given interface is an internal language interface
|
||||
*/
|
||||
protected boolean isInternalLanguageInterface(Class<?> ifc) {
|
||||
return ifc.getName().equals("groovy.lang.GroovyObject");
|
||||
return (ifc.getName().equals("groovy.lang.GroovyObject") ||
|
||||
ifc.getName().endsWith(".cglib.proxy.Factory") ||
|
||||
ifc.getName().endsWith(".bytebuddy.MockAccess"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,7 +26,7 @@ import org.springframework.aop.AfterReturningAdvice;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Interceptor to wrap am {@link org.springframework.aop.AfterReturningAdvice}.
|
||||
* Interceptor to wrap an {@link org.springframework.aop.AfterReturningAdvice}.
|
||||
* Used internally by the AOP framework; application developers should not need
|
||||
* to use this class directly.
|
||||
*
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,7 +54,8 @@ public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyC
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
super.setBeanFactory(beanFactory);
|
||||
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
|
||||
throw new IllegalStateException("Cannot use AdvisorAutoProxyCreator without a ConfigurableListableBeanFactory");
|
||||
throw new IllegalArgumentException(
|
||||
"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
|
||||
}
|
||||
initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
|
||||
}
|
||||
|
||||
+24
-25
@@ -55,26 +55,25 @@ import org.springframework.util.StringUtils;
|
||||
* before invoking the bean itself.
|
||||
*
|
||||
* <p>This class distinguishes between "common" interceptors: shared for all proxies it
|
||||
* creates, and "specific" interceptors: unique per bean instance. There need not
|
||||
* be any common interceptors. If there are, they are set using the interceptorNames
|
||||
* property. As with ProxyFactoryBean, interceptors names in the current factory
|
||||
* are used rather than bean references to allow correct handling of prototype
|
||||
* advisors and interceptors: for example, to support stateful mixins.
|
||||
* Any advice type is supported for "interceptorNames" entries.
|
||||
* creates, and "specific" interceptors: unique per bean instance. There need not be any
|
||||
* common interceptors. If there are, they are set using the interceptorNames property.
|
||||
* As with {@link org.springframework.aop.framework.ProxyFactoryBean}, interceptors names
|
||||
* in the current factory are used rather than bean references to allow correct handling
|
||||
* of prototype advisors and interceptors: for example, to support stateful mixins.
|
||||
* Any advice type is supported for {@link #setInterceptorNames "interceptorNames"} entries.
|
||||
*
|
||||
* <p>Such auto-proxying is particularly useful if there's a large number of beans that
|
||||
* need to be wrapped with similar proxies, i.e. delegating to the same interceptors.
|
||||
* Instead of x repetitive proxy definitions for x target beans, you can register
|
||||
* one single such post processor with the bean factory to achieve the same effect.
|
||||
*
|
||||
* <p>Subclasses can apply any strategy to decide if a bean is to be proxied,
|
||||
* e.g. by type, by name, by definition details, etc. They can also return
|
||||
* additional interceptors that should just be applied to the specific bean
|
||||
* instance. The default concrete implementation is BeanNameAutoProxyCreator,
|
||||
* identifying the beans to be proxied via a list of bean names.
|
||||
* <p>Subclasses can apply any strategy to decide if a bean is to be proxied, e.g. by type,
|
||||
* by name, by definition details, etc. They can also return additional interceptors that
|
||||
* should just be applied to the specific bean instance. A simple concrete implementation is
|
||||
* {@link BeanNameAutoProxyCreator}, identifying the beans to be proxied via given names.
|
||||
*
|
||||
* <p>Any number of {@link TargetSourceCreator} implementations can be used to create
|
||||
* a custom target source - for example, to pool prototype objects. Auto-proxying will
|
||||
* a custom target source: for example, to pool prototype objects. Auto-proxying will
|
||||
* occur even if there is no advice, as long as a TargetSourceCreator specifies a custom
|
||||
* {@link org.springframework.aop.TargetSource}. If there are no TargetSourceCreators set,
|
||||
* or if none matches, a {@link org.springframework.aop.target.SingletonTargetSource}
|
||||
@@ -156,8 +155,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the AdvisorAdapterRegistry to use.
|
||||
* Default is the global AdvisorAdapterRegistry.
|
||||
* Specify the {@link AdvisorAdapterRegistry} to use.
|
||||
* <p>Default is the global {@link AdvisorAdapterRegistry}.
|
||||
* @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry
|
||||
*/
|
||||
public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
|
||||
@@ -165,18 +164,18 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom TargetSourceCreators to be applied in this order.
|
||||
* If the list is empty, or they all return null, a SingletonTargetSource
|
||||
* Set custom {@code TargetSourceCreators} to be applied in this order.
|
||||
* If the list is empty, or they all return null, a {@link SingletonTargetSource}
|
||||
* will be created for each bean.
|
||||
* <p>Note that TargetSourceCreators will kick in even for target beans
|
||||
* where no advices or advisors have been found. If a TargetSourceCreator
|
||||
* returns a TargetSource for a specific bean, that bean will be proxied
|
||||
* where no advices or advisors have been found. If a {@code TargetSourceCreator}
|
||||
* returns a {@link TargetSource} for a specific bean, that bean will be proxied
|
||||
* in any case.
|
||||
* <p>TargetSourceCreators can only be invoked if this post processor is used
|
||||
* in a BeanFactory, and its BeanFactoryAware callback is used.
|
||||
* @param targetSourceCreators list of TargetSourceCreator.
|
||||
* Ordering is significant: The TargetSource returned from the first matching
|
||||
* TargetSourceCreator (that is, the first that returns non-null) will be used.
|
||||
* <p>{@code TargetSourceCreators} can only be invoked if this post processor is used
|
||||
* in a {@link BeanFactory} and its {@link BeanFactoryAware} callback is triggered.
|
||||
* @param targetSourceCreators the list of {@code TargetSourceCreators}.
|
||||
* Ordering is significant: The {@code TargetSource} returned from the first matching
|
||||
* {@code TargetSourceCreator} (that is, the first that returns non-null) will be used.
|
||||
*/
|
||||
public void setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators) {
|
||||
this.customTargetSourceCreators = targetSourceCreators;
|
||||
@@ -207,8 +206,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the owning BeanFactory.
|
||||
* May be {@code null}, as this object doesn't need to belong to a bean factory.
|
||||
* Return the owning {@link BeanFactory}.
|
||||
* May be {@code null}, as this post-processor doesn't need to belong to a bean factory.
|
||||
*/
|
||||
protected BeanFactory getBeanFactory() {
|
||||
return this.beanFactory;
|
||||
|
||||
+15
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,15 +19,16 @@ package org.springframework.aop.framework.autoproxy;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
|
||||
/**
|
||||
* BeanPostProcessor implementation that creates AOP proxies based on all candidate
|
||||
* Advisors in the current BeanFactory. This class is completely generic; it contains
|
||||
* no special code to handle any particular aspects, such as pooling aspects.
|
||||
* {@code BeanPostProcessor} implementation that creates AOP proxies based on all
|
||||
* candidate {@code Advisor}s in the current {@code BeanFactory}. This class is
|
||||
* completely generic; it contains no special code to handle any particular aspects,
|
||||
* such as pooling aspects.
|
||||
*
|
||||
* <p>It's possible to filter out advisors - for example, to use multiple post processors
|
||||
* of this type in the same factory - by setting the {@code usePrefix} property
|
||||
* to true, in which case only advisors beginning with the DefaultAdvisorAutoProxyCreator's
|
||||
* bean name followed by a dot (like "aapc.") will be used. This default prefix can be
|
||||
* changed from the bean name by setting the {@code advisorBeanNamePrefix} property.
|
||||
* of this type in the same factory - by setting the {@code usePrefix} property to true,
|
||||
* in which case only advisors beginning with the DefaultAdvisorAutoProxyCreator's bean
|
||||
* name followed by a dot (like "aapc.") will be used. This default prefix can be changed
|
||||
* from the bean name by setting the {@code advisorBeanNamePrefix} property.
|
||||
* The separator (.) will also be used in this case.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
@@ -40,22 +41,22 @@ public class DefaultAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCrea
|
||||
public final static String SEPARATOR = ".";
|
||||
|
||||
|
||||
private boolean usePrefix;
|
||||
private boolean usePrefix = false;
|
||||
|
||||
private String advisorBeanNamePrefix;
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to exclude advisors with a certain prefix
|
||||
* in the bean name.
|
||||
* Set whether to only include advisors with a certain prefix in the bean name.
|
||||
* <p>Default is {@code false}, including all beans of type {@code Advisor}.
|
||||
* @see #setAdvisorBeanNamePrefix
|
||||
*/
|
||||
public void setUsePrefix(boolean usePrefix) {
|
||||
this.usePrefix = usePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to exclude advisors with a certain prefix
|
||||
* in the bean name.
|
||||
* Return whether to only include advisors with a certain prefix in the bean name.
|
||||
*/
|
||||
public boolean isUsePrefix() {
|
||||
return this.usePrefix;
|
||||
@@ -89,7 +90,7 @@ public class DefaultAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCrea
|
||||
|
||||
|
||||
/**
|
||||
* Consider Advisor beans with the specified prefix as eligible, if activated.
|
||||
* Consider {@code Advisor} beans with the specified prefix as eligible, if activated.
|
||||
* @see #setUsePrefix
|
||||
* @see #setAdvisorBeanNamePrefix
|
||||
*/
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,12 +22,12 @@ import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
/**
|
||||
* Base class for monitoring interceptors, such as performance monitors.
|
||||
* Provides {@code prefix} and {@code suffix} properties
|
||||
* that help to classify/group performance monitoring results.
|
||||
* Provides configurable "prefix and "suffix" properties that help to
|
||||
* classify/group performance monitoring results.
|
||||
*
|
||||
* <p>Subclasses should call the {@code createInvocationTraceName(MethodInvocation)}
|
||||
* method to create a name for the given trace that includes information about the
|
||||
* method invocation under trace along with the prefix and suffix added as appropriate.
|
||||
* <p>In their {@link #invokeUnderTrace} implementation, subclasses should call the
|
||||
* {@link #createInvocationTraceName} method to create a name for the given trace,
|
||||
* including information about the method invocation along with a prefix/suffix.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
|
||||
+56
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -58,6 +58,12 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
|
||||
*/
|
||||
private boolean hideProxyClassNames = false;
|
||||
|
||||
/**
|
||||
* Indicates whether to pass an exception to the logger.
|
||||
* @see #writeToLog(Log, String, Throwable)
|
||||
*/
|
||||
private boolean logExceptionStackTrace = true;
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to use a dynamic logger or a static logger.
|
||||
@@ -98,6 +104,17 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
|
||||
this.hideProxyClassNames = hideProxyClassNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to pass an exception to the logger, suggesting inclusion
|
||||
* of its stack trace into the log. Default is "true"; set this to "false"
|
||||
* in order to reduce the log output to just the trace message (which may
|
||||
* include the exception class name and exception message, if applicable).
|
||||
* @since 4.3.10
|
||||
*/
|
||||
public void setLogExceptionStackTrace(boolean logExceptionStackTrace) {
|
||||
this.logExceptionStackTrace = logExceptionStackTrace;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether or not logging is enabled for the particular {@code MethodInvocation}.
|
||||
@@ -171,6 +188,40 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
|
||||
return logger.isTraceEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the supplied trace message to the supplied {@code Log} instance.
|
||||
* <p>To be called by {@link #invokeUnderTrace} for enter/exit messages.
|
||||
* <p>Delegates to {@link #writeToLog(Log, String, Throwable)} as the
|
||||
* ultimate delegate that controls the underlying logger invocation.
|
||||
* @since 4.3.10
|
||||
* @see #writeToLog(Log, String, Throwable)
|
||||
*/
|
||||
protected void writeToLog(Log logger, String message) {
|
||||
writeToLog(logger, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the supplied trace message and {@link Throwable} to the
|
||||
* supplied {@code Log} instance.
|
||||
* <p>To be called by {@link #invokeUnderTrace} for enter/exit outcomes,
|
||||
* potentially including an exception. Note that an exception's stack trace
|
||||
* won't get logged when {@link #setLogExceptionStackTrace} is "false".
|
||||
* <p>By default messages are written at {@code TRACE} level. Subclasses
|
||||
* can override this method to control which level the message is written
|
||||
* at, typically also overriding {@link #isLogEnabled} accordingly.
|
||||
* @since 4.3.10
|
||||
* @see #setLogExceptionStackTrace
|
||||
* @see #isLogEnabled
|
||||
*/
|
||||
protected void writeToLog(Log logger, String message, Throwable ex) {
|
||||
if (ex != null && this.logExceptionStackTrace) {
|
||||
logger.trace(message, ex);
|
||||
}
|
||||
else {
|
||||
logger.trace(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses must override this method to perform any tracing around the
|
||||
@@ -180,13 +231,15 @@ public abstract class AbstractTraceInterceptor implements MethodInterceptor, Ser
|
||||
* <p>By default, the passed-in {@code Log} instance will have log level
|
||||
* "trace" enabled. Subclasses do not have to check for this again, unless
|
||||
* they overwrite the {@code isInterceptorEnabled} method to modify
|
||||
* the default behavior.
|
||||
* the default behavior, and may delegate to {@code writeToLog} for actual
|
||||
* messages to be written.
|
||||
* @param logger the {@code Log} to write trace messages to
|
||||
* @return the result of the call to {@code MethodInvocation.proceed()}
|
||||
* @throws Throwable if the call to {@code MethodInvocation.proceed()}
|
||||
* encountered any errors
|
||||
* @see #isInterceptorEnabled
|
||||
* @see #isLogEnabled
|
||||
* @see #writeToLog(Log, String)
|
||||
* @see #writeToLog(Log, String, Throwable)
|
||||
*/
|
||||
protected abstract Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable;
|
||||
|
||||
|
||||
+9
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -228,6 +228,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
return beanFactory.getBean(TaskExecutor.class);
|
||||
}
|
||||
catch (NoUniqueBeanDefinitionException ex) {
|
||||
logger.debug("Could not find unique TaskExecutor bean", ex);
|
||||
try {
|
||||
return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
|
||||
}
|
||||
@@ -241,8 +242,14 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
logger.debug("Could not find default TaskExecutor bean", ex);
|
||||
try {
|
||||
return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex2) {
|
||||
logger.info("No task executor bean found for async processing: " +
|
||||
"no bean of type TaskExecutor and no bean named 'taskExecutor' either");
|
||||
}
|
||||
// Giving up -> either using local default executor or none at all...
|
||||
logger.info("No TaskExecutor bean found for async processing");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
+20
-45
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -128,20 +128,20 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
/**
|
||||
* The default message used for writing method entry messages.
|
||||
*/
|
||||
private static final String DEFAULT_ENTER_MESSAGE =
|
||||
"Entering method '" + PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
|
||||
private static final String DEFAULT_ENTER_MESSAGE = "Entering method '" +
|
||||
PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
|
||||
|
||||
/**
|
||||
* The default message used for writing method exit messages.
|
||||
*/
|
||||
private static final String DEFAULT_EXIT_MESSAGE =
|
||||
"Exiting method '" + PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
|
||||
private static final String DEFAULT_EXIT_MESSAGE = "Exiting method '" +
|
||||
PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
|
||||
|
||||
/**
|
||||
* The default message used for writing exception messages.
|
||||
*/
|
||||
private static final String DEFAULT_EXCEPTION_MESSAGE =
|
||||
"Exception thrown in method '" + PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
|
||||
private static final String DEFAULT_EXCEPTION_MESSAGE = "Exception thrown in method '" +
|
||||
PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]";
|
||||
|
||||
/**
|
||||
* The {@code Pattern} used to match placeholders.
|
||||
@@ -182,14 +182,14 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
* </ul>
|
||||
*/
|
||||
public void setEnterMessage(String enterMessage) throws IllegalArgumentException {
|
||||
Assert.hasText(enterMessage, "'enterMessage' must not be empty");
|
||||
Assert.hasText(enterMessage, "enterMessage must not be empty");
|
||||
checkForInvalidPlaceholders(enterMessage);
|
||||
Assert.doesNotContain(enterMessage, PLACEHOLDER_RETURN_VALUE,
|
||||
"enterMessage cannot contain placeholder [" + PLACEHOLDER_RETURN_VALUE + "]");
|
||||
"enterMessage cannot contain placeholder " + PLACEHOLDER_RETURN_VALUE);
|
||||
Assert.doesNotContain(enterMessage, PLACEHOLDER_EXCEPTION,
|
||||
"enterMessage cannot contain placeholder [" + PLACEHOLDER_EXCEPTION + "]");
|
||||
"enterMessage cannot contain placeholder " + PLACEHOLDER_EXCEPTION);
|
||||
Assert.doesNotContain(enterMessage, PLACEHOLDER_INVOCATION_TIME,
|
||||
"enterMessage cannot contain placeholder [" + PLACEHOLDER_INVOCATION_TIME + "]");
|
||||
"enterMessage cannot contain placeholder " + PLACEHOLDER_INVOCATION_TIME);
|
||||
this.enterMessage = enterMessage;
|
||||
}
|
||||
|
||||
@@ -206,10 +206,10 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
* </ul>
|
||||
*/
|
||||
public void setExitMessage(String exitMessage) {
|
||||
Assert.hasText(exitMessage, "'exitMessage' must not be empty");
|
||||
Assert.hasText(exitMessage, "exitMessage must not be empty");
|
||||
checkForInvalidPlaceholders(exitMessage);
|
||||
Assert.doesNotContain(exitMessage, PLACEHOLDER_EXCEPTION,
|
||||
"exitMessage cannot contain placeholder [" + PLACEHOLDER_EXCEPTION + "]");
|
||||
"exitMessage cannot contain placeholder" + PLACEHOLDER_EXCEPTION);
|
||||
this.exitMessage = exitMessage;
|
||||
}
|
||||
|
||||
@@ -225,12 +225,10 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
* </ul>
|
||||
*/
|
||||
public void setExceptionMessage(String exceptionMessage) {
|
||||
Assert.hasText(exceptionMessage, "'exceptionMessage' must not be empty");
|
||||
Assert.hasText(exceptionMessage, "exceptionMessage must not be empty");
|
||||
checkForInvalidPlaceholders(exceptionMessage);
|
||||
Assert.doesNotContain(exceptionMessage, PLACEHOLDER_RETURN_VALUE,
|
||||
"exceptionMessage cannot contain placeholder [" + PLACEHOLDER_RETURN_VALUE + "]");
|
||||
Assert.doesNotContain(exceptionMessage, PLACEHOLDER_INVOCATION_TIME,
|
||||
"exceptionMessage cannot contain placeholder [" + PLACEHOLDER_INVOCATION_TIME + "]");
|
||||
"exceptionMessage cannot contain placeholder " + PLACEHOLDER_RETURN_VALUE);
|
||||
this.exceptionMessage = exceptionMessage;
|
||||
}
|
||||
|
||||
@@ -246,7 +244,7 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
*/
|
||||
@Override
|
||||
protected Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable {
|
||||
String name = invocation.getMethod().getDeclaringClass().getName() + "." + invocation.getMethod().getName();
|
||||
String name = ClassUtils.getQualifiedMethodName(invocation.getMethod());
|
||||
StopWatch stopWatch = new StopWatch(name);
|
||||
Object returnValue = null;
|
||||
boolean exitThroughException = false;
|
||||
@@ -262,8 +260,8 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
stopWatch.stop();
|
||||
}
|
||||
exitThroughException = true;
|
||||
writeToLog(logger,
|
||||
replacePlaceholders(this.exceptionMessage, invocation, null, ex, stopWatch.getTotalTimeMillis()), ex);
|
||||
writeToLog(logger, replacePlaceholders(
|
||||
this.exceptionMessage, invocation, null, ex, stopWatch.getTotalTimeMillis()), ex);
|
||||
throw ex;
|
||||
}
|
||||
finally {
|
||||
@@ -271,35 +269,12 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
if (stopWatch.isRunning()) {
|
||||
stopWatch.stop();
|
||||
}
|
||||
writeToLog(logger,
|
||||
replacePlaceholders(this.exitMessage, invocation, returnValue, null, stopWatch.getTotalTimeMillis()));
|
||||
writeToLog(logger, replacePlaceholders(
|
||||
this.exitMessage, invocation, returnValue, null, stopWatch.getTotalTimeMillis()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the supplied message to the supplied {@code Log} instance.
|
||||
* @see #writeToLog(org.apache.commons.logging.Log, String, Throwable)
|
||||
*/
|
||||
protected void writeToLog(Log logger, String message) {
|
||||
writeToLog(logger, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the supplied message and {@link Throwable} to the
|
||||
* supplied {@code Log} instance. By default messages are written
|
||||
* at {@code TRACE} level. Sub-classes can override this method
|
||||
* to control which level the message is written at.
|
||||
*/
|
||||
protected void writeToLog(Log logger, String message, Throwable ex) {
|
||||
if (ex != null) {
|
||||
logger.trace(message, ex);
|
||||
}
|
||||
else {
|
||||
logger.trace(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the placeholders in the given message with the supplied values,
|
||||
* or values derived from those supplied.
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -121,7 +121,7 @@ public class JamonPerformanceMonitorInterceptor extends AbstractMonitoringInterc
|
||||
finally {
|
||||
monitor.stop();
|
||||
if (!this.trackAllInvocations || isLogEnabled(logger)) {
|
||||
logger.trace("JAMon performance statistics for method [" + name + "]:\n" + monitor);
|
||||
writeToLog(logger, "JAMon performance statistics for method [" + name + "]:\n" + monitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -63,7 +63,7 @@ public class PerformanceMonitorInterceptor extends AbstractMonitoringInterceptor
|
||||
}
|
||||
finally {
|
||||
stopWatch.stop();
|
||||
logger.trace(stopWatch.shortSummary());
|
||||
writeToLog(logger, stopWatch.shortSummary());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -55,14 +55,14 @@ public class SimpleTraceInterceptor extends AbstractTraceInterceptor {
|
||||
@Override
|
||||
protected Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable {
|
||||
String invocationDescription = getInvocationDescription(invocation);
|
||||
logger.trace("Entering " + invocationDescription);
|
||||
writeToLog(logger, "Entering " + invocationDescription);
|
||||
try {
|
||||
Object rval = invocation.proceed();
|
||||
logger.trace("Exiting " + invocationDescription);
|
||||
writeToLog(logger, "Exiting " + invocationDescription);
|
||||
return rval;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.trace("Exception thrown in " + invocationDescription, ex);
|
||||
writeToLog(logger, "Exception thrown in " + invocationDescription, ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -89,7 +89,7 @@ public abstract class ScopedProxyUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the bean name that is used within the scoped proxy to reference the target bean.
|
||||
* Generate the bean name that is used within the scoped proxy to reference the target bean.
|
||||
* @param originalBeanName the original name of bean
|
||||
* @return the generated bean to be used to reference the target bean
|
||||
*/
|
||||
|
||||
+22
-6
@@ -46,7 +46,7 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private transient Advice advice;
|
||||
private transient volatile Advice advice;
|
||||
|
||||
private transient volatile Object adviceMonitor = new Object();
|
||||
|
||||
@@ -98,12 +98,28 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
|
||||
|
||||
@Override
|
||||
public Advice getAdvice() {
|
||||
synchronized (this.adviceMonitor) {
|
||||
if (this.advice == null && this.adviceBeanName != null) {
|
||||
Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
|
||||
this.advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
|
||||
Advice advice = this.advice;
|
||||
if (advice != null || this.adviceBeanName == null) {
|
||||
return advice;
|
||||
}
|
||||
|
||||
Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
|
||||
if (this.beanFactory.isSingleton(this.adviceBeanName)) {
|
||||
// Rely on singleton semantics provided by the factory.
|
||||
advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
|
||||
this.advice = advice;
|
||||
return advice;
|
||||
}
|
||||
else {
|
||||
// No singleton guarantees from the factory -> let's lock locally but
|
||||
// reuse the factory's singleton lock, just in case a lazy dependency
|
||||
// of our advice bean happens to trigger the singleton lock implicitly...
|
||||
synchronized (this.adviceMonitor) {
|
||||
if (this.advice == null) {
|
||||
this.advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
|
||||
}
|
||||
return this.advice;
|
||||
}
|
||||
return this.advice;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -129,8 +130,8 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return ((targetClass != null && matchesPattern(targetClass.getName() + "." + method.getName())) ||
|
||||
matchesPattern(method.getDeclaringClass().getName() + "." + method.getName()));
|
||||
return ((targetClass != null && matchesPattern(ClassUtils.getQualifiedMethodName(method, targetClass))) ||
|
||||
matchesPattern(ClassUtils.getQualifiedMethodName(method)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,8 +22,6 @@ import java.lang.reflect.Method;
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.core.ControlFlow;
|
||||
import org.springframework.core.ControlFlowFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -34,7 +32,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
* @see org.springframework.core.ControlFlow
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable {
|
||||
@@ -43,7 +41,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
|
||||
|
||||
private String methodName;
|
||||
|
||||
private int evaluations;
|
||||
private volatile int evaluations;
|
||||
|
||||
|
||||
/**
|
||||
@@ -55,11 +53,11 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new pointcut that matches all calls below the
|
||||
* given method in the given class. If the method name is null,
|
||||
* matches all control flows below that class.
|
||||
* Construct a new pointcut that matches all calls below the given method
|
||||
* in the given class. If no method name is given, matches all control flows
|
||||
* below the given class.
|
||||
* @param clazz the clazz
|
||||
* @param methodName the name of the method
|
||||
* @param methodName the name of the method (may be {@code null})
|
||||
*/
|
||||
public ControlFlowPointcut(Class<?> clazz, String methodName) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
@@ -93,8 +91,14 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass, Object... args) {
|
||||
this.evaluations++;
|
||||
ControlFlow cflow = ControlFlowFactory.createControlFlow();
|
||||
return (this.methodName != null ? cflow.under(this.clazz, this.methodName) : cflow.under(this.clazz));
|
||||
|
||||
for (StackTraceElement element : new Throwable().getStackTrace()) {
|
||||
if (element.getClassName().equals(this.clazz.getName()) &&
|
||||
(this.methodName == null || element.getMethodName().equals(this.methodName))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,8 +134,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = 17;
|
||||
code = 37 * code + this.clazz.hashCode();
|
||||
int code = this.clazz.hashCode();
|
||||
if (this.methodName != null) {
|
||||
code = 37 * code + this.methodName.hashCode();
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
/**
|
||||
* Pointcut bean for simple method name matches, as alternative to regexp patterns.
|
||||
* Does not handle overloaded methods: all methods *with a given name will be eligible.
|
||||
* Does not handle overloaded methods: all methods with a given name will be eligible.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rod Johnson
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,7 +39,7 @@ import org.springframework.aop.TargetSource;
|
||||
public abstract class AbstractRefreshableTargetSource implements TargetSource, Refreshable {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected Log logger = LogFactory.getLog(getClass());
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected Object targetObject;
|
||||
|
||||
|
||||
+15
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.aop.scope;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
@@ -27,19 +29,24 @@ import static org.springframework.tests.TestResourceUtils.*;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public final class ScopedProxyAutowireTests {
|
||||
public class ScopedProxyAutowireTests {
|
||||
|
||||
private static final Class<?> CLASS = ScopedProxyAutowireTests.class;
|
||||
private static final Resource SCOPED_AUTOWIRE_FALSE_CONTEXT =
|
||||
qualifiedResource(ScopedProxyAutowireTests.class, "scopedAutowireFalse.xml");
|
||||
private static final Resource SCOPED_AUTOWIRE_TRUE_CONTEXT =
|
||||
qualifiedResource(ScopedProxyAutowireTests.class, "scopedAutowireTrue.xml");
|
||||
|
||||
private static final Resource SCOPED_AUTOWIRE_TRUE_CONTEXT = qualifiedResource(CLASS, "scopedAutowireTrue.xml");
|
||||
private static final Resource SCOPED_AUTOWIRE_FALSE_CONTEXT = qualifiedResource(CLASS, "scopedAutowireFalse.xml");
|
||||
|
||||
@Test
|
||||
public void testScopedProxyInheritsAutowireCandidateFalse() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(SCOPED_AUTOWIRE_FALSE_CONTEXT);
|
||||
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, false, false)).contains("scoped"));
|
||||
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, true, false)).contains("scoped"));
|
||||
assertFalse(bf.containsSingleton("scoped"));
|
||||
TestBean autowired = (TestBean) bf.getBean("autowired");
|
||||
TestBean unscoped = (TestBean) bf.getBean("unscoped");
|
||||
assertSame(unscoped, autowired.getChild());
|
||||
@@ -49,6 +56,9 @@ public final class ScopedProxyAutowireTests {
|
||||
public void testScopedProxyReplacesAutowireCandidateTrue() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(SCOPED_AUTOWIRE_TRUE_CONTEXT);
|
||||
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, true, false)).contains("scoped"));
|
||||
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, false, false)).contains("scoped"));
|
||||
assertFalse(bf.containsSingleton("scoped"));
|
||||
TestBean autowired = (TestBean) bf.getBean("autowired");
|
||||
TestBean scoped = (TestBean) bf.getBean("scoped");
|
||||
assertSame(scoped, autowired.getChild());
|
||||
|
||||
+10
-13
@@ -1,6 +1,5 @@
|
||||
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,27 +28,21 @@ public class NopInterceptor implements MethodInterceptor {
|
||||
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* @see org.aopalliance.intercept.MethodInterceptor#invoke(MethodInvocation)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
increment();
|
||||
return invocation.proceed();
|
||||
}
|
||||
|
||||
protected void increment() {
|
||||
this.count++;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return this.count;
|
||||
}
|
||||
|
||||
protected void increment() {
|
||||
++count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
@@ -62,5 +55,9 @@ public class NopInterceptor implements MethodInterceptor {
|
||||
return this.count == ((NopInterceptor) other).count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return NopInterceptor.class.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,22 +28,10 @@ import org.springframework.util.ObjectUtils;
|
||||
@SuppressWarnings("serial")
|
||||
public class SerializablePerson implements Person, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
private String name;
|
||||
|
||||
private int age;
|
||||
|
||||
@Override
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -55,6 +43,16 @@ public class SerializablePerson implements Person, Serializable {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object echo(Object o) throws Throwable {
|
||||
if (o instanceof Throwable) {
|
||||
@@ -63,10 +61,6 @@ public class SerializablePerson implements Person, Serializable {
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
@@ -77,4 +71,9 @@ public class SerializablePerson implements Person, Serializable {
|
||||
return p.age == age && ObjectUtils.nullSafeEquals(name, p.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return SerializablePerson.class.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
<config xmlns="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
|
||||
|
||||
<pointcut id="testPointcut" expression="execution(* foo(..)) and within(springbank.dao.AccountDao+)"/>
|
||||
<pointcut id="testPointcut1" expression="execution(* springbank.dao.AccountDao.foo(..))"/>
|
||||
@@ -9,4 +9,4 @@
|
||||
<after method="foo" pointcut-ref="testPointcut"/>
|
||||
</aspect>
|
||||
|
||||
</config>
|
||||
</config>
|
||||
|
||||
+9
-9
@@ -1,16 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
|
||||
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" scope="prototype" autowire-candidate="false">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
|
||||
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true"/>
|
||||
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true"/>
|
||||
|
||||
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
|
||||
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
|
||||
|
||||
</beans>
|
||||
|
||||
+9
-9
@@ -1,16 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
|
||||
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" scope="singleton" autowire-candidate="true">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
|
||||
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false"/>
|
||||
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false"/>
|
||||
|
||||
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
|
||||
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
|
||||
|
||||
</beans>
|
||||
|
||||
+2
@@ -36,7 +36,9 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
* @deprecated as of Spring 4.3, in favor of a custom aspect for such purposes
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {
|
||||
|
||||
private final Expectations expectations = new Expectations();
|
||||
|
||||
+2
@@ -59,7 +59,9 @@ import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
* @see MockStaticEntityMethods
|
||||
* @deprecated as of Spring 4.3, in favor of a custom aspect for such purposes
|
||||
*/
|
||||
@Deprecated
|
||||
@RequiredTypes("javax.persistence.Entity")
|
||||
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
|
||||
|
||||
|
||||
+2
@@ -29,7 +29,9 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Sam Brannen
|
||||
* @deprecated as of Spring 4.3, in favor of a custom aspect for such purposes
|
||||
*/
|
||||
@Deprecated
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface MockStaticEntityMethods {
|
||||
|
||||
+42
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,55 +18,45 @@ package org.springframework.transaction.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.tests.transaction.CallCountingTransactionManager;
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class TransactionAspectTests extends org.springframework.test.AbstractDependencyInjectionSpringContextTests {
|
||||
public class TransactionAspectTests {
|
||||
|
||||
private CallCountingTransactionManager txManager;
|
||||
private final CallCountingTransactionManager txManager = new CallCountingTransactionManager();
|
||||
|
||||
private TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface;
|
||||
private final TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface =
|
||||
new TransactionalAnnotationOnlyOnClassWithNoInterface();
|
||||
|
||||
private ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod;
|
||||
private final ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod =
|
||||
new ClassWithProtectedAnnotatedMember();
|
||||
|
||||
private ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod;
|
||||
private final ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod =
|
||||
new ClassWithPrivateAnnotatedMember();
|
||||
|
||||
private MethodAnnotationOnClassWithNoInterface methodAnnotationOnly = new MethodAnnotationOnClassWithNoInterface();
|
||||
private final MethodAnnotationOnClassWithNoInterface methodAnnotationOnly =
|
||||
new MethodAnnotationOnClassWithNoInterface();
|
||||
|
||||
|
||||
public void setAnnotationOnlyOnClassWithNoInterface(
|
||||
TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface) {
|
||||
this.annotationOnlyOnClassWithNoInterface = annotationOnlyOnClassWithNoInterface;
|
||||
}
|
||||
|
||||
public void setClassWithAnnotatedProtectedMethod(ClassWithProtectedAnnotatedMember aBean) {
|
||||
this.beanWithAnnotatedProtectedMethod = aBean;
|
||||
}
|
||||
|
||||
public void setClassWithAnnotatedPrivateMethod(ClassWithPrivateAnnotatedMember aBean) {
|
||||
this.beanWithAnnotatedPrivateMethod = aBean;
|
||||
}
|
||||
|
||||
public void setTransactionAspect(TransactionAspectSupport transactionAspect) {
|
||||
this.txManager = (CallCountingTransactionManager) transactionAspect.getTransactionManager();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String[] getConfigPaths() {
|
||||
return new String[] { "TransactionAspectTests-context.xml" };
|
||||
@Before
|
||||
public void initContext() {
|
||||
AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCommitOnAnnotatedClass() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -74,6 +64,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommitOnAnnotatedProtectedMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -81,6 +72,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommitOnAnnotatedPrivateMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -88,6 +80,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoCommitOnNonAnnotatedNonPublicMethodInTransactionalType() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0,txManager.begun);
|
||||
@@ -95,6 +88,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(0,txManager.begun);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommitOnAnnotatedMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -102,6 +96,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotTransactional() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -109,6 +104,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(0, txManager.begun);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommitOnAnnotatedClass() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
try {
|
||||
@@ -125,6 +121,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultRollbackOnAnnotatedClass() throws Throwable {
|
||||
final RuntimeException ex = new RuntimeException();
|
||||
try {
|
||||
@@ -141,10 +138,11 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommitOnSubclassOfAnnotatedClass() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
try {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
@Override
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return new SubclassOfClassWithTransactionalAnnotation().echo(ex);
|
||||
@@ -157,6 +155,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
try {
|
||||
@@ -173,6 +172,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommitOnImplementationOfAnnotatedInterface() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
testNotTransactional(new TransactionOperationCallback() {
|
||||
@@ -185,16 +185,19 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
|
||||
/**
|
||||
* Note: resolution does not occur. Thus we can't make a class transactional if
|
||||
* it implements a transactionally annotated interface. This behaviour could only
|
||||
* it implements a transactionally annotated interface. This behavior could only
|
||||
* be changed in AbstractFallbackTransactionAttributeSource in Spring proper.
|
||||
* See SPR-14322.
|
||||
*/
|
||||
@Test
|
||||
public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws Exception {
|
||||
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
|
||||
Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
|
||||
TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class);
|
||||
Method method = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
|
||||
TransactionAttribute ta = atas.getTransactionAttribute(method, ImplementsAnnotatedInterface.class);
|
||||
assertNull(ta);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultRollbackOnImplementationOfAnnotatedInterface() throws Throwable {
|
||||
final Exception rollbackProvokingException = new RuntimeException();
|
||||
testNotTransactional(new TransactionOperationCallback() {
|
||||
@@ -237,15 +240,19 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
|
||||
|
||||
private interface TransactionOperationCallback {
|
||||
|
||||
Object performTransactionalOperation() throws Throwable;
|
||||
}
|
||||
|
||||
|
||||
public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface {
|
||||
}
|
||||
|
||||
|
||||
public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface {
|
||||
}
|
||||
|
||||
|
||||
public static class ImplementsAnnotatedInterface implements ITransactional {
|
||||
|
||||
@Override
|
||||
@@ -257,6 +264,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class NotTransactional {
|
||||
|
||||
public void noop() {
|
||||
|
||||
+10
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -303,7 +303,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
Collection constructorArgs = null;
|
||||
if (!ObjectUtils.isEmpty(args)) {
|
||||
int index = args.length;
|
||||
Object lastArg = args[index-1];
|
||||
Object lastArg = args[index - 1];
|
||||
if (lastArg instanceof Closure) {
|
||||
callable = (Closure) lastArg;
|
||||
index--;
|
||||
@@ -456,14 +456,14 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
* @return the bean definition wrapper
|
||||
*/
|
||||
private GroovyBeanDefinitionWrapper invokeBeanDefiningMethod(String beanName, Object[] args) {
|
||||
boolean hasClosureArgument = args[args.length - 1] instanceof Closure;
|
||||
boolean hasClosureArgument = (args[args.length - 1] instanceof Closure);
|
||||
if (args[0] instanceof Class) {
|
||||
Class<?> beanClass = (args[0] instanceof Class ? (Class) args[0] : args[0].getClass());
|
||||
Class<?> beanClass = (Class<?>) args[0];
|
||||
if (args.length >= 1) {
|
||||
if (hasClosureArgument) {
|
||||
if (args.length-1 != 1) {
|
||||
if (args.length - 1 != 1) {
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(
|
||||
beanName, beanClass, resolveConstructorArguments(args,1,args.length-1));
|
||||
beanName, beanClass, resolveConstructorArguments(args, 1, args.length - 1));
|
||||
}
|
||||
else {
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, beanClass);
|
||||
@@ -471,7 +471,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
else {
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(
|
||||
beanName, beanClass, resolveConstructorArguments(args,1,args.length));
|
||||
beanName, beanClass, resolveConstructorArguments(args, 1, args.length));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -483,7 +483,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
else if (args[0] instanceof Map) {
|
||||
// named constructor arguments
|
||||
if (args.length > 1 && args[1] instanceof Class) {
|
||||
List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length-1 : args.length);
|
||||
List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length);
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class)args[1], constructorArgs);
|
||||
Map namedArgs = (Map)args[0];
|
||||
for (Object o : namedArgs.keySet()) {
|
||||
@@ -519,12 +519,12 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
this.currentBeanDefinition.getBeanDefinition().setAbstract(true);
|
||||
}
|
||||
else {
|
||||
List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length-1 : args.length);
|
||||
List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length - 1 : args.length);
|
||||
currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, null, constructorArgs);
|
||||
}
|
||||
|
||||
if (hasClosureArgument) {
|
||||
Closure callable = (Closure)args[args.length-1];
|
||||
Closure callable = (Closure) args[args.length - 1];
|
||||
callable.setDelegate(this);
|
||||
callable.setResolveStrategy(Closure.DELEGATE_FIRST);
|
||||
callable.call(new Object[]{currentBeanDefinition});
|
||||
|
||||
+186
-177
@@ -94,7 +94,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
|
||||
private String nestedPath = "";
|
||||
|
||||
private Object rootObject;
|
||||
Object rootObject;
|
||||
|
||||
/**
|
||||
* Map with cached nested Accessors: nested path -> Accessor instance.
|
||||
@@ -284,198 +284,212 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
|
||||
String propertyName = tokens.canonicalName;
|
||||
String actualName = tokens.actualName;
|
||||
|
||||
if (tokens.keys != null) {
|
||||
// Apply indexes and map keys: fetch value for all keys but the last one.
|
||||
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
|
||||
getterTokens.canonicalName = tokens.canonicalName;
|
||||
getterTokens.actualName = tokens.actualName;
|
||||
getterTokens.keys = new String[tokens.keys.length - 1];
|
||||
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);
|
||||
Object propValue;
|
||||
processKeyedProperty(tokens, pv);
|
||||
}
|
||||
else {
|
||||
processLocalProperty(tokens, pv);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) {
|
||||
Object propValue = getPropertyHoldingValue(tokens);
|
||||
String lastKey = tokens.keys[tokens.keys.length - 1];
|
||||
|
||||
if (propValue.getClass().isArray()) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
|
||||
Class<?> requiredType = propValue.getClass().getComponentType();
|
||||
int arrayIndex = Integer.parseInt(lastKey);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
propValue = getPropertyValue(getterTokens);
|
||||
}
|
||||
catch (NotReadablePropertyException ex) {
|
||||
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + propertyName + "'", ex);
|
||||
}
|
||||
// Set value for last key.
|
||||
String key = tokens.keys[tokens.keys.length - 1];
|
||||
if (propValue == null) {
|
||||
// null map value case
|
||||
if (isAutoGrowNestedPaths()) {
|
||||
// TODO: cleanup, this is pretty hacky
|
||||
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
|
||||
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
|
||||
propValue = setDefaultValue(getterTokens);
|
||||
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
|
||||
oldValue = Array.get(propValue, arrayIndex);
|
||||
}
|
||||
else {
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + propertyName + "': returned null");
|
||||
}
|
||||
}
|
||||
if (propValue.getClass().isArray()) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(actualName);
|
||||
Class<?> requiredType = propValue.getClass().getComponentType();
|
||||
int arrayIndex = Integer.parseInt(key);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
|
||||
oldValue = Array.get(propValue, arrayIndex);
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
requiredType, ph.nested(tokens.keys.length));
|
||||
int length = Array.getLength(propValue);
|
||||
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
|
||||
Class<?> componentType = propValue.getClass().getComponentType();
|
||||
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
|
||||
System.arraycopy(propValue, 0, newArray, 0, length);
|
||||
setPropertyValue(actualName, newArray);
|
||||
propValue = getPropertyValue(actualName);
|
||||
}
|
||||
Array.set(propValue, arrayIndex, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Invalid array index in property path '" + propertyName + "'", ex);
|
||||
}
|
||||
}
|
||||
else if (propValue instanceof List) {
|
||||
PropertyHandler ph = getPropertyHandler(actualName);
|
||||
Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
|
||||
List<Object> list = (List<Object>) propValue;
|
||||
int index = Integer.parseInt(key);
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor() && index < list.size()) {
|
||||
oldValue = list.get(index);
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
|
||||
requiredType, ph.nested(tokens.keys.length));
|
||||
int size = list.size();
|
||||
if (index >= size && index < this.autoGrowCollectionLimit) {
|
||||
for (int i = size; i < index; i++) {
|
||||
try {
|
||||
list.add(null);
|
||||
}
|
||||
catch (NullPointerException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot set element with index " + index + " in List of size " +
|
||||
size + ", accessed using property path '" + propertyName +
|
||||
"': List does not support filling up gaps with null elements");
|
||||
}
|
||||
}
|
||||
list.add(convertedValue);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
list.set(index, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Invalid list index in property path '" + propertyName + "'", ex);
|
||||
}
|
||||
int length = Array.getLength(propValue);
|
||||
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
|
||||
Class<?> componentType = propValue.getClass().getComponentType();
|
||||
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
|
||||
System.arraycopy(propValue, 0, newArray, 0, length);
|
||||
setPropertyValue(tokens.actualName, newArray);
|
||||
propValue = getPropertyValue(tokens.actualName);
|
||||
}
|
||||
Array.set(propValue, arrayIndex, convertedValue);
|
||||
}
|
||||
else if (propValue instanceof Map) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(actualName);
|
||||
Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
|
||||
Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);
|
||||
Map<Object, Object> map = (Map<Object, Object>) propValue;
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
|
||||
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor()) {
|
||||
oldValue = map.get(convertedMapKey);
|
||||
}
|
||||
// Pass full property name and old value in here, since we want full
|
||||
// conversion ability for map values.
|
||||
Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
mapValueType, ph.nested(tokens.keys.length));
|
||||
map.put(convertedMapKey, convertedMapValue);
|
||||
}
|
||||
else {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Property referenced in indexed property path '" + propertyName +
|
||||
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Invalid array index in property path '" + tokens.canonicalName + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
PropertyHandler ph = getLocalPropertyHandler(actualName);
|
||||
if (ph == null || !ph.isWritable()) {
|
||||
if (pv.isOptional()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Ignoring optional value for property '" + actualName +
|
||||
"' - property not found on bean class [" + getRootClass().getName() + "]");
|
||||
else if (propValue instanceof List) {
|
||||
PropertyHandler ph = getPropertyHandler(tokens.actualName);
|
||||
Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
|
||||
List<Object> list = (List<Object>) propValue;
|
||||
int index = Integer.parseInt(lastKey);
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor() && index < list.size()) {
|
||||
oldValue = list.get(index);
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
|
||||
requiredType, ph.nested(tokens.keys.length));
|
||||
int size = list.size();
|
||||
if (index >= size && index < this.autoGrowCollectionLimit) {
|
||||
for (int i = size; i < index; i++) {
|
||||
try {
|
||||
list.add(null);
|
||||
}
|
||||
catch (NullPointerException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Cannot set element with index " + index + " in List of size " +
|
||||
size + ", accessed using property path '" + tokens.canonicalName +
|
||||
"': List does not support filling up gaps with null elements");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw createNotWritablePropertyException(propertyName);
|
||||
list.add(convertedValue);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
list.set(index, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Invalid list index in property path '" + tokens.canonicalName + "'", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (propValue instanceof Map) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
|
||||
Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
|
||||
Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);
|
||||
Map<Object, Object> map = (Map<Object, Object>) propValue;
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
|
||||
Object convertedMapKey = convertIfNecessary(null, null, lastKey, mapKeyType, typeDescriptor);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
Object originalValue = pv.getValue();
|
||||
Object valueToApply = originalValue;
|
||||
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
|
||||
if (pv.isConverted()) {
|
||||
valueToApply = pv.getConvertedValue();
|
||||
}
|
||||
else {
|
||||
if (isExtractOldValueForEditor() && ph.isReadable()) {
|
||||
try {
|
||||
oldValue = ph.getValue();
|
||||
if (isExtractOldValueForEditor()) {
|
||||
oldValue = map.get(convertedMapKey);
|
||||
}
|
||||
// Pass full property name and old value in here, since we want full
|
||||
// conversion ability for map values.
|
||||
Object convertedMapValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
|
||||
mapValueType, ph.nested(tokens.keys.length));
|
||||
map.put(convertedMapKey, convertedMapValue);
|
||||
}
|
||||
|
||||
else {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Property referenced in indexed property path '" + tokens.canonicalName +
|
||||
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private Object getPropertyHoldingValue(PropertyTokenHolder tokens) {
|
||||
// Apply indexes and map keys: fetch value for all keys but the last one.
|
||||
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
|
||||
getterTokens.canonicalName = tokens.canonicalName;
|
||||
getterTokens.actualName = tokens.actualName;
|
||||
getterTokens.keys = new String[tokens.keys.length - 1];
|
||||
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);
|
||||
|
||||
Object propValue;
|
||||
try {
|
||||
propValue = getPropertyValue(getterTokens);
|
||||
}
|
||||
catch (NotReadablePropertyException ex) {
|
||||
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + tokens.canonicalName + "'", ex);
|
||||
}
|
||||
|
||||
if (propValue == null) {
|
||||
// null map value case
|
||||
if (isAutoGrowNestedPaths()) {
|
||||
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
|
||||
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
|
||||
propValue = setDefaultValue(getterTokens);
|
||||
}
|
||||
else {
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + tokens.canonicalName + "': returned null");
|
||||
}
|
||||
}
|
||||
return propValue;
|
||||
}
|
||||
|
||||
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
|
||||
if (ph == null || !ph.isWritable()) {
|
||||
if (pv.isOptional()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Ignoring optional value for property '" + tokens.actualName +
|
||||
"' - property not found on bean class [" + getRootClass().getName() + "]");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw createNotWritablePropertyException(tokens.canonicalName);
|
||||
}
|
||||
}
|
||||
|
||||
Object oldValue = null;
|
||||
try {
|
||||
Object originalValue = pv.getValue();
|
||||
Object valueToApply = originalValue;
|
||||
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
|
||||
if (pv.isConverted()) {
|
||||
valueToApply = pv.getConvertedValue();
|
||||
}
|
||||
else {
|
||||
if (isExtractOldValueForEditor() && ph.isReadable()) {
|
||||
try {
|
||||
oldValue = ph.getValue();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex instanceof PrivilegedActionException) {
|
||||
ex = ((PrivilegedActionException) ex).getException();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex instanceof PrivilegedActionException) {
|
||||
ex = ((PrivilegedActionException) ex).getException();
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not read previous value of property '" +
|
||||
this.nestedPath + propertyName + "'", ex);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not read previous value of property '" +
|
||||
this.nestedPath + tokens.canonicalName + "'", ex);
|
||||
}
|
||||
}
|
||||
valueToApply = convertForProperty(
|
||||
propertyName, oldValue, originalValue, ph.toTypeDescriptor());
|
||||
}
|
||||
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
|
||||
valueToApply = convertForProperty(
|
||||
tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
|
||||
}
|
||||
ph.setValue(this.wrappedObject, valueToApply);
|
||||
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
throw ex;
|
||||
ph.setValue(this.wrappedObject, valueToApply);
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
|
||||
this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
|
||||
if (ex.getTargetException() instanceof ClassCastException) {
|
||||
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
PropertyChangeEvent propertyChangeEvent =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
if (ex.getTargetException() instanceof ClassCastException) {
|
||||
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
|
||||
}
|
||||
else {
|
||||
Throwable cause = ex.getTargetException();
|
||||
if (cause instanceof UndeclaredThrowableException) {
|
||||
// May happen e.g. with Groovy-generated methods
|
||||
cause = cause.getCause();
|
||||
}
|
||||
throw new MethodInvocationException(propertyChangeEvent, cause);
|
||||
else {
|
||||
Throwable cause = ex.getTargetException();
|
||||
if (cause instanceof UndeclaredThrowableException) {
|
||||
// May happen e.g. with Groovy-generated methods
|
||||
cause = cause.getCause();
|
||||
}
|
||||
throw new MethodInvocationException(propertyChangeEvent, cause);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
throw new MethodInvocationException(pce, ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
PropertyChangeEvent pce = new PropertyChangeEvent(
|
||||
this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
|
||||
throw new MethodInvocationException(pce, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,7 +604,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
|
||||
throw new ConversionNotSupportedException(pce, requiredType, ex);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
catch (IllegalArgumentException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
|
||||
throw new TypeMismatchException(pce, requiredType, ex);
|
||||
@@ -914,11 +928,9 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
return BeanUtils.instantiate(type);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// TODO: Root cause exception context is lost here; just exception message preserved.
|
||||
// Should we throw another exception type that preserves context instead?
|
||||
catch (Throwable ex) {
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name,
|
||||
"Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path: " + ex);
|
||||
"Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -975,9 +987,6 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle a given property.
|
||||
*/
|
||||
protected abstract static class PropertyHandler {
|
||||
|
||||
private final Class<?> propertyType;
|
||||
|
||||
@@ -148,7 +148,7 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyAccessException if the property was valid but the
|
||||
* accessor method failed or a type mismatch occured
|
||||
* accessor method failed or a type mismatch occurred
|
||||
*/
|
||||
@Override
|
||||
public abstract void setPropertyValue(String propertyName, Object value) throws BeansException;
|
||||
|
||||
@@ -63,11 +63,10 @@ public abstract class BeanUtils {
|
||||
|
||||
/**
|
||||
* Convenience method to instantiate a class using its no-arg constructor.
|
||||
* As this method doesn't try to load classes by name, it should avoid
|
||||
* class-loading issues.
|
||||
* @param clazz class to instantiate
|
||||
* @return the new instance
|
||||
* @throws BeanInstantiationException if the bean cannot be instantiated
|
||||
* @see Class#newInstance()
|
||||
*/
|
||||
public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
@@ -87,13 +86,12 @@ public abstract class BeanUtils {
|
||||
|
||||
/**
|
||||
* Instantiate a class using its no-arg constructor.
|
||||
* As this method doesn't try to load classes by name, it should avoid
|
||||
* class-loading issues.
|
||||
* <p>Note that this method tries to set the constructor accessible
|
||||
* if given a non-accessible (that is, non-public) constructor.
|
||||
* @param clazz class to instantiate
|
||||
* @return the new instance
|
||||
* @throws BeanInstantiationException if the bean cannot be instantiated
|
||||
* @see Constructor#newInstance
|
||||
*/
|
||||
public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
@@ -111,17 +109,15 @@ public abstract class BeanUtils {
|
||||
/**
|
||||
* Instantiate a class using its no-arg constructor and return the new instance
|
||||
* as the specified assignable type.
|
||||
* <p>Useful in cases where
|
||||
* the type of the class to instantiate (clazz) is not available, but the type
|
||||
* desired (assignableTo) is known.
|
||||
* <p>As this method doesn't try to load classes by name, it should avoid
|
||||
* class-loading issues.
|
||||
* <p>Note that this method tries to set the constructor accessible
|
||||
* if given a non-accessible (that is, non-public) constructor.
|
||||
* <p>Useful in cases where the type of the class to instantiate (clazz) is not
|
||||
* available, but the type desired (assignableTo) is known.
|
||||
* <p>Note that this method tries to set the constructor accessible if given a
|
||||
* non-accessible (that is, non-public) constructor.
|
||||
* @param clazz class to instantiate
|
||||
* @param assignableTo type that clazz must be assignableTo
|
||||
* @return the new instance
|
||||
* @throws BeanInstantiationException if the bean cannot be instantiated
|
||||
* @see Constructor#newInstance
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo) throws BeanInstantiationException {
|
||||
@@ -131,14 +127,13 @@ public abstract class BeanUtils {
|
||||
|
||||
/**
|
||||
* Convenience method to instantiate a class using the given constructor.
|
||||
* As this method doesn't try to load classes by name, it should avoid
|
||||
* class-loading issues.
|
||||
* <p>Note that this method tries to set the constructor accessible
|
||||
* if given a non-accessible (that is, non-public) constructor.
|
||||
* <p>Note that this method tries to set the constructor accessible if given a
|
||||
* non-accessible (that is, non-public) constructor.
|
||||
* @param ctor the constructor to instantiate
|
||||
* @param args the constructor arguments to apply
|
||||
* @return the new instance
|
||||
* @throws BeanInstantiationException if the bean cannot be instantiated
|
||||
* @see Constructor#newInstance
|
||||
*/
|
||||
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
|
||||
Assert.notNull(ctor, "Constructor must not be null");
|
||||
|
||||
@@ -141,6 +141,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
|
||||
*/
|
||||
public void setBeanInstance(Object object) {
|
||||
this.wrappedObject = object;
|
||||
this.rootObject = object;
|
||||
this.typeConverterDelegate = new TypeConverterDelegate(this, this.wrappedObject);
|
||||
setIntrospectionClass(object.getClass());
|
||||
}
|
||||
|
||||
+14
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ package org.springframework.beans;
|
||||
* spouse property of the target object has a null value.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class NullValueInNestedPathException extends InvalidPropertyException {
|
||||
@@ -47,4 +48,16 @@ public class NullValueInNestedPathException extends InvalidPropertyException {
|
||||
super(beanClass, propertyName, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new NullValueInNestedPathException.
|
||||
* @param beanClass the offending bean class
|
||||
* @param propertyName the offending property
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public NullValueInNestedPathException(Class<?> beanClass, String propertyName, String msg, Throwable cause) {
|
||||
super(beanClass, propertyName, msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,8 +18,6 @@ package org.springframework.beans;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
|
||||
import org.springframework.core.ErrorCoded;
|
||||
|
||||
/**
|
||||
* Superclass for exceptions related to a property access,
|
||||
* such as type mismatch or invocation target exception.
|
||||
@@ -27,8 +25,8 @@ import org.springframework.core.ErrorCoded;
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class PropertyAccessException extends BeansException implements ErrorCoded {
|
||||
@SuppressWarnings({"serial", "deprecation"})
|
||||
public abstract class PropertyAccessException extends BeansException implements org.springframework.core.ErrorCoded {
|
||||
|
||||
private transient PropertyChangeEvent propertyChangeEvent;
|
||||
|
||||
@@ -77,4 +75,10 @@ public abstract class PropertyAccessException extends BeansException implements
|
||||
return (this.propertyChangeEvent != null ? this.propertyChangeEvent.getNewValue() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a corresponding error code for this type of exception.
|
||||
*/
|
||||
@Override
|
||||
public abstract String getErrorCode();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -120,7 +120,7 @@ public interface PropertyAccessor {
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyAccessException if the property was valid but the
|
||||
* accessor method failed or a type mismatch occured
|
||||
* accessor method failed or a type mismatch occurred
|
||||
*/
|
||||
void setPropertyValue(String propertyName, Object value) throws BeansException;
|
||||
|
||||
@@ -130,7 +130,7 @@ public interface PropertyAccessor {
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyAccessException if the property was valid but the
|
||||
* accessor method failed or a type mismatch occured
|
||||
* accessor method failed or a type mismatch occurred
|
||||
*/
|
||||
void setPropertyValue(PropertyValue pv) throws BeansException;
|
||||
|
||||
@@ -144,7 +144,7 @@ public interface PropertyAccessor {
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyBatchUpdateException if one or more PropertyAccessExceptions
|
||||
* occured for specific properties during the batch update. This exception bundles
|
||||
* occurred for specific properties during the batch update. This exception bundles
|
||||
* all individual PropertyAccessExceptions. All other properties will have been
|
||||
* successfully updated.
|
||||
*/
|
||||
@@ -164,7 +164,7 @@ public interface PropertyAccessor {
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyBatchUpdateException if one or more PropertyAccessExceptions
|
||||
* occured for specific properties during the batch update. This exception bundles
|
||||
* occurred for specific properties during the batch update. This exception bundles
|
||||
* all individual PropertyAccessExceptions. All other properties will have been
|
||||
* successfully updated.
|
||||
* @see #setPropertyValues(PropertyValues, boolean, boolean)
|
||||
@@ -185,7 +185,7 @@ public interface PropertyAccessor {
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyBatchUpdateException if one or more PropertyAccessExceptions
|
||||
* occured for specific properties during the batch update. This exception bundles
|
||||
* occurred for specific properties during the batch update. This exception bundles
|
||||
* all individual PropertyAccessExceptions. All other properties will have been
|
||||
* successfully updated.
|
||||
* @see #setPropertyValues(PropertyValues, boolean, boolean)
|
||||
@@ -208,7 +208,7 @@ public interface PropertyAccessor {
|
||||
* @throws InvalidPropertyException if there is no such property or
|
||||
* if the property isn't writable
|
||||
* @throws PropertyBatchUpdateException if one or more PropertyAccessExceptions
|
||||
* occured for specific properties during the batch update. This exception bundles
|
||||
* occurred for specific properties during the batch update. This exception bundles
|
||||
* all individual PropertyAccessExceptions. All other properties will have been
|
||||
* successfully updated.
|
||||
*/
|
||||
|
||||
+15
-1
@@ -59,6 +59,7 @@ import org.springframework.beans.propertyeditors.FileEditor;
|
||||
import org.springframework.beans.propertyeditors.InputSourceEditor;
|
||||
import org.springframework.beans.propertyeditors.InputStreamEditor;
|
||||
import org.springframework.beans.propertyeditors.LocaleEditor;
|
||||
import org.springframework.beans.propertyeditors.PathEditor;
|
||||
import org.springframework.beans.propertyeditors.PatternEditor;
|
||||
import org.springframework.beans.propertyeditors.PropertiesEditor;
|
||||
import org.springframework.beans.propertyeditors.ReaderEditor;
|
||||
@@ -87,11 +88,21 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
||||
|
||||
private static Class<?> pathClass;
|
||||
|
||||
private static Class<?> zoneIdClass;
|
||||
|
||||
static {
|
||||
ClassLoader cl = PropertyEditorRegistrySupport.class.getClassLoader();
|
||||
try {
|
||||
zoneIdClass = ClassUtils.forName("java.time.ZoneId", PropertyEditorRegistrySupport.class.getClassLoader());
|
||||
pathClass = ClassUtils.forName("java.nio.file.Path", cl);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Java 7 Path class not available
|
||||
pathClass = null;
|
||||
}
|
||||
try {
|
||||
zoneIdClass = ClassUtils.forName("java.time.ZoneId", cl);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Java 8 ZoneId class not available
|
||||
@@ -211,6 +222,9 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
||||
this.defaultEditors.put(InputStream.class, new InputStreamEditor());
|
||||
this.defaultEditors.put(InputSource.class, new InputSourceEditor());
|
||||
this.defaultEditors.put(Locale.class, new LocaleEditor());
|
||||
if (pathClass != null) {
|
||||
this.defaultEditors.put(pathClass, new PathEditor());
|
||||
}
|
||||
this.defaultEditors.put(Pattern.class, new PatternEditor());
|
||||
this.defaultEditors.put(Properties.class, new PropertiesEditor());
|
||||
this.defaultEditors.put(Reader.class, new ReaderEditor());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,8 +30,8 @@ import org.springframework.util.StringUtils;
|
||||
* Helper class for calculating property matches, according to a configurable
|
||||
* distance. Provide the list of potential matches and an easy way to generate
|
||||
* an error message. Works for both java bean properties and fields.
|
||||
* <p>
|
||||
* Mainly for use within the framework and in particular the binding facility
|
||||
*
|
||||
* <p>Mainly for use within the framework and in particular the binding facility.
|
||||
*
|
||||
* @author Alef Arendsen
|
||||
* @author Arjen Poutsma
|
||||
@@ -43,14 +43,12 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class PropertyMatches {
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Static section
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/** Default maximum property distance: 2 */
|
||||
public static final int DEFAULT_MAX_DISTANCE = 2;
|
||||
|
||||
|
||||
// Static factory methods
|
||||
|
||||
/**
|
||||
* Create PropertyMatches for the given bean property.
|
||||
* @param propertyName the name of the property to find possible matches for
|
||||
@@ -90,9 +88,7 @@ public abstract class PropertyMatches {
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Instance section
|
||||
//---------------------------------------------------------------------
|
||||
// Instance state
|
||||
|
||||
private final String propertyName;
|
||||
|
||||
@@ -107,18 +103,19 @@ public abstract class PropertyMatches {
|
||||
this.possibleMatches = possibleMatches;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of the requested property.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
return this.propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the calculated possible matches.
|
||||
*/
|
||||
public String[] getPossibleMatches() {
|
||||
return possibleMatches;
|
||||
return this.possibleMatches;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,6 +124,9 @@ public abstract class PropertyMatches {
|
||||
*/
|
||||
public abstract String buildErrorMessage();
|
||||
|
||||
|
||||
// Implementation support for subclasses
|
||||
|
||||
protected void appendHintMessage(StringBuilder msg) {
|
||||
msg.append("Did you mean ");
|
||||
for (int i = 0; i < this.possibleMatches.length; i++) {
|
||||
@@ -150,10 +150,10 @@ public abstract class PropertyMatches {
|
||||
* @return the distance value
|
||||
*/
|
||||
private static int calculateStringDistance(String s1, String s2) {
|
||||
if (s1.length() == 0) {
|
||||
if (s1.isEmpty()) {
|
||||
return s2.length();
|
||||
}
|
||||
if (s2.length() == 0) {
|
||||
if (s2.isEmpty()) {
|
||||
return s1.length();
|
||||
}
|
||||
int d[][] = new int[s1.length() + 1][s2.length() + 1];
|
||||
@@ -184,9 +184,12 @@ public abstract class PropertyMatches {
|
||||
return d[s1.length()][s2.length()];
|
||||
}
|
||||
|
||||
|
||||
// Concrete subclasses
|
||||
|
||||
private static class BeanPropertyMatches extends PropertyMatches {
|
||||
|
||||
private BeanPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
public BeanPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
super(propertyName, calculateMatches(propertyName,
|
||||
BeanUtils.getPropertyDescriptors(beanClass), maxDistance));
|
||||
}
|
||||
@@ -231,12 +234,12 @@ public abstract class PropertyMatches {
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class FieldPropertyMatches extends PropertyMatches {
|
||||
|
||||
private FieldPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
public FieldPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
super(propertyName, calculateMatches(propertyName, beanClass, maxDistance));
|
||||
}
|
||||
|
||||
@@ -255,7 +258,6 @@ public abstract class PropertyMatches {
|
||||
return StringUtils.toStringArray(candidates);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String buildErrorMessage() {
|
||||
String propertyName = getPropertyName();
|
||||
@@ -270,7 +272,6 @@ public abstract class PropertyMatches {
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -45,8 +45,6 @@ public class PropertyValue extends BeanMetadataAttributeAccessor implements Seri
|
||||
|
||||
private final Object value;
|
||||
|
||||
private Object source;
|
||||
|
||||
private boolean optional = false;
|
||||
|
||||
private boolean converted = false;
|
||||
@@ -78,12 +76,12 @@ public class PropertyValue extends BeanMetadataAttributeAccessor implements Seri
|
||||
Assert.notNull(original, "Original must not be null");
|
||||
this.name = original.getName();
|
||||
this.value = original.getValue();
|
||||
this.source = original.getSource();
|
||||
this.optional = original.isOptional();
|
||||
this.converted = original.converted;
|
||||
this.convertedValue = original.convertedValue;
|
||||
this.conversionNecessary = original.conversionNecessary;
|
||||
this.resolvedTokens = original.resolvedTokens;
|
||||
setSource(original.getSource());
|
||||
copyAttributesFrom(original);
|
||||
}
|
||||
|
||||
@@ -97,10 +95,10 @@ public class PropertyValue extends BeanMetadataAttributeAccessor implements Seri
|
||||
Assert.notNull(original, "Original must not be null");
|
||||
this.name = original.getName();
|
||||
this.value = newValue;
|
||||
this.source = original;
|
||||
this.optional = original.isOptional();
|
||||
this.conversionNecessary = original.conversionNecessary;
|
||||
this.resolvedTokens = original.resolvedTokens;
|
||||
setSource(original);
|
||||
copyAttributesFrom(original);
|
||||
}
|
||||
|
||||
@@ -129,16 +127,28 @@ public class PropertyValue extends BeanMetadataAttributeAccessor implements Seri
|
||||
*/
|
||||
public PropertyValue getOriginalPropertyValue() {
|
||||
PropertyValue original = this;
|
||||
while (original.source instanceof PropertyValue && original.source != original) {
|
||||
original = (PropertyValue) original.source;
|
||||
Object source = getSource();
|
||||
while (source instanceof PropertyValue && source != original) {
|
||||
original = (PropertyValue) source;
|
||||
source = original.getSource();
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this is an optional value, that is, to be ignored
|
||||
* when no corresponding property exists on the target class.
|
||||
* @since 3.0
|
||||
*/
|
||||
public void setOptional(boolean optional) {
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this is an optional value, that is, to be ignored
|
||||
* when no corresponding property exists on the target class.
|
||||
* @since 3.0
|
||||
*/
|
||||
public boolean isOptional() {
|
||||
return this.optional;
|
||||
}
|
||||
@@ -180,7 +190,7 @@ public class PropertyValue extends BeanMetadataAttributeAccessor implements Seri
|
||||
PropertyValue otherPv = (PropertyValue) other;
|
||||
return (this.name.equals(otherPv.name) &&
|
||||
ObjectUtils.nullSafeEquals(this.value, otherPv.value) &&
|
||||
ObjectUtils.nullSafeEquals(this.source, otherPv.source));
|
||||
ObjectUtils.nullSafeEquals(getSource(), otherPv.getSource()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -269,7 +269,7 @@ class TypeConverterDelegate {
|
||||
}
|
||||
else {
|
||||
// convertedValue == null
|
||||
if (javaUtilOptionalEmpty != null && requiredType.equals(javaUtilOptionalEmpty.getClass())) {
|
||||
if (javaUtilOptionalEmpty != null && requiredType == javaUtilOptionalEmpty.getClass()) {
|
||||
convertedValue = javaUtilOptionalEmpty;
|
||||
}
|
||||
}
|
||||
@@ -290,15 +290,15 @@ class TypeConverterDelegate {
|
||||
|
||||
// Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Cannot convert value of type [").append(ClassUtils.getDescriptiveType(newValue));
|
||||
msg.append("] to required type [").append(ClassUtils.getQualifiedName(requiredType)).append("]");
|
||||
msg.append("Cannot convert value of type '").append(ClassUtils.getDescriptiveType(newValue));
|
||||
msg.append("' to required type '").append(ClassUtils.getQualifiedName(requiredType)).append("'");
|
||||
if (propertyName != null) {
|
||||
msg.append(" for property '").append(propertyName).append("'");
|
||||
}
|
||||
if (editor != null) {
|
||||
msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
|
||||
"] returned inappropriate value of type [").append(
|
||||
ClassUtils.getDescriptiveType(convertedValue)).append("]");
|
||||
"] returned inappropriate value of type '").append(
|
||||
ClassUtils.getDescriptiveType(convertedValue)).append("'");
|
||||
throw new IllegalArgumentException(msg.toString());
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -73,7 +73,7 @@ public abstract class TypeConverterSupport extends PropertyEditorRegistrySupport
|
||||
catch (IllegalStateException ex) {
|
||||
throw new ConversionNotSupportedException(value, requiredType, ex);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
catch (IllegalArgumentException ex) {
|
||||
throw new TypeMismatchException(value, requiredType, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -57,10 +57,10 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
*/
|
||||
public TypeMismatchException(PropertyChangeEvent propertyChangeEvent, Class<?> requiredType, Throwable cause) {
|
||||
super(propertyChangeEvent,
|
||||
"Failed to convert property value of type [" +
|
||||
ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "]" +
|
||||
"Failed to convert property value of type '" +
|
||||
ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "'" +
|
||||
(requiredType != null ?
|
||||
" to required type [" + ClassUtils.getQualifiedName(requiredType) + "]" : "") +
|
||||
" to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : "") +
|
||||
(propertyChangeEvent.getPropertyName() != null ?
|
||||
" for property '" + propertyChangeEvent.getPropertyName() + "'" : ""),
|
||||
cause);
|
||||
@@ -84,8 +84,8 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
* @param cause the root cause (may be {@code null})
|
||||
*/
|
||||
public TypeMismatchException(Object value, Class<?> requiredType, Throwable cause) {
|
||||
super("Failed to convert value of type [" + ClassUtils.getDescriptiveType(value) + "]" +
|
||||
(requiredType != null ? " to required type [" + ClassUtils.getQualifiedName(requiredType) + "]" : ""),
|
||||
super("Failed to convert value of type '" + ClassUtils.getDescriptiveType(value) + "'" +
|
||||
(requiredType != null ? " to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : ""),
|
||||
cause);
|
||||
this.value = value;
|
||||
this.requiredType = requiredType;
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ public class BeanCreationException extends FatalBeanException {
|
||||
|
||||
/**
|
||||
* Add a related cause to this bean creation exception,
|
||||
* not being a direct cause of the failure but having occured
|
||||
* not being a direct cause of the failure but having occurred
|
||||
* earlier in the creation of the same bean instance.
|
||||
* @param ex the related cause to add
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -63,28 +63,35 @@ import org.springframework.core.ResolvableType;
|
||||
* are supposed to override beans of the same name in any parent factory.
|
||||
*
|
||||
* <p>Bean factory implementations should support the standard bean lifecycle interfaces
|
||||
* as far as possible. The full set of initialization methods and their standard order is:<br>
|
||||
* 1. BeanNameAware's {@code setBeanName}<br>
|
||||
* 2. BeanClassLoaderAware's {@code setBeanClassLoader}<br>
|
||||
* 3. BeanFactoryAware's {@code setBeanFactory}<br>
|
||||
* 4. ResourceLoaderAware's {@code setResourceLoader}
|
||||
* (only applicable when running in an application context)<br>
|
||||
* 5. ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
|
||||
* (only applicable when running in an application context)<br>
|
||||
* 6. MessageSourceAware's {@code setMessageSource}
|
||||
* (only applicable when running in an application context)<br>
|
||||
* 7. ApplicationContextAware's {@code setApplicationContext}
|
||||
* (only applicable when running in an application context)<br>
|
||||
* 8. ServletContextAware's {@code setServletContext}
|
||||
* (only applicable when running in a web application context)<br>
|
||||
* 9. {@code postProcessBeforeInitialization} methods of BeanPostProcessors<br>
|
||||
* 10. InitializingBean's {@code afterPropertiesSet}<br>
|
||||
* 11. a custom init-method definition<br>
|
||||
* 12. {@code postProcessAfterInitialization} methods of BeanPostProcessors
|
||||
* as far as possible. The full set of initialization methods and their standard order is:
|
||||
* <ol>
|
||||
* <li>BeanNameAware's {@code setBeanName}
|
||||
* <li>BeanClassLoaderAware's {@code setBeanClassLoader}
|
||||
* <li>BeanFactoryAware's {@code setBeanFactory}
|
||||
* <li>EnvironmentAware's {@code setEnvironment}
|
||||
* <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
|
||||
* <li>ResourceLoaderAware's {@code setResourceLoader}
|
||||
* (only applicable when running in an application context)
|
||||
* <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
|
||||
* (only applicable when running in an application context)
|
||||
* <li>MessageSourceAware's {@code setMessageSource}
|
||||
* (only applicable when running in an application context)
|
||||
* <li>ApplicationContextAware's {@code setApplicationContext}
|
||||
* (only applicable when running in an application context)
|
||||
* <li>ServletContextAware's {@code setServletContext}
|
||||
* (only applicable when running in a web application context)
|
||||
* <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
|
||||
* <li>InitializingBean's {@code afterPropertiesSet}
|
||||
* <li>a custom init-method definition
|
||||
* <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
|
||||
* </ol>
|
||||
*
|
||||
* <p>On shutdown of a bean factory, the following lifecycle methods apply:<br>
|
||||
* 1. DisposableBean's {@code destroy}<br>
|
||||
* 2. a custom destroy-method definition
|
||||
* <p>On shutdown of a bean factory, the following lifecycle methods apply:
|
||||
* <ol>
|
||||
* <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
|
||||
* <li>DisposableBean's {@code destroy}
|
||||
* <li>a custom destroy-method definition
|
||||
* </ol>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -153,12 +160,12 @@ public interface BeanFactory {
|
||||
|
||||
/**
|
||||
* Return the bean instance that uniquely matches the given object type, if any.
|
||||
* @param requiredType type the bean must match; can be an interface or superclass.
|
||||
* {@code null} is disallowed.
|
||||
* <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
|
||||
* but may also be translated into a conventional by-name lookup based on the name
|
||||
* of the given type. For more extensive retrieval operations across sets of beans,
|
||||
* use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}.
|
||||
* @param requiredType type the bean must match; can be an interface or superclass.
|
||||
* {@code null} is disallowed.
|
||||
* @return an instance of the single bean matching the required type
|
||||
* @throws NoSuchBeanDefinitionException if no bean of the given type was found
|
||||
* @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.beans.factory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Thrown when a bean doesn't match the expected type.
|
||||
@@ -45,8 +46,8 @@ public class BeanNotOfRequiredTypeException extends BeansException {
|
||||
* the expected type
|
||||
*/
|
||||
public BeanNotOfRequiredTypeException(String beanName, Class<?> requiredType, Class<?> actualType) {
|
||||
super("Bean named '" + beanName + "' must be of type [" + requiredType.getName() +
|
||||
"], but was actually of type [" + actualType.getName() + "]");
|
||||
super("Bean named '" + beanName + "' is expected to be of type '" + ClassUtils.getQualifiedName(requiredType) +
|
||||
"' but was actually of type '" + ClassUtils.getQualifiedName(actualType) + "'");
|
||||
this.beanName = beanName;
|
||||
this.requiredType = requiredType;
|
||||
this.actualType = actualType;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,31 +17,34 @@
|
||||
package org.springframework.beans.factory;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by objects used within a {@link BeanFactory}
|
||||
* which are themselves factories. If a bean implements this interface,
|
||||
* it is used as a factory for an object to expose, not directly as a bean
|
||||
* instance that will be exposed itself.
|
||||
* Interface to be implemented by objects used within a {@link BeanFactory} which
|
||||
* are themselves factories for individual objects. If a bean implements this
|
||||
* interface, it is used as a factory for an object to expose, not directly as a
|
||||
* bean instance that will be exposed itself.
|
||||
*
|
||||
* <p><b>NB: A bean that implements this interface cannot be used as a
|
||||
* normal bean.</b> A FactoryBean is defined in a bean style, but the
|
||||
* object exposed for bean references ({@link #getObject()} is always
|
||||
* the object that it creates.
|
||||
* <p><b>NB: A bean that implements this interface cannot be used as a normal bean.</b>
|
||||
* A FactoryBean is defined in a bean style, but the object exposed for bean
|
||||
* references ({@link #getObject()}) is always the object that it creates.
|
||||
*
|
||||
* <p>FactoryBeans can support singletons and prototypes, and can
|
||||
* either create objects lazily on demand or eagerly on startup.
|
||||
* The {@link SmartFactoryBean} interface allows for exposing
|
||||
* more fine-grained behavioral metadata.
|
||||
* <p>FactoryBeans can support singletons and prototypes, and can either create
|
||||
* objects lazily on demand or eagerly on startup. The {@link SmartFactoryBean}
|
||||
* interface allows for exposing more fine-grained behavioral metadata.
|
||||
*
|
||||
* <p>This interface is heavily used within the framework itself, for
|
||||
* example for the AOP {@link org.springframework.aop.framework.ProxyFactoryBean}
|
||||
* or the {@link org.springframework.jndi.JndiObjectFactoryBean}.
|
||||
* It can be used for application components as well; however,
|
||||
* this is not common outside of infrastructure code.
|
||||
* <p>This interface is heavily used within the framework itself, for example for
|
||||
* the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the
|
||||
* {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for
|
||||
* custom components as well; however, this is only common for infrastructure code.
|
||||
*
|
||||
* <p><b>NOTE:</b> FactoryBean objects participate in the containing
|
||||
* BeanFactory's synchronization of bean creation. There is usually no
|
||||
* need for internal synchronization other than for purposes of lazy
|
||||
* initialization within the FactoryBean itself (or the like).
|
||||
* <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not
|
||||
* supposed to rely on annotation-driven injection or other reflective facilities.</b>
|
||||
* {@link #getObjectType()} {@link #getObject()} invocations may arrive early in
|
||||
* the bootstrap process, even ahead of any post-processor setup. If you need access
|
||||
* other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
|
||||
*
|
||||
* <p>Finally, FactoryBean objects participate in the containing BeanFactory's
|
||||
* synchronization of bean creation. There is usually no need for internal
|
||||
* synchronization other than for purposes of lazy initialization within the
|
||||
* FactoryBean itself (or the like).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -111,6 +111,17 @@ public class InjectionPoint {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field/parameter annotation of the given type, if any.
|
||||
* @param annotationType the annotation type to retrieve
|
||||
* @return the annotation instance, or {@code null} if none found
|
||||
* @since 4.3.9
|
||||
*/
|
||||
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
|
||||
return (this.field != null ? this.field.getAnnotation(annotationType) :
|
||||
this.methodParameter.getParameterAnnotation(annotationType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type declared by the underlying field or method/constructor parameter,
|
||||
* indicating the injection type.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,10 +17,10 @@
|
||||
package org.springframework.beans.factory;
|
||||
|
||||
/**
|
||||
* Counterpart of BeanNameAware. Returns the bean name of an object.
|
||||
* Counterpart of {@link BeanNameAware}. Returns the bean name of an object.
|
||||
*
|
||||
* <p>This interface can be introduced to avoid a brittle dependence
|
||||
* on bean name in objects used with Spring IoC and Spring AOP.
|
||||
* <p>This interface can be introduced to avoid a brittle dependence on
|
||||
* bean name in objects used with Spring IoC and Spring AOP.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since 2.0
|
||||
@@ -29,7 +29,7 @@ package org.springframework.beans.factory;
|
||||
public interface NamedBean {
|
||||
|
||||
/**
|
||||
* Return the name of this bean in a Spring bean factory.
|
||||
* Return the name of this bean in a Spring bean factory, if known.
|
||||
*/
|
||||
String getBeanName();
|
||||
|
||||
|
||||
+47
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,8 @@
|
||||
package org.springframework.beans.factory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -26,6 +28,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @see BeanFactory#getBean(String)
|
||||
* @see BeanFactory#getBean(Class)
|
||||
* @see NoUniqueBeanDefinitionException
|
||||
@@ -33,11 +36,9 @@ import org.springframework.util.StringUtils;
|
||||
@SuppressWarnings("serial")
|
||||
public class NoSuchBeanDefinitionException extends BeansException {
|
||||
|
||||
/** Name of the missing bean */
|
||||
private String beanName;
|
||||
|
||||
/** Required type of the missing bean */
|
||||
private Class<?> beanType;
|
||||
private ResolvableType resolvableType;
|
||||
|
||||
|
||||
/**
|
||||
@@ -45,7 +46,7 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
||||
* @param name the name of the missing bean
|
||||
*/
|
||||
public NoSuchBeanDefinitionException(String name) {
|
||||
super("No bean named '" + name + "' is defined");
|
||||
super("No bean named '" + name + "' available");
|
||||
this.beanName = name;
|
||||
}
|
||||
|
||||
@@ -55,7 +56,7 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
||||
* @param message detailed message describing the problem
|
||||
*/
|
||||
public NoSuchBeanDefinitionException(String name, String message) {
|
||||
super("No bean named '" + name + "' is defined: " + message);
|
||||
super("No bean named '" + name + "' available: " + message);
|
||||
this.beanName = name;
|
||||
}
|
||||
|
||||
@@ -64,8 +65,7 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
||||
* @param type required type of the missing bean
|
||||
*/
|
||||
public NoSuchBeanDefinitionException(Class<?> type) {
|
||||
super("No qualifying bean of type [" + type.getName() + "] is defined");
|
||||
this.beanType = type;
|
||||
this(ResolvableType.forClass(type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,8 +74,28 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
||||
* @param message detailed message describing the problem
|
||||
*/
|
||||
public NoSuchBeanDefinitionException(Class<?> type, String message) {
|
||||
super("No qualifying bean of type [" + type.getName() + "] is defined: " + message);
|
||||
this.beanType = type;
|
||||
this(ResolvableType.forClass(type), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code NoSuchBeanDefinitionException}.
|
||||
* @param type full type declaration of the missing bean
|
||||
* @since 4.3.4
|
||||
*/
|
||||
public NoSuchBeanDefinitionException(ResolvableType type) {
|
||||
super("No qualifying bean of type '" + type + "' available");
|
||||
this.resolvableType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code NoSuchBeanDefinitionException}.
|
||||
* @param type full type declaration of the missing bean
|
||||
* @param message detailed message describing the problem
|
||||
* @since 4.3.4
|
||||
*/
|
||||
public NoSuchBeanDefinitionException(ResolvableType type, String message) {
|
||||
super("No qualifying bean of type '" + type + "' available: " + message);
|
||||
this.resolvableType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,12 +103,15 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
||||
* @param type required type of the missing bean
|
||||
* @param dependencyDescription a description of the originating dependency
|
||||
* @param message detailed message describing the problem
|
||||
* @deprecated as of 4.3.4, in favor of {@link #NoSuchBeanDefinitionException(ResolvableType, String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public NoSuchBeanDefinitionException(Class<?> type, String dependencyDescription, String message) {
|
||||
super("No qualifying bean of type [" + type.getName() + "] found for dependency" +
|
||||
super("No qualifying bean" + (!StringUtils.hasLength(dependencyDescription) ?
|
||||
" of type '" + ClassUtils.getQualifiedName(type) + "'" : "") + " found for dependency" +
|
||||
(StringUtils.hasLength(dependencyDescription) ? " [" + dependencyDescription + "]" : "") +
|
||||
": " + message);
|
||||
this.beanType = type;
|
||||
this.resolvableType = ResolvableType.forClass(type);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,10 +123,20 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the required type of the missing bean, if it was a lookup <em>by type</em> that failed.
|
||||
* Return the required type of the missing bean, if it was a lookup <em>by type</em>
|
||||
* that failed.
|
||||
*/
|
||||
public Class<?> getBeanType() {
|
||||
return this.beanType;
|
||||
return (this.resolvableType != null ? this.resolvableType.resolve() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the required {@link ResolvableType} of the missing bean, if it was a lookup
|
||||
* <em>by type</em> that failed.
|
||||
* @since 4.3.4
|
||||
*/
|
||||
public ResolvableType getResolvableType() {
|
||||
return this.resolvableType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+7
-4
@@ -18,6 +18,7 @@ package org.springframework.beans.factory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Exception thrown when a bean depends on other beans or simple properties
|
||||
@@ -46,7 +47,7 @@ public class UnsatisfiedDependencyException extends BeanCreationException {
|
||||
|
||||
super(resourceDescription, beanName,
|
||||
"Unsatisfied dependency expressed through bean property '" + propertyName + "'" +
|
||||
(msg != null ? ": " + msg : ""));
|
||||
(StringUtils.hasLength(msg) ? ": " + msg : ""));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,7 +60,7 @@ public class UnsatisfiedDependencyException extends BeanCreationException {
|
||||
public UnsatisfiedDependencyException(
|
||||
String resourceDescription, String beanName, String propertyName, BeansException ex) {
|
||||
|
||||
this(resourceDescription, beanName, propertyName, (ex != null ? ex.getMessage() : ""));
|
||||
this(resourceDescription, beanName, propertyName, "");
|
||||
initCause(ex);
|
||||
}
|
||||
|
||||
@@ -74,7 +75,9 @@ public class UnsatisfiedDependencyException extends BeanCreationException {
|
||||
public UnsatisfiedDependencyException(
|
||||
String resourceDescription, String beanName, InjectionPoint injectionPoint, String msg) {
|
||||
|
||||
super(resourceDescription, beanName, "Unsatisfied dependency expressed through " + injectionPoint + ": " + msg);
|
||||
super(resourceDescription, beanName,
|
||||
"Unsatisfied dependency expressed through " + injectionPoint +
|
||||
(StringUtils.hasLength(msg) ? ": " + msg : ""));
|
||||
this.injectionPoint = injectionPoint;
|
||||
}
|
||||
|
||||
@@ -89,7 +92,7 @@ public class UnsatisfiedDependencyException extends BeanCreationException {
|
||||
public UnsatisfiedDependencyException(
|
||||
String resourceDescription, String beanName, InjectionPoint injectionPoint, BeansException ex) {
|
||||
|
||||
this(resourceDescription, beanName, injectionPoint, (ex != null ? ex.getMessage() : ""));
|
||||
this(resourceDescription, beanName, injectionPoint, "");
|
||||
initCause(ex);
|
||||
}
|
||||
|
||||
|
||||
+67
-44
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -220,10 +220,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
|
||||
throw new IllegalArgumentException(
|
||||
"AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory");
|
||||
"AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory: " + beanFactory);
|
||||
}
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
@@ -238,35 +238,56 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
|
||||
@Override
|
||||
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeansException {
|
||||
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
|
||||
throws BeanCreationException {
|
||||
|
||||
// Let's check for lookup methods here..
|
||||
if (!this.lookupMethodsChecked.contains(beanName)) {
|
||||
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
Lookup lookup = method.getAnnotation(Lookup.class);
|
||||
if (lookup != null) {
|
||||
LookupOverride override = new LookupOverride(method, lookup.value());
|
||||
try {
|
||||
RootBeanDefinition mbd = (RootBeanDefinition) beanFactory.getMergedBeanDefinition(beanName);
|
||||
mbd.getMethodOverrides().addOverride(override);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Cannot apply @Lookup to beans without corresponding bean definition");
|
||||
try {
|
||||
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
Lookup lookup = method.getAnnotation(Lookup.class);
|
||||
if (lookup != null) {
|
||||
LookupOverride override = new LookupOverride(method, lookup.value());
|
||||
try {
|
||||
RootBeanDefinition mbd = (RootBeanDefinition) beanFactory.getMergedBeanDefinition(beanName);
|
||||
mbd.getMethodOverrides().addOverride(override);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Cannot apply @Lookup to beans without corresponding bean definition");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
|
||||
}
|
||||
catch (NoClassDefFoundError err) {
|
||||
throw new BeanCreationException(beanName, "Failed to introspect bean class [" + beanClass.getName() +
|
||||
"] for lookup method metadata: could not find class that it depends on", err);
|
||||
}
|
||||
this.lookupMethodsChecked.add(beanName);
|
||||
}
|
||||
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
|
||||
if (candidateConstructors == null) {
|
||||
// Fully synchronized resolution now...
|
||||
synchronized (this.candidateConstructorsCache) {
|
||||
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
|
||||
if (candidateConstructors == null) {
|
||||
Constructor<?>[] rawCandidates = beanClass.getDeclaredConstructors();
|
||||
Constructor<?>[] rawCandidates;
|
||||
try {
|
||||
rawCandidates = beanClass.getDeclaredConstructors();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
|
||||
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
|
||||
}
|
||||
List<Constructor<?>> candidates = new ArrayList<Constructor<?>>(rawCandidates.length);
|
||||
Constructor<?> requiredConstructor = null;
|
||||
Constructor<?> defaultConstructor = null;
|
||||
@@ -292,10 +313,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
". Found constructor with 'required' Autowired annotation already: " +
|
||||
requiredConstructor);
|
||||
}
|
||||
if (candidate.getParameterTypes().length == 0) {
|
||||
throw new IllegalStateException(
|
||||
"Autowired annotation requires at least one argument: " + candidate);
|
||||
}
|
||||
boolean required = determineRequiredStatus(ann);
|
||||
if (required) {
|
||||
if (!candidates.isEmpty()) {
|
||||
@@ -320,9 +337,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
else if (candidates.size() == 1 && logger.isWarnEnabled()) {
|
||||
logger.warn("Inconsistent constructor declaration on bean with name '" + beanName +
|
||||
"': single autowire-marked constructor flagged as optional - this constructor " +
|
||||
"is effectively required since there is no default constructor to fall back to: " +
|
||||
candidates.get(0));
|
||||
"': single autowire-marked constructor flagged as optional - " +
|
||||
"this constructor is effectively required since there is no " +
|
||||
"default constructor to fall back to: " + candidates.get(0));
|
||||
}
|
||||
}
|
||||
candidateConstructors = candidates.toArray(new Constructor<?>[candidates.size()]);
|
||||
@@ -342,7 +359,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
@Override
|
||||
public PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
|
||||
|
||||
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
|
||||
try {
|
||||
@@ -361,9 +378,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
* 'Native' processing method for direct calls with an arbitrary target instance,
|
||||
* resolving all of its fields and methods which are annotated with {@code @Autowired}.
|
||||
* @param bean the target instance to process
|
||||
* @throws BeansException if autowiring failed
|
||||
* @throws BeanCreationException if autowiring failed
|
||||
*/
|
||||
public void processInjection(Object bean) throws BeansException {
|
||||
public void processInjection(Object bean) throws BeanCreationException {
|
||||
Class<?> clazz = bean.getClass();
|
||||
InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);
|
||||
try {
|
||||
@@ -373,7 +390,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
throw ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);
|
||||
throw new BeanCreationException(
|
||||
"Injection of autowired dependencies failed for class [" + clazz + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,7 +464,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
if (method.getParameterTypes().length == 0) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Autowired annotation should be used on methods with parameters: " + method);
|
||||
logger.warn("Autowired annotation should only be used on methods with parameters: " +
|
||||
method);
|
||||
}
|
||||
}
|
||||
boolean required = determineRequiredStatus(ann);
|
||||
@@ -577,7 +596,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||
if (beanFactory.containsBean(autowiredBeanName)) {
|
||||
if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
|
||||
this.cachedFieldValue = new ShortcutDependencyDescriptor(desc, autowiredBeanName);
|
||||
this.cachedFieldValue = new ShortcutDependencyDescriptor(
|
||||
desc, autowiredBeanName, field.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -628,7 +648,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
arguments = new Object[paramTypes.length];
|
||||
DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(paramTypes.length);
|
||||
Set<String> autowiredBeans = new LinkedHashSet<String>(paramTypes.length);
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
@@ -636,7 +656,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
currDesc.setContainingClass(bean.getClass());
|
||||
descriptors[i] = currDesc;
|
||||
try {
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeanNames, typeConverter);
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
|
||||
if (arg == null && !this.required) {
|
||||
arguments = null;
|
||||
break;
|
||||
@@ -654,15 +674,15 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
this.cachedMethodArguments[i] = descriptors[i];
|
||||
}
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == paramTypes.length) {
|
||||
Iterator<String> it = autowiredBeanNames.iterator();
|
||||
registerDependentBeans(beanName, autowiredBeans);
|
||||
if (autowiredBeans.size() == paramTypes.length) {
|
||||
Iterator<String> it = autowiredBeans.iterator();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
String autowiredBeanName = it.next();
|
||||
if (beanFactory.containsBean(autowiredBeanName)) {
|
||||
if (beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
|
||||
this.cachedMethodArguments[i] =
|
||||
new ShortcutDependencyDescriptor(descriptors[i], autowiredBeanName);
|
||||
this.cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
|
||||
descriptors[i], autowiredBeanName, paramTypes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -705,16 +725,19 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
@SuppressWarnings("serial")
|
||||
private static class ShortcutDependencyDescriptor extends DependencyDescriptor {
|
||||
|
||||
private final String shortcutBeanName;
|
||||
private final String shortcut;
|
||||
|
||||
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcutBeanName) {
|
||||
private final Class<?> requiredType;
|
||||
|
||||
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) {
|
||||
super(original);
|
||||
this.shortcutBeanName = shortcutBeanName;
|
||||
this.shortcut = shortcut;
|
||||
this.requiredType = requiredType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveShortcut(BeanFactory beanFactory) {
|
||||
return resolveCandidate(this.shortcutBeanName, beanFactory);
|
||||
return resolveCandidate(this.shortcut, this.requiredType, beanFactory);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,27 +18,30 @@ package org.springframework.beans.factory.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
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.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Convenience methods performing bean lookups related to annotations, for example
|
||||
* Spring's {@link Qualifier @Qualifier} annotation.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 3.1.2
|
||||
* @see BeanFactoryUtils
|
||||
*/
|
||||
public class BeanFactoryAnnotationUtils {
|
||||
public abstract class BeanFactoryAnnotationUtils {
|
||||
|
||||
/**
|
||||
* Obtain a bean of type {@code T} from the given {@code BeanFactory} declaring a
|
||||
@@ -48,9 +51,16 @@ public class BeanFactoryAnnotationUtils {
|
||||
* @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 NoUniqueBeanDefinitionException if multiple matching beans of type {@code T} found
|
||||
* @throws NoSuchBeanDefinitionException if no matching bean of type {@code T} found
|
||||
* @throws BeansException if the bean could not be created
|
||||
* @see BeanFactory#getBean(Class)
|
||||
*/
|
||||
public static <T> T qualifiedBeanOfType(BeanFactory beanFactory, Class<T> beanType, String qualifier) {
|
||||
public static <T> T qualifiedBeanOfType(BeanFactory beanFactory, Class<T> beanType, String qualifier)
|
||||
throws BeansException {
|
||||
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
||||
|
||||
if (beanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
// Full qualifier matching supported.
|
||||
return qualifiedBeanOfType((ConfigurableListableBeanFactory) beanFactory, beanType, qualifier);
|
||||
@@ -74,7 +84,6 @@ public class BeanFactoryAnnotationUtils {
|
||||
* @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) {
|
||||
String[] candidateBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(bf, beanType);
|
||||
@@ -82,8 +91,7 @@ public class BeanFactoryAnnotationUtils {
|
||||
for (String beanName : candidateBeans) {
|
||||
if (isQualifierMatch(qualifier, beanName, bf)) {
|
||||
if (matchingBean != null) {
|
||||
throw new NoSuchBeanDefinitionException(qualifier, "No unique " + beanType.getSimpleName() +
|
||||
" bean found for qualifier '" + qualifier + "'");
|
||||
throw new NoUniqueBeanDefinitionException(beanType, matchingBean, beanName);
|
||||
}
|
||||
matchingBean = beanName;
|
||||
}
|
||||
|
||||
+2
-1
@@ -40,6 +40,7 @@ import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcess
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -349,7 +350,7 @@ public class InitDestroyAnnotationBeanPostProcessor
|
||||
}
|
||||
this.method = method;
|
||||
this.identifier = (Modifier.isPrivate(method.getModifiers()) ?
|
||||
method.getDeclaringClass() + "." + method.getName() : method.getName());
|
||||
ClassUtils.getQualifiedMethodName(method) : method.getName());
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
|
||||
+29
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.beans.factory.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
@@ -49,6 +50,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.5
|
||||
* @see AutowireCandidateQualifier
|
||||
* @see Qualifier
|
||||
@@ -225,8 +227,12 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
||||
qualifier = bd.getQualifier(ClassUtils.getShortName(type));
|
||||
}
|
||||
if (qualifier == null) {
|
||||
// First, check annotation on factory method, if applicable
|
||||
Annotation targetAnnotation = getFactoryMethodAnnotation(bd, type);
|
||||
// First, check annotation on qualified element, if any
|
||||
Annotation targetAnnotation = getQualifiedElementAnnotation(bd, type);
|
||||
// Then, check annotation on factory method, if applicable
|
||||
if (targetAnnotation == null) {
|
||||
targetAnnotation = getFactoryMethodAnnotation(bd, type);
|
||||
}
|
||||
if (targetAnnotation == null) {
|
||||
RootBeanDefinition dbd = getResolvedDecoratedDefinition(bd);
|
||||
if (dbd != null) {
|
||||
@@ -291,6 +297,11 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Annotation getQualifiedElementAnnotation(RootBeanDefinition bd, Class<? extends Annotation> type) {
|
||||
AnnotatedElement qualifiedElement = bd.getQualifiedElement();
|
||||
return (qualifiedElement != null ? AnnotationUtils.getAnnotation(qualifiedElement, type) : null);
|
||||
}
|
||||
|
||||
protected Annotation getFactoryMethodAnnotation(RootBeanDefinition bd, Class<? extends Annotation> type) {
|
||||
Method resolvedFactoryMethod = bd.getResolvedFactoryMethod();
|
||||
return (resolvedFactoryMethod != null ? AnnotationUtils.getAnnotation(resolvedFactoryMethod, type) : null);
|
||||
@@ -298,7 +309,21 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the given dependency carries a value annotation.
|
||||
* Determine whether the given dependency declares an autowired annotation,
|
||||
* checking its required flag.
|
||||
* @see Autowired#required()
|
||||
*/
|
||||
@Override
|
||||
public boolean isRequired(DependencyDescriptor descriptor) {
|
||||
if (!super.isRequired(descriptor)) {
|
||||
return false;
|
||||
}
|
||||
Autowired autowired = descriptor.getAnnotation(Autowired.class);
|
||||
return (autowired == null || autowired.required());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given dependency declares a value annotation.
|
||||
* @see Value
|
||||
*/
|
||||
@Override
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -141,8 +141,7 @@ public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanP
|
||||
|
||||
@Override
|
||||
public PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
|
||||
throws BeansException {
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
|
||||
|
||||
if (!this.validatedBeanNames.contains(beanName)) {
|
||||
if (!shouldSkip(this.beanFactory, beanName)) {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -208,7 +208,7 @@ public abstract class AbstractFactoryBean<T>
|
||||
* <p>Invoked on initialization of this FactoryBean in case of
|
||||
* a singleton; else, on each {@link #getObject()} call.
|
||||
* @return the object returned by this factory
|
||||
* @throws Exception if an exception occured during object creation
|
||||
* @throws Exception if an exception occurred during object creation
|
||||
* @see #getObject()
|
||||
*/
|
||||
protected abstract T createInstance() throws Exception;
|
||||
|
||||
+47
-17
@@ -21,6 +21,8 @@ import java.util.Set;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
|
||||
/**
|
||||
* Extension of the {@link org.springframework.beans.factory.BeanFactory}
|
||||
@@ -154,15 +156,6 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
|
||||
*/
|
||||
Object configureBean(Object existingBean, String beanName) throws BeansException;
|
||||
|
||||
/**
|
||||
* Resolve the specified dependency against the beans defined in this factory.
|
||||
* @param descriptor the descriptor for the dependency
|
||||
* @param beanName the name of the bean which declares the present dependency
|
||||
* @return the resolved object, or {@code null} if none found
|
||||
* @throws BeansException if dependency resolution failed
|
||||
*/
|
||||
Object resolveDependency(DependencyDescriptor descriptor, String beanName) throws BeansException;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Specialized methods for fine-grained control over the bean lifecycle
|
||||
@@ -312,18 +305,55 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
|
||||
*/
|
||||
void destroyBean(Object existingBean);
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Delegate methods for resolving injection points
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Resolve the bean instance that uniquely matches the given object type, if any,
|
||||
* including its bean name.
|
||||
* <p>This is effectively a variant of {@link #getBean(Class)} which preserves the
|
||||
* bean name of the matching instance.
|
||||
* @param requiredType type the bean must match; can be an interface or superclass.
|
||||
* {@code null} is disallowed.
|
||||
* @return the bean name plus bean instance
|
||||
* @throws NoSuchBeanDefinitionException if no matching bean was found
|
||||
* @throws NoUniqueBeanDefinitionException if more than one matching bean was found
|
||||
* @throws BeansException if the bean could not be created
|
||||
* @since 4.3.3
|
||||
* @see #getBean(Class)
|
||||
*/
|
||||
<T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
|
||||
|
||||
/**
|
||||
* Resolve the specified dependency against the beans defined in this factory.
|
||||
* @param descriptor the descriptor for the dependency
|
||||
* @param beanName the name of the bean which declares the present dependency
|
||||
* @param autowiredBeanNames a Set that all names of autowired beans (used for
|
||||
* resolving the present dependency) are supposed to be added to
|
||||
* @param typeConverter the TypeConverter to use for populating arrays and
|
||||
* collections
|
||||
* @param descriptor the descriptor for the dependency (field/method/constructor)
|
||||
* @param requestingBeanName the name of the bean which declares the given dependency
|
||||
* @return the resolved object, or {@code null} if none found
|
||||
* @throws BeansException if dependency resolution failed
|
||||
* @throws NoSuchBeanDefinitionException if no matching bean was found
|
||||
* @throws NoUniqueBeanDefinitionException if more than one matching bean was found
|
||||
* @throws BeansException if dependency resolution failed for any other reason
|
||||
* @since 2.5
|
||||
* @see #resolveDependency(DependencyDescriptor, String, Set, TypeConverter)
|
||||
*/
|
||||
Object resolveDependency(DependencyDescriptor descriptor, String beanName,
|
||||
Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName) throws BeansException;
|
||||
|
||||
/**
|
||||
* Resolve the specified dependency against the beans defined in this factory.
|
||||
* @param descriptor the descriptor for the dependency (field/method/constructor)
|
||||
* @param requestingBeanName the name of the bean which declares the given dependency
|
||||
* @param autowiredBeanNames a Set that all names of autowired beans (used for
|
||||
* resolving the given dependency) are supposed to be added to
|
||||
* @param typeConverter the TypeConverter to use for populating arrays and collections
|
||||
* @return the resolved object, or {@code null} if none found
|
||||
* @throws NoSuchBeanDefinitionException if no matching bean was found
|
||||
* @throws NoUniqueBeanDefinitionException if more than one matching bean was found
|
||||
* @throws BeansException if dependency resolution failed for any other reason
|
||||
* @since 2.5
|
||||
* @see DependencyDescriptor
|
||||
*/
|
||||
Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName,
|
||||
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException;
|
||||
|
||||
}
|
||||
|
||||
+72
-58
@@ -79,10 +79,7 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
int ROLE_INFRASTRUCTURE = 2;
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of the parent definition of this bean definition, if any.
|
||||
*/
|
||||
String getParentName();
|
||||
// Modifiable attributes
|
||||
|
||||
/**
|
||||
* Set the name of the parent definition of this bean definition, if any.
|
||||
@@ -90,52 +87,33 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
void setParentName(String parentName);
|
||||
|
||||
/**
|
||||
* Return the current bean class name of this bean definition.
|
||||
* <p>Note that this does not have to be the actual class name used at runtime, in
|
||||
* case of a child definition overriding/inheriting the class name from its parent.
|
||||
* Hence, do <i>not</i> consider this to be the definitive bean type at runtime but
|
||||
* rather only use it for parsing purposes at the individual bean definition level.
|
||||
* Return the name of the parent definition of this bean definition, if any.
|
||||
*/
|
||||
String getBeanClassName();
|
||||
String getParentName();
|
||||
|
||||
/**
|
||||
* Override the bean class name of this bean definition.
|
||||
* Specify the bean class name of this bean definition.
|
||||
* <p>The class name can be modified during bean factory post-processing,
|
||||
* typically replacing the original class name with a parsed variant of it.
|
||||
* @see #setParentName
|
||||
* @see #setFactoryBeanName
|
||||
* @see #setFactoryMethodName
|
||||
*/
|
||||
void setBeanClassName(String beanClassName);
|
||||
|
||||
/**
|
||||
* Return the factory bean name, if any.
|
||||
* Return the current bean class name of this bean definition.
|
||||
* <p>Note that this does not have to be the actual class name used at runtime, in
|
||||
* case of a child definition overriding/inheriting the class name from its parent.
|
||||
* Also, this may just be the class that a factory method is called on, or it may
|
||||
* even be empty in case of a factory bean reference that a method is called on.
|
||||
* Hence, do <i>not</i> consider this to be the definitive bean type at runtime but
|
||||
* rather only use it for parsing purposes at the individual bean definition level.
|
||||
* @see #getParentName()
|
||||
* @see #getFactoryBeanName()
|
||||
* @see #getFactoryMethodName()
|
||||
*/
|
||||
String getFactoryBeanName();
|
||||
|
||||
/**
|
||||
* Specify the factory bean to use, if any.
|
||||
*/
|
||||
void setFactoryBeanName(String factoryBeanName);
|
||||
|
||||
/**
|
||||
* Return a factory method, if any.
|
||||
*/
|
||||
String getFactoryMethodName();
|
||||
|
||||
/**
|
||||
* Specify a factory method, if any. This method will be invoked with
|
||||
* constructor arguments, or with no arguments if none are specified.
|
||||
* The method will be invoked on the specified factory bean, if any,
|
||||
* or otherwise as a static method on the local bean class.
|
||||
* @param factoryMethodName static factory method name,
|
||||
* or {@code null} if normal constructor creation should be used
|
||||
* @see #getBeanClassName()
|
||||
*/
|
||||
void setFactoryMethodName(String factoryMethodName);
|
||||
|
||||
/**
|
||||
* Return the name of the current target scope for this bean,
|
||||
* or {@code null} if not known yet.
|
||||
*/
|
||||
String getScope();
|
||||
String getBeanClassName();
|
||||
|
||||
/**
|
||||
* Override the target scope of this bean, specifying a new scope name.
|
||||
@@ -145,10 +123,10 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
void setScope(String scope);
|
||||
|
||||
/**
|
||||
* Return whether this bean should be lazily initialized, i.e. not
|
||||
* eagerly instantiated on startup. Only applicable to a singleton bean.
|
||||
* Return the name of the current target scope for this bean,
|
||||
* or {@code null} if not known yet.
|
||||
*/
|
||||
boolean isLazyInit();
|
||||
String getScope();
|
||||
|
||||
/**
|
||||
* Set whether this bean should be lazily initialized.
|
||||
@@ -158,9 +136,10 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
void setLazyInit(boolean lazyInit);
|
||||
|
||||
/**
|
||||
* Return the bean names that this bean depends on.
|
||||
* Return whether this bean should be lazily initialized, i.e. not
|
||||
* eagerly instantiated on startup. Only applicable to a singleton bean.
|
||||
*/
|
||||
String[] getDependsOn();
|
||||
boolean isLazyInit();
|
||||
|
||||
/**
|
||||
* Set the names of the beans that this bean depends on being initialized.
|
||||
@@ -168,30 +147,63 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
*/
|
||||
void setDependsOn(String... dependsOn);
|
||||
|
||||
/**
|
||||
* Return the bean names that this bean depends on.
|
||||
*/
|
||||
String[] getDependsOn();
|
||||
|
||||
/**
|
||||
* Set whether this bean is a candidate for getting autowired into some other bean.
|
||||
* <p>Note that this flag is designed to only affect type-based autowiring.
|
||||
* It does not affect explicit references by name, which will get resolved even
|
||||
* if the specified bean is not marked as an autowire candidate. As a consequence,
|
||||
* autowiring by name will nevertheless inject a bean if the name matches.
|
||||
*/
|
||||
void setAutowireCandidate(boolean autowireCandidate);
|
||||
|
||||
/**
|
||||
* Return whether this bean is a candidate for getting autowired into some other bean.
|
||||
*/
|
||||
boolean isAutowireCandidate();
|
||||
|
||||
/**
|
||||
* Set whether this bean is a candidate for getting autowired into some other bean.
|
||||
*/
|
||||
void setAutowireCandidate(boolean autowireCandidate);
|
||||
|
||||
/**
|
||||
* Return whether this bean is a primary autowire candidate.
|
||||
* If this value is true for exactly one bean among multiple
|
||||
* matching candidates, it will serve as a tie-breaker.
|
||||
*/
|
||||
boolean isPrimary();
|
||||
|
||||
/**
|
||||
* Set whether this bean is a primary autowire candidate.
|
||||
* <p>If this value is true for exactly one bean among multiple
|
||||
* <p>If this value is {@code true} for exactly one bean among multiple
|
||||
* matching candidates, it will serve as a tie-breaker.
|
||||
*/
|
||||
void setPrimary(boolean primary);
|
||||
|
||||
/**
|
||||
* Return whether this bean is a primary autowire candidate.
|
||||
*/
|
||||
boolean isPrimary();
|
||||
|
||||
/**
|
||||
* Specify the factory bean to use, if any.
|
||||
* This the name of the bean to call the specified factory method on.
|
||||
* @see #setFactoryMethodName
|
||||
*/
|
||||
void setFactoryBeanName(String factoryBeanName);
|
||||
|
||||
/**
|
||||
* Return the factory bean name, if any.
|
||||
*/
|
||||
String getFactoryBeanName();
|
||||
|
||||
/**
|
||||
* Specify a factory method, if any. This method will be invoked with
|
||||
* constructor arguments, or with no arguments if none are specified.
|
||||
* The method will be invoked on the specified factory bean, if any,
|
||||
* or otherwise as a static method on the local bean class.
|
||||
* @see #setFactoryBeanName
|
||||
* @see #setBeanClassName
|
||||
*/
|
||||
void setFactoryMethodName(String factoryMethodName);
|
||||
|
||||
/**
|
||||
* Return a factory method, if any.
|
||||
*/
|
||||
String getFactoryMethodName();
|
||||
|
||||
/**
|
||||
* Return the constructor argument values for this bean.
|
||||
@@ -208,6 +220,8 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
MutablePropertyValues getPropertyValues();
|
||||
|
||||
|
||||
// Read-only attributes
|
||||
|
||||
/**
|
||||
* Return whether this a <b>Singleton</b>, with a single, shared instance
|
||||
* returned on all calls.
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -102,12 +102,12 @@ public class CustomScopeConfigurer implements BeanFactoryPostProcessor, BeanClas
|
||||
}
|
||||
else if (value instanceof Class) {
|
||||
Class<?> scopeClass = (Class<?>) value;
|
||||
Assert.isAssignable(Scope.class, scopeClass);
|
||||
Assert.isAssignable(Scope.class, scopeClass, "Invalid scope class");
|
||||
beanFactory.registerScope(scopeKey, (Scope) BeanUtils.instantiateClass(scopeClass));
|
||||
}
|
||||
else if (value instanceof String) {
|
||||
Class<?> scopeClass = ClassUtils.resolveClassName((String) value, this.beanClassLoader);
|
||||
Assert.isAssignable(Scope.class, scopeClass);
|
||||
Assert.isAssignable(Scope.class, scopeClass, "Invalid scope class");
|
||||
beanFactory.registerScope(scopeKey, (Scope) BeanUtils.instantiateClass(scopeClass));
|
||||
}
|
||||
else {
|
||||
|
||||
+44
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,7 +28,6 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.InjectionPoint;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
@@ -63,6 +62,8 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
|
||||
private Class<?> containingClass;
|
||||
|
||||
private volatile ResolvableType resolvableType;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new descriptor for a method or constructor parameter.
|
||||
@@ -172,21 +173,6 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the specified bean name, as a candidate result of the matching
|
||||
* algorithm for this dependency, to a bean instance from the given factory.
|
||||
* <p>The default implementation calls {@link BeanFactory#getBean(String)}.
|
||||
* Subclasses may provide additional arguments or other customizations.
|
||||
* @param beanName the bean name, as a candidate result for this dependency
|
||||
* @param beanFactory the associated factory
|
||||
* @return the bean instance (never {@code null})
|
||||
* @since 4.3
|
||||
* @see BeanFactory#getBean(String)
|
||||
*/
|
||||
public Object resolveCandidate(String beanName, BeanFactory beanFactory) {
|
||||
return beanFactory.getBean(beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a shortcut for this dependency against the given factory, for example
|
||||
* taking some pre-resolved information into account.
|
||||
@@ -196,12 +182,32 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
* pre-cached information while still receiving {@link InjectionPoint} exposure etc.
|
||||
* @param beanFactory the associated factory
|
||||
* @return the shortcut result if any, or {@code null} if none
|
||||
* @throws BeansException if the shortcut could not be obtained
|
||||
* @since 4.3.1
|
||||
*/
|
||||
public Object resolveShortcut(BeanFactory beanFactory) {
|
||||
public Object resolveShortcut(BeanFactory beanFactory) throws BeansException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the specified bean name, as a candidate result of the matching
|
||||
* algorithm for this dependency, to a bean instance from the given factory.
|
||||
* <p>The default implementation calls {@link BeanFactory#getBean(String)}.
|
||||
* Subclasses may provide additional arguments or other customizations.
|
||||
* @param beanName the bean name, as a candidate result for this dependency
|
||||
* @param requiredType the expected type of the bean (as an assertion)
|
||||
* @param beanFactory the associated factory
|
||||
* @return the bean instance (never {@code null})
|
||||
* @throws BeansException if the bean could not be obtained
|
||||
* @since 4.3.2
|
||||
* @see BeanFactory#getBean(String)
|
||||
*/
|
||||
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
|
||||
return beanFactory.getBean(beanName, requiredType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Increase this descriptor's nesting level.
|
||||
@@ -209,6 +215,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
*/
|
||||
public void increaseNestingLevel() {
|
||||
this.nestingLevel++;
|
||||
this.resolvableType = null;
|
||||
if (this.methodParameter != null) {
|
||||
this.methodParameter.increaseNestingLevel();
|
||||
}
|
||||
@@ -222,6 +229,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
*/
|
||||
public void setContainingClass(Class<?> containingClass) {
|
||||
this.containingClass = containingClass;
|
||||
this.resolvableType = null;
|
||||
if (this.methodParameter != null) {
|
||||
GenericTypeResolver.resolveParameterType(this.methodParameter, containingClass);
|
||||
}
|
||||
@@ -232,8 +240,12 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
* @since 4.0
|
||||
*/
|
||||
public ResolvableType getResolvableType() {
|
||||
return (this.field != null ? ResolvableType.forField(this.field, this.nestingLevel, this.containingClass) :
|
||||
ResolvableType.forMethodParameter(this.methodParameter));
|
||||
if (this.resolvableType == null) {
|
||||
this.resolvableType = (this.field != null ?
|
||||
ResolvableType.forField(this.field, this.nestingLevel, this.containingClass) :
|
||||
ResolvableType.forMethodParameter(this.methodParameter));
|
||||
}
|
||||
return this.resolvableType;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,31 +331,37 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
/**
|
||||
* Determine the generic element type of the wrapped Collection parameter/field, if any.
|
||||
* @return the generic type, or {@code null} if none
|
||||
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
|
||||
*/
|
||||
@Deprecated
|
||||
public Class<?> getCollectionType() {
|
||||
return (this.field != null ?
|
||||
GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
|
||||
GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
|
||||
org.springframework.core.GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
|
||||
org.springframework.core.GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the generic key type of the wrapped Map parameter/field, if any.
|
||||
* @return the generic type, or {@code null} if none
|
||||
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
|
||||
*/
|
||||
@Deprecated
|
||||
public Class<?> getMapKeyType() {
|
||||
return (this.field != null ?
|
||||
GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
|
||||
GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
|
||||
org.springframework.core.GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
|
||||
org.springframework.core.GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the generic value type of the wrapped Map parameter/field, if any.
|
||||
* @return the generic type, or {@code null} if none
|
||||
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
|
||||
*/
|
||||
@Deprecated
|
||||
public Class<?> getMapValueType() {
|
||||
return (this.field != null ?
|
||||
GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
|
||||
GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
|
||||
org.springframework.core.GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
|
||||
org.springframework.core.GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -71,9 +71,8 @@ public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
|
||||
/**
|
||||
* Perform operations after the bean has been instantiated, via a constructor or factory method,
|
||||
* but before Spring property population (from explicit properties or autowiring) occurs.
|
||||
* <p>This is the ideal callback for performing field injection on the given bean instance.
|
||||
* See Spring's own {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor}
|
||||
* for a typical example.
|
||||
* <p>This is the ideal callback for performing custom field injection on the given bean
|
||||
* instance, right before Spring's autowiring kicks in.
|
||||
* @param bean the bean instance created, with properties not having been set yet
|
||||
* @param beanName the name of the bean
|
||||
* @return {@code true} if properties should be set on the bean; {@code false}
|
||||
@@ -103,7 +102,6 @@ public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
|
||||
* @see org.springframework.beans.MutablePropertyValues
|
||||
*/
|
||||
PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
|
||||
throws BeansException;
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;
|
||||
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -66,8 +66,7 @@ public abstract class InstantiationAwareBeanPostProcessorAdapter implements Smar
|
||||
|
||||
@Override
|
||||
public PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
|
||||
throws BeansException {
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
|
||||
|
||||
return pvs;
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
/**
|
||||
* Simple factory for shared List instances. Allows for central setup
|
||||
@@ -86,7 +86,7 @@ public class ListFactoryBean extends AbstractFactoryBean<List<Object>> {
|
||||
}
|
||||
Class<?> valueType = null;
|
||||
if (this.targetListClass != null) {
|
||||
valueType = GenericCollectionTypeResolver.getCollectionType(this.targetListClass);
|
||||
valueType = ResolvableType.forClass(this.targetListClass).asCollection().resolveGeneric();
|
||||
}
|
||||
if (valueType != null) {
|
||||
TypeConverter converter = getBeanTypeConverter();
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,7 @@ import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
/**
|
||||
* Simple factory for shared Map instances. Allows for central setup
|
||||
@@ -87,8 +87,9 @@ public class MapFactoryBean extends AbstractFactoryBean<Map<Object, Object>> {
|
||||
Class<?> keyType = null;
|
||||
Class<?> valueType = null;
|
||||
if (this.targetMapClass != null) {
|
||||
keyType = GenericCollectionTypeResolver.getMapKeyType(this.targetMapClass);
|
||||
valueType = GenericCollectionTypeResolver.getMapValueType(this.targetMapClass);
|
||||
ResolvableType mapType = ResolvableType.forClass(this.targetMapClass).asMap();
|
||||
keyType = mapType.resolveGeneric(0);
|
||||
valueType = mapType.resolveGeneric(1);
|
||||
}
|
||||
if (keyType != null || valueType != null) {
|
||||
TypeConverter converter = getBeanTypeConverter();
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -69,7 +69,7 @@ import org.springframework.beans.factory.FactoryBeanNotInitializedException;
|
||||
* </bean>
|
||||
*
|
||||
* <bean id="javaVersion" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
|
||||
* <property name="targetObject" value="sysProps"/>
|
||||
* <property name="targetObject" ref="sysProps"/>
|
||||
* <property name="targetMethod" value="getProperty"/>
|
||||
* <property name="arguments" value="java.version"/>
|
||||
* </bean></pre>
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.factory.NamedBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A simple holder for a given bean name plus bean instance.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.3.3
|
||||
* @see AutowireCapableBeanFactory#resolveNamedBean(Class)
|
||||
*/
|
||||
public class NamedBeanHolder<T> implements NamedBean {
|
||||
|
||||
private final String beanName;
|
||||
|
||||
private final T beanInstance;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new holder for the given bean name plus instance.
|
||||
* @param beanName the name of the bean
|
||||
* @param beanInstance the corresponding bean instance
|
||||
*/
|
||||
public NamedBeanHolder(String beanName, T beanInstance) {
|
||||
Assert.notNull(beanName, "Bean name must not be null");
|
||||
this.beanName = beanName;
|
||||
this.beanInstance = beanInstance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of the bean (never {@code null}).
|
||||
*/
|
||||
@Override
|
||||
public String getBeanName() {
|
||||
return this.beanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the corresponding bean instance (can be {@code null}).
|
||||
*/
|
||||
public T getBeanInstance() {
|
||||
return this.beanInstance;
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -95,7 +95,7 @@ public class PropertiesFactoryBean extends PropertiesLoaderSupport
|
||||
* <p>Invoked on initialization of this FactoryBean in case of a
|
||||
* shared singleton; else, on each {@link #getObject()} call.
|
||||
* @return the object returned by this factory
|
||||
* @throws IOException if an exception occured during properties loading
|
||||
* @throws IOException if an exception occurred during properties loading
|
||||
* @see #mergeProperties()
|
||||
*/
|
||||
protected Properties createProperties() throws IOException {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -68,6 +68,7 @@ public interface Scope {
|
||||
* @param objectFactory the {@link ObjectFactory} to use to create the scoped
|
||||
* object if it is not present in the underlying storage mechanism
|
||||
* @return the desired object (never {@code null})
|
||||
* @throws IllegalStateException if the underlying scope is not currently active
|
||||
*/
|
||||
Object get(String name, ObjectFactory<?> objectFactory);
|
||||
|
||||
@@ -84,6 +85,7 @@ public interface Scope {
|
||||
* removing an object.
|
||||
* @param name the name of the object to remove
|
||||
* @return the removed object, or {@code null} if no object was present
|
||||
* @throws IllegalStateException if the underlying scope is not currently active
|
||||
* @see #registerDestructionCallback
|
||||
*/
|
||||
Object remove(String name);
|
||||
@@ -112,6 +114,7 @@ public interface Scope {
|
||||
* 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.
|
||||
* @throws IllegalStateException if the underlying scope is not currently active
|
||||
* @see org.springframework.beans.factory.DisposableBean
|
||||
* @see org.springframework.beans.factory.support.AbstractBeanDefinition#getDestroyMethodName()
|
||||
* @see DestructionAwareBeanPostProcessor
|
||||
@@ -123,6 +126,7 @@ public interface Scope {
|
||||
* E.g. the HttpServletRequest object for key "request".
|
||||
* @param key the contextual key
|
||||
* @return the corresponding object, or {@code null} if none found
|
||||
* @throws IllegalStateException if the underlying scope is not currently active
|
||||
*/
|
||||
Object resolveContextualObject(String key);
|
||||
|
||||
@@ -139,6 +143,7 @@ public interface Scope {
|
||||
* underlying storage mechanism has no obvious candidate for such an ID.
|
||||
* @return the conversation ID, or {@code null} if there is no
|
||||
* conversation ID for the current scope
|
||||
* @throws IllegalStateException if the underlying scope is not currently active
|
||||
*/
|
||||
String getConversationId();
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,7 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
/**
|
||||
* Simple factory for shared Set instances. Allows for central setup
|
||||
@@ -86,7 +86,7 @@ public class SetFactoryBean extends AbstractFactoryBean<Set<Object>> {
|
||||
}
|
||||
Class<?> valueType = null;
|
||||
if (this.targetSetClass != null) {
|
||||
valueType = GenericCollectionTypeResolver.getCollectionType(this.targetSetClass);
|
||||
valueType = ResolvableType.forClass(this.targetSetClass).asCollection().resolveGeneric();
|
||||
}
|
||||
if (valueType != null) {
|
||||
TypeConverter converter = getBeanTypeConverter();
|
||||
|
||||
+14
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,12 +25,16 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Factory for a Map that reads from a YAML source. YAML is a nice human-readable
|
||||
* format for configuration, and it has some useful hierarchical properties. It's
|
||||
* more or less a superset of JSON, so it has a lot of similar features. If
|
||||
* multiple resources are provided the later ones will override entries in the
|
||||
* earlier ones hierarchically - that is all entries with the same nested key of
|
||||
* type Map at any depth are merged. For example:
|
||||
* Factory for a {@code Map} that reads from a YAML source, preserving the
|
||||
* YAML-declared value types and their structure.
|
||||
*
|
||||
* <p>YAML is a nice human-readable format for configuration, and it has some
|
||||
* useful hierarchical properties. It's more or less a superset of JSON, so it
|
||||
* has a lot of similar features.
|
||||
*
|
||||
* <p>If multiple resources are provided the later ones will override entries in
|
||||
* the earlier ones hierarchically; that is, all entries with the same nested key
|
||||
* of type {@code Map} at any depth are merged. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* foo:
|
||||
@@ -62,6 +66,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
* with the value in the second, but its nested values are merged.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
*/
|
||||
public class YamlMapFactoryBean extends YamlProcessor implements FactoryBean<Map<String, Object>>, InitializingBean {
|
||||
@@ -104,10 +109,10 @@ public class YamlMapFactoryBean extends YamlProcessor implements FactoryBean<Map
|
||||
|
||||
/**
|
||||
* Template method that subclasses may override to construct the object
|
||||
* returned by this factory. The default implementation returns the
|
||||
* merged Map instance.
|
||||
* returned by this factory.
|
||||
* <p>Invoked lazily the first time {@link #getObject()} is invoked in
|
||||
* case of a shared singleton; else, on each {@link #getObject()} call.
|
||||
* <p>The default implementation returns the merged {@code Map} instance.
|
||||
* @return the object returned by this factory
|
||||
* @see #process(java.util.Map, MatchCallback)
|
||||
*/
|
||||
|
||||
+12
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,6 +37,7 @@ import org.yaml.snakeyaml.nodes.MappingNode;
|
||||
import org.yaml.snakeyaml.parser.ParserException;
|
||||
import org.yaml.snakeyaml.reader.UnicodeReader;
|
||||
|
||||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -45,6 +46,7 @@ import org.springframework.util.StringUtils;
|
||||
* Base class for YAML factories.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
*/
|
||||
public abstract class YamlProcessor {
|
||||
@@ -217,7 +219,7 @@ public abstract class YamlProcessor {
|
||||
}
|
||||
|
||||
private boolean process(Map<String, Object> map, MatchCallback callback) {
|
||||
Properties properties = new Properties();
|
||||
Properties properties = CollectionFactory.createStringAdaptingProperties();
|
||||
properties.putAll(getFlattenedMap(map));
|
||||
|
||||
if (this.documentMatchers.isEmpty()) {
|
||||
@@ -278,7 +280,7 @@ public abstract class YamlProcessor {
|
||||
key = path + key;
|
||||
}
|
||||
else {
|
||||
key = path + "." + key;
|
||||
key = path + '.' + key;
|
||||
}
|
||||
}
|
||||
Object value = entry.getValue();
|
||||
@@ -302,21 +304,23 @@ public abstract class YamlProcessor {
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.put(key, value != null ? value : "");
|
||||
result.put(key, (value != null ? value : ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback interface used to process properties in a resulting map.
|
||||
* Callback interface used to process the YAML parsing results.
|
||||
*/
|
||||
public interface MatchCallback {
|
||||
|
||||
/**
|
||||
* Process the properties.
|
||||
* @param properties the properties to process
|
||||
* @param map a mutable result map
|
||||
* Process the given representation of the parsing results.
|
||||
* @param properties the properties to process (as a flattened
|
||||
* representation with indexed keys in case of a collection or map)
|
||||
* @param map the result map (preserving the original value structure
|
||||
* in the YAML document)
|
||||
*/
|
||||
void process(Properties properties, Map<String, Object> map);
|
||||
}
|
||||
|
||||
+20
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,13 +21,23 @@ import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.CollectionFactory;
|
||||
|
||||
/**
|
||||
* Factory for Java Properties that reads from a YAML source. YAML is a nice
|
||||
* human-readable format for configuration, and it has some useful hierarchical
|
||||
* properties. It's more or less a superset of JSON, so it has a lot of similar
|
||||
* features. The Properties created by this factory have nested paths for
|
||||
* hierarchical objects, so for instance this YAML
|
||||
* Factory for {@link java.util.Properties} that reads from a YAML source,
|
||||
* exposing a flat structure of String property values.
|
||||
*
|
||||
* <p>YAML is a nice human-readable format for configuration, and it has some
|
||||
* useful hierarchical properties. It's more or less a superset of JSON, so it
|
||||
* has a lot of similar features.
|
||||
*
|
||||
* <p><b>Note: All exposed values are of type {@code String}</b> for access through
|
||||
* the common {@link Properties#getProperty} method (e.g. in configuration property
|
||||
* resolution through {@link PropertyResourceConfigurer#setProperties(Properties)}).
|
||||
* If this is not desirable, use {@link YamlMapFactoryBean} instead.
|
||||
*
|
||||
* <p>The Properties created by this factory have nested paths for hierarchical
|
||||
* objects, so for instance this YAML
|
||||
*
|
||||
* <pre class="code">
|
||||
* environments:
|
||||
@@ -39,7 +49,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
* name: My Cool App
|
||||
* </pre>
|
||||
*
|
||||
* is transformed into these Properties:
|
||||
* is transformed into these properties:
|
||||
*
|
||||
* <pre class="code">
|
||||
* environments.dev.url=http://dev.bar.com
|
||||
@@ -57,7 +67,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
* - foo.bar.com
|
||||
* </pre>
|
||||
*
|
||||
* becomes Java Properties like this:
|
||||
* becomes properties like this:
|
||||
*
|
||||
* <pre class="code">
|
||||
* servers[0]=dev.bar.com
|
||||
@@ -66,6 +76,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Stephane Nicoll
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
*/
|
||||
public class YamlPropertiesFactoryBean extends YamlProcessor implements FactoryBean<Properties>, InitializingBean {
|
||||
@@ -116,7 +127,7 @@ public class YamlPropertiesFactoryBean extends YamlProcessor implements FactoryB
|
||||
* @see #process(MatchCallback) ()
|
||||
*/
|
||||
protected Properties createProperties() {
|
||||
final Properties result = new Properties();
|
||||
final Properties result = CollectionFactory.createStringAdaptingProperties();
|
||||
process(new MatchCallback() {
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -76,8 +76,7 @@ public class BeanComponentDefinition extends BeanDefinitionHolder implements Com
|
||||
List<BeanDefinition> innerBeans = new ArrayList<BeanDefinition>();
|
||||
List<BeanReference> references = new ArrayList<BeanReference>();
|
||||
PropertyValues propertyValues = beanDefinition.getPropertyValues();
|
||||
for (int i = 0; i < propertyValues.getPropertyValues().length; i++) {
|
||||
PropertyValue propertyValue = propertyValues.getPropertyValues()[i];
|
||||
for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
|
||||
Object value = propertyValue.getValue();
|
||||
if (value instanceof BeanDefinitionHolder) {
|
||||
innerBeans.add(((BeanDefinitionHolder) value).getBeanDefinition());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,7 +42,7 @@ public class Problem {
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link Problem} class.
|
||||
* @param message a message detailing the problem
|
||||
* @param message a message detailing the problem
|
||||
* @param location the location within a bean configuration source that triggered the error
|
||||
*/
|
||||
public Problem(String message, Location location) {
|
||||
@@ -51,7 +51,7 @@ public class Problem {
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link Problem} class.
|
||||
* @param message a message detailing the problem
|
||||
* @param message a message detailing the problem
|
||||
* @param parseState the {@link ParseState} at the time of the error
|
||||
* @param location the location within a bean configuration source that triggered the error
|
||||
*/
|
||||
@@ -61,8 +61,8 @@ public class Problem {
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link Problem} class.
|
||||
* @param message a message detailing the problem
|
||||
* @param rootCause the underlying expection that caused the error (may be {@code null})
|
||||
* @param message a message detailing the problem
|
||||
* @param rootCause the underlying exception that caused the error (may be {@code null})
|
||||
* @param parseState the {@link ParseState} at the time of the error
|
||||
* @param location the location within a bean configuration source that triggered the error
|
||||
*/
|
||||
@@ -107,7 +107,7 @@ public class Problem {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying expection that caused the error (may be {@code null}).
|
||||
* Get the underlying exception that caused the error (may be {@code null}).
|
||||
*/
|
||||
public Throwable getRootCause() {
|
||||
return this.rootCause;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user