mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
690 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f9593da1c | |||
| aac21fdcec | |||
| dfd75352d3 | |||
| 6316448453 | |||
| 40015e3de3 | |||
| 5e448af903 | |||
| 1f3ce640c9 | |||
| cca44f411e | |||
| 9b0412f35f | |||
| 7eee3b9926 | |||
| b5a279d2c8 | |||
| 0862a29066 | |||
| 8d83f6966e | |||
| ce5117c9ed | |||
| 836e3c9253 | |||
| 2006eecb18 | |||
| 91287828f7 | |||
| efd2fc7688 | |||
| 74b5487a28 | |||
| 2882ae29b2 | |||
| 4a7b96c4ca | |||
| 7398e0ea97 | |||
| beaad20795 | |||
| 1bd84db56e | |||
| 6316a45927 | |||
| e298c202af | |||
| 288408e89f | |||
| 53a244d408 | |||
| 8213d0cb50 | |||
| b9868a498e | |||
| df7bdfa7c6 | |||
| f8402e9f82 | |||
| 7eeb654eec | |||
| b558c62953 | |||
| d64dd1943f | |||
| bffa50e31a | |||
| 143cb50986 | |||
| b3ccc438af | |||
| 94513c1a28 | |||
| c9607fdaf2 | |||
| 7c108c1e77 | |||
| 77372d7cdb | |||
| 173f307ec9 | |||
| 2c987b0ffb | |||
| 46a4ac9628 | |||
| c2997f4dd9 | |||
| 0150000d8b | |||
| cad5eb836c | |||
| c82dab6497 | |||
| e6f4e16219 | |||
| d0032f43c7 | |||
| 8a43dd172c | |||
| 11aaefffbf | |||
| c6b36cc207 | |||
| 5856db6f72 | |||
| 3c5e02a54a | |||
| db0c921313 | |||
| 641bc35a50 | |||
| c166803d41 | |||
| 12e1784a99 | |||
| bfabd58106 | |||
| 540845e613 | |||
| 8e7982397c | |||
| 84890ebc0d | |||
| a9f28575b1 | |||
| a730bf47df | |||
| b5ec65cef6 | |||
| 965c12b0f8 | |||
| 7187029ef6 | |||
| 6363bb4b5b | |||
| 58ea5a702d | |||
| 97b988ade8 | |||
| 227234288f | |||
| 05a7b65d43 | |||
| cee6cb859d | |||
| 19c6a4e209 | |||
| b9089a8f9d | |||
| 7a20ed7d70 | |||
| 99588950d2 | |||
| a2129a132f | |||
| 0f1c10bc1c | |||
| 585745de32 | |||
| 65077d262c | |||
| da36c2b8b8 | |||
| 8f01770f29 | |||
| c51b9a7be2 | |||
| 3ffc0a2da2 | |||
| acac25b2eb | |||
| cb0c0c503f | |||
| 215ccc2e10 | |||
| d95cbe23ee | |||
| ac1ffff9db | |||
| c0257aba9b | |||
| 79aa661dd6 | |||
| 18540debf6 | |||
| 7605707c18 | |||
| d48c3b5d4f | |||
| b122cf87df | |||
| 183523d045 | |||
| a4f62bb863 | |||
| 80def4b695 | |||
| 42e18e6c4e | |||
| d8767774c9 | |||
| f67e726be7 | |||
| 41b9a461df | |||
| 037497cb4f | |||
| 3ecb6b1a03 | |||
| 6b92f66ebd | |||
| 070a723ef2 | |||
| d4be29e661 | |||
| 3a3f15f144 | |||
| 3edf8566ed | |||
| a2f00f205a | |||
| 340a8b28f9 | |||
| 83c5753ae1 | |||
| 67bb044a6f | |||
| 9ddfb375cb | |||
| 6fc6a9e80c | |||
| f18fa08aa0 | |||
| aa4ecdb79e | |||
| 8041f6abdd | |||
| 210c77ddb0 | |||
| 24cb345b6c | |||
| 0fdd7550b8 | |||
| f1fb0e5330 | |||
| d4c2f63160 | |||
| b167f3f7a6 | |||
| 63fe7bdd34 | |||
| 270db64243 | |||
| 15fd972417 | |||
| 10d9860457 | |||
| 01eab03dca | |||
| eb50eec85b | |||
| 4faa5af3f8 | |||
| 218e64cc80 | |||
| b82edcca04 | |||
| d8a4949faf | |||
| 22739bebf3 | |||
| fece2c1125 | |||
| 8b55b34d79 | |||
| d1e998bedd | |||
| 2ddb14ae5b | |||
| ae74fbdd4b | |||
| 28769e906f | |||
| 47c21bf73b | |||
| 59fda2dbab | |||
| 43f8eca91b | |||
| 6cb6bd751e | |||
| 58d68cef98 | |||
| 5f3f30fdb4 | |||
| 7a6b2cfe1f | |||
| a8ab9af002 | |||
| ca19b14f13 | |||
| 175f6d4bc5 | |||
| 0206845341 | |||
| a37a9e8a38 | |||
| 577755d580 | |||
| 610812949f | |||
| 82ec515e59 | |||
| d418eed56f | |||
| 244c96151e | |||
| 92298469bf | |||
| bfd54f4f35 | |||
| c5e53ee432 | |||
| 8c9b64c948 | |||
| 171f1ee097 | |||
| be21358db7 | |||
| 5da5fc6499 | |||
| c7aaa85ef6 | |||
| a25e4d794e | |||
| 3c067e5db6 | |||
| 0f924820e8 | |||
| 1f1577e33e | |||
| e1dbb66798 | |||
| 1933b648c3 | |||
| 5cb06f5da2 | |||
| ffa4ed093f | |||
| 4c73a29f99 | |||
| 0195b0da3c | |||
| 27a10c74d1 | |||
| 7893b3ebf6 | |||
| 21d6883139 | |||
| a6569a2930 | |||
| d9d7fb6f9a | |||
| 4108927b28 | |||
| ac5b1bcfab | |||
| c5c1d70aa3 | |||
| 043ec2c8b2 | |||
| 1f296403da | |||
| 35da7bdb44 | |||
| ab21dbad08 | |||
| c32c0d5674 | |||
| e506ccf4e1 | |||
| 0ef971b82b | |||
| b062de1133 | |||
| 3740380a7a | |||
| cb434793d5 | |||
| 9114f80b68 | |||
| ae3cfff380 | |||
| c046419acd | |||
| bd22bed10a | |||
| a0fead1880 | |||
| f7cd9865f4 | |||
| ebe8052d55 | |||
| 6b3c299a50 | |||
| 722778c74a | |||
| 1cd77e2a15 | |||
| 5be9473136 | |||
| 7553b76f15 | |||
| d78eda8aeb | |||
| 061063257a | |||
| 4e43ba544b | |||
| ccded10d86 | |||
| 2433feab09 | |||
| be04aca037 | |||
| 153680a5e6 | |||
| a15d023b45 | |||
| 63b8ae085a | |||
| 1c6e131746 | |||
| 00984781af | |||
| e1fb19f4e1 | |||
| 21cca695e5 | |||
| ba2bac17de | |||
| 5918e2fa9c | |||
| 6d94c92d97 | |||
| 3f0462510e | |||
| 40fa8afce4 | |||
| aac2de9221 | |||
| cbab6fa59f | |||
| b7b2a25953 | |||
| d9b54a524d | |||
| 9008e08171 | |||
| eb0990b37e | |||
| 1fc6de0403 | |||
| b467f2c858 | |||
| e211c09065 | |||
| f88f69e700 | |||
| eda6268d9d | |||
| 668207d59d | |||
| 803b336354 | |||
| 4c154d3cab | |||
| 7ad191c912 | |||
| 70cb81b4b5 | |||
| 6e516b7281 | |||
| aab05c4da9 | |||
| 562747ef41 | |||
| c1d2c36f32 | |||
| e8b9c6d5ff | |||
| b2b195e2cf | |||
| 2c559aa8c8 | |||
| bf90a2ddb6 | |||
| a3f155220b | |||
| 6d4faa6c52 | |||
| d8ecc76d4c | |||
| 05bcc4028d | |||
| 334a294e2a | |||
| 99f7142e3f | |||
| aa54518e2e | |||
| c2dab9c200 | |||
| 609f91e1b4 | |||
| 87e7258c9a | |||
| 134e79c0fd | |||
| 08fb61316d | |||
| 4b89069cab | |||
| 5f2d88f74a | |||
| 53692a79e2 | |||
| b07a7be262 | |||
| 7a42ff16ac | |||
| f848e5081d | |||
| 91a53a36ec | |||
| 1247d2085b | |||
| 90636f66a8 | |||
| c33df5977a | |||
| 6f69b7b752 | |||
| 912d349366 | |||
| 284f98f12a | |||
| 907febd86e | |||
| af7203b839 | |||
| a251d6a6cc | |||
| 449337a544 | |||
| f92f295055 | |||
| 6a4bc3e39f | |||
| 88e0dcfa06 | |||
| bd05b046d0 | |||
| 7e5215b5d4 | |||
| ba946c08dd | |||
| 3eda5144ae | |||
| e68f2f0a5f | |||
| 45d9b0cb2d | |||
| 66b4499973 | |||
| e035477e6a | |||
| 479b4c1b84 | |||
| 05a3f3ad8d | |||
| b67da6c3f8 | |||
| 0485f15998 | |||
| b60a7a2e07 | |||
| e6425ee41f | |||
| 0a17e41755 | |||
| 055c343ce0 | |||
| 3f68ccadd9 | |||
| 4e3227441b | |||
| e56cfb8173 | |||
| 66a5bb7c22 | |||
| 82bcef037d | |||
| 5ddf8245dd | |||
| 3e5aca86d5 | |||
| d7e0776148 | |||
| 416004b1bc | |||
| 2182287d3e | |||
| e3298061d2 | |||
| 9aafa1c6b2 | |||
| b72cca5403 | |||
| d0f13b5beb | |||
| 4504ab8bc2 | |||
| 7730e76c06 | |||
| dbfa049e1e | |||
| 9f05f28727 | |||
| a9da123259 | |||
| 001d676dec | |||
| 061b2c91a0 | |||
| 9ab2c6628b | |||
| 2f980d95ff | |||
| 9857ba077b | |||
| 9a088b8128 | |||
| e4792aaf33 | |||
| b58e19b04c | |||
| 48869a86cc | |||
| a032ce12cb | |||
| ecb351c475 | |||
| b51f067f74 | |||
| 9b3fbc2333 | |||
| ee04046ed7 | |||
| 3cf22a0255 | |||
| 0aec5efb56 | |||
| 5c3cf5f672 | |||
| d1afb29074 | |||
| b2b1ff60dd | |||
| 255d1ad434 | |||
| 5b0448c609 | |||
| 1841b14b21 | |||
| 19fcbeafb4 | |||
| ace7b072f1 | |||
| fd159246ed | |||
| 2516bc0faf | |||
| 3963ff6e3b | |||
| a5b30fd074 | |||
| 35971f9f90 | |||
| 49a2970def | |||
| 665a997f66 | |||
| 5109501d16 | |||
| e27f4b1577 | |||
| f8690cf791 | |||
| f6c07b371f | |||
| 29b12adbaa | |||
| a79c015297 | |||
| 01b65cd201 | |||
| 61fcef1471 | |||
| 34ebad5fff | |||
| 9bd0bd9c3a | |||
| 99733aef2a | |||
| 8a23ce917a | |||
| 6e303d25c4 | |||
| ac1d2d93d6 | |||
| b90260f8d2 | |||
| 258a47435d | |||
| 1503a139e2 | |||
| 3d2dd447af | |||
| abf523698c | |||
| e3400f77c9 | |||
| 9008cf907a | |||
| 720f7ecf48 | |||
| 87caa13363 | |||
| cecee4d02b | |||
| f45bb92917 | |||
| 73ec840279 | |||
| 771db05608 | |||
| e250ff0fb4 | |||
| b4cd58394a | |||
| bda3d81bc9 | |||
| 2b4e714c68 | |||
| 82730830d1 | |||
| f5b0edbebd | |||
| 48874801a3 | |||
| 58b07f586d | |||
| 7cddb1c50e | |||
| a8133a9917 | |||
| bf4b9f5ffb | |||
| 0625990020 | |||
| e116a29795 | |||
| d97f899bee | |||
| 5ce4cada53 | |||
| b87b23087d | |||
| bab902e85b | |||
| 5e64f228b6 | |||
| edad222e6a | |||
| 91172f4f43 | |||
| 3a9fc70f91 | |||
| 30b0e5e250 | |||
| 55f2fe7dd5 | |||
| d109879b6c | |||
| 4af36454ba | |||
| 753cda3d81 | |||
| b054ca4a48 | |||
| 9ef47b82a5 | |||
| 103297cf59 | |||
| 6adf8d18df | |||
| 8e77701358 | |||
| c1246d506c | |||
| af0fac9099 | |||
| 367048c5d1 | |||
| 061af2f25f | |||
| faad0f4bb1 | |||
| c3a639f07d | |||
| bd4f4d0d30 | |||
| 3e0003a1a0 | |||
| 60a69bd653 | |||
| 72da237474 | |||
| d3cb310962 | |||
| d4f73c1d3d | |||
| 3c0ce48cbd | |||
| 8e5c033446 | |||
| f04febaf2d | |||
| b261d336b1 | |||
| 8519a2d705 | |||
| f90125f984 | |||
| 18af8a00f9 | |||
| b7b7c067c6 | |||
| 60fa490b50 | |||
| 605ac0e230 | |||
| 7304c09021 | |||
| 9bcfc5480d | |||
| 022e74ea3d | |||
| 4d5a9c41e0 | |||
| 11886f2149 | |||
| 1dce03af78 | |||
| 3afe8aee18 | |||
| e26fc66523 | |||
| c24ffc9175 | |||
| 228c0b18cb | |||
| b456bc107b | |||
| f25a04c69c | |||
| f8425a5f7b | |||
| dcad6c341b | |||
| 66abad2540 | |||
| e0e1cb3c24 | |||
| df5e9b1211 | |||
| 263fabb0fc | |||
| d1d5e2d52a | |||
| 96b9cf6ca9 | |||
| 3918518779 | |||
| 7e9e8401f7 | |||
| cb72fe1be2 | |||
| f5ced9be38 | |||
| 88560fd910 | |||
| 6de707d8e0 | |||
| 0c1424acb6 | |||
| 0d405fd124 | |||
| 45ed0ba43c | |||
| cd271fca43 | |||
| 3f31a1cf75 | |||
| 4d56b89619 | |||
| f9017ea05d | |||
| ce6194c7c3 | |||
| 8bd0633697 | |||
| db7531be60 | |||
| 94292cad1c | |||
| 8d5662ec7a | |||
| c059f53823 | |||
| 3160ddf0e8 | |||
| ccdd1a9efd | |||
| d956da2fa1 | |||
| 9e4140e549 | |||
| 942c656970 | |||
| 7faf4a6713 | |||
| 41d6f8e9ed | |||
| 0d7ce3eac5 | |||
| e6b708376d | |||
| 8f8fc97b79 | |||
| 27b04036a9 | |||
| 7f91153bba | |||
| 5d6937bab1 | |||
| ef3b70d40a | |||
| ab13e9b5ec | |||
| 5a1bd20864 | |||
| e11a40f809 | |||
| 868d3a4451 | |||
| 569cb91573 | |||
| 32167790b0 | |||
| 20ea69e06b | |||
| b2204ec94e | |||
| de06de11fe | |||
| 07e9f1775b | |||
| d49c067770 | |||
| 89fadb987c | |||
| 037c277351 | |||
| 5e5a8a09cf | |||
| 91560774a0 | |||
| b31c34ed7d | |||
| 7b189d1124 | |||
| bd88bbab4a | |||
| 420f8237c0 | |||
| 897aab9f59 | |||
| a383633630 | |||
| 4a0c2f8879 | |||
| 0e59fc4a15 | |||
| 96b1dc9db4 | |||
| 902938e95f | |||
| 379bc5a8a6 | |||
| cbb90236dc | |||
| 53ed9b282b | |||
| 3d3f8f3219 | |||
| 28a765f32b | |||
| 65655b949f | |||
| c8984d2e30 | |||
| 11330baf77 | |||
| 433b4eff8f | |||
| 2f4453a99c | |||
| 65885d1dfd | |||
| 723f94fd0e | |||
| 2a140addfd | |||
| eb3a3a6de2 | |||
| e12fbd3e2b | |||
| 928f5423af | |||
| 65622bd546 | |||
| 882289b06e | |||
| 12cffc68c8 | |||
| c58f46f056 | |||
| 632c0e7c5e | |||
| 392accd910 | |||
| 8446fd1b26 | |||
| 5f9b2db90b | |||
| 4cef52a86f | |||
| de866a0ff6 | |||
| d684e49462 | |||
| fe1e7f0d6c | |||
| 857faec1f3 | |||
| 5b420e20c7 | |||
| 78c906caaa | |||
| 2ef3a86c4f | |||
| 53cdb9dfeb | |||
| cc238207f9 | |||
| 5330dc48aa | |||
| 4764fa53f0 | |||
| f72c431e8a | |||
| 0dc29cb2d3 | |||
| 5801af9ef5 | |||
| d0393ea109 | |||
| 75c5405d6f | |||
| 3a5af35d37 | |||
| dea5918d66 | |||
| 2136b04b65 | |||
| b4af04ba9d | |||
| f0777d130f | |||
| 1532119787 | |||
| 6c6004a93b | |||
| b90fa49ebc | |||
| bca067abb2 | |||
| 0c6b38b0b5 | |||
| 8800bab8a6 | |||
| ed3cb4217d | |||
| 66aca1e8b3 | |||
| d7f72fbbd4 | |||
| 2676771255 | |||
| 3cf303cabd | |||
| a6d9c90841 | |||
| 0390c2b9fe | |||
| f9736ec3f6 | |||
| 6fe5871e91 | |||
| ecf2d8c5de | |||
| 469e30b507 | |||
| 8a3c56b6d5 | |||
| 680bfbe718 | |||
| d600e35157 | |||
| 101d8381ef | |||
| ae56f3a361 | |||
| de326e5e95 | |||
| 2c2df7f555 | |||
| 2ad2022058 | |||
| 57a503b274 | |||
| 0b8140b50d | |||
| a8ed98255f | |||
| 738d84f75c | |||
| 7f24edc3d5 | |||
| ff4f749adb | |||
| 578e80c1cf | |||
| d9a664a588 | |||
| e9ecf5d716 | |||
| 27be8434f1 | |||
| 3f885d0302 | |||
| 9f9a27a1d8 | |||
| d22a6f9da9 | |||
| 8ccd74b6c8 | |||
| ceb668ac6c | |||
| 68055ba4c9 | |||
| ad5c7aeb31 | |||
| 59d2d35f4a | |||
| 103c1aa82f | |||
| a1e4f4f406 | |||
| fa7472c057 | |||
| bd1b559d47 | |||
| 15df7b11d0 | |||
| 4955a73047 | |||
| 11bb7264a2 | |||
| 853eab8b4c | |||
| 15fe75b1a1 | |||
| dad714710f | |||
| 365737b515 | |||
| 026523d24b | |||
| 2b0655b459 | |||
| f53621a86f | |||
| 42cdfbcd89 | |||
| 9919cc976b | |||
| a45d33a158 | |||
| c0aac20081 | |||
| b0afa0c472 | |||
| 17a1362ed8 | |||
| dd8c18188f | |||
| 159f98728e | |||
| c1f18582e7 | |||
| f8a05da1c9 | |||
| a910ce68ff | |||
| aa216672ae | |||
| 4ddcd35d13 | |||
| 02cc37cc16 | |||
| 03415960ff | |||
| c2707150b1 | |||
| 8ce4037af2 | |||
| 101a5cd8ff | |||
| 8df0403e99 | |||
| 07920fc3df | |||
| 87e327773e | |||
| b28310b051 | |||
| 20d3085dc8 | |||
| 218ee6d24c | |||
| 3f06a92b6b | |||
| 5057c4a69c | |||
| 4cab4a7545 | |||
| 3dbe38e418 | |||
| c5f83686d2 | |||
| 77074c6c87 | |||
| 1e34e2725a | |||
| 7790dedff2 | |||
| 399b388ea5 | |||
| 5af6d917e9 | |||
| ea9eb853fa | |||
| 05360c095c | |||
| 1ed05eceb9 | |||
| 69c4cdf975 | |||
| 3f6cc3f552 | |||
| e21a1c5a61 | |||
| 86906d1b4d | |||
| 6e13cc9eaa | |||
| b25462ddf9 | |||
| e60389283d | |||
| 066b4d542b | |||
| 594596f361 | |||
| bf03d0d56f | |||
| 33252495cf | |||
| a71514222a | |||
| 8464ac90c7 | |||
| ebbf63f4e0 | |||
| e6018afe8b | |||
| b9aeba23ef | |||
| d98da7d240 | |||
| e7c99b2b62 | |||
| 64d6a42dfd | |||
| bf1a95c771 | |||
| f6b56a591c | |||
| 2a19148eed | |||
| 7048f32666 | |||
| b3b5b356d2 | |||
| 7355dff967 | |||
| eb7f8309e2 | |||
| 67ba18f956 | |||
| 12ce250c6c | |||
| e6b0a1d4d7 | |||
| 385298b808 | |||
| 03120b70d0 | |||
| 4d2a398cbc | |||
| 353781021d | |||
| 688dd1a018 | |||
| d34d8764b0 | |||
| 28da6e0d98 | |||
| 4ee6735376 | |||
| ff6abbd369 | |||
| ecda2aee4a | |||
| e2a9bc9c66 | |||
| b5b60cafb7 | |||
| 270fab4fd0 | |||
| f7f0d18e41 |
+9
-1
@@ -1,5 +1,13 @@
|
||||
.springBeans
|
||||
.DS_Store
|
||||
target
|
||||
integration-repo
|
||||
ivy-cache
|
||||
spring-build
|
||||
jmx.log
|
||||
jxl.log
|
||||
jmx.log
|
||||
org.springframework.jdbc/derby.log
|
||||
org.springframework.spring-parent/.classpath
|
||||
org.springframework.spring-parent/.project
|
||||
org.springframework.test/test-output/
|
||||
spring-build/lib/docbook
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
<!-- Main targets -->
|
||||
<target name="publish-documentation" depends="publish-documentation.init">
|
||||
<sshexec host="spring02.managed.contegix.com" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
<sshexec host="static.springsource.org" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
command="mkdir /opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version}"/>
|
||||
|
||||
<scp remoteToDir="${username}@spring02.managed.contegix.com:/opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version}"
|
||||
<scp remoteToDir="${username}@static.springsource.org:/opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version}"
|
||||
keyfile="${key.file}" passphrase="${passphrase}" sftp="true" verbose="true">
|
||||
<fileset dir="${package.output.dir}">
|
||||
<include name="changelog.txt" />
|
||||
@@ -16,7 +16,7 @@
|
||||
<fileset dir="${package.docs.dir}" />
|
||||
</scp>
|
||||
|
||||
<sshexec host="spring02.managed.contegix.com" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
<sshexec host="static.springsource.org" username="${username}" keyfile="${key.file}" passphrase="${passphrase}"
|
||||
command="rm /opt/www/domains/springframework.org/www/htdocs/spring/docs/3.0.x ; ln -s /opt/www/domains/springframework.org/www/htdocs/spring/docs/${bundle.version} /opt/www/domains/springframework.org/www/htdocs/spring/docs/3.0.x"/>
|
||||
</target>
|
||||
|
||||
|
||||
@@ -3,6 +3,257 @@ SPRING FRAMEWORK CHANGELOG
|
||||
http://www.springsource.org
|
||||
|
||||
|
||||
Changes in version 3.0.7 (2011-12-22)
|
||||
-------------------------------------
|
||||
|
||||
* fixed GenericTypeResolver to consistently return null if not resolvable
|
||||
* added proper "contentLength()" implementation to ByteArrayResource
|
||||
* refined Resource "exists()" check for HTTP URLs to always return false for 404 status
|
||||
* LocaleEditor and StringToLocaleConverter do not restrict variant part through validation
|
||||
* LinkedCaseInsensitiveMap overrides putAll method as well (for IBM JDK 1.6 compatibility)
|
||||
* ConversionService prevents Converter from trying to convert to a subtype of its actual target type
|
||||
* ConversionService is able to work with "Collections.emptyList()" as target type (again)
|
||||
* CollectionCollection/MapToMapConverter preserve original Collection/Map if no converted elements
|
||||
* fixed nested element conversion with a DataBinder + ConversionService + PropertyEditor
|
||||
* restored DataBinder's ability to bind to an auto-growing List with unknown element type
|
||||
* optimized DefaultListableBeanFactory's PropertyDescriptor caching for concurrent access
|
||||
* context:property-placeholder's "file-encoding" attribute value is being applied correctly
|
||||
* SpringValidatorAdapter accepts non-indexed set paths (for Hibernate Validator compatibility)
|
||||
* fixed AbstractAsyncExecutionAspect's setExecutor method to correctly wrap in a TaskExecutorAdapter
|
||||
* @Transactional qualifiers match against transaction manager definitions in parent contexts as well
|
||||
* TransactionSynchronizationManager eagerly cleans up void ResourceHolders on any access
|
||||
* updated H2 error codes in sql-error-codes.xml
|
||||
* fixed NamedParameterJdbcTemplate to use correct maximum type for queryForInt/Long
|
||||
* SimpleJdbcTestUtils executeSqlScript properly closes its LineNumberReader after use
|
||||
* Hibernate synchronization properly unbinds Session even in case of afterCompletion exception
|
||||
* JDO PersistenceManager synchronization performs close attempt after completion (if necessary)
|
||||
* JPA EntityManagerFactoryUtils silently ignores IllegalArgumentExceptions from setHint calls
|
||||
* added "forwarder" property to ConnectorServerFactoryBean, accepting an MBeanServerForwarder
|
||||
* JmsInvokerClientInterceptor/FactoryBean always uses createConnection/createSession when on JMS 1.1
|
||||
* RmiClientInterceptor detects nested SocketException as connect failure as well
|
||||
* Servlet/PortletContextResource's getFile prefers "file:" URL resolution over calling getRealPath
|
||||
* Portlet session mutex uses global session attribute to be shared among all portlets in the session
|
||||
* fixed ServletServerHttpRequest to reconstruct from "request.getParameterMap()" for form POST only
|
||||
* fixed @RequestMapping header matching to correctly process negated header conditions
|
||||
* added "getObjectMapper()" accessor to MappingJacksonHttpMessageConverter
|
||||
* ResourceHttpRequestHandler sends content without content-type header if no media type found
|
||||
* AbstractCachingViewResolver allows for caching unresolved view names ("cacheUnresolved"=true)
|
||||
* fixed "formMultiSelect"/"formCheckboxes" FreeMarker macros to compare against actual field value
|
||||
|
||||
|
||||
Changes in version 3.0.6 (2011-08-18)
|
||||
-------------------------------------
|
||||
|
||||
* fixed aspects bundle to declare dependencies for @Async aspect as well
|
||||
* ProxyCreationContext uses "ThreadLocal.remove()" over "ThreadLocal.set(null)" as well
|
||||
* DefaultListableBeanFactory is only deserializable through a SerializedBeanFactoryReference
|
||||
* DefaultListableBeanFactory's getBean(name, type) attempts type conversion if necessary
|
||||
* DefaultListableBeanFactory allows for init methods to register further bean definitions (again)
|
||||
* XmlBeanDefinitionReader accepts description subelement within map entry as well (as per the XSD)
|
||||
* ConfigurationClassPostProcessor supports use of same processor instance with several factories
|
||||
* fixed potential InjectionMetadata NPE when using SpringBeanAutowiringInterceptor
|
||||
* SpringBeanAutowiringSupport is able to process @Value annotations on any given target instance
|
||||
* overridden @PersistenceContext annotations on subclass methods are being processed correctly
|
||||
* BeanDefinitionVisitor now actually visits factory method names
|
||||
* restored support for String-to-ContextResource conversion
|
||||
* restored original GenericConversionService behavior with respect to empty collections/maps
|
||||
* restored original FormattingConversionService behavior with respect to the use of subtypes
|
||||
* added "formatters" property to FormattingConversionServiceFactoryBean
|
||||
* collection/array conversion returns original collection if possible (instead of first element)
|
||||
* fixed collection element resolution when using a ConversionService with a DataBinder
|
||||
* DataBinder uses a default limit of 256 for array/collection auto-growing
|
||||
* added "autoGrowNestedPaths" property to ConfigurableWebBindingInitializer
|
||||
* Servlet/PortletRequestDataBinder perform unwrapping for MultipartRequest as well
|
||||
* fixed AbstractBindingResult to avoid NPE in "hashCode()" if target is null
|
||||
* fixed several HttpHeaders issues (charset handling, quoting/unquoting)
|
||||
* SimpleClientHttpRequest uses fixed-length streaming mode (always sets content-length header)
|
||||
* added "connectTimeout" and "readTimeout" properties to Simple/CommonsClientHttpRequestFactory
|
||||
* explicit status code in RedirectView respected in HTTP 1.0 compatibility mode
|
||||
* FormHttpMessageConverter correctly processes POST requests
|
||||
* ResourceHttpRequestHandler does not set Content-Length header for 304 response
|
||||
* ResourceHttpRequestHandler detects invalid directory traversal in given path
|
||||
* LocaleChangeInterceptor validates locale values in order to prevent XSS vulnerability
|
||||
* HtmlUtils properly escapes single quotes as well
|
||||
* added support for web.xml context-param "springJspExpressionSupport" (explicit "true"/"false")
|
||||
* ContextLoader and FrameworkServlet support "contextId" parameter for custom serialization id
|
||||
* RemoteExporter uses an opaque proxy for 'serviceInterface' (no AOP interfaces exposed)
|
||||
* added "acceptProxyClasses" flag to RemoteInvocationSerializingExporter
|
||||
* refined WebLogic RMI descriptor to only mark 'getTargetInterfaceName' method as idempotent
|
||||
* EhCacheManagerFactoryBean properly closes "ehcache.xml" input stream, if any
|
||||
* revised JMS CachedConnectionFactory to avoid unnecessary rollback calls on Session return
|
||||
* fixed JMS CachedConnectionFactory to fully synchronize its Session list
|
||||
* fixed NamedParameterJdbcTemplate's handling of arrays as query parameters
|
||||
* fixed JPA 2.0 timeout hints to correctly specify milliseconds
|
||||
* updated Quartz package to support Quartz 1.8 as well (note: not supporting Quartz 2.0 yet)
|
||||
* fixed @Rule execution order in SpringJUnit4ClassRunner to match standard JUnit 4 behavior
|
||||
|
||||
|
||||
Changes in version 3.0.5 (2010-10-20)
|
||||
-------------------------------------
|
||||
|
||||
* support for Hibernate 3.6 final
|
||||
* added core serializer abstraction with default implementations using Java Serialization
|
||||
* consistent use of JDK 1.5's "ThreadLocal.remove()" over "ThreadLocal.set(null)"
|
||||
* fixed JodaTimeContextHolder to use a non-inheritable ThreadLocal and expose a reset method
|
||||
* revised "ClassUtils.isAssignable" semantics to cover primitives vs wrappers in both directions
|
||||
* optimized AnnotationUtils findAnnotation performance for repeated search on same interfaces
|
||||
* ConversionService protects itself against infinite recursion in ObjectToCollectionConverter
|
||||
* fixed TypeDescriptor to correctly resolve nested collections and their element types
|
||||
* BeanWrapper does not attempt to populate Map values on access (just auto-grows Map itself)
|
||||
* fixed Autowired/CommonAnnotationBeanPostProcessor to prevent race condition in skipping check
|
||||
* fixed @Value injection to correctly cache temporary null results for non-singleton beans
|
||||
* ApplicationContext registers context-specific ClassArrayEditor for its bean ClassLoader
|
||||
* refined ApplicationContext singleton processing to not fail for manually registered null instances
|
||||
* fixed ApplicationContext event processing for repeated invocations to non-singleton listener beans
|
||||
* optimized @Bean error messages for static factory methods as well as for argument type mismatches
|
||||
* modified expression parsing to pass full TypeDescriptor context through to ConversionService calls
|
||||
* adapted expression parser's Constructor/MethodResolver to accept TypeDescriptors instead of raw types
|
||||
* SpEL supports projection on any kind of Collection (not just on Lists and arrays)
|
||||
* SpEL MapAccessor consistently rejects "target.key" style access to Maps if no such key is found
|
||||
* SpEL method invocations prefer method with fewest parameters (e.g. no-arg over vararg)
|
||||
* AspectJExpressionPointcut uses bean ClassLoader for initializing the AspectJ pointcut parser
|
||||
* added AnnotationAsyncExecutionAspect as AspectJ-based variant of @Async processing
|
||||
* added mode="proxy"/"aspectj" and proxy-target-class options to task:annotation-driven
|
||||
* JDBC bundle uses local ClassLoader as bean ClassLoader for "sql-error-codes.xml" parsing
|
||||
* EmbeddedDatabaseFactory shuts down database when failing to populate it in "initDatabase()"
|
||||
* embedded database support now also works with Derby >= 10.6
|
||||
* "jdbc:embedded-database" uses id as database name to allow multiple ones in parallel
|
||||
* ResourceDatabasePopulator throws descriptive ScriptStatementFailedException with resource details
|
||||
* added configurable Connection/Statement/ResultSet target types to Jdbc4NativeJdbcExtractor
|
||||
* added OracleJdbc4NativeJdbcExtractor with pre-configured Oracle JDBC API types
|
||||
* DefaultLobHandler's "wrapAsLob" mode works with PostgreSQL's "getAsciiStream()" requirement
|
||||
* ResultSetWrappingSqlRowSet (as used by JdbcTemplate's "queryForRowSet") supports column labels now
|
||||
* LocalSessionFactoryBean's "entityCacheStrategies" works with region names on Hibernate 3.6 as well
|
||||
* fixed DefaultMessageListenerContainer's no-message-received commit to work without Session caching
|
||||
* DefaultMessageListenerContainer's skips no-message-received commit on Tibco (avoiding a deadlock)
|
||||
* JaxWsPortClientInterceptor does not fall back to annotation-specified name as portName anymore
|
||||
* UriTemplate is serializable now
|
||||
* fixed AnnotationMethodHandlerAdapter's caching to avoid concurrency issues in RequestMappingInfo
|
||||
* fixed @MVC processing of parameter-level annotations to work with interface-based proxies again
|
||||
* revised @RequestParam processing to support CSV-to-array/collection binding with ConversionService
|
||||
* fixed EvalTag's EvaluationContext caching to properly handle JSP tag caching across requests
|
||||
* AbstractJasperReportsView only sets locale model attributes if not present already
|
||||
* DispatcherPortlet throws custom NoHandlerFoundException instead of misleading UnavailableException
|
||||
* DispatcherPortlet copies all action parameters to render parameters in case of an action exception
|
||||
* DispatcherPortlet's default resource serving explicitly prevents access to WEB-INF and META-INF
|
||||
* Portlet @ExceptionHandler methods allow for writing the response directly (like in the Servlet case)
|
||||
* MockHttpServletRequest/HttpSession/etc returns independent Enumeration from "getAttributeNames()"
|
||||
|
||||
|
||||
Changes in version 3.0.4 (2010-08-19)
|
||||
-------------------------------------
|
||||
|
||||
* support for Hibernate Core 3.6, Hibernate Validator 4.1, EclipseLink 2.1, EHCache 2.2
|
||||
* OSGi manifest version range accepts EHCache 2.x as well
|
||||
* added "contentLength()" method to Resource abstraction
|
||||
* URL-based Resource variants introspect "last-modified" and "content-length" response headers
|
||||
* refined "exists()" check for UrlResource (HEAD request) and ClassPathResource (URL resolution)
|
||||
* ConversionService is able to deal with empty collections and nested collections (fixed regression)
|
||||
* ConversionService properly handles nested Resource arrays in Map values (fixed regression)
|
||||
* ConversionService does not accidentally use copy constructor for same type
|
||||
* fixed double ConversionFailedException nesting for ObjectToObjectConverter invocations
|
||||
* BeanWrapper preserves annotation information for individual array/list/map elements
|
||||
* Spring's constructor resolution consistently finds non-public multi-arg constructors
|
||||
* revised constructor argument caching, avoiding a race condition for converted argument values
|
||||
* SpEL passes full collection type context (generics, annotations) to ConversionService
|
||||
* SpEL 'select last' operator now works consistently with maps
|
||||
* BeanWrapper/DataBinder's "autoGrowNestedPaths" works for Maps as well
|
||||
* fixed concurrency issue in TypedStringValue, showing for nested typed Maps in prototype beans
|
||||
* fixed WeakReferenceMonitor to never stop its monitoring thread if an entry has been registered
|
||||
* fixed CronTrigger to correctly parse month parts expressed as numbers (1-12 instead of 0-11)
|
||||
* TaskExecutorFactoryBean (as used by task:executor) exposes full ThreadPoolTaskExecutor type
|
||||
* JmsResourceHolder does not ignore IllegalStateException from locally synchronized transaction
|
||||
* fixed JMS CachingConnectionFactory to correctly cache a producer without fixed destination as well
|
||||
* DefaultMessageListenerContainer triggers Session commit even if no message has been received
|
||||
* DefaultMessageListenerContainer supports client id setting even for non-shared Connections
|
||||
* Spring's MessageEndpointFactory classes are now JCA 1.6 compliant as well
|
||||
* AbstractJaxWsServiceExporter supports "bindingType" bean property, overriding @BindingType
|
||||
* AbstractJaxWsServiceExporter supports "webServiceFeatures" bean property on JAX-WS 2.2
|
||||
* JaxWsPortProxyFactoryBean takes "wsdlDocumentUrl", "namespaceUri" etc defaults from @WebService
|
||||
* Jaxb2Marshaller's "marshallerProperties" Map accepts any value type
|
||||
* SpringTemplateLoader for FreeMarker supports last-modified timestamp through Resource abstraction
|
||||
* HibernateJpaDialect correctly closes borrowed connections even for nested JDBC executions
|
||||
* DefaultJdoDialect supports JDO 3.0 query timeout facility (as supported by DataNucleus 2.1)
|
||||
* transaction names based on method id from most specific method (target class instead of interface)
|
||||
* added "validationMessageSource" to LocalValidatorFactoryBean, for Spring-based validation messages
|
||||
* Spring field error arguments include actually declared annotation attributes in alphabetical order
|
||||
* JSR-303 Pattern message resolvable through Spring MessageSource (despite special characters)
|
||||
* DispatcherServlet applies default view name translation to error views as well
|
||||
* mvc:annotation-driven reliably detects JSR-303 and JAXB2 in an OSGi environment as well
|
||||
* revised @MVC handler method resolution with respect to handler methods on generic interfaces
|
||||
* @MVC handler methods reliably resolve MultipartRequest arguments with HiddenHttpMethodFilter
|
||||
* WebDataBinder and @MVC request params detect and introspect MultipartFile arrays as well
|
||||
* fixed @PathVariable regression in combination with ConversionService usage on DataBinder
|
||||
* @CookieValue returns decoded cookie value in a Servlet environment (analogous to @RequestParam)
|
||||
* MVC HandlerExceptionResolvers prevent caching for exception views if preventResponseCaching=true
|
||||
* @ExceptionHandler works for inherited method and CGLIB proxies on Portlet controllers as well
|
||||
* Portlet @MVC's implicit render model will be updated at the end of the event phase
|
||||
* Portlet AbstractController consistently uses session mutex if "synchronizeOnSession" is active
|
||||
* PortletWrappingController supports Portlet 2.0 resource and event requests as well
|
||||
* fixed JSP EvalTag to render null result as empty String instead of "null" String
|
||||
* JSP EvalTag resolves "@myBeanName" references in expressions against the WebApplicationContext
|
||||
* added support for static resource serving: ResourceHttpRequestHandler, mvc:resources
|
||||
* revised DispatcherServlet's last-modified handling to properly work with scoped controllers
|
||||
* MockMultipartHttpServletRequest pre-defines method "POST" and content type "multipart/form-data"
|
||||
|
||||
|
||||
Changes in version 3.0.3 (2010-06-15)
|
||||
-------------------------------------
|
||||
|
||||
* Spring autodetects JodaTime 1.3 or higher (as required), ignoring older JodaTime versions
|
||||
* clarified that Spring's Jackson support requires Jackson 1.3 or higher
|
||||
* JPA 2.0 support tested and supported with Hibernate 3.5.2 and OpenJPA 2.0.0 GA as well
|
||||
* revised VFS support for Spring's component scanning to work on JBoss AS 6.0.0 M3 as well
|
||||
* fixed URIEditor's URI construction to consider fragment as well
|
||||
* added default InputSourceEditor for SAX InputSource construction with a URL String as system id
|
||||
* CachedIntrospectionResults only caches GenericTypeAwarePropertyDescriptors if fully safe
|
||||
* revised BeanWrapper's exception wrapping to consistently handle ConversionExceptions
|
||||
* DefaultListableBeanFactory checks for alias circle on registerAlias (avoiding endless loop)
|
||||
* ConversionService is able to apply Converters to interface-based array elements
|
||||
* ConversionService fully supports conversion from String to MediaType now (through 'valueOf')
|
||||
* revised exception handling in ObjectToObjectConverter, avoiding InvocationTargetExceptions
|
||||
* a context ConversionService is able to override an ApplicationContext's resource editors
|
||||
* refined LifecycleProcessor exception handling, properly wrapping a start exception from a bean
|
||||
* revised DefaultLifecycleProcessor's handling of circular dependencies to avoid stack overflow
|
||||
* fixed constructor argument caching for prototypes with multiple constructor matches
|
||||
* specific detection of CGLIB subclasses in order to properly handle CGLIB interfaces
|
||||
* registerDependentBean resolves to the canonical bean name in order to handle alias references
|
||||
* fixed registerResolvableDependency mechanism to correctly handle non-serializable factory objects
|
||||
* added "expose-proxy" attribute to aop namespace (enforcing AopContext proxy exposure with CGLIB)
|
||||
* revised AbstractInterceptorDrivenBeanDefinitionDecorator for further alignment with auto-proxying
|
||||
* BeanDefinitionVisitor/PropertyPlaceholderConfigurer finds and resolves values in arrays as well
|
||||
* property placeholders can deal with nested expressions which happen to use the same suffix
|
||||
* SpEL's Elvis operator is able to deal with #{${myProp}?:defaultValue} case if myProp is empty
|
||||
* introduced EmbeddedValueResolverAware callback interface for convenient placeholder resolution
|
||||
* @Transactional qualifier value matches against @Qualifier annotations on @Bean methods as well
|
||||
* setTransactionIsolation on JDBC Connection only called when actually necessary (for PostgreSQL)
|
||||
* added limit for parsed SQL cache to NamedParameterJdbcTemplate (default is 256; configurable)
|
||||
* CachingConnectionFactory detects destination equality for WebSphere MQ as well (using toString)
|
||||
* DefaultPersistenceUnitManager's getPersistenceUnitInfo method has 2.5 compatible signature again
|
||||
* DefaultMessageListenerContainer reacts to maxConcurrentConsumers reduction for long-lived tasks
|
||||
* added "idleConsumerLimit" bean property to DefaultMessageListenerContainer (default is 1)
|
||||
* AsyncAnnotationBeanPostProcessor consistently adds @Async processing as first Advisor in the chain
|
||||
* ScheduledTaskRegistrar (as used for @Scheduled processing) properly shuts down its default executor
|
||||
* CronTrigger defensively protects itself against accidental re-fires if a task runs too early
|
||||
* MailSendException includes all messages as failed messages in case of a connect failure
|
||||
* added support for JAX-WS 2.1 WebServiceFeatures to JaxWsPortClientInterceptor/PortProxyFactoryBean
|
||||
* added XmlAwareFormHttpMessageConverter, taking over the 3.0.2-introduced XML multipart support
|
||||
* ServletContextResourcePatternResolver handles "/WEB-INF/lib/*.jar!/**/context.xml" style patterns
|
||||
* fixed MVC mapping regression for servlet url-pattern "/" case on servers other than WebSphere
|
||||
* MVC mappings properly apply even to welcome file entries that forward to a DispatcherServlet
|
||||
* fixed @ExceptionHandler resolution in case of multiple matches at different inheritance levels
|
||||
* revised Portlet SessionStatus.setComplete() to avoid re-exposure of attributes in render phase
|
||||
* shortened Portlet MVC's implicit model render parameter name to "implicitModel"
|
||||
* added convenient "checkRefresh" bean property to TilesConfigurer
|
||||
* TilesConfigurer's "definitionsFactoryClass" property applies common Tiles DefinitionsFactory setup
|
||||
* JSP FormTag calculates proper default form action even when using a rewrite filter on WebSphere
|
||||
* JSP HiddenInputTag allows for using common HTML attributes (equivalent to LabelTag)
|
||||
* fixed JSP ErrorsTag to avoid invalid "*.errors" id, using form object name as id prefix instead
|
||||
* fixed JSP SelectTag's support for rendering enum constants
|
||||
* JSP Radiobutton/CheckboxesTag utilizes PropertyEditor/ConversionService for label rendering
|
||||
* MockHttpServletResponse supports multiple includes
|
||||
|
||||
|
||||
Changes in version 3.0.2 (2010-04-02)
|
||||
-------------------------------------
|
||||
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
SPRING FRAMEWORK 3.0.2 (April 2010)
|
||||
-----------------------------------
|
||||
http://www.springframework.org
|
||||
SPRING FRAMEWORK 3.0.7 (December 2011)
|
||||
--------------------------------------
|
||||
http://www.springsource.org
|
||||
|
||||
1. INTRODUCTION
|
||||
|
||||
Spring Framework 3.0 is the next generation of the Spring: fully Java 5 based,
|
||||
EL enabled, REST enabled, and with support for JSR-330 (Dependency Injection)
|
||||
and JSR-303 (Bean Validation).
|
||||
Spring Framework 3.0 is the next generation of Spring: fully Java 5 based,
|
||||
EL enabled, REST enabled, and with support for JSR-330 (Dependency
|
||||
Injection) and JSR-303 (Bean Validation).
|
||||
|
||||
2. RELEASE NOTES
|
||||
|
||||
This release comes with complete reference documentation. For further details,
|
||||
consult the provided javadoc for specific packages and classes.
|
||||
This release comes with complete reference documentation. For further
|
||||
details, consult the provided javadoc for specific packages and classes.
|
||||
|
||||
3. DISTRIBUTION JAR FILES
|
||||
|
||||
The Spring Framework module jar files can be found in the 'dist' directory. Note that
|
||||
this release does not contain a 'spring.jar' file anymore, in contrast to previous Spring
|
||||
generations. Furthermore, the jar file names follow bundle repository conventions now.
|
||||
The Spring Framework module jar files can be found in the 'dist'
|
||||
directory. Note that this release does not contain a 'spring.jar' file
|
||||
anymore, in contrast to previous Spring generations. Furthermore, the jar
|
||||
file names now follow bundle repository conventions.
|
||||
|
||||
4. GETTING STARTED
|
||||
|
||||
Please consult the blog examples at http://blog.springsource.com as well as the sections
|
||||
of interest in the reference documentation. Sample applications and related material
|
||||
will be provided as separate downloads.
|
||||
Please consult the blog examples at http://blog.springsource.com as well
|
||||
as sections of interest in the reference documentation. Sample
|
||||
applications and related material are provided as separate downloads.
|
||||
|
||||
+30
-30
@@ -1,30 +1,30 @@
|
||||
version=3.0.2
|
||||
# osgi ranges
|
||||
spring.osgi.range.nq=${version:[=.=.=, =.=.+1)}
|
||||
spring.osgi.range="${spring.osgi.range.nq}"
|
||||
aj.osgi.range="[1.5.4, 2.0.0)"
|
||||
|
||||
#
|
||||
release.type=release
|
||||
build.stamp=RELEASE
|
||||
natural.name=spring-framework
|
||||
project.name=Spring Framework
|
||||
project.key=SPR
|
||||
ivy.cache.dir=${basedir}/../ivy-cache
|
||||
integration.repo.dir=${basedir}/../integration-repo
|
||||
javadoc.exclude.package.names=org/springframework/samples/**
|
||||
javadoc.max.memory=256M
|
||||
test.vm.args=-Xmx1024M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError
|
||||
compiler.args=-enableJavadoc -warn:none
|
||||
|
||||
# For when releasing
|
||||
#release.type=release
|
||||
#build.stamp=RELEASE
|
||||
|
||||
# For when releasing milestones
|
||||
#release.type=milestone
|
||||
#build.stamp=M1
|
||||
|
||||
# For development in trunk
|
||||
#release.type=integration
|
||||
#build.stamp=BUILD-SNAPSHOT
|
||||
version=3.0.8
|
||||
# osgi ranges
|
||||
spring.osgi.range.nq=${version:[=.=.=, =.=.+1)}
|
||||
spring.osgi.range="${spring.osgi.range.nq}"
|
||||
aj.osgi.range="[1.5.4, 2.0.0)"
|
||||
|
||||
#
|
||||
#release.type=integration
|
||||
natural.name=spring-framework
|
||||
project.name=Spring Framework
|
||||
project.key=SPR
|
||||
ivy.cache.dir=${basedir}/../ivy-cache
|
||||
integration.repo.dir=${basedir}/../integration-repo
|
||||
license.dir=${basedir}/../build-spring-framework/resources
|
||||
javadoc.exclude.package.names=org/springframework/samples/**
|
||||
javadoc.max.memory=256M
|
||||
test.vm.args=-Xmx1024M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError
|
||||
compiler.args=-enableJavadoc -warn:none
|
||||
|
||||
# For when releasing
|
||||
#release.type=release
|
||||
#build.stamp=RELEASE
|
||||
|
||||
# For when releasing milestones
|
||||
#release.type=milestone
|
||||
#build.stamp=M1
|
||||
|
||||
# For development in trunk
|
||||
release.type=integration
|
||||
build.stamp=BUILD-SNAPSHOT
|
||||
|
||||
+5
-6
@@ -1,6 +1,5 @@
|
||||
#common dependency versions
|
||||
aspectj.version=1.6.8.RELEASE
|
||||
commons.pool.version=1.5.3
|
||||
slf4j.version=1.5.6
|
||||
org.testng.version=5.10.0
|
||||
org.junit.version=4.7.0
|
||||
#common dependency versions
|
||||
aspectj.version=1.6.8.RELEASE
|
||||
slf4j.version=1.5.3
|
||||
junit.version=4.7.0
|
||||
testng.version=5.10.0
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
<artifact name="license" type="license" ext="txt"/>
|
||||
<artifact name="notice" type="notice" ext="txt"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
@@ -28,14 +30,14 @@
|
||||
<dependency org="net.sourceforge.cglib" name="com.springsource.net.sf.cglib" rev="2.2.0" conf="optional, bytecode-proxy->compile"/>
|
||||
<dependency org="org.aopalliance" name="com.springsource.org.aopalliance" rev="1.0.0" conf="compile->compile"/>
|
||||
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile, commons-logging->compile"/>
|
||||
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.pool" rev="${commons.pool.version}" conf="optional, pooling->compile"/>
|
||||
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.pool" rev="1.5.3" conf="optional, pooling->compile"/>
|
||||
<dependency org="org.aspectj" name="com.springsource.org.aspectj.weaver" rev="${aspectj.version}" conf="optional, aspectj->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.beans" rev="latest.integration" conf="compile->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.core" rev="latest.integration" conf="compile->compile"/>
|
||||
<!-- test dependencies -->
|
||||
<dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15" conf="test->runtime"/>
|
||||
<dependency org="org.easymock" name="com.springsource.org.easymock" rev="2.5.1" conf="test->compile"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${org.junit.version}" conf="test->runtime"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->runtime"/>
|
||||
<dependency org="org.springframework" name="org.springframework.asm" rev="latest.integration" conf="test->runtime"/>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -34,6 +34,6 @@ public interface TargetClassAware {
|
||||
* (typically a proxy configuration or an actual proxy).
|
||||
* @return the target Class, or <code>null</code> if not known
|
||||
*/
|
||||
Class getTargetClass();
|
||||
Class<?> getTargetClass();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*<
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,7 +39,7 @@ public interface TargetSource extends TargetClassAware {
|
||||
* target class.
|
||||
* @return the type of targets returned by this {@link TargetSource}
|
||||
*/
|
||||
Class getTargetClass();
|
||||
Class<?> getTargetClass();
|
||||
|
||||
/**
|
||||
* Will all calls to {@link #getTarget()} return the same object?
|
||||
|
||||
+25
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,6 +54,7 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -95,12 +96,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class);
|
||||
|
||||
private transient PointcutParser pointcutParser;
|
||||
|
||||
private transient PointcutExpression pointcutExpression;
|
||||
|
||||
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
|
||||
private Class pointcutDeclarationScope;
|
||||
|
||||
private String[] pointcutParameterNames = new String[0];
|
||||
@@ -109,12 +104,15 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private transient PointcutExpression pointcutExpression;
|
||||
|
||||
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
|
||||
|
||||
/**
|
||||
* Create a new default AspectJExpressionPointcut.
|
||||
*/
|
||||
public AspectJExpressionPointcut() {
|
||||
initializePointcutParser();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +122,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
* @param paramTypes the parameter types for the pointcut
|
||||
*/
|
||||
public AspectJExpressionPointcut(Class declarationScope, String[] paramNames, Class[] paramTypes) {
|
||||
initializePointcutParser();
|
||||
this.pointcutDeclarationScope = declarationScope;
|
||||
if (paramNames.length != paramTypes.length) {
|
||||
throw new IllegalStateException(
|
||||
@@ -134,13 +131,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
this.pointcutParameterTypes = paramTypes;
|
||||
}
|
||||
|
||||
private void initializePointcutParser() {
|
||||
this.pointcutParser =
|
||||
PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(
|
||||
SUPPORTED_PRIMITIVES);
|
||||
this.pointcutParser.registerPointcutDesignatorHandler(new BeanNamePointcutDesignatorHandler());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the declaration scope for the pointcut.
|
||||
@@ -196,15 +186,30 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
private PointcutExpression buildPointcutExpression() {
|
||||
PointcutParser parser = initializePointcutParser();
|
||||
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
|
||||
for (int i = 0; i < pointcutParameters.length; i++) {
|
||||
pointcutParameters[i] = this.pointcutParser.createPointcutParameter(
|
||||
pointcutParameters[i] = parser.createPointcutParameter(
|
||||
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
|
||||
}
|
||||
return this.pointcutParser.parsePointcutExpression(
|
||||
return parser.parsePointcutExpression(
|
||||
replaceBooleanOperators(getExpression()), this.pointcutDeclarationScope, pointcutParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the underlying AspectJ pointcut parser.
|
||||
*/
|
||||
private PointcutParser initializePointcutParser() {
|
||||
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||
Thread.currentThread().getContextClassLoader());
|
||||
PointcutParser parser =
|
||||
PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
|
||||
SUPPORTED_PRIMITIVES, cl);
|
||||
parser.registerPointcutDesignatorHandler(new BeanNamePointcutDesignatorHandler());
|
||||
return parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a pointcut expression has been specified in XML, the user cannot
|
||||
* write <code>and</code> as "&&" (though && will work).
|
||||
@@ -218,6 +223,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
@@ -226,7 +232,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
return this.pointcutExpression;
|
||||
}
|
||||
|
||||
|
||||
public boolean matches(Class targetClass) {
|
||||
checkReadyToMatch();
|
||||
try {
|
||||
@@ -455,7 +460,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
/**
|
||||
* Matcher class for the BeanNamePointcutDesignatorHandler.
|
||||
*
|
||||
* <p>Dynamic match tests for this matcher always return true,
|
||||
* since the matching decision is made at the proxy creation time.
|
||||
* For static match tests, this matcher abstains to allow the overall
|
||||
@@ -535,7 +539,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
ois.defaultReadObject();
|
||||
|
||||
// Initialize transient fields.
|
||||
initializePointcutParser();
|
||||
// pointcutExpression will be initialized lazily by checkReadyToMatch()
|
||||
this.shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
}
|
||||
|
||||
|
||||
+31
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -215,9 +215,10 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
*/
|
||||
protected static class AspectJAnnotation<A extends Annotation> {
|
||||
|
||||
private static Map<Class,AspectJAnnotationType> annotationTypes = new HashMap<Class,AspectJAnnotationType>();
|
||||
private static final String[] EXPRESSION_PROPERTIES = new String[] {"value", "pointcut"};
|
||||
|
||||
private static final String[] EXPRESSION_PROPERTIES = new String[]{"value", "pointcut"};
|
||||
private static Map<Class, AspectJAnnotationType> annotationTypes =
|
||||
new HashMap<Class, AspectJAnnotationType>();
|
||||
|
||||
static {
|
||||
annotationTypes.put(Pointcut.class,AspectJAnnotationType.AtPointcut);
|
||||
@@ -229,46 +230,48 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
}
|
||||
|
||||
private final A annotation;
|
||||
private AspectJAnnotationType annotationType;
|
||||
private final String expression;
|
||||
private final String argNames;
|
||||
|
||||
public AspectJAnnotation(A aspectjAnnotation) {
|
||||
this.annotation = aspectjAnnotation;
|
||||
for (Class type : annotationTypes.keySet()) {
|
||||
if (type.isInstance(this.annotation)) {
|
||||
this.annotationType = annotationTypes.get(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this.annotationType == null) {
|
||||
throw new IllegalStateException("Unknown annotation type: " + this.annotation.toString());
|
||||
}
|
||||
private final AspectJAnnotationType annotationType;
|
||||
|
||||
private final String pointcutExpression;
|
||||
|
||||
private final String argumentNames;
|
||||
|
||||
public AspectJAnnotation(A annotation) {
|
||||
this.annotation = annotation;
|
||||
this.annotationType = determineAnnotationType(annotation);
|
||||
// We know these methods exist with the same name on each object,
|
||||
// but need to invoke them reflectively as there isn't a common interface.
|
||||
try {
|
||||
this.expression = resolveExpression();
|
||||
this.argNames = (String)
|
||||
this.annotation.getClass().getMethod("argNames", (Class[]) null).invoke(this.annotation);
|
||||
this.pointcutExpression = resolveExpression(annotation);
|
||||
this.argumentNames = (String) annotation.getClass().getMethod("argNames").invoke(annotation);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException(aspectjAnnotation + " cannot be an AspectJ annotation", ex);
|
||||
throw new IllegalArgumentException(annotation + " cannot be an AspectJ annotation", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveExpression() throws Exception {
|
||||
private AspectJAnnotationType determineAnnotationType(A annotation) {
|
||||
for (Class type : annotationTypes.keySet()) {
|
||||
if (type.isInstance(annotation)) {
|
||||
return annotationTypes.get(type);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Unknown annotation type: " + annotation.toString());
|
||||
}
|
||||
|
||||
private String resolveExpression(A annotation) throws Exception {
|
||||
String expression = null;
|
||||
for (String methodName : EXPRESSION_PROPERTIES) {
|
||||
Method method;
|
||||
try {
|
||||
method = this.annotation.getClass().getDeclaredMethod(methodName);
|
||||
method = annotation.getClass().getDeclaredMethod(methodName);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
method = null;
|
||||
}
|
||||
if (method != null) {
|
||||
String candidate = (String) method.invoke(this.annotation);
|
||||
String candidate = (String) method.invoke(annotation);
|
||||
if (StringUtils.hasText(candidate)) {
|
||||
expression = candidate;
|
||||
}
|
||||
@@ -286,11 +289,11 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
}
|
||||
|
||||
public String getPointcutExpression() {
|
||||
return this.expression;
|
||||
return this.pointcutExpression;
|
||||
}
|
||||
|
||||
public String getArgNames() {
|
||||
return this.argNames;
|
||||
public String getArgumentNames() {
|
||||
return this.argumentNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -314,7 +317,7 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
if (annotation == null) {
|
||||
return null;
|
||||
}
|
||||
StringTokenizer strTok = new StringTokenizer(annotation.getArgNames(), ",");
|
||||
StringTokenizer strTok = new StringTokenizer(annotation.getArgumentNames(), ",");
|
||||
if (strTok.countTokens() > 0) {
|
||||
String[] names = new String[strTok.countTokens()];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
|
||||
+8
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -97,6 +97,13 @@ public abstract class AopConfigUtils {
|
||||
}
|
||||
}
|
||||
|
||||
static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
|
||||
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
|
||||
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
|
||||
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static BeanDefinition registerOrEscalateApcAsRequired(Class cls, BeanDefinitionRegistry registry, Object source) {
|
||||
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
|
||||
|
||||
+10
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,6 +46,11 @@ public abstract class AopNamespaceUtils {
|
||||
*/
|
||||
public static final String PROXY_TARGET_CLASS_ATTRIBUTE = "proxy-target-class";
|
||||
|
||||
/**
|
||||
* The <code>expose-proxy</code> attribute as found on AOP-related XML tags.
|
||||
*/
|
||||
private static final String EXPOSE_PROXY_ATTRIBUTE = "expose-proxy";
|
||||
|
||||
|
||||
public static void registerAutoProxyCreatorIfNecessary(
|
||||
ParserContext parserContext, Element sourceElement) {
|
||||
@@ -102,6 +107,10 @@ public abstract class AopNamespaceUtils {
|
||||
if (proxyTargetClass) {
|
||||
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
|
||||
}
|
||||
boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
|
||||
if (exposeProxy) {
|
||||
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-14
@@ -102,20 +102,17 @@ class ConfigBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
configureAutoProxyCreator(parserContext, element);
|
||||
|
||||
NodeList childNodes = element.getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node node = childNodes.item(i);
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
String localName = parserContext.getDelegate().getLocalName(node);
|
||||
if (POINTCUT.equals(localName)) {
|
||||
parsePointcut((Element) node, parserContext);
|
||||
}
|
||||
else if (ADVISOR.equals(localName)) {
|
||||
parseAdvisor((Element) node, parserContext);
|
||||
}
|
||||
else if (ASPECT.equals(localName)) {
|
||||
parseAspect((Element) node, parserContext);
|
||||
}
|
||||
List<Element> childElts = DomUtils.getChildElements(element);
|
||||
for (Element elt: childElts) {
|
||||
String localName = parserContext.getDelegate().getLocalName(elt);
|
||||
if (POINTCUT.equals(localName)) {
|
||||
parsePointcut(elt, parserContext);
|
||||
}
|
||||
else if (ADVISOR.equals(localName)) {
|
||||
parseAdvisor(elt, parserContext);
|
||||
}
|
||||
else if (ASPECT.equals(localName)) {
|
||||
parseAspect(elt, parserContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -162,7 +162,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
this.targetSource = EmptyTargetSource.forClass(targetClass);
|
||||
}
|
||||
|
||||
public Class getTargetClass() {
|
||||
public Class<?> getTargetClass() {
|
||||
return this.targetSource.getTargetClass();
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -76,7 +76,12 @@ public abstract class AopContext {
|
||||
*/
|
||||
static Object setCurrentProxy(Object proxy) {
|
||||
Object old = currentProxy.get();
|
||||
currentProxy.set(proxy);
|
||||
if (proxy != null) {
|
||||
currentProxy.set(proxy);
|
||||
}
|
||||
else {
|
||||
currentProxy.remove();
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
+36
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,10 @@ package org.springframework.aop.framework;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.aop.SpringProxy;
|
||||
import org.springframework.aop.TargetClassAware;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.aop.target.SingletonTargetSource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -34,6 +38,37 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public abstract class AopProxyUtils {
|
||||
|
||||
/**
|
||||
* 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 -
|
||||
* as long as possible without side effects, that is, just for singleton targets.
|
||||
* @param candidate the instance to check (might be an AOP proxy)
|
||||
* @return the target class (or the plain class of the given object as fallback;
|
||||
* never <code>null</code>)
|
||||
* @see org.springframework.aop.TargetClassAware#getTargetClass()
|
||||
* @see org.springframework.aop.framework.Advised#getTargetSource()
|
||||
*/
|
||||
public static Class<?> ultimateTargetClass(Object candidate) {
|
||||
Assert.notNull(candidate, "Candidate object must not be null");
|
||||
Object current = candidate;
|
||||
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;
|
||||
}
|
||||
if (result == null) {
|
||||
result = (AopUtils.isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the complete set of interfaces to proxy for the given AOP configuration.
|
||||
* <p>This will always add the {@link Advised} interface unless the AdvisedSupport's
|
||||
|
||||
+5
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -268,7 +268,7 @@ final class Cglib2AopProxy implements AopProxy, Serializable {
|
||||
|
||||
// Choose a "straight to target" interceptor. (used for calls that are
|
||||
// unadvised but can return this). May be required to expose the proxy.
|
||||
Callback targetInterceptor = null;
|
||||
Callback targetInterceptor;
|
||||
if (exposeProxy) {
|
||||
targetInterceptor = isStatic ?
|
||||
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
|
||||
@@ -316,12 +316,8 @@ final class Cglib2AopProxy implements AopProxy, Serializable {
|
||||
// Now copy both the callbacks from mainCallbacks
|
||||
// and fixedCallbacks into the callbacks array.
|
||||
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
|
||||
for (int x = 0; x < mainCallbacks.length; x++) {
|
||||
callbacks[x] = mainCallbacks[x];
|
||||
}
|
||||
for (int x = 0; x < fixedCallbacks.length; x++) {
|
||||
callbacks[x + mainCallbacks.length] = fixedCallbacks[x];
|
||||
}
|
||||
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
|
||||
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
|
||||
this.fixedInterceptorOffset = mainCallbacks.length;
|
||||
}
|
||||
else {
|
||||
@@ -610,7 +606,7 @@ final class Cglib2AopProxy implements AopProxy, Serializable {
|
||||
targetClass = target.getClass();
|
||||
}
|
||||
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
|
||||
Object retVal = null;
|
||||
Object retVal;
|
||||
// Check whether we only have one InvokerInterceptor: that is,
|
||||
// no real advice, but just reflective invocation of the target.
|
||||
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
|
||||
|
||||
+5
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -113,12 +113,14 @@ public class ProxyConfig implements Serializable {
|
||||
* ThreadLocal for retrieval via the AopContext class. This is useful
|
||||
* if an advised object needs to call another advised method on itself.
|
||||
* (If it uses <code>this</code>, the invocation will not be advised).
|
||||
* <p>Default is "false", for optimal performance.
|
||||
* <p>Default is "false", in order to avoid unnecessary extra interception.
|
||||
* This means that no guarantees are provided that AopContext access will
|
||||
* work consistently within any method of the advised object.
|
||||
*/
|
||||
public void setExposeProxy(boolean exposeProxy) {
|
||||
this.exposeProxy = exposeProxy;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return whether the AOP proxy will expose the AOP proxy for
|
||||
* each invocation.
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,7 +46,12 @@ public class ProxyCreationContext {
|
||||
* @param beanName the name of the bean, or <code>null</code> to reset it
|
||||
*/
|
||||
static void setCurrentProxiedBeanName(String beanName) {
|
||||
currentProxiedBeanName.set(beanName);
|
||||
if (beanName != null) {
|
||||
currentProxiedBeanName.set(beanName);
|
||||
}
|
||||
else {
|
||||
currentProxiedBeanName.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -70,8 +70,9 @@ public class ExposeInvocationInterceptor implements MethodInterceptor, Ordered,
|
||||
MethodInvocation mi = invocation.get();
|
||||
if (mi == null)
|
||||
throw new IllegalStateException(
|
||||
"No MethodInvocation found: Check that an AOP invocation is in progress, " +
|
||||
"and that the ExposeInvocationInterceptor is in the interceptor chain.");
|
||||
"No MethodInvocation found: Check that an AOP invocation is in progress, and that the " +
|
||||
"ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that " +
|
||||
"advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!");
|
||||
return mi;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,13 +98,13 @@ public abstract class AopUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the target class of the given bean instance,
|
||||
* which might be an AOP proxy.
|
||||
* Determine the target class of the given bean instance which might be an AOP proxy.
|
||||
* <p>Returns the target class for an AOP proxy and the plain class else.
|
||||
* @param candidate the instance to check (might be an AOP proxy)
|
||||
* @return the target class (or the plain class of the given object as fallback;
|
||||
* never <code>null</code>)
|
||||
* @see org.springframework.aop.TargetClassAware#getTargetClass()
|
||||
* @see org.springframework.aop.framework.AopProxyUtils#ultimateTargetClass(Object)
|
||||
*/
|
||||
public static Class<?> getTargetClass(Object candidate) {
|
||||
Assert.notNull(candidate, "Candidate object must not be null");
|
||||
@@ -301,7 +301,7 @@ public abstract class AopUtils {
|
||||
* @throws org.springframework.aop.AopInvocationException in case of a reflection error
|
||||
*/
|
||||
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
throws Throwable {
|
||||
|
||||
// Use reflection to invoke the method.
|
||||
try {
|
||||
|
||||
+8
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,15 +16,12 @@
|
||||
|
||||
package org.springframework.aop.target;
|
||||
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -65,7 +62,7 @@ public abstract class AbstractBeanFactoryBasedTargetSource
|
||||
private String targetBeanName;
|
||||
|
||||
/** Class of the target */
|
||||
private Class targetClass;
|
||||
private Class<?> targetClass;
|
||||
|
||||
/**
|
||||
* BeanFactory that owns this TargetSource. We need to hold onto this
|
||||
@@ -108,7 +105,7 @@ public abstract class AbstractBeanFactoryBasedTargetSource
|
||||
* Set the owning BeanFactory. We need to save a reference so that we can
|
||||
* use the <code>getBean</code> method on every invocation.
|
||||
*/
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
if (this.targetBeanName == null) {
|
||||
throw new IllegalStateException("Property'targetBeanName' is required");
|
||||
}
|
||||
@@ -123,7 +120,7 @@ public abstract class AbstractBeanFactoryBasedTargetSource
|
||||
}
|
||||
|
||||
|
||||
public synchronized Class getTargetClass() {
|
||||
public synchronized Class<?> getTargetClass() {
|
||||
if (this.targetClass == null && this.beanFactory != null) {
|
||||
// Determine type of the target bean.
|
||||
this.targetClass = this.beanFactory.getType(this.targetBeanName);
|
||||
@@ -131,7 +128,10 @@ public abstract class AbstractBeanFactoryBasedTargetSource
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Getting bean with name '" + this.targetBeanName + "' in order to determine type");
|
||||
}
|
||||
this.targetClass = this.beanFactory.getBean(this.targetBeanName).getClass();
|
||||
Object beanInstance = this.beanFactory.getBean(this.targetBeanName);
|
||||
if (beanInstance != null) {
|
||||
this.targetClass = beanInstance.getClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.targetClass;
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -64,7 +64,7 @@ public abstract class AbstractLazyCreationTargetSource implements TargetSource {
|
||||
* a meaningful value when the target is still <code>null</code>.
|
||||
* @see #isInitialized()
|
||||
*/
|
||||
public synchronized Class getTargetClass() {
|
||||
public synchronized Class<?> getTargetClass() {
|
||||
return (this.lazyTarget != null ? this.lazyTarget.getClass() : null);
|
||||
}
|
||||
|
||||
|
||||
+8
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.springframework.aop.target;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
@@ -91,6 +93,11 @@ public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFac
|
||||
// Serialization support
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||
throw new NotSerializableException("A prototype-based TargetSource itself is not deserializable - " +
|
||||
"just a disconnected SingletonTargetSource is");
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces this object with a SingletonTargetSource on serialization.
|
||||
* Protected as otherwise it won't be invoked for subclasses.
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -89,7 +89,7 @@ public class EmptyTargetSource implements TargetSource, Serializable {
|
||||
/**
|
||||
* Always returns the specified target Class, or <code>null</code> if none.
|
||||
*/
|
||||
public Class getTargetClass() {
|
||||
public Class<?> getTargetClass() {
|
||||
return this.targetClass;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,7 +59,7 @@ public class HotSwappableTargetSource implements TargetSource, Serializable {
|
||||
* Return the type of the current target object.
|
||||
* <p>The returned type should usually be constant across all target objects.
|
||||
*/
|
||||
public synchronized Class getTargetClass() {
|
||||
public synchronized Class<?> getTargetClass() {
|
||||
return this.target.getClass();
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -55,7 +55,7 @@ public class SingletonTargetSource implements TargetSource, Serializable {
|
||||
}
|
||||
|
||||
|
||||
public Class getTargetClass() {
|
||||
public Class<?> getTargetClass() {
|
||||
return this.target.getClass();
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -106,7 +106,7 @@ public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
|
||||
this.targetSet.clear();
|
||||
}
|
||||
// Clear ThreadLocal, just in case.
|
||||
this.targetInThread.set(null);
|
||||
this.targetInThread.remove();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -63,7 +63,7 @@ public abstract class AbstractRefreshableTargetSource implements TargetSource, R
|
||||
}
|
||||
|
||||
|
||||
public synchronized Class getTargetClass() {
|
||||
public synchronized Class<?> getTargetClass() {
|
||||
if (this.targetObject == null) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
+18
@@ -56,6 +56,15 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="expose-proxy" type="xsd:boolean" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicate that the proxy should be exposed by the AOP framework as a
|
||||
ThreadLocal for retrieval via the AopContext class. Off by default,
|
||||
i.e. no guarantees that AopContext access will work.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
@@ -84,6 +93,15 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="expose-proxy" type="xsd:boolean" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicate that the proxy should be exposed by the AOP framework as a
|
||||
ThreadLocal for retrieval via the AopContext class. Off by default,
|
||||
i.e. no guarantees that AopContext access will work.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
+16
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -293,20 +293,33 @@ public final class ProxyFactoryTests {
|
||||
public void testProxyTargetClassWithInterfaceAsTarget() {
|
||||
ProxyFactory pf = new ProxyFactory();
|
||||
pf.setTargetClass(ITestBean.class);
|
||||
|
||||
Object proxy = pf.getProxy();
|
||||
assertTrue("Proxy is a JDK proxy", AopUtils.isJdkDynamicProxy(proxy));
|
||||
assertTrue(proxy instanceof ITestBean);
|
||||
assertEquals(ITestBean.class, AopProxyUtils.ultimateTargetClass(proxy));
|
||||
|
||||
ProxyFactory pf2 = new ProxyFactory(proxy);
|
||||
Object proxy2 = pf2.getProxy();
|
||||
assertTrue("Proxy is a JDK proxy", AopUtils.isJdkDynamicProxy(proxy2));
|
||||
assertTrue(proxy2 instanceof ITestBean);
|
||||
assertEquals(ITestBean.class, AopProxyUtils.ultimateTargetClass(proxy2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProxyTargetClassWithConcreteClassAsTarget() {
|
||||
ProxyFactory pf = new ProxyFactory();
|
||||
pf.setTargetClass(TestBean.class);
|
||||
|
||||
Object proxy = pf.getProxy();
|
||||
assertTrue("Proxy is a CGLIB proxy", AopUtils.isCglibProxy(proxy));
|
||||
assertTrue(proxy instanceof TestBean);
|
||||
assertEquals(TestBean.class, AopProxyUtils.ultimateTargetClass(proxy));
|
||||
|
||||
ProxyFactory pf2 = new ProxyFactory(proxy);
|
||||
pf2.setProxyTargetClass(true);
|
||||
Object proxy2 = pf2.getProxy();
|
||||
assertTrue("Proxy is a CGLIB proxy", AopUtils.isCglibProxy(proxy2));
|
||||
assertTrue(proxy2 instanceof TestBean);
|
||||
assertEquals(TestBean.class, AopProxyUtils.ultimateTargetClass(proxy2));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<artifacts pattern="${jar.output.dir}/[artifact].[ext]"/>
|
||||
<artifacts pattern="${source-jar.output.dir}/[artifact].[ext]"/>
|
||||
<artifacts pattern="${ivy.output.dir}/[artifact].[ext]"/>
|
||||
<artifacts pattern="${license.dir}/[artifact].[ext]"/>
|
||||
</ivy:publish>
|
||||
</target>
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
<artifact name="license" type="license" ext="txt"/>
|
||||
<artifact name="notice" type="notice" ext="txt"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-asm</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>jarjar</id>
|
||||
<phase>process-classes</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpathref="maven.plugin.classpath" />
|
||||
<jarjar jarfile="${project.build.directory}${file.separator}${project.build.finalName}-jarjar.jar">
|
||||
<zipfileset src="${project.build.directory}/jarjar-staging/com.springsource.org.objectweb.asm.jar"/>
|
||||
<zipfileset src="${project.build.directory}/jarjar-staging/com.springsource.org.objectweb.asm.commons.jar"/>
|
||||
<rule pattern="org.objectweb.asm.**" result="org.springframework.asm.@1"/>
|
||||
</jarjar>
|
||||
<unjar src="${project.build.directory}${file.separator}${project.build.finalName}-jarjar.jar"
|
||||
dest="${project.build.outputDirectory}">
|
||||
<patternset>
|
||||
<include name="**/*.class"/>
|
||||
<exclude name="*"/>
|
||||
</patternset>
|
||||
</unjar>
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code</groupId>
|
||||
<artifactId>jarjar</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-asm</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>jarjar</id>
|
||||
<phase>process-classes</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpathref="maven.plugin.classpath" />
|
||||
<jarjar jarfile="${project.build.directory}${file.separator}${project.build.finalName}-jarjar.jar">
|
||||
<zipfileset src="${project.build.directory}/jarjar-staging/com.springsource.org.objectweb.asm.jar"/>
|
||||
<zipfileset src="${project.build.directory}/jarjar-staging/com.springsource.org.objectweb.asm.commons.jar"/>
|
||||
<rule pattern="org.objectweb.asm.**" result="org.springframework.asm.@1"/>
|
||||
</jarjar>
|
||||
<unjar src="${project.build.directory}${file.separator}${project.build.finalName}-jarjar.jar"
|
||||
dest="${project.build.outputDirectory}">
|
||||
<patternset>
|
||||
<include name="**/*.class"/>
|
||||
<exclude name="*"/>
|
||||
</patternset>
|
||||
</unjar>
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code</groupId>
|
||||
<artifactId>jarjar</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
<artifact name="license" type="license" ext="txt"/>
|
||||
<artifact name="notice" type="notice" ext="txt"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
@@ -31,9 +33,9 @@
|
||||
<dependency org="org.springframework" name="org.springframework.test" rev="latest.integration" conf="test->runtime"/>
|
||||
<dependency org="org.springframework" name="org.springframework.context" rev="latest.integration" conf="test->runtime"/>
|
||||
<dependency org="org.springframework" name="org.springframework.context.support" rev="latest.integration" conf="test->runtime"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${org.junit.version}" conf="test->compile"/>
|
||||
<dependency org="javax.persistence" name="com.springsource.javax.persistence" rev="1.0.0" conf="optional, compile->compile"/>
|
||||
<dependency org="javax.mail" name="com.springsource.javax.mail" rev="1.4.0" conf="test->compile"/>
|
||||
<dependency org="javax.persistence" name="com.springsource.javax.persistence" rev="1.0.0" conf="optional, orm->compile"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->compile"/>
|
||||
<dependency org="javax.mail" name="com.springsource.javax.mail" rev="1.4.0" conf="optional, test->compile"/>
|
||||
</dependencies>
|
||||
|
||||
</ivy-module>
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aspects</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<!-- common logging dependency is in spring-core -->
|
||||
<!-- commons logging dependency is in spring-core -->
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
@@ -31,6 +31,12 @@
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-orm</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
@@ -49,6 +55,12 @@
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>1.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
@@ -58,12 +70,7 @@
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>mail</artifactId>
|
||||
<version>1.4</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
+16
-1
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -12,7 +28,6 @@ import java.util.List;
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {
|
||||
|
||||
|
||||
+26
-13
@@ -1,18 +1,33 @@
|
||||
package org.springframework.mock.staticmock;
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import javax.persistence.Entity;
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
/**
|
||||
* Annotation-based aspect to use in test build to enable mocking static methods
|
||||
* on Entity classes, as used by Roo for finders.
|
||||
* <br>
|
||||
* Mocking will occur in the call stack of any method in a class (typically a test class)
|
||||
* on JPA-annotated <code>@Entity</code> classes, as used by Roo for finders.
|
||||
*
|
||||
* <p>Mocking will occur in the call stack of any method in a class (typically a test class)
|
||||
* that is annotated with the @MockStaticEntityMethods annotation.
|
||||
* <br>
|
||||
* Also provides static methods to simplify the programming model for
|
||||
*
|
||||
* <p>Also provides static methods to simplify the programming model for
|
||||
* entering playback mode and setting expected return values.
|
||||
* <br>
|
||||
* Usage:<ol>
|
||||
*
|
||||
* <p>Usage:
|
||||
* <ol>
|
||||
* <li>Annotate a test class with @MockStaticEntityMethods.
|
||||
* <li>In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode.
|
||||
* Invoke static methods on Entity classes, with each recording-mode invocation
|
||||
@@ -23,11 +38,9 @@ import javax.persistence.Entity;
|
||||
* occur automatically.
|
||||
* </ol>
|
||||
*
|
||||
* @see MockStaticEntityMethods
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @see MockStaticEntityMethods
|
||||
*/
|
||||
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
|
||||
|
||||
@@ -50,6 +63,6 @@ public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodM
|
||||
// @MockStatics classes to invoke each other without resetting the mocking environment
|
||||
protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..));
|
||||
|
||||
protected pointcut methodToMock() : execution(public static * (@Entity *).*(..));
|
||||
protected pointcut methodToMock() : execution(public static * (@javax.persistence.Entity *).*(..));
|
||||
|
||||
}
|
||||
|
||||
+17
-4
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
@@ -8,11 +23,9 @@ import java.lang.annotation.Target;
|
||||
/**
|
||||
* Annotation to indicate a test class for whose @Test methods
|
||||
* static methods on Entity classes should be mocked.
|
||||
*
|
||||
* @see AbstractMethodMockingControl
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @see AbstractMethodMockingControl
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.scheduling.aspectj;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.support.TaskExecutorAdapter;
|
||||
|
||||
/**
|
||||
* Abstract aspect that routes selected methods asynchronously.
|
||||
*
|
||||
* <p>This aspect needs to be injected with an implementation of
|
||||
* {@link Executor} to activate it for a specific thread pool.
|
||||
* Otherwise it will simply delegate all calls synchronously.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0.5
|
||||
*/
|
||||
public abstract aspect AbstractAsyncExecutionAspect {
|
||||
|
||||
private AsyncTaskExecutor asyncExecutor;
|
||||
|
||||
public void setExecutor(Executor executor) {
|
||||
if (executor instanceof AsyncTaskExecutor) {
|
||||
this.asyncExecutor = (AsyncTaskExecutor) executor;
|
||||
}
|
||||
else {
|
||||
this.asyncExecutor = new TaskExecutorAdapter(executor);
|
||||
}
|
||||
}
|
||||
|
||||
Object around() : asyncMethod() {
|
||||
if (this.asyncExecutor == null) {
|
||||
return proceed();
|
||||
}
|
||||
Callable<Object> callable = new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
Object result = proceed();
|
||||
if (result instanceof Future) {
|
||||
return ((Future<?>) result).get();
|
||||
}
|
||||
return null;
|
||||
}};
|
||||
Future<?> result = this.asyncExecutor.submit(callable);
|
||||
if (Future.class.isAssignableFrom(((MethodSignature) thisJoinPointStaticPart.getSignature()).getReturnType())) {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract pointcut asyncMethod();
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.scheduling.aspectj;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
/**
|
||||
* Aspect to route methods based on the {@link Async} annotation.
|
||||
*
|
||||
* <p>This aspect routes methods marked with the {@link Async} annotation
|
||||
* as well as methods in classes marked with the same. Any method expected
|
||||
* to be routed asynchronously must return either void, {@link Future},
|
||||
* or a subtype of {@link Future}. This aspect, therefore, will produce
|
||||
* a compile-time error for methods that violate this constraint on the return type.
|
||||
* If, however, a class marked with <code>@Async</code> contains a method that
|
||||
* violates this constraint, it produces only a warning.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @since 3.0.5
|
||||
*/
|
||||
public aspect AnnotationAsyncExecutionAspect extends AbstractAsyncExecutionAspect {
|
||||
|
||||
private pointcut asyncMarkedMethod()
|
||||
: execution(@Async (void || Future+) *(..));
|
||||
|
||||
private pointcut asyncTypeMarkedMethod()
|
||||
: execution((void || Future+) (@Async *).*(..));
|
||||
|
||||
public pointcut asyncMethod() : asyncMarkedMethod() || asyncTypeMarkedMethod();
|
||||
|
||||
declare error:
|
||||
execution(@Async !(void||Future) *(..)):
|
||||
"Only methods that return void or Future may have an @Async annotation";
|
||||
|
||||
declare warning:
|
||||
execution(!(void||Future) (@Async *).*(..)):
|
||||
"Methods in a class marked with @Async that do not return void or Future will be routed synchronously";
|
||||
|
||||
}
|
||||
+93
-93
@@ -1,93 +1,93 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.transaction.interceptor.TransactionAttributeSource;
|
||||
|
||||
/**
|
||||
* Abstract superaspect for AspectJ transaction aspects. Concrete
|
||||
* subaspects will implement the <code>transactionalMethodExecution()</code>
|
||||
* pointcut using a strategy such as Java 5 annotations.
|
||||
*
|
||||
* <p>Suitable for use inside or outside the Spring IoC container.
|
||||
* Set the "transactionManager" property appropriately, allowing
|
||||
* use of any transaction implementation supported by Spring.
|
||||
*
|
||||
* <p><b>NB:</b> If a method implements an interface that is itself
|
||||
* transactionally annotated, the relevant Spring transaction attribute
|
||||
* will <i>not</i> be resolved. This behavior will vary from that of Spring AOP
|
||||
* if proxying an interface (but not when proxying a class). We recommend that
|
||||
* transaction annotations should be added to classes, rather than business
|
||||
* interfaces, as they are an implementation detail rather than a contract
|
||||
* specification validation.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport {
|
||||
|
||||
/**
|
||||
* Construct object using the given transaction metadata retrieval strategy.
|
||||
* @param tas TransactionAttributeSource implementation, retrieving Spring
|
||||
* transaction metadata for each joinpoint. Write the subclass to pass in null
|
||||
* if it's intended to be configured by Setter Injection.
|
||||
*/
|
||||
protected AbstractTransactionAspect(TransactionAttributeSource tas) {
|
||||
setTransactionAttributeSource(tas);
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
before(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
TransactionInfo txInfo = createTransactionIfNecessary(method, txObject.getClass());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) throwing(Throwable t) : transactionalMethodExecution(txObject) {
|
||||
try {
|
||||
completeTransactionAfterThrowing(TransactionAspectSupport.currentTransactionInfo(), t);
|
||||
}
|
||||
catch (Throwable t2) {
|
||||
logger.error("Failed to close transaction after throwing in a transactional method", t2);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) returning() : transactionalMethodExecution(txObject) {
|
||||
commitTransactionAfterReturning(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
cleanupTransactionInfo(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete subaspects must implement this pointcut, to identify
|
||||
* transactional methods. For each selected joinpoint, TransactionMetadata
|
||||
* will be retrieved using Spring's TransactionAttributeSource interface.
|
||||
*/
|
||||
protected abstract pointcut transactionalMethodExecution(Object txObject);
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.transaction.interceptor.TransactionAttributeSource;
|
||||
|
||||
/**
|
||||
* Abstract superaspect for AspectJ transaction aspects. Concrete
|
||||
* subaspects will implement the <code>transactionalMethodExecution()</code>
|
||||
* pointcut using a strategy such as Java 5 annotations.
|
||||
*
|
||||
* <p>Suitable for use inside or outside the Spring IoC container.
|
||||
* Set the "transactionManager" property appropriately, allowing
|
||||
* use of any transaction implementation supported by Spring.
|
||||
*
|
||||
* <p><b>NB:</b> If a method implements an interface that is itself
|
||||
* transactionally annotated, the relevant Spring transaction attribute
|
||||
* will <i>not</i> be resolved. This behavior will vary from that of Spring AOP
|
||||
* if proxying an interface (but not when proxying a class). We recommend that
|
||||
* transaction annotations should be added to classes, rather than business
|
||||
* interfaces, as they are an implementation detail rather than a contract
|
||||
* specification validation.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport {
|
||||
|
||||
/**
|
||||
* Construct object using the given transaction metadata retrieval strategy.
|
||||
* @param tas TransactionAttributeSource implementation, retrieving Spring
|
||||
* transaction metadata for each joinpoint. Write the subclass to pass in null
|
||||
* if it's intended to be configured by Setter Injection.
|
||||
*/
|
||||
protected AbstractTransactionAspect(TransactionAttributeSource tas) {
|
||||
setTransactionAttributeSource(tas);
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
before(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
TransactionInfo txInfo = createTransactionIfNecessary(method, txObject.getClass());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) throwing(Throwable t) : transactionalMethodExecution(txObject) {
|
||||
try {
|
||||
completeTransactionAfterThrowing(TransactionAspectSupport.currentTransactionInfo(), t);
|
||||
}
|
||||
catch (Throwable t2) {
|
||||
logger.error("Failed to close transaction after throwing in a transactional method", t2);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) returning() : transactionalMethodExecution(txObject) {
|
||||
commitTransactionAfterReturning(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
cleanupTransactionInfo(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete subaspects must implement this pointcut, to identify
|
||||
* transactional methods. For each selected joinpoint, TransactionMetadata
|
||||
* will be retrieved using Spring's TransactionAttributeSource interface.
|
||||
*/
|
||||
protected abstract pointcut transactionalMethodExecution(Object txObject);
|
||||
|
||||
}
|
||||
|
||||
+75
-76
@@ -1,76 +1,75 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Concrete AspectJ transaction aspect using Spring Transactional annotation
|
||||
* for JDK 1.5+.
|
||||
*
|
||||
* <p>When using this aspect, you <i>must</i> annotate the implementation class
|
||||
* (and/or methods within that class), <i>not</i> the interface (if any) that
|
||||
* the class implements. AspectJ follows Java's rule that annotations on
|
||||
* interfaces are <i>not</i> inherited.
|
||||
*
|
||||
* <p>A @Transactional annotation on a class specifies the default transaction
|
||||
* semantics for the execution of any <b>public</b> operation in the class.
|
||||
*
|
||||
* <p>A @Transactional annotation on a method within the class overrides the
|
||||
* default transaction semantics given by the class annotation (if present).
|
||||
* Any method may be annotated (regardless of visibility).
|
||||
* Annotating non-public methods directly is the only way
|
||||
* to get transaction demarcation for the execution of such operations.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
*/
|
||||
public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {
|
||||
|
||||
public AnnotationTransactionAspect() {
|
||||
super(new AnnotationTransactionAttributeSource(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the
|
||||
* Transactional annotation, or any subtype of a type with the
|
||||
* Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
|
||||
execution(public * ((@Transactional *)+).*(..)) && @this(Transactional);
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the
|
||||
* Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfTransactionalMethod() :
|
||||
execution(* *(..)) && @annotation(Transactional);
|
||||
|
||||
/**
|
||||
* Definition of pointcut from super aspect - matched join points
|
||||
* will have Spring transaction management applied.
|
||||
*/
|
||||
protected pointcut transactionalMethodExecution(Object txObject) :
|
||||
(executionOfAnyPublicMethodInAtTransactionalType()
|
||||
|| executionOfTransactionalMethod() )
|
||||
&& this(txObject);
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Concrete AspectJ transaction aspect using Spring's @Transactional annotation.
|
||||
*
|
||||
* <p>When using this aspect, you <i>must</i> annotate the implementation class
|
||||
* (and/or methods within that class), <i>not</i> the interface (if any) that
|
||||
* the class implements. AspectJ follows Java's rule that annotations on
|
||||
* interfaces are <i>not</i> inherited.
|
||||
*
|
||||
* <p>A @Transactional annotation on a class specifies the default transaction
|
||||
* semantics for the execution of any <b>public</b> operation in the class.
|
||||
*
|
||||
* <p>A @Transactional annotation on a method within the class overrides the
|
||||
* default transaction semantics given by the class annotation (if present).
|
||||
* Any method may be annotated (regardless of visibility).
|
||||
* Annotating non-public methods directly is the only way
|
||||
* to get transaction demarcation for the execution of such operations.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
*/
|
||||
public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {
|
||||
|
||||
public AnnotationTransactionAspect() {
|
||||
super(new AnnotationTransactionAttributeSource(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the
|
||||
* Transactional annotation, or any subtype of a type with the
|
||||
* Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
|
||||
execution(public * ((@Transactional *)+).*(..)) && @this(Transactional);
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the
|
||||
* Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfTransactionalMethod() :
|
||||
execution(* *(..)) && @annotation(Transactional);
|
||||
|
||||
/**
|
||||
* Definition of pointcut from super aspect - matched join points
|
||||
* will have Spring transaction management applied.
|
||||
*/
|
||||
protected pointcut transactionalMethodExecution(Object txObject) :
|
||||
(executionOfAnyPublicMethodInAtTransactionalType()
|
||||
|| executionOfTransactionalMethod() )
|
||||
&& this(txObject);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
AspectJ load-time weaving config file to install common Spring aspects.
|
||||
-->
|
||||
<aspectj>
|
||||
|
||||
<!--
|
||||
<weaver options="-showWeaveInfo"/>
|
||||
-->
|
||||
|
||||
<aspects>
|
||||
<aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/>
|
||||
<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
|
||||
</aspects>
|
||||
|
||||
</aspectj>
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
AspectJ load-time weaving config file to install common Spring aspects.
|
||||
-->
|
||||
<aspectj>
|
||||
|
||||
<!--
|
||||
<weaver options="-showWeaveInfo"/>
|
||||
-->
|
||||
|
||||
<aspects>
|
||||
<aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/>
|
||||
<aspect name="org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect"/>
|
||||
<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
|
||||
</aspects>
|
||||
|
||||
</aspectj>
|
||||
|
||||
+1
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,12 +16,9 @@
|
||||
|
||||
package org.springframework.aop.aspectj.autoproxy;
|
||||
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
*/
|
||||
@Aspect
|
||||
public aspect CodeStyleAspect {
|
||||
|
||||
private String foo;
|
||||
|
||||
+146
-146
@@ -1,146 +1,146 @@
|
||||
/*
|
||||
* Copyright 2009 SpringSource Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test for static entity mocking framework.
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
@MockStaticEntityMethods
|
||||
@RunWith(JUnit4.class)
|
||||
public class AnnotationDrivenStaticEntityMockingControlTest {
|
||||
|
||||
@Test
|
||||
public void testNoArgIntReturn() {
|
||||
int expectedCount = 13;
|
||||
Person.countPeople();
|
||||
expectReturn(expectedCount);
|
||||
playback();
|
||||
Assert.assertEquals(expectedCount, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected=PersistenceException.class)
|
||||
public void testNoArgThrows() {
|
||||
Person.countPeople();
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodMatches() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLongSeriesOfCalls() {
|
||||
long id1 = 13;
|
||||
long id2 = 24;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(id2);
|
||||
expectReturn(found2);
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person.countPeople();
|
||||
expectReturn(0);
|
||||
playback();
|
||||
|
||||
Assert.assertEquals(found1, Person.findPerson(id1));
|
||||
Assert.assertEquals(found2, Person.findPerson(id2));
|
||||
Assert.assertEquals(found1, Person.findPerson(id1));
|
||||
Assert.assertEquals(0, Person.countPeople());
|
||||
}
|
||||
|
||||
// Note delegation is used when tests are invalid and should fail, as otherwise
|
||||
// the failure will occur on the verify() method in the aspect after
|
||||
// this method returns, failing the test case
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
try {
|
||||
new Delegate().testArgMethodNoMatchExpectReturn();
|
||||
Assert.fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
new Delegate().testArgMethodNoMatchExpectThrow();
|
||||
}
|
||||
|
||||
private void called(Person found, long id) {
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReentrant() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
called(found, id);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testRejectUnexpectedCall() {
|
||||
new Delegate().rejectUnexpectedCall();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testFailTooFewCalls() {
|
||||
new Delegate().failTooFewCalls();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
// Test that verification check doesn't blow up if no replay() call happened
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverReplay() {
|
||||
new Delegate().doesntEverReplay();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverSetReturn() {
|
||||
new Delegate().doesntEverSetReturn();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test for static entity mocking framework.
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
@MockStaticEntityMethods
|
||||
@RunWith(JUnit4.class)
|
||||
public class AnnotationDrivenStaticEntityMockingControlTest {
|
||||
|
||||
@Test
|
||||
public void testNoArgIntReturn() {
|
||||
int expectedCount = 13;
|
||||
Person.countPeople();
|
||||
expectReturn(expectedCount);
|
||||
playback();
|
||||
Assert.assertEquals(expectedCount, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected=PersistenceException.class)
|
||||
public void testNoArgThrows() {
|
||||
Person.countPeople();
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodMatches() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLongSeriesOfCalls() {
|
||||
long id1 = 13;
|
||||
long id2 = 24;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(id2);
|
||||
expectReturn(found2);
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person.countPeople();
|
||||
expectReturn(0);
|
||||
playback();
|
||||
|
||||
Assert.assertEquals(found1, Person.findPerson(id1));
|
||||
Assert.assertEquals(found2, Person.findPerson(id2));
|
||||
Assert.assertEquals(found1, Person.findPerson(id1));
|
||||
Assert.assertEquals(0, Person.countPeople());
|
||||
}
|
||||
|
||||
// Note delegation is used when tests are invalid and should fail, as otherwise
|
||||
// the failure will occur on the verify() method in the aspect after
|
||||
// this method returns, failing the test case
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
try {
|
||||
new Delegate().testArgMethodNoMatchExpectReturn();
|
||||
Assert.fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
new Delegate().testArgMethodNoMatchExpectThrow();
|
||||
}
|
||||
|
||||
private void called(Person found, long id) {
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReentrant() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
called(found, id);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testRejectUnexpectedCall() {
|
||||
new Delegate().rejectUnexpectedCall();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testFailTooFewCalls() {
|
||||
new Delegate().failTooFewCalls();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
// Test that verification check doesn't blow up if no replay() call happened
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverReplay() {
|
||||
new Delegate().doesntEverReplay();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverSetReturn() {
|
||||
new Delegate().doesntEverSetReturn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+92
-76
@@ -1,76 +1,92 @@
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl;
|
||||
import org.springframework.mock.staticmock.MockStaticEntityMethods;
|
||||
|
||||
//Used because verification failures occur after method returns,
|
||||
//so we can't test for them in the test case itself
|
||||
@MockStaticEntityMethods
|
||||
@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl
|
||||
public class Delegate {
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failTooFewCalls() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverReplay() {
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverSetReturn() {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectUnexpectedCall() {
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected=RemoteException.class)
|
||||
public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
// No calls to allow verification failure
|
||||
throw new RemoteException();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl;
|
||||
import org.springframework.mock.staticmock.MockStaticEntityMethods;
|
||||
|
||||
//Used because verification failures occur after method returns,
|
||||
//so we can't test for them in the test case itself
|
||||
@MockStaticEntityMethods
|
||||
@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl
|
||||
public class Delegate {
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failTooFewCalls() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Assert.assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverReplay() {
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverSetReturn() {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectUnexpectedCall() {
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected=RemoteException.class)
|
||||
public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
// No calls to allow verification failure
|
||||
throw new RemoteException();
|
||||
}
|
||||
}
|
||||
|
||||
+24
-8
@@ -1,8 +1,24 @@
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
@Entity
|
||||
public class Person {
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
@Entity
|
||||
public class Person {
|
||||
}
|
||||
|
||||
|
||||
+100
-84
@@ -1,84 +1,100 @@
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
privileged aspect Person_Roo_Entity {
|
||||
|
||||
@javax.persistence.PersistenceContext
|
||||
transient javax.persistence.EntityManager Person.entityManager;
|
||||
|
||||
@javax.persistence.Id
|
||||
@javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
|
||||
@javax.persistence.Column(name = "id")
|
||||
private java.lang.Long Person.id;
|
||||
|
||||
@javax.persistence.Version
|
||||
@javax.persistence.Column(name = "version")
|
||||
private java.lang.Integer Person.version;
|
||||
|
||||
public java.lang.Long Person.getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void Person.setId(java.lang.Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public java.lang.Integer Person.getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public void Person.setVersion(java.lang.Integer version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.persist() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.persist(this);
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.remove() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.remove(this);
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.flush() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.flush();
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.merge() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
Person merged = this.entityManager.merge(this);
|
||||
this.entityManager.flush();
|
||||
this.id = merged.getId();
|
||||
}
|
||||
|
||||
public static long Person.countPeople() {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return (Long) em.createQuery("select count(o) from Person o").getSingleResult();
|
||||
}
|
||||
|
||||
public static java.util.List<Person> Person.findAllPeople() {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.createQuery("select o from Person o").getResultList();
|
||||
}
|
||||
|
||||
public static Person Person.findPerson(java.lang.Long id) {
|
||||
if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Person");
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.find(Person.class, id);
|
||||
}
|
||||
|
||||
public static java.util.List<Person> Person.findPersonEntries(int firstResult, int maxResults) {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.createQuery("select o from Person o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
privileged aspect Person_Roo_Entity {
|
||||
|
||||
@javax.persistence.PersistenceContext
|
||||
transient javax.persistence.EntityManager Person.entityManager;
|
||||
|
||||
@javax.persistence.Id
|
||||
@javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
|
||||
@javax.persistence.Column(name = "id")
|
||||
private java.lang.Long Person.id;
|
||||
|
||||
@javax.persistence.Version
|
||||
@javax.persistence.Column(name = "version")
|
||||
private java.lang.Integer Person.version;
|
||||
|
||||
public java.lang.Long Person.getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void Person.setId(java.lang.Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public java.lang.Integer Person.getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public void Person.setVersion(java.lang.Integer version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.persist() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.persist(this);
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.remove() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.remove(this);
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.flush() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
this.entityManager.flush();
|
||||
}
|
||||
|
||||
@org.springframework.transaction.annotation.Transactional
|
||||
public void Person.merge() {
|
||||
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
Person merged = this.entityManager.merge(this);
|
||||
this.entityManager.flush();
|
||||
this.id = merged.getId();
|
||||
}
|
||||
|
||||
public static long Person.countPeople() {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return (Long) em.createQuery("select count(o) from Person o").getSingleResult();
|
||||
}
|
||||
|
||||
public static java.util.List<Person> Person.findAllPeople() {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.createQuery("select o from Person o").getResultList();
|
||||
}
|
||||
|
||||
public static Person Person.findPerson(java.lang.Long id) {
|
||||
if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Person");
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.find(Person.class, id);
|
||||
}
|
||||
|
||||
public static java.util.List<Person> Person.findPersonEntries(int firstResult, int maxResults) {
|
||||
javax.persistence.EntityManager em = new Person().entityManager;
|
||||
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
|
||||
return em.createQuery("select o from Person o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.scheduling.aspectj;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import static junit.framework.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.AsyncResult;
|
||||
|
||||
/**
|
||||
* @author Ramnivas Laddad
|
||||
*/
|
||||
public class AnnotationAsyncExecutionAspectTests {
|
||||
|
||||
private static final long WAIT_TIME = 1000; //milli seconds
|
||||
|
||||
private CountingExecutor executor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
executor = new CountingExecutor();
|
||||
AnnotationAsyncExecutionAspect.aspectOf().setExecutor(executor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodGetsRoutedAsynchronously() {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
obj.incrementAsync();
|
||||
executor.waitForCompletion();
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodReturningFutureGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
Future<Integer> future = obj.incrementReturningAFuture();
|
||||
// No need to executor.waitForCompletion() as future.get() will have the same effect
|
||||
assertEquals(5, future.get().intValue());
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syncMethodGetsRoutedSynchronously() {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
obj.increment();
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(0, executor.submitStartCounter);
|
||||
assertEquals(0, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void voidMethodInAsyncClassGetsRoutedAsynchronously() {
|
||||
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
|
||||
obj.increment();
|
||||
executor.waitForCompletion();
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodReturningFutureInAsyncClassGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException {
|
||||
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
|
||||
Future<Integer> future = obj.incrementReturningAFuture();
|
||||
assertEquals(5, future.get().intValue());
|
||||
assertEquals(1, obj.counter);
|
||||
assertEquals(1, executor.submitStartCounter);
|
||||
assertEquals(1, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodReturningNonVoidNonFutureInAsyncClassGetsRoutedSynchronously() {
|
||||
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
|
||||
int returnValue = obj.return5();
|
||||
assertEquals(5, returnValue);
|
||||
assertEquals(0, executor.submitStartCounter);
|
||||
assertEquals(0, executor.submitCompleteCounter);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class CountingExecutor extends SimpleAsyncTaskExecutor {
|
||||
int submitStartCounter;
|
||||
int submitCompleteCounter;
|
||||
|
||||
@Override
|
||||
public <T> Future<T> submit(Callable<T> task) {
|
||||
submitStartCounter++;
|
||||
Future<T> future = super.submit(task);
|
||||
submitCompleteCounter++;
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
public synchronized void waitForCompletion() {
|
||||
try {
|
||||
wait(WAIT_TIME);
|
||||
} catch (InterruptedException e) {
|
||||
Assert.fail("Didn't finish the async job in " + WAIT_TIME + " milliseconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class ClassWithoutAsyncAnnotation {
|
||||
int counter;
|
||||
|
||||
@Async public void incrementAsync() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
public void increment() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
@Async public Future<Integer> incrementReturningAFuture() {
|
||||
counter++;
|
||||
return new AsyncResult<Integer>(5);
|
||||
}
|
||||
|
||||
// It should be an error to attach @Async to a method that returns a non-void
|
||||
// or non-Future.
|
||||
// We need to keep this commented out, otherwise there will be a compile-time error.
|
||||
// Please uncomment and re-comment this periodically to check that the compiler
|
||||
// produces an error message due to the 'declare error' statement
|
||||
// in AnnotationAsyncExecutionAspect
|
||||
// @Async public int getInt() {
|
||||
// return 0;
|
||||
// }
|
||||
}
|
||||
|
||||
@Async
|
||||
static class ClassWithAsyncAnnotation {
|
||||
int counter;
|
||||
|
||||
public void increment() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
// Manually check that there is a warning from the 'declare warning' statement in AnnotationAsynchExecutionAspect
|
||||
public int return5() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
public Future<Integer> incrementReturningAFuture() {
|
||||
counter++;
|
||||
return new AsyncResult<Integer>(5);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ Import-Template:
|
||||
org.aspectj.*;version=${aj.osgi.range};resolution:=optional,
|
||||
org.springframework.beans.*;version=${spring.osgi.range},
|
||||
org.springframework.transaction.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.core.task.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.orm.jpa.*;version=${spring.osgi.range};resolution:=optional,
|
||||
org.springframework.dao.*;version=${spring.osgi.range};resolution:=optional
|
||||
Ignored-Existing-Headers:
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
<artifact name="license" type="license" ext="txt"/>
|
||||
<artifact name="notice" type="notice" ext="txt"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
@@ -28,7 +30,7 @@
|
||||
<dependency org="org.springframework" name="org.springframework.core" rev="latest.integration" conf="compile->compile"/>
|
||||
<!-- test dependencies -->
|
||||
<dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15" conf="test->runtime"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${org.junit.version}" conf="test->runtime"/>
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->runtime"/>
|
||||
<dependency org="org.easymock" name="com.springsource.org.easymock" rev="2.5.1" conf="test->compile"/>
|
||||
<dependency org="org.springframework" name="org.springframework.asm" rev="latest.integration" conf="compile->compile"/>
|
||||
</dependencies>
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-parent</artifactId>
|
||||
<relativePath>../org.springframework.spring-parent</relativePath>
|
||||
<version>3.0.2.RELEASE</version>
|
||||
<version>3.0.8.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -92,4 +92,15 @@ public interface BeanWrapper extends ConfigurablePropertyAccessor {
|
||||
*/
|
||||
boolean isAutoGrowNestedPaths();
|
||||
|
||||
/**
|
||||
* Specify a limit for array and collection auto-growing.
|
||||
* <p>Default is unlimited on a plain BeanWrapper.
|
||||
*/
|
||||
void setAutoGrowCollectionLimit(int autoGrowCollectionLimit);
|
||||
|
||||
/**
|
||||
* Return the limit for array and collection auto-growing.
|
||||
*/
|
||||
int getAutoGrowCollectionLimit();
|
||||
|
||||
}
|
||||
|
||||
+158
-150
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -120,6 +120,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
|
||||
private boolean autoGrowNestedPaths = false;
|
||||
|
||||
private int autoGrowCollectionLimit = Integer.MAX_VALUE;
|
||||
|
||||
|
||||
/**
|
||||
* Create new empty BeanWrapperImpl. Wrapped instance needs to be set afterwards.
|
||||
@@ -184,6 +186,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
setWrappedInstance(object, nestedPath, superBw.getWrappedInstance());
|
||||
setExtractOldValueForEditor(superBw.isExtractOldValueForEditor());
|
||||
setAutoGrowNestedPaths(superBw.isAutoGrowNestedPaths());
|
||||
setAutoGrowCollectionLimit(superBw.getAutoGrowCollectionLimit());
|
||||
setConversionService(superBw.getConversionService());
|
||||
setSecurityContext(superBw.acc);
|
||||
}
|
||||
@@ -251,22 +254,38 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
|
||||
/**
|
||||
* If this BeanWrapper should "auto grow" nested paths.
|
||||
* When true, auto growth is triggered on nested paths when null values are encountered.
|
||||
* When true, auto growth is triggered on collection properties when out of bounds indexes are accessed.
|
||||
* Default is false.
|
||||
* Set whether this BeanWrapper should attempt to "auto-grow" a nested path that contains a null value.
|
||||
* <p>If "true", a null path location will be populated with a default object value and traversed
|
||||
* instead of resulting in a {@link NullValueInNestedPathException}. Turning this flag on also
|
||||
* enables auto-growth of collection elements when accessing an out-of-bounds index.
|
||||
* <p>Default is "false" on a plain BeanWrapper.
|
||||
*/
|
||||
public void setAutoGrowNestedPaths(boolean autoGrowNestedPaths) {
|
||||
this.autoGrowNestedPaths = autoGrowNestedPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this BeanWrapper should "auto grow" nested paths.
|
||||
* Return whether "auto-growing" of nested paths has been activated.
|
||||
*/
|
||||
public boolean isAutoGrowNestedPaths() {
|
||||
return this.autoGrowNestedPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a limit for array and collection auto-growing.
|
||||
* <p>Default is unlimited on a plain BeanWrapper.
|
||||
*/
|
||||
public void setAutoGrowCollectionLimit(int autoGrowCollectionLimit) {
|
||||
this.autoGrowCollectionLimit = autoGrowCollectionLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the limit for array and collection auto-growing.
|
||||
*/
|
||||
public int getAutoGrowCollectionLimit() {
|
||||
return this.autoGrowCollectionLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the security context used during the invocation of the wrapped instance methods.
|
||||
* Can be null.
|
||||
@@ -422,8 +441,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
return false;
|
||||
}
|
||||
|
||||
public <T> T convertIfNecessary(
|
||||
Object value, Class<T> requiredType, MethodParameter methodParam) throws TypeMismatchException {
|
||||
public <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam)
|
||||
throws TypeMismatchException {
|
||||
try {
|
||||
return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
|
||||
}
|
||||
@@ -441,6 +460,39 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
|
||||
private Object convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<?> requiredType,
|
||||
TypeDescriptor td) throws TypeMismatchException {
|
||||
try {
|
||||
return this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td);
|
||||
}
|
||||
catch (ConverterNotFoundException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
|
||||
throw new ConversionNotSupportedException(pce, td.getType(), ex);
|
||||
}
|
||||
catch (ConversionException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
|
||||
throw new TypeMismatchException(pce, requiredType, ex);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
|
||||
throw new ConversionNotSupportedException(pce, requiredType, ex);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
|
||||
throw new TypeMismatchException(pce, requiredType, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Object convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<?> requiredType)
|
||||
throws TypeMismatchException {
|
||||
|
||||
return convertIfNecessary(propertyName, oldValue, newValue, requiredType, TypeDescriptor.valueOf(requiredType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given value for the specified property to the latter's type.
|
||||
* <p>This method is only intended for optimizations in a BeanFactory.
|
||||
@@ -457,19 +509,14 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"No property '" + propertyName + "' found");
|
||||
}
|
||||
try {
|
||||
return this.typeConverterDelegate.convertIfNecessary(null, value, pd);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, null, value);
|
||||
throw new TypeMismatchException(pce, pd.getPropertyType(), ex);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, null, value);
|
||||
throw new ConversionNotSupportedException(pce, pd.getPropertyType(), ex);
|
||||
}
|
||||
return convertForProperty(propertyName, null, value, pd);
|
||||
}
|
||||
|
||||
private Object convertForProperty(String propertyName, Object oldValue, Object newValue, PropertyDescriptor pd)
|
||||
throws TypeMismatchException {
|
||||
|
||||
return convertIfNecessary(propertyName, oldValue, newValue, pd.getPropertyType(),
|
||||
new PropertyTypeDescriptor(pd, BeanUtils.getWriteMethodParameter(pd)));
|
||||
}
|
||||
|
||||
|
||||
@@ -558,21 +605,25 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
PropertyTokenHolder tokens = new PropertyTokenHolder();
|
||||
tokens.actualName = propertyName;
|
||||
tokens.canonicalName = propertyName;
|
||||
setPropertyValue(tokens, createDefaultPropertyValue(tokens));
|
||||
return getPropertyValue(tokens);
|
||||
return setDefaultValue(tokens);
|
||||
}
|
||||
|
||||
private Object setDefaultValue(PropertyTokenHolder tokens) {
|
||||
setPropertyValue(tokens, createDefaultPropertyValue(tokens));
|
||||
PropertyValue pv = createDefaultPropertyValue(tokens);
|
||||
setPropertyValue(tokens, pv);
|
||||
return getPropertyValue(tokens);
|
||||
}
|
||||
|
||||
|
||||
private PropertyValue createDefaultPropertyValue(PropertyTokenHolder tokens) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(tokens.actualName);
|
||||
Object defaultValue = newValue(pd.getPropertyType(), tokens.canonicalName);
|
||||
Class type = getPropertyType(tokens.canonicalName);
|
||||
if (type == null) {
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Could not determine property type for auto-growing a default value");
|
||||
}
|
||||
Object defaultValue = newValue(type, tokens.canonicalName);
|
||||
return new PropertyValue(tokens.canonicalName, defaultValue);
|
||||
}
|
||||
|
||||
|
||||
private Object newValue(Class<?> type, String name) {
|
||||
try {
|
||||
if (type.isArray()) {
|
||||
@@ -587,13 +638,14 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
return Array.newInstance(componentType, 0);
|
||||
}
|
||||
}
|
||||
else if (Collection.class.isAssignableFrom(type)) {
|
||||
return CollectionFactory.createCollection(type, 16);
|
||||
}
|
||||
else if (Map.class.isAssignableFrom(type)) {
|
||||
return CollectionFactory.createMap(type, 16);
|
||||
}
|
||||
else {
|
||||
if (Collection.class.isAssignableFrom(type)) {
|
||||
return CollectionFactory.createCollection(type, 16);
|
||||
}
|
||||
else {
|
||||
return type.newInstance();
|
||||
}
|
||||
return type.newInstance();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
@@ -601,7 +653,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
"Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new nested BeanWrapper instance.
|
||||
* <p>Default implementation creates a BeanWrapperImpl instance.
|
||||
@@ -690,7 +742,6 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
|
||||
Object value;
|
||||
|
||||
if (System.getSecurityManager() != null) {
|
||||
try {
|
||||
value = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
||||
@@ -704,7 +755,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = readMethod.invoke(object, (Object[]) null);
|
||||
value = readMethod.invoke(object, (Object[]) null);
|
||||
}
|
||||
|
||||
if (tokens.keys != null) {
|
||||
@@ -761,9 +812,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
Class<?> mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(pd.getReadMethod(), i + 1);
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
Object convertedMapKey = this.typeConverterDelegate.convertIfNecessary(key, mapKeyType);
|
||||
// Pass full property name and old value in here, since we want full
|
||||
// conversion ability for map values.
|
||||
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType,
|
||||
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), mapKeyType));
|
||||
value = map.get(convertedMapKey);
|
||||
}
|
||||
else {
|
||||
@@ -776,15 +826,6 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
return value;
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Getter for property '" + actualName + "' threw exception", ex);
|
||||
}
|
||||
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Illegal attempt to get property '" + actualName + "' threw exception", ex);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Index of out of bounds in property path '" + propertyName + "'", ex);
|
||||
@@ -793,10 +834,18 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Invalid index in property path '" + propertyName + "'", ex);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
catch (TypeMismatchException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Invalid index in property path '" + propertyName + "'", ex);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Getter for property '" + actualName + "' threw exception", ex);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Illegal attempt to get property '" + actualName + "' threw exception", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Object growArrayIfNecessary(Object array, int index, String name) {
|
||||
@@ -804,26 +853,31 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
return array;
|
||||
}
|
||||
int length = Array.getLength(array);
|
||||
if (index >= length) {
|
||||
if (index >= length && index < this.autoGrowCollectionLimit) {
|
||||
Class<?> componentType = array.getClass().getComponentType();
|
||||
Object newArray = Array.newInstance(componentType, index + 1);
|
||||
System.arraycopy(array, 0, newArray, 0, length);
|
||||
for (int i = length; i < Array.getLength(newArray); i++) {
|
||||
Array.set(newArray, i, newValue(componentType, name));
|
||||
}
|
||||
// TODO this is not efficient because conversion may create a copy ... set directly because we know it is assignable.
|
||||
setPropertyValue(name, newArray);
|
||||
return newArray;
|
||||
return getPropertyValue(name);
|
||||
}
|
||||
else {
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
private void growCollectionIfNecessary(Collection collection, int index, String name, PropertyDescriptor pd, int nestingLevel) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void growCollectionIfNecessary(
|
||||
Collection collection, int index, String name, PropertyDescriptor pd, int nestingLevel) {
|
||||
|
||||
if (!this.autoGrowNestedPaths) {
|
||||
return;
|
||||
}
|
||||
if (index >= collection.size()) {
|
||||
int size = collection.size();
|
||||
if (index >= size && index < this.autoGrowCollectionLimit) {
|
||||
Class elementType = GenericCollectionTypeResolver.getCollectionReturnType(pd.getReadMethod(), nestingLevel);
|
||||
if (elementType != null) {
|
||||
for (int i = collection.size(); i < index + 1; i++) {
|
||||
@@ -832,7 +886,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setPropertyValue(String propertyName, Object value) throws BeansException {
|
||||
BeanWrapperImpl nestedBw;
|
||||
@@ -899,27 +953,18 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + propertyName + "': returned null");
|
||||
}
|
||||
else if (propValue.getClass().isArray()) {
|
||||
if (propValue.getClass().isArray()) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
|
||||
Class requiredType = propValue.getClass().getComponentType();
|
||||
int arrayIndex = Integer.parseInt(key);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
if (isExtractOldValueForEditor()) {
|
||||
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
|
||||
oldValue = Array.get(propValue, arrayIndex);
|
||||
}
|
||||
Object convertedValue = this.typeConverterDelegate.convertIfNecessary(
|
||||
propertyName, oldValue, pv.getValue(), requiredType);
|
||||
Array.set(propValue, Integer.parseInt(key), convertedValue);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
throw new TypeMismatchException(pce, requiredType, ex);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
throw new ConversionNotSupportedException(pce, requiredType, ex);
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType,
|
||||
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType));
|
||||
Array.set(propValue, arrayIndex, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
@@ -936,32 +981,32 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
if (isExtractOldValueForEditor() && index < list.size()) {
|
||||
oldValue = list.get(index);
|
||||
}
|
||||
try {
|
||||
Object convertedValue = this.typeConverterDelegate.convertIfNecessary(
|
||||
propertyName, oldValue, pv.getValue(), requiredType);
|
||||
if (index < list.size()) {
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType,
|
||||
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType));
|
||||
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);
|
||||
}
|
||||
else if (index >= list.size()) {
|
||||
for (int i = list.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 " +
|
||||
list.size() + ", accessed using property path '" + propertyName +
|
||||
"': List does not support filling up gaps with null elements");
|
||||
}
|
||||
}
|
||||
list.add(convertedValue);
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Invalid list index in property path '" + propertyName + "'", ex);
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
throw new TypeMismatchException(pce, requiredType, ex);
|
||||
}
|
||||
}
|
||||
else if (propValue instanceof Map) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
|
||||
@@ -970,34 +1015,19 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
Class mapValueType = GenericCollectionTypeResolver.getMapValueReturnType(
|
||||
pd.getReadMethod(), tokens.keys.length);
|
||||
Map map = (Map) propValue;
|
||||
Object convertedMapKey;
|
||||
Object convertedMapValue;
|
||||
try {
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
convertedMapKey = this.typeConverterDelegate.convertIfNecessary(key, mapKeyType);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, null, pv.getValue());
|
||||
throw new TypeMismatchException(pce, mapKeyType, ex);
|
||||
}
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType,
|
||||
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), mapKeyType));
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor()) {
|
||||
oldValue = map.get(convertedMapKey);
|
||||
}
|
||||
try {
|
||||
// Pass full property name and old value in here, since we want full
|
||||
// conversion ability for map values.
|
||||
convertedMapValue = this.typeConverterDelegate.convertIfNecessary(
|
||||
propertyName, oldValue, pv.getValue(), mapValueType,
|
||||
new MethodParameter(pd.getReadMethod(), -1, tokens.keys.length + 1));
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
throw new TypeMismatchException(pce, mapValueType, ex);
|
||||
}
|
||||
// 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,
|
||||
new TypeDescriptor(new MethodParameter(pd.getReadMethod(), -1, tokens.keys.length + 1)));
|
||||
map.put(convertedMapKey, convertedMapValue);
|
||||
}
|
||||
else {
|
||||
@@ -1038,7 +1068,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
else {
|
||||
if (isExtractOldValueForEditor() && pd.getReadMethod() != null) {
|
||||
final Method readMethod = pd.getReadMethod();
|
||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers()) && !readMethod.isAccessible()) {
|
||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers()) &&
|
||||
!readMethod.isAccessible()) {
|
||||
if (System.getSecurityManager()!= null) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
public Object run() {
|
||||
@@ -1057,7 +1088,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
public Object run() throws Exception {
|
||||
return readMethod.invoke(object);
|
||||
}
|
||||
},acc);
|
||||
}, acc);
|
||||
}
|
||||
else {
|
||||
oldValue = readMethod.invoke(object);
|
||||
@@ -1073,7 +1104,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
}
|
||||
valueToApply = this.typeConverterDelegate.convertIfNecessary(oldValue, originalValue, pd);
|
||||
valueToApply = convertForProperty(propertyName, oldValue, originalValue, pd);
|
||||
}
|
||||
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
|
||||
}
|
||||
@@ -1094,7 +1125,6 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
final Object value = valueToApply;
|
||||
|
||||
if (System.getSecurityManager() != null) {
|
||||
try {
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
||||
@@ -1103,14 +1133,17 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
return null;
|
||||
}
|
||||
}, acc);
|
||||
} catch (PrivilegedActionException ex) {
|
||||
}
|
||||
catch (PrivilegedActionException ex) {
|
||||
throw ex.getException();
|
||||
}
|
||||
}
|
||||
else {
|
||||
writeMethod.invoke(object, value);
|
||||
writeMethod.invoke(this.object, value);
|
||||
}
|
||||
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
PropertyChangeEvent propertyChangeEvent =
|
||||
@@ -1122,34 +1155,9 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
throw new MethodInvocationException(propertyChangeEvent, ex.getTargetException());
|
||||
}
|
||||
}
|
||||
catch (ConverterNotFoundException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
throw new ConversionNotSupportedException(pce, pd.getPropertyType(), ex);
|
||||
}
|
||||
catch (ConversionException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
throw new TypeMismatchException(pce, pd.getPropertyType(), ex);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
throw new ConversionNotSupportedException(pce, pd.getPropertyType(), ex);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
throw new TypeMismatchException(pce, pd.getPropertyType(), ex);
|
||||
}
|
||||
catch (IllegalAccessException 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 + propertyName, oldValue, pv.getValue());
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
throw new MethodInvocationException(pce, ex);
|
||||
}
|
||||
}
|
||||
|
||||
+39
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,11 +22,10 @@ import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
@@ -141,19 +140,20 @@ public class CachedIntrospectionResults {
|
||||
results = (CachedIntrospectionResults) value;
|
||||
}
|
||||
if (results == null) {
|
||||
// can throw BeansException
|
||||
results = new CachedIntrospectionResults(beanClass);
|
||||
// On JDK 1.5 and higher, it is almost always safe to cache the bean class...
|
||||
// The sole exception is a custom BeanInfo class being provided in a non-safe ClassLoader.
|
||||
if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
|
||||
isClassLoaderAccepted(beanClass.getClassLoader()) ||
|
||||
!ClassUtils.isPresent(beanClass.getName() + "BeanInfo", beanClass.getClassLoader())) {
|
||||
boolean fullyCacheable =
|
||||
ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
|
||||
isClassLoaderAccepted(beanClass.getClassLoader());
|
||||
if (fullyCacheable || !ClassUtils.isPresent(beanClass.getName() + "BeanInfo", beanClass.getClassLoader())) {
|
||||
results = new CachedIntrospectionResults(beanClass, fullyCacheable);
|
||||
classCache.put(beanClass, results);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Not strongly caching class [" + beanClass.getName() + "] because it is not cache-safe");
|
||||
}
|
||||
results = new CachedIntrospectionResults(beanClass, true);
|
||||
classCache.put(beanClass, new WeakReference<CachedIntrospectionResults>(results));
|
||||
}
|
||||
}
|
||||
@@ -216,7 +216,7 @@ public class CachedIntrospectionResults {
|
||||
* @param beanClass the bean class to analyze
|
||||
* @throws BeansException in case of introspection failure
|
||||
*/
|
||||
private CachedIntrospectionResults(Class beanClass) throws BeansException {
|
||||
private CachedIntrospectionResults(Class beanClass, boolean cacheFullMetadata) throws BeansException {
|
||||
try {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Getting BeanInfo for class [" + beanClass.getName() + "]");
|
||||
@@ -237,24 +237,29 @@ public class CachedIntrospectionResults {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]");
|
||||
}
|
||||
this.propertyDescriptorCache = new HashMap<String, PropertyDescriptor>();
|
||||
this.propertyDescriptorCache = new LinkedHashMap<String, PropertyDescriptor>();
|
||||
|
||||
// This call is slow so we do it once.
|
||||
PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
|
||||
for (PropertyDescriptor pd : pds) {
|
||||
if (Class.class.equals(beanClass) && "classLoader".equals(pd.getName())) {
|
||||
// Ignore Class.getClassLoader() method - nobody needs to bind to that
|
||||
continue;
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Found bean property '" + pd.getName() + "'" +
|
||||
(pd.getPropertyType() != null ? " of type [" + pd.getPropertyType().getName() + "]" : "") +
|
||||
(pd.getPropertyEditorClass() != null ?
|
||||
"; editor [" + pd.getPropertyEditorClass().getName() + "]" : ""));
|
||||
}
|
||||
pd = new GenericTypeAwarePropertyDescriptor(beanClass, pd.getName(), pd.getReadMethod(),
|
||||
pd.getWriteMethod(), pd.getPropertyEditorClass());
|
||||
if (cacheFullMetadata) {
|
||||
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
|
||||
}
|
||||
this.propertyDescriptorCache.put(pd.getName(), pd);
|
||||
}
|
||||
}
|
||||
catch (IntrospectionException ex) {
|
||||
throw new FatalBeanException("Cannot get BeanInfo for object of class [" + beanClass.getName() + "]", ex);
|
||||
throw new FatalBeanException("Failed to obtain BeanInfo for class [" + beanClass.getName() + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,17 +274,35 @@ public class CachedIntrospectionResults {
|
||||
PropertyDescriptor getPropertyDescriptor(String name) {
|
||||
PropertyDescriptor pd = this.propertyDescriptorCache.get(name);
|
||||
if (pd == null && StringUtils.hasLength(name)) {
|
||||
// Same lenient fallback checking as in PropertyTypeDescriptor...
|
||||
pd = this.propertyDescriptorCache.get(name.substring(0, 1).toLowerCase() + name.substring(1));
|
||||
if (pd == null) {
|
||||
pd = this.propertyDescriptorCache.get(name.substring(0, 1).toUpperCase() + name.substring(1));
|
||||
}
|
||||
}
|
||||
return pd;
|
||||
return (pd == null || pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
|
||||
buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd));
|
||||
}
|
||||
|
||||
PropertyDescriptor[] getPropertyDescriptors() {
|
||||
Collection<PropertyDescriptor> descriptorCollection = this.propertyDescriptorCache.values();
|
||||
return descriptorCollection.toArray(new PropertyDescriptor[descriptorCollection.size()]);
|
||||
PropertyDescriptor[] pds = new PropertyDescriptor[this.propertyDescriptorCache.size()];
|
||||
int i = 0;
|
||||
for (PropertyDescriptor pd : this.propertyDescriptorCache.values()) {
|
||||
pds[i] = (pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
|
||||
buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd));
|
||||
i++;
|
||||
}
|
||||
return pds;
|
||||
}
|
||||
|
||||
private PropertyDescriptor buildGenericTypeAwarePropertyDescriptor(Class beanClass, PropertyDescriptor pd) {
|
||||
try {
|
||||
return new GenericTypeAwarePropertyDescriptor(beanClass, pd.getName(), pd.getReadMethod(),
|
||||
pd.getWriteMethod(), pd.getPropertyEditorClass());
|
||||
}
|
||||
catch (IntrospectionException ex) {
|
||||
throw new FatalBeanException("Failed to re-introspect class [" + beanClass.getName() + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -124,7 +124,8 @@ public class DirectFieldAccessor extends AbstractPropertyAccessor {
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
oldValue = field.get(this.target);
|
||||
Object convertedValue = this.typeConverterDelegate.convertIfNecessary(oldValue, newValue, field);
|
||||
Object convertedValue = this.typeConverterDelegate.convertIfNecessary(
|
||||
field.getName(), oldValue, newValue, field.getType(), new TypeDescriptor(field));
|
||||
field.set(this.target, convertedValue);
|
||||
}
|
||||
catch (ConverterNotFoundException ex) {
|
||||
|
||||
+6
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,7 +50,7 @@ public class MutablePropertyValues implements PropertyValues, Serializable {
|
||||
* @see #add(String, Object)
|
||||
*/
|
||||
public MutablePropertyValues() {
|
||||
this.propertyValueList = new ArrayList<PropertyValue>();
|
||||
this.propertyValueList = new ArrayList<PropertyValue>(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,8 +339,10 @@ public class MutablePropertyValues implements PropertyValues, Serializable {
|
||||
@Override
|
||||
public String toString() {
|
||||
PropertyValue[] pvs = getPropertyValues();
|
||||
StringBuilder sb = new StringBuilder("PropertyValues: length=" + pvs.length + "; ");
|
||||
sb.append(StringUtils.arrayToDelimitedString(pvs, "; "));
|
||||
StringBuilder sb = new StringBuilder("PropertyValues: length=").append(pvs.length);
|
||||
if (pvs.length > 0) {
|
||||
sb.append("; ").append(StringUtils.arrayToDelimitedString(pvs, "; "));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
+32
-3
@@ -42,6 +42,8 @@ import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import org.springframework.beans.propertyeditors.ByteArrayPropertyEditor;
|
||||
import org.springframework.beans.propertyeditors.CharArrayPropertyEditor;
|
||||
import org.springframework.beans.propertyeditors.CharacterEditor;
|
||||
@@ -54,6 +56,7 @@ import org.springframework.beans.propertyeditors.CustomCollectionEditor;
|
||||
import org.springframework.beans.propertyeditors.CustomMapEditor;
|
||||
import org.springframework.beans.propertyeditors.CustomNumberEditor;
|
||||
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.PatternEditor;
|
||||
@@ -90,6 +93,8 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
||||
|
||||
private Map<Class, PropertyEditor> defaultEditors;
|
||||
|
||||
private Map<Class, PropertyEditor> overriddenDefaultEditors;
|
||||
|
||||
private Map<Class, PropertyEditor> customEditors;
|
||||
|
||||
private Map<String, CustomEditorHolder> customEditorsForPath;
|
||||
@@ -138,6 +143,22 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
||||
this.configValueEditorsActive = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default editor for the specified type with the given property editor.
|
||||
* <p>Note that this is different from registering a custom editor in that the editor
|
||||
* semantically still is a default editor. A ConversionService will override such a
|
||||
* default editor, whereas custom editors usually override the ConversionService.
|
||||
* @param requiredType the type of the property
|
||||
* @param propertyEditor the editor to register
|
||||
* @see #registerCustomEditor(Class, PropertyEditor)
|
||||
*/
|
||||
public void overrideDefaultEditor(Class requiredType, PropertyEditor propertyEditor) {
|
||||
if (this.overriddenDefaultEditors == null) {
|
||||
this.overriddenDefaultEditors = new HashMap<Class, PropertyEditor>();
|
||||
}
|
||||
this.overriddenDefaultEditors.put(requiredType, propertyEditor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the default editor for the given property type, if any.
|
||||
* <p>Lazily registers the default editors, if they are active.
|
||||
@@ -149,8 +170,14 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
||||
if (!this.defaultEditorsActive) {
|
||||
return null;
|
||||
}
|
||||
if (this.overriddenDefaultEditors != null) {
|
||||
PropertyEditor editor = this.overriddenDefaultEditors.get(requiredType);
|
||||
if (editor != null) {
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
if (this.defaultEditors == null) {
|
||||
doRegisterDefaultEditors();
|
||||
createDefaultEditors();
|
||||
}
|
||||
return this.defaultEditors.get(requiredType);
|
||||
}
|
||||
@@ -158,7 +185,7 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
||||
/**
|
||||
* Actually register the default editors for this registry instance.
|
||||
*/
|
||||
private void doRegisterDefaultEditors() {
|
||||
private void createDefaultEditors() {
|
||||
this.defaultEditors = new HashMap<Class, PropertyEditor>(64);
|
||||
|
||||
// Simple editors, without parameterization capabilities.
|
||||
@@ -169,6 +196,7 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
||||
this.defaultEditors.put(Currency.class, new CurrencyEditor());
|
||||
this.defaultEditors.put(File.class, new FileEditor());
|
||||
this.defaultEditors.put(InputStream.class, new InputStreamEditor());
|
||||
this.defaultEditors.put(InputSource.class, new InputSourceEditor());
|
||||
this.defaultEditors.put(Locale.class, new LocaleEditor());
|
||||
this.defaultEditors.put(Pattern.class, new PatternEditor());
|
||||
this.defaultEditors.put(Properties.class, new PropertiesEditor());
|
||||
@@ -230,9 +258,10 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
||||
* @param target the target registry to copy to
|
||||
*/
|
||||
protected void copyDefaultEditorsTo(PropertyEditorRegistrySupport target) {
|
||||
target.defaultEditors = this.defaultEditors;
|
||||
target.defaultEditorsActive = this.defaultEditorsActive;
|
||||
target.configValueEditorsActive = this.configValueEditorsActive;
|
||||
target.defaultEditors = this.defaultEditors;
|
||||
target.overriddenDefaultEditors = this.overriddenDefaultEditors;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+10
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,8 @@
|
||||
package org.springframework.beans;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
|
||||
/**
|
||||
* Simple implementation of the TypeConverter interface that does not operate
|
||||
@@ -46,12 +48,18 @@ public class SimpleTypeConverter extends PropertyEditorRegistrySupport implement
|
||||
try {
|
||||
return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
catch (ConverterNotFoundException ex) {
|
||||
throw new ConversionNotSupportedException(value, requiredType, ex);
|
||||
}
|
||||
catch (ConversionException ex) {
|
||||
throw new TypeMismatchException(value, requiredType, ex);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw new ConversionNotSupportedException(value, requiredType, ex);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
throw new TypeMismatchException(value, requiredType, ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+44
-76
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import java.beans.PropertyEditor;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
@@ -77,18 +78,6 @@ class TypeConverterDelegate {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the value to the specified required type.
|
||||
* @param newValue the proposed new value
|
||||
* @param requiredType the type we must convert to
|
||||
* (or <code>null</code> if not known, for example in case of a collection element)
|
||||
* @return the new value, possibly the result of type conversion
|
||||
* @throws IllegalArgumentException if type conversion failed
|
||||
*/
|
||||
public <T> T convertIfNecessary(Object newValue, Class<T> requiredType) throws IllegalArgumentException {
|
||||
return convertIfNecessary(null, null, newValue, requiredType, TypeDescriptor.valueOf(requiredType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to the specified required type.
|
||||
* @param newValue the proposed new value
|
||||
@@ -123,54 +112,6 @@ class TypeConverterDelegate {
|
||||
return convertIfNecessary(propertyName, oldValue, newValue, requiredType, TypeDescriptor.valueOf(requiredType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to the required type (if necessary from a String),
|
||||
* for the specified property.
|
||||
* @param propertyName name of the property
|
||||
* @param oldValue the previous value, if available (may be <code>null</code>)
|
||||
* @param newValue the proposed new value
|
||||
* @param requiredType the type we must convert to
|
||||
* (or <code>null</code> if not known, for example in case of a collection element)
|
||||
* @param methodParam the method parameter that is the target of the conversion
|
||||
* @return the new value, possibly the result of type conversion
|
||||
* @throws IllegalArgumentException if type conversion failed
|
||||
*/
|
||||
public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
|
||||
Class<T> requiredType, MethodParameter methodParam) throws IllegalArgumentException {
|
||||
|
||||
return convertIfNecessary(propertyName, oldValue, newValue, requiredType, new TypeDescriptor(methodParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to the required type for the specified property.
|
||||
* @param oldValue the previous value, if available (may be <code>null</code>)
|
||||
* @param newValue the proposed new value
|
||||
* @param descriptor the JavaBeans descriptor for the property
|
||||
* @return the new value, possibly the result of type conversion
|
||||
* @throws IllegalArgumentException if type conversion failed
|
||||
*/
|
||||
public Object convertIfNecessary(Object oldValue, Object newValue, PropertyDescriptor descriptor)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
return convertIfNecessary(descriptor.getName(), oldValue, newValue, descriptor.getPropertyType(),
|
||||
new PropertyTypeDescriptor(descriptor, BeanUtils.getWriteMethodParameter(descriptor)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to the required type for the specified property.
|
||||
* @param oldValue the previous value, if available (may be <code>null</code>)
|
||||
* @param newValue the proposed new value
|
||||
* @param field the field that is the target of the conversion
|
||||
* @return the new value, possibly the result of type conversion
|
||||
* @throws IllegalArgumentException if type conversion failed
|
||||
*/
|
||||
public Object convertIfNecessary(Object oldValue, Object newValue, Field field)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
return convertIfNecessary(field.getName(), oldValue, newValue, field.getType(), new TypeDescriptor(field));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the value to the required type (if necessary from a String),
|
||||
* for the specified property.
|
||||
@@ -184,7 +125,7 @@ class TypeConverterDelegate {
|
||||
* @throws IllegalArgumentException if type conversion failed
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
|
||||
public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
|
||||
Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
|
||||
|
||||
Object convertedValue = newValue;
|
||||
@@ -196,7 +137,10 @@ class TypeConverterDelegate {
|
||||
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
|
||||
if (editor == null && conversionService != null && convertedValue != null) {
|
||||
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(convertedValue);
|
||||
TypeDescriptor targetTypeDesc = typeDescriptor.forElementType(requiredType);
|
||||
TypeDescriptor targetTypeDesc = typeDescriptor;
|
||||
if (requiredType != null && !requiredType.isAssignableFrom(typeDescriptor.getType())) {
|
||||
targetTypeDesc = typeDescriptor.forElementType(requiredType);
|
||||
}
|
||||
if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) {
|
||||
return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc);
|
||||
}
|
||||
@@ -283,7 +227,8 @@ class TypeConverterDelegate {
|
||||
}
|
||||
if (editor != null) {
|
||||
msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
|
||||
"] returned inappropriate value");
|
||||
"] returned inappropriate value of type [").append(
|
||||
ClassUtils.getDescriptiveType(convertedValue)).append("]");
|
||||
throw new IllegalArgumentException(msg.toString());
|
||||
}
|
||||
else {
|
||||
@@ -519,11 +464,20 @@ class TypeConverterDelegate {
|
||||
protected Collection convertToTypedCollection(
|
||||
Collection original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
|
||||
|
||||
boolean originalAllowed = requiredType.isInstance(original);
|
||||
if (!originalAllowed && !Collection.class.isAssignableFrom(requiredType)) {
|
||||
if (!Collection.class.isAssignableFrom(requiredType)) {
|
||||
return original;
|
||||
}
|
||||
|
||||
boolean approximable = CollectionFactory.isApproximableCollectionType(requiredType);
|
||||
if (!approximable && !canCreateCopy(requiredType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Custom Collection type [" + original.getClass().getName() +
|
||||
"] does not allow for creating a copy - injecting original Collection as-is");
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
boolean originalAllowed = requiredType.isInstance(original);
|
||||
MethodParameter methodParam = typeDescriptor.getMethodParameter();
|
||||
Class elementType = null;
|
||||
if (methodParam != null) {
|
||||
@@ -548,14 +502,14 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cannot access Collection of type [" + original.getClass().getName() +
|
||||
"] - injecting original Collection as-is", ex);
|
||||
"] - injecting original Collection as-is: " + ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
Collection convertedCopy;
|
||||
try {
|
||||
if (CollectionFactory.isApproximableCollectionType(requiredType)) {
|
||||
if (approximable) {
|
||||
convertedCopy = CollectionFactory.createApproximateCollection(original, original.size());
|
||||
}
|
||||
else {
|
||||
@@ -565,7 +519,7 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cannot create copy of Collection type [" + original.getClass().getName() +
|
||||
"] - injecting original Collection as-is", ex);
|
||||
"] - injecting original Collection as-is: " + ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
@@ -588,7 +542,7 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Collection type [" + original.getClass().getName() +
|
||||
"] seems to be read-only - injecting original Collection as-is", ex);
|
||||
"] seems to be read-only - injecting original Collection as-is: " + ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
@@ -601,11 +555,20 @@ class TypeConverterDelegate {
|
||||
protected Map convertToTypedMap(
|
||||
Map original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
|
||||
|
||||
boolean originalAllowed = requiredType.isInstance(original);
|
||||
if (!originalAllowed && !Map.class.isAssignableFrom(requiredType)) {
|
||||
if (!Map.class.isAssignableFrom(requiredType)) {
|
||||
return original;
|
||||
}
|
||||
|
||||
boolean approximable = CollectionFactory.isApproximableMapType(requiredType);
|
||||
if (!approximable && !canCreateCopy(requiredType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Custom Map type [" + original.getClass().getName() +
|
||||
"] does not allow for creating a copy - injecting original Map as-is");
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
boolean originalAllowed = requiredType.isInstance(original);
|
||||
Class keyType = null;
|
||||
Class valueType = null;
|
||||
MethodParameter methodParam = typeDescriptor.getMethodParameter();
|
||||
@@ -632,14 +595,14 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cannot access Map of type [" + original.getClass().getName() +
|
||||
"] - injecting original Map as-is", ex);
|
||||
"] - injecting original Map as-is: " + ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
Map convertedCopy;
|
||||
try {
|
||||
if (CollectionFactory.isApproximableMapType(requiredType)) {
|
||||
if (approximable) {
|
||||
convertedCopy = CollectionFactory.createApproximateMap(original, original.size());
|
||||
}
|
||||
else {
|
||||
@@ -649,7 +612,7 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cannot create copy of Map type [" + original.getClass().getName() +
|
||||
"] - injecting original Map as-is", ex);
|
||||
"] - injecting original Map as-is: " + ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
@@ -677,7 +640,7 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Map type [" + original.getClass().getName() +
|
||||
"] seems to be read-only - injecting original Map as-is", ex);
|
||||
"] seems to be read-only - injecting original Map as-is: " + ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
@@ -698,4 +661,9 @@ class TypeConverterDelegate {
|
||||
null);
|
||||
}
|
||||
|
||||
private boolean canCreateCopy(Class requiredType) {
|
||||
return (!requiredType.isInterface() && !Modifier.isAbstract(requiredType.getModifiers()) &&
|
||||
Modifier.isPublic(requiredType.getModifiers()) && ClassUtils.hasConstructor(requiredType));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+31
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -208,6 +208,11 @@ public abstract class BeanFactoryUtils {
|
||||
* <p>Does consider objects created by FactoryBeans, which means that FactoryBeans
|
||||
* will get initialized. If the object created by the FactoryBean doesn't match,
|
||||
* the raw FactoryBean itself will be matched against the type.
|
||||
* <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level,
|
||||
* i.e. such beans will be returned from the lowest factory that they are being found in,
|
||||
* hiding corresponding beans in ancestor factories.</b> This feature allows for
|
||||
* 'replacing' beans by explicitly choosing the same bean name in a child factory;
|
||||
* the bean in the ancestor factory won't be visible then, not even for by-type lookups.
|
||||
* @param lbf the bean factory
|
||||
* @param type type of bean to match
|
||||
* @return the Map of matching bean instances, or an empty Map if none
|
||||
@@ -239,12 +244,16 @@ public abstract class BeanFactoryUtils {
|
||||
* Return all beans of the given type or subtypes, also picking up beans defined in
|
||||
* ancestor bean factories if the current bean factory is a HierarchicalBeanFactory.
|
||||
* The returned Map will only contain beans of this type.
|
||||
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit"
|
||||
* flag is set, which means that FactoryBeans will get initialized. If the
|
||||
* object created by the FactoryBean doesn't match, the raw FactoryBean itself
|
||||
* will be matched against the type. If "allowEagerInit" is not set,
|
||||
* only raw FactoryBeans will be checked (which doesn't require initialization
|
||||
* of each FactoryBean).
|
||||
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set,
|
||||
* which means that FactoryBeans will get initialized. If the object created by the
|
||||
* FactoryBean doesn't match, the raw FactoryBean itself will be matched against the
|
||||
* type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked
|
||||
* (which doesn't require initialization of each FactoryBean).
|
||||
* <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level,
|
||||
* i.e. such beans will be returned from the lowest factory that they are being found in,
|
||||
* hiding corresponding beans in ancestor factories.</b> This feature allows for
|
||||
* 'replacing' beans by explicitly choosing the same bean name in a child factory;
|
||||
* the bean in the ancestor factory won't be visible then, not even for by-type lookups.
|
||||
* @param lbf the bean factory
|
||||
* @param type type of bean to match
|
||||
* @param includeNonSingletons whether to include prototype or scoped beans too
|
||||
@@ -291,6 +300,11 @@ public abstract class BeanFactoryUtils {
|
||||
* the raw FactoryBean itself will be matched against the type.
|
||||
* <p>This version of <code>beanOfTypeIncludingAncestors</code> automatically includes
|
||||
* prototypes and FactoryBeans.
|
||||
* <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level,
|
||||
* i.e. such beans will be returned from the lowest factory that they are being found in,
|
||||
* hiding corresponding beans in ancestor factories.</b> This feature allows for
|
||||
* 'replacing' beans by explicitly choosing the same bean name in a child factory;
|
||||
* the bean in the ancestor factory won't be visible then, not even for by-type lookups.
|
||||
* @param lbf the bean factory
|
||||
* @param type type of bean to match
|
||||
* @return the matching bean instance
|
||||
@@ -315,12 +329,16 @@ public abstract class BeanFactoryUtils {
|
||||
* defined in ancestor bean factories if the current bean factory is a
|
||||
* HierarchicalBeanFactory. Useful convenience method when we expect a
|
||||
* single bean and don't care about the bean name.
|
||||
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit"
|
||||
* flag is set, which means that FactoryBeans will get initialized. If the
|
||||
* object created by the FactoryBean doesn't match, the raw FactoryBean itself
|
||||
* will be matched against the type. If "allowEagerInit" is not set,
|
||||
* only raw FactoryBeans will be checked (which doesn't require initialization
|
||||
* of each FactoryBean).
|
||||
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set,
|
||||
* which means that FactoryBeans will get initialized. If the object created by the
|
||||
* FactoryBean doesn't match, the raw FactoryBean itself will be matched against the
|
||||
* type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked
|
||||
* (which doesn't require initialization of each FactoryBean).
|
||||
* <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level,
|
||||
* i.e. such beans will be returned from the lowest factory that they are being found in,
|
||||
* hiding corresponding beans in ancestor factories.</b> This feature allows for
|
||||
* 'replacing' beans by explicitly choosing the same bean name in a child factory;
|
||||
* the bean in the ancestor factory won't be visible then, not even for by-type lookups.
|
||||
* @param lbf the bean factory
|
||||
* @param type type of bean to match
|
||||
* @param includeNonSingletons whether to include prototype or scoped beans too
|
||||
|
||||
+13
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.beans.factory.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -46,16 +47,25 @@ import java.lang.annotation.Target;
|
||||
* declared value type. In case of a Map, the keys must be declared as
|
||||
* type String and will be resolved to the corresponding bean names.
|
||||
*
|
||||
* <p>Please do consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
|
||||
* <p>Note that actual injection is performed through a
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* BeanPostProcessor} which in turn means that you <em>cannot</em>
|
||||
* use {@code @Autowired} to inject references into
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* BeanPostProcessor} or {@link BeanFactoryPostProcessor} types. Please
|
||||
* consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
|
||||
* class (which, by default, checks for the presence of this annotation).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
* @see AutowiredAnnotationBeanPostProcessor
|
||||
* @see Qualifier
|
||||
* @see Value
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Autowired {
|
||||
|
||||
/**
|
||||
|
||||
+50
-65
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,7 +38,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
@@ -51,6 +50,7 @@ import org.springframework.beans.factory.config.InstantiationAwareBeanPostProces
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.Ordered;
|
||||
@@ -62,8 +62,11 @@ import org.springframework.util.ReflectionUtils;
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
|
||||
* that autowires annotated fields, setter methods and arbitrary config methods.
|
||||
* Such members to be injected are detected through a Java 5 annotation:
|
||||
* by default, Spring's {@link Autowired} annotation.
|
||||
* Such members to be injected are detected through a Java 5 annotation: by default,
|
||||
* Spring's {@link Autowired @Autowired} and {@link Value @Value} annotations.
|
||||
*
|
||||
* <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
|
||||
* if available, as a direct alternative to Spring's own <code>@Autowired</code>.
|
||||
*
|
||||
* <p>Only one constructor (at max) of any given bean class may carry this
|
||||
* annotation with the 'required' parameter set to <code>true</code>,
|
||||
@@ -78,27 +81,25 @@ import org.springframework.util.ReflectionUtils;
|
||||
* <p>Fields are injected right after construction of a bean, before any
|
||||
* config methods are invoked. Such a config field does not have to be public.
|
||||
*
|
||||
* <p>Config methods may have an arbitrary name and any number of arguments;
|
||||
* each of those arguments will be autowired with a matching bean in the
|
||||
* Spring container. Bean property setter methods are effectively just
|
||||
* a special case of such a general config method. Such config methods
|
||||
* do not have to be public.
|
||||
*
|
||||
* <p>Also supports JSR-330's {@link javax.inject.Inject} annotation, if available.
|
||||
* <p>Config methods may have an arbitrary name and any number of arguments; each of
|
||||
* those arguments will be autowired with a matching bean in the Spring container.
|
||||
* Bean property setter methods are effectively just a special case of such a
|
||||
* general config method. Config methods do not have to be public.
|
||||
*
|
||||
* <p>Note: A default AutowiredAnnotationBeanPostProcessor will be registered
|
||||
* by the "context:annotation-config" and "context:component-scan" XML tags.
|
||||
* Remove or turn off the default annotation configuration there if you intend
|
||||
* to specify a custom AutowiredAnnotationBeanPostProcessor bean definition.
|
||||
* <p><b>NOTE:</b> Annotation injection will be performed <i>before</i> XML injection; thus
|
||||
* the latter configuration will override the former for properties wired through
|
||||
* both approaches.
|
||||
*
|
||||
* <p><b>NOTE:</b> Annotation injection will be performed <i>before</i> XML injection;
|
||||
* thus the latter configuration will override the former for properties wired through
|
||||
* both approaches.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
* @see #setAutowiredAnnotationType
|
||||
* @see Autowired
|
||||
* @see Value
|
||||
*/
|
||||
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
|
||||
implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
|
||||
@@ -116,8 +117,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
private final Map<Class<?>, Constructor[]> candidateConstructorsCache =
|
||||
new ConcurrentHashMap<Class<?>, Constructor[]>();
|
||||
private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache =
|
||||
new ConcurrentHashMap<Class<?>, Constructor<?>[]>();
|
||||
|
||||
private final Map<Class<?>, InjectionMetadata> injectionMetadataCache =
|
||||
new ConcurrentHashMap<Class<?>, InjectionMetadata>();
|
||||
@@ -306,7 +307,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
|
||||
|
||||
private InjectionMetadata findAutowiringMetadata(Class clazz) {
|
||||
private InjectionMetadata findAutowiringMetadata(Class<?> clazz) {
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
|
||||
if (metadata == null) {
|
||||
@@ -321,7 +322,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private InjectionMetadata buildAutowiringMetadata(Class clazz) {
|
||||
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
|
||||
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
Class<?> targetClass = clazz;
|
||||
|
||||
@@ -341,7 +342,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
}
|
||||
for (Method method : targetClass.getDeclaredMethods()) {
|
||||
Annotation annotation = findAutowiredAnnotation(method);
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
Annotation annotation = BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod) ?
|
||||
findAutowiredAnnotation(bridgedMethod) : findAutowiredAnnotation(method);
|
||||
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
@@ -469,14 +472,14 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
||||
}
|
||||
else {
|
||||
DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
|
||||
this.cachedFieldValue = descriptor;
|
||||
value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
|
||||
if (value != null) {
|
||||
if (value != null || this.required) {
|
||||
this.cachedFieldValue = descriptor;
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == 1) {
|
||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||
@@ -492,10 +495,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
else {
|
||||
// Already cached in the meantime...
|
||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value != null) {
|
||||
@@ -528,11 +527,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
@Override
|
||||
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
|
||||
if (this.skip == null && this.pd != null && pvs != null && pvs.contains(this.pd.getName())) {
|
||||
// Explicit value provided as part of the bean definition.
|
||||
this.skip = Boolean.TRUE;
|
||||
}
|
||||
if (this.skip != null && this.skip) {
|
||||
if (checkPropertySkipping(pvs)) {
|
||||
return;
|
||||
}
|
||||
Method method = (Method) this.member;
|
||||
@@ -543,26 +538,29 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
arguments = resolveCachedArguments(beanName);
|
||||
}
|
||||
else {
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
arguments = new Object[paramTypes.length];
|
||||
DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(paramTypes.length);
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
GenericTypeResolver.resolveParameterType(methodParam, bean.getClass());
|
||||
descriptors[i] = new DependencyDescriptor(methodParam, this.required);
|
||||
arguments[i] = beanFactory.resolveDependency(
|
||||
descriptors[i], beanName, autowiredBeanNames, typeConverter);
|
||||
if (arguments[i] == null && !this.required) {
|
||||
arguments = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
arguments = new Object[paramTypes.length];
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(arguments.length);
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
this.cachedMethodArguments = new Object[arguments.length];
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
GenericTypeResolver.resolveParameterType(methodParam, bean.getClass());
|
||||
DependencyDescriptor descriptor = new DependencyDescriptor(methodParam, this.required);
|
||||
this.cachedMethodArguments[i] = descriptor;
|
||||
arguments[i] = beanFactory.resolveDependency(
|
||||
descriptor, beanName, autowiredBeanNames, typeConverter);
|
||||
if (arguments[i] == null) {
|
||||
arguments = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (arguments != null) {
|
||||
this.cachedMethodArguments = new Object[arguments.length];
|
||||
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();
|
||||
@@ -573,9 +571,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
this.cachedMethodArguments[i] = new RuntimeBeanReference(autowiredBeanName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.cachedMethodArguments[i] = arguments[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -584,18 +579,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
else {
|
||||
// Already cached in the meantime...
|
||||
arguments = resolveCachedArguments(beanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.skip == null) {
|
||||
if (this.pd != null && pvs instanceof MutablePropertyValues) {
|
||||
((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());
|
||||
}
|
||||
this.skip = Boolean.FALSE;
|
||||
}
|
||||
if (arguments != null) {
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
method.invoke(bean, arguments);
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,10 +34,10 @@ import java.lang.annotation.Target;
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface Configurable {
|
||||
|
||||
/**
|
||||
|
||||
+20
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -147,10 +147,7 @@ public class InjectionMetadata {
|
||||
field.set(target, getResourceToInject(target, requestingBeanName));
|
||||
}
|
||||
else {
|
||||
if (this.skip == null) {
|
||||
this.skip = checkPropertySkipping(pvs);
|
||||
}
|
||||
if (this.skip) {
|
||||
if (checkPropertySkipping(pvs)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -170,16 +167,26 @@ public class InjectionMetadata {
|
||||
* affected property as processed for other processors to ignore it.
|
||||
*/
|
||||
protected boolean checkPropertySkipping(PropertyValues pvs) {
|
||||
if (this.pd != null && pvs != null) {
|
||||
if (pvs.contains(this.pd.getName())) {
|
||||
// Explicit value provided as part of the bean definition.
|
||||
return true;
|
||||
}
|
||||
else if (pvs instanceof MutablePropertyValues) {
|
||||
((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());
|
||||
if (this.skip == null) {
|
||||
if (pvs != null) {
|
||||
synchronized (pvs) {
|
||||
if (this.skip == null) {
|
||||
if (this.pd != null) {
|
||||
if (pvs.contains(this.pd.getName())) {
|
||||
// Explicit value provided as part of the bean definition.
|
||||
this.skip = true;
|
||||
return true;
|
||||
}
|
||||
else if (pvs instanceof MutablePropertyValues) {
|
||||
((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.skip = false;
|
||||
}
|
||||
return false;
|
||||
return this.skip;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,9 +31,10 @@ import java.lang.annotation.Target;
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see Autowired
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface Qualifier {
|
||||
|
||||
+6
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -164,8 +164,11 @@ public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanP
|
||||
* @return <code>true</code> to skip the bean; <code>false</code> to process it
|
||||
*/
|
||||
protected boolean shouldSkip(ConfigurableListableBeanFactory beanFactory, String beanName) {
|
||||
return (beanFactory != null && beanFactory.containsBeanDefinition(beanName) &&
|
||||
Boolean.TRUE.equals(beanFactory.getBeanDefinition(beanName).getAttribute(SKIP_REQUIRED_CHECK_ATTRIBUTE)));
|
||||
if (beanFactory == null || !beanFactory.containsBeanDefinition(beanName)) {
|
||||
return false;
|
||||
}
|
||||
Object value = beanFactory.getBeanDefinition(beanName).getAttribute(SKIP_REQUIRED_CHECK_ATTRIBUTE);
|
||||
return (value != null && (Boolean.TRUE.equals(value) || Boolean.valueOf(value.toString())));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+15
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.beans.factory.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -31,13 +32,25 @@ import java.lang.annotation.Target;
|
||||
* <p>A common use case is to assign default field values using
|
||||
* "#{systemProperties.myProp}" style expressions.
|
||||
*
|
||||
* <p>Note that actual processing of the {@code @Value} annotation is performed
|
||||
* by a {@link org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* BeanPostProcessor} which in turn means that you <em>cannot</em> use
|
||||
* {@code @Value} within
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* BeanPostProcessor} or {@link BeanFactoryPostProcessor} types. Please
|
||||
* consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
|
||||
* class (which, by default, checks for the presence of this annotation).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see AutowiredAnnotationBeanPostProcessor
|
||||
* @see Autowired
|
||||
* @see org.springframework.beans.factory.config.BeanExpressionResolver
|
||||
* @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Value {
|
||||
|
||||
/**
|
||||
|
||||
+16
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -115,7 +115,7 @@ public class BeanDefinitionVisitor {
|
||||
}
|
||||
|
||||
protected void visitFactoryMethodName(BeanDefinition beanDefinition) {
|
||||
String factoryMethodName = beanDefinition.getFactoryBeanName();
|
||||
String factoryMethodName = beanDefinition.getFactoryMethodName();
|
||||
if (factoryMethodName != null) {
|
||||
String resolvedName = resolveStringValue(factoryMethodName);
|
||||
if (!factoryMethodName.equals(resolvedName)) {
|
||||
@@ -183,6 +183,9 @@ public class BeanDefinitionVisitor {
|
||||
return new RuntimeBeanNameReference(newBeanName);
|
||||
}
|
||||
}
|
||||
else if (value instanceof Object[]) {
|
||||
visitArray((Object[]) value);
|
||||
}
|
||||
else if (value instanceof List) {
|
||||
visitList((List) value);
|
||||
}
|
||||
@@ -206,6 +209,17 @@ public class BeanDefinitionVisitor {
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void visitArray(Object[] arrayVal) {
|
||||
for (int i = 0; i < arrayVal.length; i++) {
|
||||
Object elem = arrayVal[i];
|
||||
Object newVal = resolveValue(elem);
|
||||
if (!ObjectUtils.nullSafeEquals(newVal, elem)) {
|
||||
arrayVal[i] = newVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void visitList(List listVal) {
|
||||
for (int i = 0; i < listVal.size(); i++) {
|
||||
|
||||
+6
@@ -31,6 +31,12 @@ import org.springframework.beans.BeansException;
|
||||
* <p>See PropertyResourceConfigurer and its concrete implementations
|
||||
* for out-of-the-box solutions that address such configuration needs.
|
||||
*
|
||||
* <p>A BeanFactoryPostProcessor may interact with and modify bean
|
||||
* definitions, but never bean instances. Doing so may cause premature bean
|
||||
* instantiation, violating the container and causing unintended side-effects.
|
||||
* If bean instance interaction is required, consider implementing
|
||||
* {@link BeanPostProcessor} instead.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 06.07.2003
|
||||
* @see BeanPostProcessor
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -173,7 +173,7 @@ public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, Single
|
||||
* @param requiredType type of the property
|
||||
* @param propertyEditorClass the {@link PropertyEditor} class to register
|
||||
*/
|
||||
void registerCustomEditor(Class requiredType, Class<? extends PropertyEditor> propertyEditorClass);
|
||||
void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass);
|
||||
|
||||
/**
|
||||
* Initialize the given PropertyEditorRegistry with the custom editors
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,7 +42,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
public class ConstructorArgumentValues {
|
||||
|
||||
private final Map<Integer, ValueHolder> indexedArgumentValues = new LinkedHashMap<Integer, ValueHolder>();
|
||||
private final Map<Integer, ValueHolder> indexedArgumentValues = new LinkedHashMap<Integer, ValueHolder>(0);
|
||||
|
||||
private final List<ValueHolder> genericArgumentValues = new LinkedList<ValueHolder>();
|
||||
|
||||
|
||||
+30
-14
@@ -35,13 +35,15 @@ import org.springframework.util.ClassUtils;
|
||||
/**
|
||||
* {@link BeanFactoryPostProcessor} implementation that allows for convenient
|
||||
* registration of custom {@link PropertyEditor property editors}.
|
||||
*
|
||||
* <p>As of Spring 2.0, the recommended usage is to use custom
|
||||
* {@link PropertyEditorRegistrar} implementations that in turn register
|
||||
* any desired editors on a given
|
||||
* {@link org.springframework.beans.PropertyEditorRegistry registry}.
|
||||
* Each PropertyEditorRegistrar can register any number of custom editors.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* In case you want to register {@link PropertyEditor} instances, the
|
||||
* recommended usage as of Spring 2.0 is to use custom
|
||||
* {@link PropertyEditorRegistrar} implementations that in turn register any
|
||||
* desired editor instances on a given
|
||||
* {@link org.springframework.beans.PropertyEditorRegistry registry}. Each
|
||||
* PropertyEditorRegistrar can register any number of custom editors.
|
||||
*
|
||||
* <pre class="code">
|
||||
* <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
|
||||
* <property name="propertyEditorRegistrars">
|
||||
@@ -50,10 +52,14 @@ import org.springframework.util.ClassUtils;
|
||||
* <bean class="mypackage.MyObjectEditorRegistrar"/>
|
||||
* </list>
|
||||
* </property>
|
||||
* </bean></pre>
|
||||
*
|
||||
* <p>Alternative configuration example with custom editor classes:
|
||||
*
|
||||
* </bean>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* It's perfectly fine to register {@link PropertyEditor} <em>classes</em> via
|
||||
* the {@code customEditors} property. Spring will create fresh instances of
|
||||
* them for each editing attempt then:
|
||||
*
|
||||
* <pre class="code">
|
||||
* <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
|
||||
* <property name="customEditors">
|
||||
@@ -62,9 +68,19 @@ import org.springframework.util.ClassUtils;
|
||||
* <entry key="mypackage.MyObject" value="mypackage.MyObjectEditor"/>
|
||||
* </map>
|
||||
* </property>
|
||||
* </bean></pre>
|
||||
*
|
||||
* <p>Also supports "java.lang.String[]"-style array class names and primitive
|
||||
* </bean>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Note, that you shouldn't register {@link PropertyEditor} bean instances via
|
||||
* the {@code customEditors} property as {@link PropertyEditor}s are stateful
|
||||
* and the instances will then have to be synchronized for every editing
|
||||
* attempt. In case you need control over the instantiation process of
|
||||
* {@link PropertyEditor}s, use a {@link PropertyEditorRegistrar} to register
|
||||
* them.
|
||||
*
|
||||
* <p>
|
||||
* Also supports "java.lang.String[]"-style array class names and primitive
|
||||
* class names (e.g. "boolean"). Delegates to {@link ClassUtils} for actual
|
||||
* class name resolution.
|
||||
*
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Bean factory post processor that logs a warning for {@link Deprecated @Deprecated} beans.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.0.3
|
||||
*/
|
||||
public class DeprecatedBeanWarner implements BeanFactoryPostProcessor {
|
||||
|
||||
/**
|
||||
* Logger available to subclasses.
|
||||
*/
|
||||
protected transient Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/**
|
||||
* Set the name of the logger to use. The name will be passed to the underlying logger implementation through
|
||||
* Commons Logging, getting interpreted as log category according to the logger's configuration.
|
||||
* <p>This can be specified to not log into the category of this warner class but rather into a specific named category.
|
||||
* @see org.apache.commons.logging.LogFactory#getLog(String)
|
||||
* @see org.apache.log4j.Logger#getLogger(String)
|
||||
* @see java.util.logging.Logger#getLogger(String)
|
||||
*/
|
||||
public void setLoggerName(String loggerName) {
|
||||
this.logger = LogFactory.getLog(loggerName);
|
||||
}
|
||||
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
if (isLogEnabled()) {
|
||||
String[] beanNames = beanFactory.getBeanDefinitionNames();
|
||||
for (String beanName : beanNames) {
|
||||
Class<?> beanType = beanFactory.getType(beanName);
|
||||
if (beanType != null && beanType.isAnnotationPresent(Deprecated.class)) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
|
||||
logDeprecatedBean(beanName, beanDefinition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a warning for a bean annotated with {@link Deprecated @Deprecated}.
|
||||
*
|
||||
* @param beanName the name of the deprecated bean
|
||||
* @param beanDefinition the definition of the deprecated bean
|
||||
*/
|
||||
protected void logDeprecatedBean(String beanName, BeanDefinition beanDefinition) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(beanDefinition.getBeanClassName());
|
||||
builder.append(" ['");
|
||||
builder.append(beanName);
|
||||
builder.append('\'');
|
||||
String resourceDescription = beanDefinition.getResourceDescription();
|
||||
if (StringUtils.hasLength(resourceDescription)) {
|
||||
builder.append(" in ");
|
||||
builder.append(resourceDescription);
|
||||
}
|
||||
builder.append(" ] has been deprecated");
|
||||
logger.warn(builder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the {@link #logger} field is enabled.
|
||||
* <p>Default is {@code true} when the "warn" level is enabled. Subclasses can override this to change the level
|
||||
* under which logging occurs.
|
||||
*/
|
||||
protected boolean isLogEnabled() {
|
||||
return logger.isWarnEnabled();
|
||||
}
|
||||
|
||||
}
|
||||
+33
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -66,7 +66,7 @@ public class PropertiesFactoryBean extends PropertiesLoaderSupport
|
||||
|
||||
public final void afterPropertiesSet() throws IOException {
|
||||
if (this.singleton) {
|
||||
this.singletonInstance = mergeProperties();
|
||||
this.singletonInstance = createProperties();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public class PropertiesFactoryBean extends PropertiesLoaderSupport
|
||||
return this.singletonInstance;
|
||||
}
|
||||
else {
|
||||
return mergeProperties();
|
||||
return createProperties();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,4 +83,34 @@ public class PropertiesFactoryBean extends PropertiesLoaderSupport
|
||||
return Properties.class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Template method that subclasses may override to construct the object
|
||||
* returned by this factory. The default implementation returns the
|
||||
* plain merged Properties instance.
|
||||
* <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
|
||||
* @see #mergeProperties()
|
||||
*/
|
||||
protected Properties createProperties() throws IOException {
|
||||
return (Properties) createInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that subclasses may override to construct the object
|
||||
* returned by this factory. The default implementation returns the
|
||||
* plain merged Properties instance.
|
||||
* <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
|
||||
* @deprecated as of Spring 3.0, in favor of {@link #createProperties()}
|
||||
*/
|
||||
@Deprecated
|
||||
protected Object createInstance() throws IOException {
|
||||
return mergeProperties();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+18
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -140,6 +140,7 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Set the prefix that a placeholder string starts with.
|
||||
* The default is "${".
|
||||
@@ -158,6 +159,16 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer
|
||||
this.placeholderSuffix = placeholderSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the separating character between the placeholder variable
|
||||
* and the associated default value, or <code>null</code> if no such
|
||||
* special character should be processed as a value separator.
|
||||
* The default is ":".
|
||||
*/
|
||||
public void setValueSeparator(String valueSeparator) {
|
||||
this.valueSeparator = valueSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the system property mode by the name of the corresponding constant,
|
||||
* e.g. "SYSTEM_PROPERTIES_MODE_OVERRIDE".
|
||||
@@ -208,8 +219,11 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to ignore unresolvable placeholders. Default is "false":
|
||||
* An exception will be thrown if a placeholder cannot be resolved.
|
||||
* Set whether to ignore unresolvable placeholders.
|
||||
* <p>Default is "false": An exception will be thrown if a placeholder fails
|
||||
* to resolve. Switch this flag to "true" in order to preserve the placeholder
|
||||
* String as-is in such a case, leaving it up to other placeholder configurers
|
||||
* to resolve it.
|
||||
*/
|
||||
public void setIgnoreUnresolvablePlaceholders(boolean ignoreUnresolvablePlaceholders) {
|
||||
this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
|
||||
@@ -252,6 +266,7 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
|
||||
throws BeansException {
|
||||
|
||||
+20
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -92,7 +92,7 @@ public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
|
||||
while (propertyNames.hasMoreElements()) {
|
||||
String propertyName = (String) propertyNames.nextElement();
|
||||
String propertyValue = props.getProperty(propertyName);
|
||||
String convertedValue = convertPropertyValue(propertyValue);
|
||||
String convertedValue = convertProperty(propertyName, propertyValue);
|
||||
if (!ObjectUtils.nullSafeEquals(propertyValue, convertedValue)) {
|
||||
props.setProperty(propertyName, convertedValue);
|
||||
}
|
||||
@@ -100,8 +100,21 @@ public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given property value from the properties source
|
||||
* to the value that should be applied.
|
||||
* Convert the given property from the properties source to the value
|
||||
* which should be applied.
|
||||
* <p>The default implementation calls {@link #convertPropertyValue(String)}.
|
||||
* @param propertyName the name of the property that the value is defined for
|
||||
* @param propertyValue the original value from the properties source
|
||||
* @return the converted value, to be used for processing
|
||||
* @see #convertPropertyValue(String)
|
||||
*/
|
||||
protected String convertProperty(String propertyName, String propertyValue) {
|
||||
return convertPropertyValue(propertyValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given property value from the properties source to the value
|
||||
* which should be applied.
|
||||
* <p>The default implementation simply returns the original value.
|
||||
* Can be overridden in subclasses, for example to detect
|
||||
* encrypted values and decrypt them accordingly.
|
||||
@@ -111,14 +124,16 @@ public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
|
||||
* @see #setProperties
|
||||
* @see #setLocations
|
||||
* @see #setLocation
|
||||
* @see #convertProperty(String, String)
|
||||
*/
|
||||
protected String convertPropertyValue(String originalValue) {
|
||||
return originalValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Apply the given Properties to the given BeanFactory.
|
||||
* @param beanFactory the BeanFactory used by the application context
|
||||
* @param beanFactory the BeanFactory used by the application context
|
||||
* @param props the Properties to apply
|
||||
* @throws org.springframework.beans.BeansException in case of errors
|
||||
*/
|
||||
|
||||
+9
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,7 +38,7 @@ public class TypedStringValue implements BeanMetadataElement {
|
||||
|
||||
private String value;
|
||||
|
||||
private Object targetType;
|
||||
private volatile Object targetType;
|
||||
|
||||
private Object source;
|
||||
|
||||
@@ -110,10 +110,11 @@ public class TypedStringValue implements BeanMetadataElement {
|
||||
* Return the type to convert to.
|
||||
*/
|
||||
public Class getTargetType() {
|
||||
if (!(this.targetType instanceof Class)) {
|
||||
Object targetTypeValue = this.targetType;
|
||||
if (!(targetTypeValue instanceof Class)) {
|
||||
throw new IllegalStateException("Typed String value does not carry a resolved target type");
|
||||
}
|
||||
return (Class) this.targetType;
|
||||
return (Class) targetTypeValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,11 +129,12 @@ public class TypedStringValue implements BeanMetadataElement {
|
||||
* Return the type to convert to.
|
||||
*/
|
||||
public String getTargetTypeName() {
|
||||
if (this.targetType instanceof Class) {
|
||||
return ((Class) this.targetType).getName();
|
||||
Object targetTypeValue = this.targetType;
|
||||
if (targetTypeValue instanceof Class) {
|
||||
return ((Class) targetTypeValue).getName();
|
||||
}
|
||||
else {
|
||||
return (String) this.targetType;
|
||||
return (String) targetTypeValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+33
-23
@@ -28,7 +28,6 @@ import java.security.PrivilegedExceptionAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -144,7 +143,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
|
||||
/** Cache of filtered PropertyDescriptors: bean Class -> PropertyDescriptor array */
|
||||
private final Map<Class, PropertyDescriptor[]> filteredPropertyDescriptorsCache =
|
||||
new HashMap<Class, PropertyDescriptor[]>();
|
||||
new ConcurrentHashMap<Class, PropertyDescriptor[]>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -567,7 +566,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class[] typesToMatch) {
|
||||
protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class... typesToMatch) {
|
||||
Class beanClass;
|
||||
if (mbd.getFactoryMethodName() != null) {
|
||||
beanClass = getTypeForFactoryMethod(beanName, mbd, typesToMatch);
|
||||
@@ -880,8 +879,18 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
}
|
||||
|
||||
// Shortcut when re-creating the same bean...
|
||||
if (mbd.resolvedConstructorOrFactoryMethod != null && args == null) {
|
||||
if (mbd.constructorArgumentsResolved) {
|
||||
boolean resolved = false;
|
||||
boolean autowireNecessary = false;
|
||||
if (args == null) {
|
||||
synchronized (mbd.constructorArgumentLock) {
|
||||
if (mbd.resolvedConstructorOrFactoryMethod != null) {
|
||||
resolved = true;
|
||||
autowireNecessary = mbd.constructorArgumentsResolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resolved) {
|
||||
if (autowireNecessary) {
|
||||
return autowireConstructor(beanName, mbd, null, null);
|
||||
}
|
||||
else {
|
||||
@@ -1095,9 +1104,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
pvs.add(propertyName, bean);
|
||||
registerDependentBean(propertyName, beanName);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
"Added autowiring by name from bean name '" + beanName + "' via property '" + propertyName +
|
||||
"' to bean named '" + propertyName + "'");
|
||||
logger.debug("Added autowiring by name from bean name '" + beanName +
|
||||
"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1147,9 +1155,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
for (String autowiredBeanName : autowiredBeanNames) {
|
||||
registerDependentBean(autowiredBeanName, beanName);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
"Autowiring by type from bean name '" + beanName + "' via property '" + propertyName +
|
||||
"' to bean named '" + autowiredBeanName + "'");
|
||||
logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
|
||||
propertyName + "' to bean named '" + autowiredBeanName + "'");
|
||||
}
|
||||
}
|
||||
autowiredBeanNames.clear();
|
||||
@@ -1193,22 +1200,25 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @see #isExcludedFromDependencyCheck
|
||||
*/
|
||||
protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw) {
|
||||
synchronized (this.filteredPropertyDescriptorsCache) {
|
||||
PropertyDescriptor[] filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
|
||||
if (filtered == null) {
|
||||
List<PropertyDescriptor> pds =
|
||||
new LinkedList<PropertyDescriptor>(Arrays.asList(bw.getPropertyDescriptors()));
|
||||
for (Iterator<PropertyDescriptor> it = pds.iterator(); it.hasNext();) {
|
||||
PropertyDescriptor pd = it.next();
|
||||
if (isExcludedFromDependencyCheck(pd)) {
|
||||
it.remove();
|
||||
PropertyDescriptor[] filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
|
||||
if (filtered == null) {
|
||||
synchronized (this.filteredPropertyDescriptorsCache) {
|
||||
filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
|
||||
if (filtered == null) {
|
||||
List<PropertyDescriptor> pds =
|
||||
new LinkedList<PropertyDescriptor>(Arrays.asList(bw.getPropertyDescriptors()));
|
||||
for (Iterator<PropertyDescriptor> it = pds.iterator(); it.hasNext();) {
|
||||
PropertyDescriptor pd = it.next();
|
||||
if (isExcludedFromDependencyCheck(pd)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
filtered = pds.toArray(new PropertyDescriptor[pds.size()]);
|
||||
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
|
||||
}
|
||||
filtered = pds.toArray(new PropertyDescriptor[pds.size()]);
|
||||
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
private boolean primary = false;
|
||||
|
||||
private final Map<String, AutowireCandidateQualifier> qualifiers =
|
||||
new LinkedHashMap<String, AutowireCandidateQualifier>();
|
||||
new LinkedHashMap<String, AutowireCandidateQualifier>(0);
|
||||
|
||||
private boolean nonPublicAccessAllowed = true;
|
||||
|
||||
|
||||
+46
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,6 +42,7 @@ import org.springframework.beans.PropertyEditorRegistry;
|
||||
import org.springframework.beans.PropertyEditorRegistrySupport;
|
||||
import org.springframework.beans.SimpleTypeConverter;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
@@ -166,6 +167,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
|
||||
new NamedThreadLocal<Object>("Prototype beans currently in creation");
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AbstractBeanFactory.
|
||||
*/
|
||||
@@ -189,7 +191,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
public Object getBean(String name) throws BeansException {
|
||||
return doGetBean(name, null, null, false);
|
||||
}
|
||||
|
||||
|
||||
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
|
||||
return doGetBean(name, requiredType, null, false);
|
||||
}
|
||||
@@ -346,7 +348,16 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
|
||||
// Check if required type matches the type of the actual bean instance.
|
||||
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
|
||||
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
|
||||
try {
|
||||
return getTypeConverter().convertIfNecessary(bean, requiredType);
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to convert bean '" + name + "' to required type [" +
|
||||
ClassUtils.getQualifiedName(requiredType) + "]", ex);
|
||||
}
|
||||
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
|
||||
}
|
||||
}
|
||||
return (T) bean;
|
||||
}
|
||||
@@ -373,6 +384,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
return !BeanFactoryUtils.isFactoryDereference(name);
|
||||
}
|
||||
}
|
||||
else if (containsSingleton(beanName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
else {
|
||||
// No singleton instance found -> check bean definition.
|
||||
@@ -465,6 +479,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
typeToMatch.isAssignableFrom(beanInstance.getClass());
|
||||
}
|
||||
}
|
||||
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
|
||||
// null instance registered
|
||||
return false;
|
||||
}
|
||||
|
||||
else {
|
||||
// No singleton instance found -> check bean definition.
|
||||
@@ -524,6 +542,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
return beanInstance.getClass();
|
||||
}
|
||||
}
|
||||
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
|
||||
// null instance registered
|
||||
return null;
|
||||
}
|
||||
|
||||
else {
|
||||
// No singleton instance found -> check bean definition.
|
||||
@@ -534,12 +556,24 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
}
|
||||
|
||||
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||
|
||||
// Check decorated bean definition, if any: We assume it'll be easier
|
||||
// to determine the decorated bean's type than the proxy's type.
|
||||
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
|
||||
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
|
||||
Class targetClass = predictBeanType(dbd.getBeanName(), tbd);
|
||||
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
|
||||
return targetClass;
|
||||
}
|
||||
}
|
||||
|
||||
Class beanClass = predictBeanType(beanName, mbd);
|
||||
|
||||
// Check bean class whether we're dealing with a FactoryBean.
|
||||
if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
|
||||
if (!BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
|
||||
// If it's a FactoryBean, we want to look at what it creates, not at the factory class.
|
||||
return getTypeForFactoryBean(beanName, mbd);
|
||||
}
|
||||
else {
|
||||
@@ -659,7 +693,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
return this.propertyEditorRegistrars;
|
||||
}
|
||||
|
||||
public void registerCustomEditor(Class requiredType, Class<? extends PropertyEditor> propertyEditorClass) {
|
||||
public void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass) {
|
||||
Assert.notNull(requiredType, "Required type must not be null");
|
||||
Assert.isAssignable(PropertyEditor.class, propertyEditorClass);
|
||||
this.customEditors.put(requiredType, propertyEditorClass);
|
||||
@@ -848,6 +882,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
if (beanInstance != null) {
|
||||
return (beanInstance instanceof FactoryBean);
|
||||
}
|
||||
else if (containsSingleton(beanName)) {
|
||||
// null instance registered
|
||||
return false;
|
||||
}
|
||||
|
||||
// No singleton instance found -> check bean definition.
|
||||
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
|
||||
@@ -892,13 +930,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
protected void afterPrototypeCreation(String beanName) {
|
||||
Object curVal = this.prototypesCurrentlyInCreation.get();
|
||||
if (curVal instanceof String) {
|
||||
this.prototypesCurrentlyInCreation.set(null);
|
||||
this.prototypesCurrentlyInCreation.remove();
|
||||
}
|
||||
else if (curVal instanceof Set) {
|
||||
Set<String> beanNameSet = (Set<String>) curVal;
|
||||
beanNameSet.remove(beanName);
|
||||
if (beanNameSet.isEmpty()) {
|
||||
this.prototypesCurrentlyInCreation.set(null);
|
||||
this.prototypesCurrentlyInCreation.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1226,7 +1264,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Class doResolveBeanClass(RootBeanDefinition mbd, Class... typesToMatch) throws ClassNotFoundException {
|
||||
if (!ObjectUtils.isEmpty(typesToMatch)) {
|
||||
ClassLoader tempClassLoader = getTempClassLoader();
|
||||
|
||||
+12
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,8 +43,8 @@ import org.springframework.util.ClassUtils;
|
||||
abstract class AutowireUtils {
|
||||
|
||||
/**
|
||||
* Sort the given constructors, preferring public constructors and "greedy" ones
|
||||
* with a maximum of arguments. The result will contain public constructors first,
|
||||
* Sort the given constructors, preferring public constructors and "greedy" ones with
|
||||
* a maximum number of arguments. The result will contain public constructors first,
|
||||
* with decreasing number of arguments, then non-public constructors, again with
|
||||
* decreasing number of arguments.
|
||||
* @param constructors the constructor array to sort
|
||||
@@ -136,11 +136,15 @@ abstract class AutowireUtils {
|
||||
* @return the resolved value
|
||||
*/
|
||||
public static Object resolveAutowiringValue(Object autowiringValue, Class requiredType) {
|
||||
if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue) &&
|
||||
autowiringValue instanceof Serializable && requiredType.isInterface()) {
|
||||
autowiringValue = Proxy.newProxyInstance(
|
||||
requiredType.getClassLoader(), new Class[] {requiredType},
|
||||
new ObjectFactoryDelegatingInvocationHandler((ObjectFactory) autowiringValue));
|
||||
if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
|
||||
ObjectFactory factory = (ObjectFactory) autowiringValue;
|
||||
if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
|
||||
autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(),
|
||||
new Class[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
|
||||
}
|
||||
else {
|
||||
return factory.getObject();
|
||||
}
|
||||
}
|
||||
return autowiringValue;
|
||||
}
|
||||
|
||||
+27
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -338,9 +338,7 @@ class BeanDefinitionValueResolver {
|
||||
Object resolved = Array.newInstance(elementType, ml.size());
|
||||
for (int i = 0; i < ml.size(); i++) {
|
||||
Array.set(resolved, i,
|
||||
resolveValueIfNecessary(
|
||||
argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX,
|
||||
ml.get(i)));
|
||||
resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i)));
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
@@ -352,9 +350,7 @@ class BeanDefinitionValueResolver {
|
||||
List<Object> resolved = new ArrayList<Object>(ml.size());
|
||||
for (int i = 0; i < ml.size(); i++) {
|
||||
resolved.add(
|
||||
resolveValueIfNecessary(
|
||||
argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX,
|
||||
ml.get(i)));
|
||||
resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i)));
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
@@ -366,8 +362,7 @@ class BeanDefinitionValueResolver {
|
||||
Set<Object> resolved = new LinkedHashSet<Object>(ms.size());
|
||||
int i = 0;
|
||||
for (Object m : ms) {
|
||||
resolved.add(resolveValueIfNecessary(
|
||||
argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX, m));
|
||||
resolved.add(resolveValueIfNecessary(new KeyedArgName(argName, i), m));
|
||||
i++;
|
||||
}
|
||||
return resolved;
|
||||
@@ -381,11 +376,32 @@ class BeanDefinitionValueResolver {
|
||||
for (Map.Entry entry : mm.entrySet()) {
|
||||
Object resolvedKey = resolveValueIfNecessary(argName, entry.getKey());
|
||||
Object resolvedValue = resolveValueIfNecessary(
|
||||
argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + entry.getKey() +
|
||||
BeanWrapper.PROPERTY_KEY_SUFFIX, entry.getValue());
|
||||
new KeyedArgName(argName, entry.getKey()), entry.getValue());
|
||||
resolved.put(resolvedKey, resolvedValue);
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holder class used for delayed toString building.
|
||||
*/
|
||||
private static class KeyedArgName {
|
||||
|
||||
private final Object argName;
|
||||
|
||||
private final Object key;
|
||||
|
||||
public KeyedArgName(Object argName, Object key) {
|
||||
this.argName = argName;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX +
|
||||
this.key + BeanWrapper.PROPERTY_KEY_SUFFIX;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+83
-61
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import static org.springframework.util.StringUtils.collectionToCommaDelimitedString;
|
||||
|
||||
import java.beans.ConstructorProperties;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Member;
|
||||
@@ -44,9 +42,8 @@ import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
@@ -112,20 +109,27 @@ class ConstructorResolver {
|
||||
this.beanFactory.initBeanWrapper(bw);
|
||||
|
||||
Constructor constructorToUse = null;
|
||||
ArgumentsHolder argsHolderToUse = null;
|
||||
Object[] argsToUse = null;
|
||||
|
||||
if (explicitArgs != null) {
|
||||
argsToUse = explicitArgs;
|
||||
}
|
||||
else {
|
||||
constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
|
||||
if (constructorToUse != null) {
|
||||
// Found a cached constructor...
|
||||
argsToUse = mbd.resolvedConstructorArguments;
|
||||
if (argsToUse == null) {
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse);
|
||||
Object[] argsToResolve = null;
|
||||
synchronized (mbd.constructorArgumentLock) {
|
||||
constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
|
||||
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
|
||||
// Found a cached constructor...
|
||||
argsToUse = mbd.resolvedConstructorArguments;
|
||||
if (argsToUse == null) {
|
||||
argsToResolve = mbd.preparedConstructorArguments;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (argsToResolve != null) {
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
|
||||
}
|
||||
}
|
||||
|
||||
if (constructorToUse == null) {
|
||||
@@ -173,13 +177,10 @@ class ConstructorResolver {
|
||||
break;
|
||||
}
|
||||
if (paramTypes.length < minNrOfArgs) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
minNrOfArgs + " constructor arguments specified but no matching constructor found in bean '" +
|
||||
beanName + "' " +
|
||||
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
|
||||
continue;
|
||||
}
|
||||
|
||||
ArgumentsHolder args;
|
||||
ArgumentsHolder argsHolder;
|
||||
if (resolvedValues != null) {
|
||||
try {
|
||||
String[] paramNames = null;
|
||||
@@ -192,7 +193,7 @@ class ConstructorResolver {
|
||||
paramNames = pnd.getParameterNames(candidate);
|
||||
}
|
||||
}
|
||||
args = createArgumentArray(
|
||||
argsHolder = createArgumentArray(
|
||||
beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
|
||||
}
|
||||
catch (UnsatisfiedDependencyException ex) {
|
||||
@@ -223,15 +224,16 @@ class ConstructorResolver {
|
||||
if (paramTypes.length != explicitArgs.length) {
|
||||
continue;
|
||||
}
|
||||
args = new ArgumentsHolder(explicitArgs);
|
||||
argsHolder = new ArgumentsHolder(explicitArgs);
|
||||
}
|
||||
|
||||
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
|
||||
args.getTypeDifferenceWeight(paramTypes) : args.getAssignabilityWeight(paramTypes));
|
||||
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
|
||||
// Choose this constructor if it represents the closest match.
|
||||
if (typeDiffWeight < minTypeDiffWeight) {
|
||||
constructorToUse = candidate;
|
||||
argsToUse = args.arguments;
|
||||
argsHolderToUse = argsHolder;
|
||||
argsToUse = argsHolder.arguments;
|
||||
minTypeDiffWeight = typeDiffWeight;
|
||||
ambiguousConstructors = null;
|
||||
}
|
||||
@@ -245,8 +247,9 @@ class ConstructorResolver {
|
||||
}
|
||||
|
||||
if (constructorToUse == null) {
|
||||
throw new BeanCreationException(
|
||||
mbd.getResourceDescription(), beanName, "Could not resolve matching constructor");
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Could not resolve matching constructor " +
|
||||
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
|
||||
}
|
||||
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
@@ -256,7 +259,7 @@ class ConstructorResolver {
|
||||
}
|
||||
|
||||
if (explicitArgs == null) {
|
||||
mbd.resolvedConstructorOrFactoryMethod = constructorToUse;
|
||||
argsHolderToUse.storeCache(mbd, constructorToUse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,8 +277,8 @@ class ConstructorResolver {
|
||||
}, beanFactory.getAccessControlContext());
|
||||
}
|
||||
else {
|
||||
beanInstance = beanFactory.getInstantiationStrategy().instantiate(
|
||||
mbd, beanName, beanFactory, constructorToUse, argsToUse);
|
||||
beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
|
||||
mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
|
||||
}
|
||||
|
||||
bw.setWrappedInstance(beanInstance);
|
||||
@@ -313,7 +316,9 @@ class ConstructorResolver {
|
||||
}
|
||||
}
|
||||
}
|
||||
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
|
||||
synchronized (mbd.constructorArgumentLock) {
|
||||
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -365,20 +370,27 @@ class ConstructorResolver {
|
||||
}
|
||||
|
||||
Method factoryMethodToUse = null;
|
||||
ArgumentsHolder argsHolderToUse = null;
|
||||
Object[] argsToUse = null;
|
||||
|
||||
if (explicitArgs != null) {
|
||||
argsToUse = explicitArgs;
|
||||
}
|
||||
else {
|
||||
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
|
||||
if (factoryMethodToUse != null) {
|
||||
// Found a cached factory method...
|
||||
argsToUse = mbd.resolvedConstructorArguments;
|
||||
if (argsToUse == null && mbd.preparedConstructorArguments != null) {
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse);
|
||||
Object[] argsToResolve = null;
|
||||
synchronized (mbd.constructorArgumentLock) {
|
||||
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
|
||||
if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
|
||||
// Found a cached factory method...
|
||||
argsToUse = mbd.resolvedConstructorArguments;
|
||||
if (argsToUse == null) {
|
||||
argsToResolve = mbd.preparedConstructorArguments;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (argsToResolve != null) {
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);
|
||||
}
|
||||
}
|
||||
|
||||
if (factoryMethodToUse == null || argsToUse == null) {
|
||||
@@ -436,7 +448,7 @@ class ConstructorResolver {
|
||||
Class[] paramTypes = candidate.getParameterTypes();
|
||||
|
||||
if (paramTypes.length >= minNrOfArgs) {
|
||||
ArgumentsHolder args;
|
||||
ArgumentsHolder argsHolder;
|
||||
|
||||
if (resolvedValues != null) {
|
||||
// Resolved constructor arguments: type conversion and/or autowiring necessary.
|
||||
@@ -446,7 +458,7 @@ class ConstructorResolver {
|
||||
if (pnd != null) {
|
||||
paramNames = pnd.getParameterNames(candidate);
|
||||
}
|
||||
args = createArgumentArray(
|
||||
argsHolder = createArgumentArray(
|
||||
beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
|
||||
}
|
||||
catch (UnsatisfiedDependencyException ex) {
|
||||
@@ -454,7 +466,7 @@ class ConstructorResolver {
|
||||
this.beanFactory.logger.trace("Ignoring factory method [" + candidate +
|
||||
"] of bean '" + beanName + "': " + ex);
|
||||
}
|
||||
if (i == candidates.length - 1 && factoryMethodToUse == null) {
|
||||
if (i == candidates.length - 1 && argsHolderToUse == null) {
|
||||
if (causes != null) {
|
||||
for (Exception cause : causes) {
|
||||
this.beanFactory.onSuppressedException(cause);
|
||||
@@ -478,15 +490,16 @@ class ConstructorResolver {
|
||||
if (paramTypes.length != explicitArgs.length) {
|
||||
continue;
|
||||
}
|
||||
args = new ArgumentsHolder(explicitArgs);
|
||||
argsHolder = new ArgumentsHolder(explicitArgs);
|
||||
}
|
||||
|
||||
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
|
||||
args.getTypeDifferenceWeight(paramTypes) : args.getAssignabilityWeight(paramTypes));
|
||||
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
|
||||
// Choose this factory method if it represents the closest match.
|
||||
if (typeDiffWeight < minTypeDiffWeight) {
|
||||
factoryMethodToUse = candidate;
|
||||
argsToUse = args.arguments;
|
||||
argsHolderToUse = argsHolder;
|
||||
argsToUse = argsHolder.arguments;
|
||||
minTypeDiffWeight = typeDiffWeight;
|
||||
ambiguousFactoryMethods = null;
|
||||
}
|
||||
@@ -501,13 +514,13 @@ class ConstructorResolver {
|
||||
}
|
||||
|
||||
if (factoryMethodToUse == null) {
|
||||
boolean hasArgs = resolvedValues.getArgumentCount() > 0;
|
||||
boolean hasArgs = (resolvedValues.getArgumentCount() > 0);
|
||||
String argDesc = "";
|
||||
if (hasArgs) {
|
||||
List<String> argTypes = new ArrayList<String>();
|
||||
for (ValueHolder value : resolvedValues.getIndexedArgumentValues().values()) {
|
||||
String argType = value.getType() != null ?
|
||||
ClassUtils.getShortName(value.getType()) : value.getValue().getClass().getSimpleName();
|
||||
String argType = (value.getType() != null ?
|
||||
ClassUtils.getShortName(value.getType()) : value.getValue().getClass().getSimpleName());
|
||||
argTypes.add(argType);
|
||||
}
|
||||
argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
|
||||
@@ -534,8 +547,8 @@ class ConstructorResolver {
|
||||
ambiguousFactoryMethods);
|
||||
}
|
||||
|
||||
if (explicitArgs == null) {
|
||||
mbd.resolvedConstructorOrFactoryMethod = factoryMethodToUse;
|
||||
if (explicitArgs == null && argsHolderToUse != null) {
|
||||
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,7 +655,6 @@ class ConstructorResolver {
|
||||
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders =
|
||||
new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length);
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);
|
||||
boolean resolveNecessary = false;
|
||||
|
||||
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
|
||||
Class<?> paramType = paramTypes[paramIndex];
|
||||
@@ -660,28 +672,31 @@ class ConstructorResolver {
|
||||
// We found a potential match - let's give it a try.
|
||||
// Do not consider the same value definition multiple times!
|
||||
usedValueHolders.add(valueHolder);
|
||||
ConstructorArgumentValues.ValueHolder sourceHolder =
|
||||
(ConstructorArgumentValues.ValueHolder) valueHolder.getSource();
|
||||
Object originalValue = valueHolder.getValue();
|
||||
Object sourceValue = sourceHolder.getValue();
|
||||
Object convertedValue;
|
||||
if (valueHolder.isConverted()) {
|
||||
convertedValue = valueHolder.getConvertedValue();
|
||||
args.preparedArguments[paramIndex] = convertedValue;
|
||||
}
|
||||
else {
|
||||
ConstructorArgumentValues.ValueHolder sourceHolder =
|
||||
(ConstructorArgumentValues.ValueHolder) valueHolder.getSource();
|
||||
Object sourceValue = sourceHolder.getValue();
|
||||
try {
|
||||
convertedValue = converter.convertIfNecessary(originalValue, paramType,
|
||||
MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex));
|
||||
// TODO re-enable once race condition has been found (SPR-7423)
|
||||
/*
|
||||
if (originalValue == sourceValue || sourceValue instanceof TypedStringValue) {
|
||||
// Either a converted value or still the original one: store converted value.
|
||||
sourceHolder.setConvertedValue(convertedValue);
|
||||
args.preparedArguments[paramIndex] = convertedValue;
|
||||
}
|
||||
else {
|
||||
resolveNecessary = true;
|
||||
*/
|
||||
args.resolveNecessary = true;
|
||||
args.preparedArguments[paramIndex] = sourceValue;
|
||||
}
|
||||
// }
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
throw new UnsatisfiedDependencyException(
|
||||
@@ -709,7 +724,7 @@ class ConstructorResolver {
|
||||
args.rawArguments[paramIndex] = autowiredArgument;
|
||||
args.arguments[paramIndex] = autowiredArgument;
|
||||
args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
|
||||
resolveNecessary = true;
|
||||
args.resolveNecessary = true;
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(
|
||||
@@ -726,13 +741,6 @@ class ConstructorResolver {
|
||||
}
|
||||
}
|
||||
|
||||
if (resolveNecessary) {
|
||||
mbd.preparedConstructorArguments = args.preparedArguments;
|
||||
}
|
||||
else {
|
||||
mbd.resolvedConstructorArguments = args.arguments;
|
||||
}
|
||||
mbd.constructorArgumentsResolved = true;
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -740,11 +748,10 @@ class ConstructorResolver {
|
||||
* Resolve the prepared arguments stored in the given bean definition.
|
||||
*/
|
||||
private Object[] resolvePreparedArguments(
|
||||
String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor) {
|
||||
String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) {
|
||||
|
||||
Class[] paramTypes = (methodOrCtor instanceof Method ?
|
||||
((Method) methodOrCtor).getParameterTypes() : ((Constructor) methodOrCtor).getParameterTypes());
|
||||
Object[] argsToResolve = mbd.preparedConstructorArguments;
|
||||
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
|
||||
this.beanFactory.getCustomTypeConverter() : bw);
|
||||
BeanDefinitionValueResolver valueResolver =
|
||||
@@ -795,11 +802,13 @@ class ConstructorResolver {
|
||||
*/
|
||||
private static class ArgumentsHolder {
|
||||
|
||||
public Object rawArguments[];
|
||||
public final Object rawArguments[];
|
||||
|
||||
public Object arguments[];
|
||||
public final Object arguments[];
|
||||
|
||||
public Object preparedArguments[];
|
||||
public final Object preparedArguments[];
|
||||
|
||||
public boolean resolveNecessary = false;
|
||||
|
||||
public ArgumentsHolder(int size) {
|
||||
this.rawArguments = new Object[size];
|
||||
@@ -836,6 +845,19 @@ class ConstructorResolver {
|
||||
}
|
||||
return Integer.MAX_VALUE - 1024;
|
||||
}
|
||||
|
||||
public void storeCache(RootBeanDefinition mbd, Object constructorOrFactoryMethod) {
|
||||
synchronized (mbd.constructorArgumentLock) {
|
||||
mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;
|
||||
mbd.constructorArgumentsResolved = true;
|
||||
if (this.resolveNecessary) {
|
||||
mbd.preparedConstructorArguments = this.preparedArguments;
|
||||
}
|
||||
else {
|
||||
mbd.resolvedConstructorArguments = this.arguments;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+36
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
@@ -248,6 +250,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
public <T> T getBean(Class<T> requiredType) throws BeansException {
|
||||
Assert.notNull(requiredType, "Required type must not be null");
|
||||
String[] beanNames = getBeanNamesForType(requiredType);
|
||||
if (beanNames.length > 1) {
|
||||
ArrayList<String> autowireCandidates = new ArrayList<String>();
|
||||
for (String beanName : beanNames) {
|
||||
if (getBeanDefinition(beanName).isAutowireCandidate()) {
|
||||
autowireCandidates.add(beanName);
|
||||
}
|
||||
}
|
||||
if (autowireCandidates.size() > 0) {
|
||||
beanNames = autowireCandidates.toArray(new String[autowireCandidates.size()]);
|
||||
}
|
||||
}
|
||||
if (beanNames.length == 1) {
|
||||
return getBean(beanNames[0], requiredType);
|
||||
}
|
||||
@@ -493,8 +506,14 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
*/
|
||||
protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd, DependencyDescriptor descriptor) {
|
||||
resolveBeanClass(mbd, beanName);
|
||||
if (mbd.isFactoryMethodUnique && mbd.resolvedConstructorOrFactoryMethod == null) {
|
||||
new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd);
|
||||
if (mbd.isFactoryMethodUnique) {
|
||||
boolean resolve;
|
||||
synchronized (mbd.constructorArgumentLock) {
|
||||
resolve = (mbd.resolvedConstructorOrFactoryMethod == null);
|
||||
}
|
||||
if (resolve) {
|
||||
new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd);
|
||||
}
|
||||
}
|
||||
return getAutowireCandidateResolver().isAutowireCandidate(
|
||||
new BeanDefinitionHolder(mbd, beanName, getAliases(beanName)), descriptor);
|
||||
@@ -524,7 +543,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers all beans as eligible for metdata caching
|
||||
* Considers all beans as eligible for metadata caching
|
||||
* if the factory's configuration has been marked as frozen.
|
||||
* @see #freezeConfiguration()
|
||||
*/
|
||||
@@ -537,9 +556,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (this.logger.isInfoEnabled()) {
|
||||
this.logger.info("Pre-instantiating singletons in " + this);
|
||||
}
|
||||
|
||||
synchronized (this.beanDefinitionMap) {
|
||||
for (String beanName : this.beanDefinitionNames) {
|
||||
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
|
||||
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
|
||||
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
|
||||
for (String beanName : beanNames) {
|
||||
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
|
||||
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
|
||||
if (isFactoryBean(beanName)) {
|
||||
@@ -553,7 +574,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}, getAccessControlContext());
|
||||
}
|
||||
else {
|
||||
isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit();
|
||||
isEagerInit = (factory instanceof SmartFactoryBean &&
|
||||
((SmartFactoryBean) factory).isEagerInit());
|
||||
}
|
||||
if (isEagerInit) {
|
||||
getBean(beanName);
|
||||
@@ -647,8 +669,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
destroySingleton(beanName);
|
||||
}
|
||||
|
||||
// Reset all bean definitions that have the given bean as parent
|
||||
// (recursively).
|
||||
// Reset all bean definitions that have the given bean as parent (recursively).
|
||||
for (String bdName : this.beanDefinitionNames) {
|
||||
if (!beanName.equals(bdName)) {
|
||||
BeanDefinition bd = this.beanDefinitionMap.get(bdName);
|
||||
@@ -694,7 +715,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (value != null) {
|
||||
if (value instanceof String) {
|
||||
String strVal = resolveEmbeddedValue((String) value);
|
||||
BeanDefinition bd = (containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
|
||||
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
|
||||
value = evaluateBeanDefinitionString(strVal, bd);
|
||||
}
|
||||
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
|
||||
@@ -927,6 +948,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
// Serialization support
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||
throw new NotSerializableException("DefaultListableBeanFactory itself is not deserializable - " +
|
||||
"just a SerializedBeanFactoryReference is");
|
||||
}
|
||||
|
||||
protected Object writeReplace() throws ObjectStreamException {
|
||||
if (this.serializationId != null) {
|
||||
return new SerializedBeanFactoryReference(this.serializationId);
|
||||
|
||||
+6
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -363,11 +363,12 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
* @param dependentBeanName the name of the dependent bean
|
||||
*/
|
||||
public void registerDependentBean(String beanName, String dependentBeanName) {
|
||||
String canonicalName = canonicalName(beanName);
|
||||
synchronized (this.dependentBeanMap) {
|
||||
Set<String> dependentBeans = this.dependentBeanMap.get(beanName);
|
||||
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
|
||||
if (dependentBeans == null) {
|
||||
dependentBeans = new LinkedHashSet<String>(8);
|
||||
this.dependentBeanMap.put(beanName, dependentBeans);
|
||||
this.dependentBeanMap.put(canonicalName, dependentBeans);
|
||||
}
|
||||
dependentBeans.add(dependentBeanName);
|
||||
}
|
||||
@@ -377,7 +378,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
dependenciesForBean = new LinkedHashSet<String>(8);
|
||||
this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
|
||||
}
|
||||
dependenciesForBean.add(beanName);
|
||||
dependenciesForBean.add(canonicalName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,7 +456,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
removeSingleton(beanName);
|
||||
|
||||
// Destroy the corresponding DisposableBean instance.
|
||||
DisposableBean disposableBean = null;
|
||||
DisposableBean disposableBean;
|
||||
synchronized (this.disposableBeans) {
|
||||
disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
|
||||
}
|
||||
|
||||
+13
-15
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -32,7 +32,7 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
* @since 1.1
|
||||
*/
|
||||
public interface InstantiationStrategy {
|
||||
|
||||
|
||||
/**
|
||||
* Return an instance of the bean with the given name in this factory.
|
||||
* @param beanDefinition the bean definition
|
||||
@@ -43,9 +43,9 @@ public interface InstantiationStrategy {
|
||||
* @return a bean instance for this bean definition
|
||||
* @throws BeansException if the instantiation failed
|
||||
*/
|
||||
Object instantiate(
|
||||
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) throws BeansException;
|
||||
|
||||
Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner)
|
||||
throws BeansException;
|
||||
|
||||
/**
|
||||
* Return an instance of the bean with the given name in this factory,
|
||||
* creating it via the given constructor.
|
||||
@@ -59,10 +59,9 @@ public interface InstantiationStrategy {
|
||||
* @return a bean instance for this bean definition
|
||||
* @throws BeansException if the instantiation failed
|
||||
*/
|
||||
Object instantiate(
|
||||
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||
Constructor ctor, Object[] args) throws BeansException;
|
||||
|
||||
Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||
Constructor<?> ctor, Object[] args) throws BeansException;
|
||||
|
||||
/**
|
||||
* Return an instance of the bean with the given name in this factory,
|
||||
* creating it via the given factory method.
|
||||
@@ -78,8 +77,7 @@ public interface InstantiationStrategy {
|
||||
* @return a bean instance for this bean definition
|
||||
* @throws BeansException if the instantiation failed
|
||||
*/
|
||||
Object instantiate(
|
||||
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||
Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||
Object factoryBean, Method factoryMethod, Object[] args) throws BeansException;
|
||||
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,7 +34,7 @@ import java.util.Set;
|
||||
*/
|
||||
public class MethodOverrides {
|
||||
|
||||
private final Set<MethodOverride> overrides = new HashSet<MethodOverride>();
|
||||
private final Set<MethodOverride> overrides = new HashSet<MethodOverride>(0);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
+19
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -48,27 +48,29 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
|
||||
private final Set<Member> externallyManagedConfigMembers = Collections.synchronizedSet(new HashSet<Member>());
|
||||
private final Set<Member> externallyManagedConfigMembers = Collections.synchronizedSet(new HashSet<Member>(0));
|
||||
|
||||
private final Set<String> externallyManagedInitMethods = Collections.synchronizedSet(new HashSet<String>());
|
||||
private final Set<String> externallyManagedInitMethods = Collections.synchronizedSet(new HashSet<String>(0));
|
||||
|
||||
private final Set<String> externallyManagedDestroyMethods = Collections.synchronizedSet(new HashSet<String>());
|
||||
private final Set<String> externallyManagedDestroyMethods = Collections.synchronizedSet(new HashSet<String>(0));
|
||||
|
||||
private BeanDefinitionHolder decoratedDefinition;
|
||||
|
||||
boolean isFactoryMethodUnique;
|
||||
|
||||
/** Package-visible field for caching the resolved constructor or factory method */
|
||||
volatile Object resolvedConstructorOrFactoryMethod;
|
||||
|
||||
/** Package-visible field for caching fully resolved constructor arguments */
|
||||
volatile Object[] resolvedConstructorArguments;
|
||||
|
||||
/** Package-visible field for caching partly prepared constructor arguments */
|
||||
volatile Object[] preparedConstructorArguments;
|
||||
Object resolvedConstructorOrFactoryMethod;
|
||||
|
||||
/** Package-visible field that marks the constructor arguments as resolved */
|
||||
volatile boolean constructorArgumentsResolved = false;
|
||||
boolean constructorArgumentsResolved = false;
|
||||
|
||||
/** Package-visible field for caching fully resolved constructor arguments */
|
||||
Object[] resolvedConstructorArguments;
|
||||
|
||||
/** Package-visible field for caching partly prepared constructor arguments */
|
||||
Object[] preparedConstructorArguments;
|
||||
|
||||
final Object constructorArgumentLock = new Object();
|
||||
|
||||
/** Package-visible field that indicates a before-instantiation post-processor having kicked in */
|
||||
volatile Boolean beforeInstantiationResolved;
|
||||
@@ -78,6 +80,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
|
||||
final Object postProcessingLock = new Object();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new RootBeanDefinition, to be configured through its bean
|
||||
* properties and configuration methods.
|
||||
@@ -264,8 +267,10 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
* @return the factory method, or <code>null</code> if not found or not resolved yet
|
||||
*/
|
||||
public Method getResolvedFactoryMethod() {
|
||||
Object candidate = this.resolvedConstructorOrFactoryMethod;
|
||||
return (candidate instanceof Method ? (Method) candidate : null);
|
||||
synchronized (this.constructorArgumentLock) {
|
||||
Object candidate = this.resolvedConstructorOrFactoryMethod;
|
||||
return (candidate instanceof Method ? (Method) candidate : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+32
-32
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,31 +42,33 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||
|
||||
public Object instantiate(
|
||||
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
|
||||
|
||||
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
|
||||
// Don't override the class with CGLIB if no overrides.
|
||||
if (beanDefinition.getMethodOverrides().isEmpty()) {
|
||||
Constructor constructorToUse = (Constructor) beanDefinition.resolvedConstructorOrFactoryMethod;
|
||||
if (constructorToUse == null) {
|
||||
final Class clazz = beanDefinition.getBeanClass();
|
||||
if (clazz.isInterface()) {
|
||||
throw new BeanInstantiationException(clazz, "Specified class is an interface");
|
||||
}
|
||||
try {
|
||||
if (System.getSecurityManager() != null) {
|
||||
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
|
||||
public Constructor run() throws Exception {
|
||||
return clazz.getDeclaredConstructor((Class[]) null);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
|
||||
Constructor<?> constructorToUse;
|
||||
synchronized (beanDefinition.constructorArgumentLock) {
|
||||
constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
|
||||
if (constructorToUse == null) {
|
||||
final Class clazz = beanDefinition.getBeanClass();
|
||||
if (clazz.isInterface()) {
|
||||
throw new BeanInstantiationException(clazz, "Specified class is an interface");
|
||||
}
|
||||
try {
|
||||
if (System.getSecurityManager() != null) {
|
||||
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
|
||||
public Constructor run() throws Exception {
|
||||
return clazz.getDeclaredConstructor((Class[]) null);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
|
||||
}
|
||||
beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
|
||||
}
|
||||
beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
|
||||
}
|
||||
}
|
||||
return BeanUtils.instantiateClass(constructorToUse);
|
||||
@@ -90,9 +92,8 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||
"Method Injection not supported in SimpleInstantiationStrategy");
|
||||
}
|
||||
|
||||
public Object instantiate(
|
||||
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||
final Constructor ctor, Object[] args) {
|
||||
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||
final Constructor<?> ctor, Object[] args) {
|
||||
|
||||
if (beanDefinition.getMethodOverrides().isEmpty()) {
|
||||
if (System.getSecurityManager() != null) {
|
||||
@@ -117,16 +118,14 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||
* the Method Injection specified in the given RootBeanDefinition.
|
||||
* Instantiation should use the given constructor and parameters.
|
||||
*/
|
||||
protected Object instantiateWithMethodInjection(
|
||||
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||
Constructor ctor, Object[] args) {
|
||||
protected Object instantiateWithMethodInjection(RootBeanDefinition beanDefinition,
|
||||
String beanName, BeanFactory owner, Constructor ctor, Object[] args) {
|
||||
|
||||
throw new UnsupportedOperationException(
|
||||
"Method Injection not supported in SimpleInstantiationStrategy");
|
||||
}
|
||||
|
||||
public Object instantiate(
|
||||
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||
Object factoryBean, final Method factoryMethod, Object[] args) {
|
||||
|
||||
try {
|
||||
@@ -159,4 +158,5 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||
"Factory method [" + factoryMethod + "] threw exception", ex.getTargetException());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+40
-29
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -621,7 +621,7 @@ public class BeanDefinitionParserDelegate {
|
||||
NodeList nl = ele.getChildNodes();
|
||||
for (int i = 0; i < nl.getLength(); i++) {
|
||||
Node node = nl.item(i);
|
||||
if (node instanceof Element && nodeNameEquals(node, META_ELEMENT)) {
|
||||
if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
|
||||
Element metaElement = (Element) node;
|
||||
String key = metaElement.getAttribute(KEY_ATTRIBUTE);
|
||||
String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
|
||||
@@ -680,7 +680,7 @@ public class BeanDefinitionParserDelegate {
|
||||
NodeList nl = beanEle.getChildNodes();
|
||||
for (int i = 0; i < nl.getLength(); i++) {
|
||||
Node node = nl.item(i);
|
||||
if (node instanceof Element && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
|
||||
if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
|
||||
parseConstructorArgElement((Element) node, bd);
|
||||
}
|
||||
}
|
||||
@@ -693,7 +693,7 @@ public class BeanDefinitionParserDelegate {
|
||||
NodeList nl = beanEle.getChildNodes();
|
||||
for (int i = 0; i < nl.getLength(); i++) {
|
||||
Node node = nl.item(i);
|
||||
if (node instanceof Element && nodeNameEquals(node, PROPERTY_ELEMENT)) {
|
||||
if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
|
||||
parsePropertyElement((Element) node, bd);
|
||||
}
|
||||
}
|
||||
@@ -706,7 +706,7 @@ public class BeanDefinitionParserDelegate {
|
||||
NodeList nl = beanEle.getChildNodes();
|
||||
for (int i = 0; i < nl.getLength(); i++) {
|
||||
Node node = nl.item(i);
|
||||
if (node instanceof Element && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
|
||||
if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
|
||||
parseQualifierElement((Element) node, bd);
|
||||
}
|
||||
}
|
||||
@@ -719,7 +719,7 @@ public class BeanDefinitionParserDelegate {
|
||||
NodeList nl = beanEle.getChildNodes();
|
||||
for (int i = 0; i < nl.getLength(); i++) {
|
||||
Node node = nl.item(i);
|
||||
if (node instanceof Element && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
|
||||
if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
|
||||
Element ele = (Element) node;
|
||||
String methodName = ele.getAttribute(NAME_ATTRIBUTE);
|
||||
String beanRef = ele.getAttribute(BEAN_ELEMENT);
|
||||
@@ -737,7 +737,7 @@ public class BeanDefinitionParserDelegate {
|
||||
NodeList nl = beanEle.getChildNodes();
|
||||
for (int i = 0; i < nl.getLength(); i++) {
|
||||
Node node = nl.item(i);
|
||||
if (node instanceof Element && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
|
||||
if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
|
||||
Element replacedMethodEle = (Element) node;
|
||||
String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
|
||||
String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
|
||||
@@ -860,7 +860,7 @@ public class BeanDefinitionParserDelegate {
|
||||
NodeList nl = ele.getChildNodes();
|
||||
for (int i = 0; i < nl.getLength(); i++) {
|
||||
Node node = nl.item(i);
|
||||
if (node instanceof Element && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
|
||||
if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
|
||||
Element attributeEle = (Element) node;
|
||||
String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);
|
||||
String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);
|
||||
@@ -952,7 +952,7 @@ public class BeanDefinitionParserDelegate {
|
||||
* <code><value></code> tag that might be created
|
||||
*/
|
||||
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
|
||||
if (!isDefaultNamespace(getNamespaceURI(ele))) {
|
||||
if (!isDefaultNamespace(ele)) {
|
||||
return parseNestedCustomElement(ele, bd);
|
||||
}
|
||||
else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
|
||||
@@ -1176,7 +1176,10 @@ public class BeanDefinitionParserDelegate {
|
||||
}
|
||||
else {
|
||||
// Child element is what we're looking for.
|
||||
if (valueEle != null) {
|
||||
if (nodeNameEquals(candidateEle, DESCRIPTION_ELEMENT)) {
|
||||
// the element is a <description> -> ignore it
|
||||
}
|
||||
else if (valueEle != null) {
|
||||
error("<entry> element must not contain more than one value sub-element", entryEle);
|
||||
}
|
||||
else {
|
||||
@@ -1384,10 +1387,6 @@ public class BeanDefinitionParserDelegate {
|
||||
return originalDef;
|
||||
}
|
||||
|
||||
public boolean isDefaultNamespace(String namespaceUri) {
|
||||
return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri));
|
||||
}
|
||||
|
||||
private BeanDefinitionHolder parseNestedCustomElement(Element ele, BeanDefinition containingBd) {
|
||||
BeanDefinition innerDefinition = parseCustomElement(ele, containingBd);
|
||||
if (innerDefinition == null) {
|
||||
@@ -1404,36 +1403,48 @@ public class BeanDefinitionParserDelegate {
|
||||
return new BeanDefinitionHolder(innerDefinition, id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the namespace URI for the supplied node. The default implementation uses {@link Node#getNamespaceURI}.
|
||||
* Get the namespace URI for the supplied node. The default implementation uses {@link Node#getNamespaceURI}.
|
||||
* Subclasses may override the default implementation to provide a different namespace identification mechanism.
|
||||
* @param node the node
|
||||
* @return the namespace URI of the the node.
|
||||
*/
|
||||
public String getNamespaceURI(Node node) {
|
||||
return node.getNamespaceURI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the name of the supplied node is equal to the supplied name.
|
||||
* The default implementation checks the supplied desired name against both {@link Node#getNodeName)
|
||||
* and {@link #getLoclName}.
|
||||
* Subclasses may override the default implementation to provide a different mechanism for comparing node names.
|
||||
* Ges the local name for the supplied {@link Node}. The default implementation calls {@link Node#getLocalName}.
|
||||
* Subclasses may override the default implementation to provide a different mechanism for getting the local name.
|
||||
* @param node the <code>Node</code>
|
||||
*/
|
||||
public String getLocalName(Node node) {
|
||||
return node.getLocalName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the name of the supplied node is equal to the supplied name.
|
||||
* <p>The default implementation checks the supplied desired name against both
|
||||
* {@link Node#getNodeName()} and {@link Node#getLocalName()}.
|
||||
* <p>Subclasses may override the default implementation to provide a different
|
||||
* mechanism for comparing node names.
|
||||
* @param node the node to compare
|
||||
* @param desiredName the name to check for
|
||||
* @return <code>true</code> if the names are equal otherwise <code>false</code>.
|
||||
*/
|
||||
public boolean nodeNameEquals(Node node, String desiredName) {
|
||||
return desiredName.equals(node.getNodeName()) || desiredName.equals(getLocalName(node));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local name for the supplied {@link Node}. The default implementation calls {@link Node#getLocalName}.
|
||||
* Subclasses may override the default implementation to provide a different mechanism for getting the local name.
|
||||
* @param node the <code>Node</code>
|
||||
* @return the local name of the supplied <code>Node</code>.
|
||||
*/
|
||||
public String getLocalName(Node node) {
|
||||
return node.getLocalName();
|
||||
public boolean isDefaultNamespace(String namespaceUri) {
|
||||
return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri));
|
||||
}
|
||||
|
||||
public boolean isDefaultNamespace(Node node) {
|
||||
return isDefaultNamespace(getNamespaceURI(node));
|
||||
}
|
||||
|
||||
private boolean isCandidateElement(Node node) {
|
||||
return (node instanceof Element && (isDefaultNamespace(node) || !isDefaultNamespace(node.getParentNode())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -122,14 +122,13 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
|
||||
* @param root the DOM root element of the document
|
||||
*/
|
||||
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
|
||||
if (delegate.isDefaultNamespace(delegate.getNamespaceURI(root))) {
|
||||
if (delegate.isDefaultNamespace(root)) {
|
||||
NodeList nl = root.getChildNodes();
|
||||
for (int i = 0; i < nl.getLength(); i++) {
|
||||
Node node = nl.item(i);
|
||||
if (node instanceof Element) {
|
||||
Element ele = (Element) node;
|
||||
String namespaceUri = delegate.getNamespaceURI(ele);
|
||||
if (delegate.isDefaultNamespace(namespaceUri)) {
|
||||
if (delegate.isDefaultNamespace(ele)) {
|
||||
parseDefaultElement(ele, delegate);
|
||||
}
|
||||
else {
|
||||
|
||||
+1
-1
@@ -344,7 +344,7 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
|
||||
finally {
|
||||
currentResources.remove(encodedResource);
|
||||
if (currentResources.isEmpty()) {
|
||||
this.resourcesCurrentlyBeingLoaded.set(null);
|
||||
this.resourcesCurrentlyBeingLoaded.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user