mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
725 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d51d8aeaf6 | |||
| c7c35aff42 | |||
| 000b6a7e95 | |||
| f3db6b996d | |||
| a42540e64a | |||
| cc2b980e5c | |||
| aa2bfd4b62 | |||
| 29fa9c1728 | |||
| 39660710f6 | |||
| e35fe33b72 | |||
| 23f396a231 | |||
| 090e394fb5 | |||
| 708e61a7ef | |||
| e24b2e6b5d | |||
| aff0d8efe7 | |||
| e3e4e49319 | |||
| 5420d7113b | |||
| 6251222a23 | |||
| 05eca05671 | |||
| 3fa4e4168d | |||
| f0f450a18d | |||
| f854803e18 | |||
| d29d4d45aa | |||
| 432fdad7d0 | |||
| 345d8186d4 | |||
| ad63a534cb | |||
| c9d341e9c0 | |||
| 950b183715 | |||
| 821ecb4cfd | |||
| 1c17305d7b | |||
| 491d1c4c78 | |||
| 7dbbf364f7 | |||
| 5204d736f3 | |||
| e0690335fc | |||
| 5cbbbed377 | |||
| 6f2fe5ddcb | |||
| da9ee06e05 | |||
| 4c28266eb6 | |||
| b3dcb64ff1 | |||
| b18f8771c8 | |||
| 93244e9f9d | |||
| f45a852aca | |||
| 4203e90655 | |||
| 1e2e114e3c | |||
| 0e73213144 | |||
| 1e1045ba42 | |||
| 8d17bcea5b | |||
| 597b31b1fc | |||
| 4049951c03 | |||
| 89441ea006 | |||
| de1ba79c55 | |||
| ffbc537835 | |||
| 9295bcc4a4 | |||
| 746b1b2fe1 | |||
| ab2c78a9d5 | |||
| ac0e71745b | |||
| f65cbe0992 | |||
| a2e5d9a14f | |||
| 360f555e77 | |||
| 7c756027a0 | |||
| 4c642ccdcd | |||
| fab7b1cebe | |||
| 101ed17b6f | |||
| 66588bae92 | |||
| d33545bdce | |||
| e8e157ebf8 | |||
| 7f5904c68b | |||
| 66e488850b | |||
| 3dba3691a7 | |||
| c80c4e001a | |||
| 8da049b613 | |||
| 1acd832759 | |||
| 261927b72a | |||
| 24aa7f546b | |||
| 4cfad25468 | |||
| 569ce840cf | |||
| fae484855b | |||
| cab20d1202 | |||
| e2bf513563 | |||
| 84e56bb5d9 | |||
| 6f5e66f00c | |||
| cda72e4a70 | |||
| e31a4c4c77 | |||
| 4809632f44 | |||
| 0d0d75e253 | |||
| cce60c479c | |||
| 1469bdbc70 | |||
| be52ec8bd5 | |||
| cd9cad31f9 | |||
| 60c551a95b | |||
| 4164fc63b1 | |||
| 0865abef83 | |||
| 90af2d5794 | |||
| 5f5cd8a7c4 | |||
| 46b7cd54a1 | |||
| 7f670bbe68 | |||
| 6aaf7596c0 | |||
| 4f2c589fe6 | |||
| aa51ed1940 | |||
| dc4e053d59 | |||
| 07ba95739b | |||
| 0468ef46ac | |||
| eb03144e9d | |||
| 29790d5bb1 | |||
| 355d394d7f | |||
| 9ddab9e69b | |||
| c20a43f72b | |||
| e0fa58aa0f | |||
| 65797d04f2 | |||
| 5811212a9f | |||
| d79e33b5a0 | |||
| dddcc5e9ad | |||
| 582b94d50e | |||
| 443c34cc90 | |||
| 959e6d1745 | |||
| 38b592444d | |||
| 2c2464b1e7 | |||
| 3b247a9c19 | |||
| d30432b6c0 | |||
| c70aed58bf | |||
| 2de7bf6e2b | |||
| a28511cdbd | |||
| 668b938832 | |||
| 091e7bb891 | |||
| b76e0c4826 | |||
| 55faf6e320 | |||
| a522ed0788 | |||
| 4152ebc2f3 | |||
| 21c90829df | |||
| 5b96c9b87e | |||
| 08855fee51 | |||
| 66cd979ce4 | |||
| 5667d459a7 | |||
| 85eb589c2e | |||
| b18cf3c873 | |||
| 399e7ebf22 | |||
| b5d6e53e50 | |||
| 865969400b | |||
| 6f4fb08bf8 | |||
| 4c7cc705de | |||
| f7fc36250e | |||
| ae7d5200e5 | |||
| ff9b68c1b6 | |||
| 36c829386b | |||
| 7316dc726a | |||
| 118c7f969b | |||
| 26ed6d8bce | |||
| 98770b15e7 | |||
| 697108cc42 | |||
| 607d918340 | |||
| 8456eaca8e | |||
| 59015344a7 | |||
| c03162e616 | |||
| 1dde30a7fd | |||
| 35196d3c62 | |||
| d7f67b3dc3 | |||
| 719e7394d6 | |||
| e4a5d2aaa5 | |||
| ab64607420 | |||
| b595dc1dfa | |||
| 86123de883 | |||
| 7c3a18490b | |||
| 01e50fb60a | |||
| 6c3a0a9026 | |||
| 3bded7659a | |||
| 7f1062159e | |||
| e4c0ff569b | |||
| e7cbe23771 | |||
| d275a4e28d | |||
| 42a23098de | |||
| d25ae4b02c | |||
| 5740eaf33e | |||
| 80d46ba80e | |||
| db9a10bf35 | |||
| 27bfcbbc82 | |||
| b153b5e53b | |||
| 1f477a5c1c | |||
| ceac2a5c3c | |||
| e03fdeaf8b | |||
| 0286549466 | |||
| 71158f4d96 | |||
| 7303680369 | |||
| 906a1f561a | |||
| e489706f13 | |||
| 69bbdce826 | |||
| 0f31830ae2 | |||
| 5d297c6387 | |||
| 320f5836b4 | |||
| af06b80bdf | |||
| 5b1ab31559 | |||
| bf05da1f8c | |||
| 63217e44f1 | |||
| 5226a67161 | |||
| 1694274e32 | |||
| 27c4e74e24 | |||
| b73eb51cb1 | |||
| f31933e67e | |||
| c7989c78c8 | |||
| f03ccd5cc9 | |||
| bcc6171a72 | |||
| a80c5fcfaf | |||
| 04ce8e0ac4 | |||
| 74f7eb11be | |||
| e05b584623 | |||
| 29955a2898 | |||
| 4b6b12bf2f | |||
| ab0e8f0617 | |||
| 0a6a6d48e2 | |||
| a08593b44b | |||
| 7954dc7a00 | |||
| 22d9012081 | |||
| 327e761536 | |||
| 4e42b5dfbc | |||
| 432c720dd0 | |||
| f7606ba51b | |||
| 0f54585f05 | |||
| d3d6e100da | |||
| a48c5f6a0d | |||
| 35ea33e13a | |||
| a2d91a562d | |||
| 97f3846971 | |||
| 44e1d6d1bf | |||
| 7adac25e7e | |||
| 7dca6a36a6 | |||
| c5ac8e8ab6 | |||
| fa4c62cab2 | |||
| 8a1182a678 | |||
| 01bea34569 | |||
| aec151e014 | |||
| 58e40d1aa2 | |||
| 85dbd2a4c3 | |||
| eca87b87de | |||
| 5e1e29a2dd | |||
| 7dc3a55648 | |||
| f982fd99d7 | |||
| ab18ab6025 | |||
| d83fb09914 | |||
| b651c10e83 | |||
| 5651695fd1 | |||
| 1a9556925d | |||
| 2dc203ffdc | |||
| 610de3ae78 | |||
| 5b2ace5742 | |||
| 5b227e5677 | |||
| 41d5048280 | |||
| a931ff12f6 | |||
| e4f753e3e3 | |||
| 4982b5fcb9 | |||
| f7678cdcdd | |||
| 3ab39eda08 | |||
| 14a6909c4a | |||
| fd17738f76 | |||
| f674652dd0 | |||
| 5476b2edff | |||
| c0fee67c6d | |||
| f229fa4b72 | |||
| 684939d5f8 | |||
| b8d75c3139 | |||
| d92c74d923 | |||
| 4f14291e2f | |||
| 7d3f42b27b | |||
| a8d553218c | |||
| 7f422f206c | |||
| 70f0895f96 | |||
| 2728a9b931 | |||
| bc261fd995 | |||
| 0eaf6d12eb | |||
| 6e264f9bdd | |||
| 6214ff153f | |||
| c6b271f1b6 | |||
| 8bf16ee1f4 | |||
| a3451f9908 | |||
| 5c38b89f4e | |||
| 9c030bacb8 | |||
| 12f8cdd715 | |||
| 2daefedf5e | |||
| 6670db9b58 | |||
| 7b6cac2c93 | |||
| 6ffeee3e6f | |||
| 1b458aeafc | |||
| 0503cf2937 | |||
| 14c802f979 | |||
| c1b1940dd2 | |||
| 97b3aa4b13 | |||
| 79b5710386 | |||
| b2bcb0f93a | |||
| 5593e95e89 | |||
| 6d4c0091b5 | |||
| 55aa8e914e | |||
| 2b017fe540 | |||
| 61cdd647b6 | |||
| f6d3d9d6e6 | |||
| ed71fe0460 | |||
| 89f70bdc46 | |||
| 3c9bd3177e | |||
| 4b80ef21b6 | |||
| d308985edc | |||
| 5aef87f120 | |||
| 70c0e104b5 | |||
| 01bf1c9021 | |||
| 530fb0808d | |||
| 48688b7b04 | |||
| 1ef8cad7bc | |||
| 86902d27b2 | |||
| 9877a9e6b7 | |||
| 75b6540bd8 | |||
| 21d77dd7c7 | |||
| 8bdc53ac5c | |||
| acb638f828 | |||
| c7e8989f16 | |||
| 78f65c4ca9 | |||
| 42e4ca1e2d | |||
| d23a108e76 | |||
| b9a612b637 | |||
| 1ee9223348 | |||
| 926c4aae52 | |||
| b61643b71a | |||
| 7efb4eade6 | |||
| e89cc9934f | |||
| 010b7375fc | |||
| 01c2e12fef | |||
| 90de1ab6d1 | |||
| 5a11569790 | |||
| 0087578469 | |||
| 1a79c54b01 | |||
| 4af7a6863b | |||
| c084936870 | |||
| 48bd81341f | |||
| 118d8133d3 | |||
| c2137a0d2f | |||
| 8c9c59eba0 | |||
| 8ed7f4703b | |||
| e04269cadd | |||
| aa73f6733e | |||
| b5147a034c | |||
| ebf6fff312 | |||
| dee12db50a | |||
| e53cce0778 | |||
| 8baf404893 | |||
| a33eac3ec0 | |||
| eb68e6a62a | |||
| a9240e0bac | |||
| 262b7d7c27 | |||
| 31d9f31806 | |||
| 0fd774e69f | |||
| ec5774e748 | |||
| 962ec38a61 | |||
| 3ec0452fed | |||
| cb3af52df2 | |||
| 5b114b7208 | |||
| f7cef2ab20 | |||
| 77a658f51b | |||
| cf4e77907f | |||
| 42a223b9cd | |||
| 6d2fec383b | |||
| 90ee22f2af | |||
| db5be44ff4 | |||
| a78c12b8d3 | |||
| dfc8406917 | |||
| 313e754a84 | |||
| 207ee9e307 | |||
| 3215880d08 | |||
| 274db2f7a9 | |||
| 1dd7d53de0 | |||
| 8535193df3 | |||
| a78701cc4b | |||
| 947387b4cd | |||
| 49ccd7ad9c | |||
| 5b97c47fc4 | |||
| 40661d62c1 | |||
| e17ca9a4e9 | |||
| 87761397b0 | |||
| ac58614be8 | |||
| 4ebd8d77b7 | |||
| 7ca47cfe6b | |||
| fd49c8f598 | |||
| ff234568d2 | |||
| efc335e198 | |||
| 1e57e572dd | |||
| 829000d511 | |||
| a315abfd32 | |||
| 36d133ce53 | |||
| 9417975f66 | |||
| ed9ec58caa | |||
| f48c3d9b67 | |||
| 6b705443a6 | |||
| c26087e848 | |||
| 7225238ad5 | |||
| ff43731347 | |||
| 29fb3f27be | |||
| 63db250ebe | |||
| b00c7075a5 | |||
| 3718c8d0e0 | |||
| ca8261cbf8 | |||
| 8de10e9199 | |||
| 7536b7f42a | |||
| bc71cc1a76 | |||
| 582559dd9e | |||
| d4c609f2f0 | |||
| 3524401bf1 | |||
| 86423c91f7 | |||
| 8807f94ad8 | |||
| da3ff29e88 | |||
| 9c6b1b645d | |||
| 0fc8bf654b | |||
| 729535d36c | |||
| 634c7710f9 | |||
| 2fbfd8a5db | |||
| 42c15be8d3 | |||
| 3baa44c5ef | |||
| 4b86a1a755 | |||
| df977a2fd2 | |||
| 99a1388bbd | |||
| 809813dd52 | |||
| d5e5dcb7e1 | |||
| defc2466b0 | |||
| a991c23db5 | |||
| b928ed8f37 | |||
| 5d70aaacef | |||
| 566ff54782 | |||
| 77b7e49fb2 | |||
| 1c6bab23ea | |||
| 3e502d4739 | |||
| 667256adf9 | |||
| 8791928f61 | |||
| c9147c4281 | |||
| d6f363c634 | |||
| 87c0e9b48a | |||
| 9a4164c4a8 | |||
| c36b80bd75 | |||
| bc90512309 | |||
| edd15646af | |||
| 53cafe728c | |||
| 58e9b187fe | |||
| 9b0c2cca95 | |||
| 26000ee29f | |||
| 0c2c66b38b | |||
| bd8e682c51 | |||
| f7c952cb3e | |||
| 6bc7e12bcd | |||
| ab94c7c016 | |||
| 8fb9796d1d | |||
| a264013d7a | |||
| cd80b6b4ac | |||
| 164b48e25f | |||
| eb7b206142 | |||
| 42061d27bd | |||
| 0d16c9100a | |||
| 7cdaaa22bd | |||
| f4c9f6b860 | |||
| 1721b0b8d7 | |||
| 836976d732 | |||
| 59818ceca9 | |||
| 08ce6baedf | |||
| c52526ad42 | |||
| 7a329eba5b | |||
| 91d542e406 | |||
| 6fde28be98 | |||
| 1e481cd14c | |||
| df4ba742cb | |||
| 996c86f448 | |||
| 0575e6637c | |||
| ad8775ef95 | |||
| 8589804012 | |||
| c649b74235 | |||
| bef5d59e43 | |||
| 99bd8115dd | |||
| 1a3ff83157 | |||
| c19b2851f1 | |||
| 3b4a3431d4 | |||
| c82a445094 | |||
| 95752ef1c9 | |||
| 0ff50d6d9e | |||
| 30cdeb23fe | |||
| ecf5113e0e | |||
| 80c4e6bb95 | |||
| 5e5d8e4a23 | |||
| d7e05aa48f | |||
| cf52246319 | |||
| c5284009a1 | |||
| 2d29fcd0bb | |||
| 5e56162394 | |||
| 45650f2b27 | |||
| 3e1b1638ef | |||
| e80a23d6ad | |||
| 8aeae49f40 | |||
| f22e2ac578 | |||
| 355aca7665 | |||
| ec5f99f981 | |||
| 03f1b65084 | |||
| 0de2833894 | |||
| cd9d562129 | |||
| 080ba5d448 | |||
| d96448fde9 | |||
| 84eed00260 | |||
| cee51b248a | |||
| 5a640bb635 | |||
| 5c1cbb769c | |||
| 4a7a2258f9 | |||
| bad8954e65 | |||
| e4566c11b8 | |||
| 9d8910d869 | |||
| aa7584d252 | |||
| e537844a09 | |||
| daa5465003 | |||
| 5a4a677fbd | |||
| 584dabbb39 | |||
| 4779323d33 | |||
| 67112b211a | |||
| 799885fd6d | |||
| 3c959d3515 | |||
| cfae40afb4 | |||
| 1b1ae33efe | |||
| d80b08084e | |||
| d1a7fed16c | |||
| 469eb8146e | |||
| 35225e5794 | |||
| a7413ea76b | |||
| c3c36ab498 | |||
| ea4fe7eaf7 | |||
| 3112dc5f81 | |||
| b07a6b3283 | |||
| 6b9d5698ce | |||
| 72a9d0ff4b | |||
| 872255a591 | |||
| 671270dae2 | |||
| 6ea39fd122 | |||
| dadef9f5bc | |||
| fceceb480f | |||
| e5ab67bd71 | |||
| 2d53570f4c | |||
| be5eb7037f | |||
| fff2291f2a | |||
| 917f3ad101 | |||
| 2fd6e6e87c | |||
| 570bdbd253 | |||
| b587a16d46 | |||
| dd8ea89bea | |||
| b0dea4d3f6 | |||
| 4ac27e4dab | |||
| b0abdee012 | |||
| e4dc863ad0 | |||
| 689b5566bf | |||
| 234b4719c6 | |||
| ce1ae2f1b2 | |||
| 69ce7d33b9 | |||
| e36d4162c2 | |||
| d387d9ae1e | |||
| 138f6bfd84 | |||
| a1cf6bbc37 | |||
| fb040479eb | |||
| d50375da8e | |||
| fb2e53276c | |||
| c040cd7b05 | |||
| dcc8dcdff8 | |||
| efa360cff7 | |||
| 5804db6479 | |||
| faa749934b | |||
| e1385090e4 | |||
| 3113917c55 | |||
| 994a35d691 | |||
| 8095ba4cd2 | |||
| bd2edf26df | |||
| 4f6d26b25c | |||
| 6d85a8a0cc | |||
| 44b29b6ecf | |||
| 91a6254187 | |||
| c8ad762b40 | |||
| 5c1176786c | |||
| eab61f692f | |||
| ee41ebc1ab | |||
| 885f6dbab9 | |||
| b0f404722e | |||
| cd7b0b11f3 | |||
| 1565f4b83e | |||
| 65a395ef0e | |||
| 947255e377 | |||
| 499be70a71 | |||
| 0cf5005a3d | |||
| f07fc76cf3 | |||
| d3e1c54354 | |||
| a109b4c31a | |||
| 00b56c026a | |||
| fbd2ffdd23 | |||
| b3a47c76f8 | |||
| 1292947f78 | |||
| ef6a582c78 | |||
| a11d1c8510 | |||
| 83c19cd60e | |||
| bcfbde9848 | |||
| 17e6cf1cc1 | |||
| ec33b4241a | |||
| 657641ebaa | |||
| 4597e9b547 | |||
| 721dacca5a | |||
| 9d124fffcb | |||
| 2a47751fcd | |||
| 06e352822a | |||
| 25101fb034 | |||
| cb44ae62e9 | |||
| 01fb4dbeba | |||
| 07fadae27d | |||
| 2b77c08e09 | |||
| cb2b141d31 | |||
| 3b92d45984 | |||
| 1195b3a0b0 | |||
| 56721669d1 | |||
| e87e03c539 | |||
| 194cebd730 | |||
| 7418c4b7b7 | |||
| ad42010785 | |||
| 10f6a22315 | |||
| c970c318f4 | |||
| 834032df1f | |||
| 5efa4ad442 | |||
| 7ef3257b03 | |||
| 0172424635 | |||
| 994ec708fc | |||
| da15fe4c94 | |||
| a1d134b086 | |||
| 3c85c263d2 | |||
| 7b3f53de50 | |||
| ec7425c1f4 | |||
| ef05eb3729 | |||
| 8ac39a50fe | |||
| d82cb15439 | |||
| 8c1d06e0c4 | |||
| 01892c6524 | |||
| 9776929a9d | |||
| 4337d8465c | |||
| 8f0ad73bfd | |||
| 3714d0e401 | |||
| 227d85a6b4 | |||
| a1320cd450 | |||
| c7f2f50c15 | |||
| 396fb0cd51 | |||
| 5328184f3a | |||
| 1e19e51c9c | |||
| 69aed83504 | |||
| 0978cc629a | |||
| 0c825621b8 | |||
| e7b0b65244 | |||
| e9caee1b6e | |||
| 622d0831a3 | |||
| 56dbe06d9b | |||
| 11f6c4e7ab | |||
| d46091565b | |||
| 42216b77df | |||
| 43faa439ab | |||
| 1f701d9bad | |||
| 73e1f24ac1 | |||
| 86f9716fef | |||
| 80701082cd | |||
| 3612990344 | |||
| dea2029e94 | |||
| 77d6f8bc00 | |||
| 23006d417b | |||
| d8dafbc49d | |||
| cc4a1af091 | |||
| fd70a9e95d | |||
| 298cb22bfe | |||
| 4ed645e710 | |||
| 7c47f554c0 | |||
| 642d47ef8d | |||
| 42e492ef2a | |||
| 4fb5d59c64 | |||
| e6324bd578 | |||
| 45a9227047 | |||
| f1af8a6ae9 | |||
| c4d7e6ff46 | |||
| 922d5d271a | |||
| 05e3f271b6 | |||
| a7cce64e5d | |||
| a0544e78ea | |||
| c92dccea1b | |||
| 9ec96f6141 | |||
| 135682e073 | |||
| 6a0377b1a2 | |||
| 8c3a05bbcf | |||
| 684e695b08 | |||
| 8130bf505f | |||
| 9beca06404 | |||
| ae75db2657 | |||
| 4cc831238c | |||
| 41835ba5a4 | |||
| de0b5bc5a1 | |||
| b29723623b | |||
| 2ee231dee2 | |||
| b56dbd2aa8 | |||
| c9b27af64f | |||
| 9139cb85bd | |||
| 367fbbb981 | |||
| 1b1ba47912 | |||
| 041bff4e56 | |||
| bc5a10c70d | |||
| 3d31750acc | |||
| c22a483c3d | |||
| 238354a081 | |||
| 51b1306d70 | |||
| 7206a23d33 | |||
| 83996b12cc | |||
| 0fd6c100a6 | |||
| 0819a9fcc9 | |||
| 0b580d194d | |||
| 500b54b86f | |||
| 942400ae47 | |||
| b92d249f45 | |||
| 204a7fe91f | |||
| 42d3bc47c9 | |||
| 94fcb37d30 | |||
| ba9325446c | |||
| 5338d8b5e9 | |||
| 1b0be5862d | |||
| 48af36c6fa | |||
| bd4e915abf | |||
| c419ea7ba7 | |||
| 66292cd7a1 | |||
| 6eec1acdac | |||
| bc32d513d9 | |||
| 3851b291da | |||
| 2b1f229998 | |||
| fc5e3c335f | |||
| daf9a82e8c | |||
| b019f30a15 | |||
| d5b5e894c9 |
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
!!! For Security Vulnerabilities, please go to https://pivotal.io/security !!!
|
||||
!!! For Security Vulnerabilities, please go to https://spring.io/security-policy !!!
|
||||
-->
|
||||
**Affects:** \<Spring Framework version>
|
||||
|
||||
@@ -14,4 +14,4 @@ Thanks for taking the time to create an issue. Please read the following:
|
||||
Issue or Pull Request? Create only one, not both. GitHub treats them as the same.
|
||||
If unsure, start with an issue, and if you submit a pull request later, the
|
||||
issue will be closed as superseded.
|
||||
-->
|
||||
-->
|
||||
|
||||
@@ -41,3 +41,6 @@ out
|
||||
test-output
|
||||
atlassian-ide-plugin.xml
|
||||
.gradletasknamecache
|
||||
|
||||
# VS Code
|
||||
.vscode/
|
||||
+3
-6
@@ -125,10 +125,7 @@ The reference documentation is in the [src/docs/asciidoc](src/docs/asciidoc) dir
|
||||
edit source files, and submit directly from GitHub.
|
||||
|
||||
When making changes locally, execute `./gradlew asciidoctor` and then browse the result under
|
||||
`build/asciidoc/html5/index.html`.
|
||||
`build/docs/ref-docs/html5/index.html`.
|
||||
|
||||
Asciidoctor also supports live editing. For more details read
|
||||
[Editing AsciiDoc with Live Preview](https://asciidoctor.org/docs/editing-asciidoc-with-live-preview/).
|
||||
Note that if you choose the
|
||||
[System Monitor](https://asciidoctor.org/docs/editing-asciidoc-with-live-preview/#using-a-system-monitor)
|
||||
option, you can find a Guardfile under `src/docs/asciidoc`.
|
||||
Asciidoctor also supports live editing. For more details see
|
||||
[AsciiDoc Tooling](https://docs.asciidoctor.org/asciidoctor/latest/tooling/).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# <img src="src/docs/spring-framework.png" width="80" height="80"> Spring Framework [](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.3.x?groups=Build")
|
||||
# <img src="src/docs/spring-framework.png" width="80" height="80"> Spring Framework [](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.3.x?groups=Build") [](https://ge.spring.io/scans?search.rootProjectNames=spring)
|
||||
|
||||
This is the home of the Spring Framework: the foundation for all [Spring projects](https://spring.io/projects). Collectively the Spring Framework and the family of Spring projects are often referred to simply as "Spring".
|
||||
|
||||
@@ -25,6 +25,10 @@ See the [Micro-Benchmarks](https://github.com/spring-projects/spring-framework/w
|
||||
|
||||
See the [Build from Source](https://github.com/spring-projects/spring-framework/wiki/Build-from-Source) Wiki page and the [CONTRIBUTING.md](CONTRIBUTING.md) file.
|
||||
|
||||
## Continuous Integration Builds
|
||||
|
||||
Information regarding CI builds can be found in the [Spring Framework Concourse pipeline](ci/README.adoc) documentation.
|
||||
|
||||
## Stay in Touch
|
||||
|
||||
Follow [@SpringCentral](https://twitter.com/springcentral), [@SpringFramework](https://twitter.com/springframework), and its [team members](https://twitter.com/springframework/lists/team/members) on Twitter. In-depth articles can be found at [The Spring Blog](https://spring.io/blog/), and releases are announced via our [news feed](https://spring.io/blog/category/news).
|
||||
|
||||
+57
-60
@@ -1,15 +1,17 @@
|
||||
plugins {
|
||||
id 'io.spring.dependency-management' version '1.0.9.RELEASE' apply false
|
||||
id 'io.spring.nohttp' version '0.0.5.RELEASE'
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.4.10' apply false
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.5.10' apply false
|
||||
id 'org.jetbrains.dokka' version '0.10.1' apply false
|
||||
id 'org.asciidoctor.jvm.convert' version '3.1.0'
|
||||
id 'org.asciidoctor.jvm.pdf' version '3.1.0'
|
||||
id 'de.undercouch.download' version '4.1.1'
|
||||
id "io.freefair.aspectj" version '5.1.1' apply false
|
||||
id "com.github.ben-manes.versions" version '0.28.0'
|
||||
id "me.champeau.gradle.jmh" version "0.5.0" apply false
|
||||
id "org.jetbrains.kotlin.plugin.serialization" version "1.4.10" apply false
|
||||
id "com.github.johnrengelman.shadow" version "6.1.0" apply false
|
||||
id "me.champeau.jmh" version "0.6.4" apply false
|
||||
id "org.jetbrains.kotlin.plugin.serialization" version "1.5.10" apply false
|
||||
id "org.unbroken-dome.xjc" version '2.0.0' apply false
|
||||
}
|
||||
|
||||
ext {
|
||||
@@ -25,18 +27,19 @@ configure(allprojects) { project ->
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.11.3"
|
||||
mavenBom "io.netty:netty-bom:4.1.53.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.0"
|
||||
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR8"
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.3"
|
||||
mavenBom "io.netty:netty-bom:4.1.65.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.7"
|
||||
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR10"
|
||||
mavenBom "io.rsocket:rsocket-bom:1.1.0"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.34.v20201102"
|
||||
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.4.10"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.4.1"
|
||||
mavenBom "org.junit:junit-bom:5.7.0"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.41.v20210516"
|
||||
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.5.10"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.5.0"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-serialization-bom:1.2.1"
|
||||
mavenBom "org.junit:junit-bom:5.7.2"
|
||||
}
|
||||
dependencies {
|
||||
dependencySet(group: 'org.apache.logging.log4j', version: '2.13.3') {
|
||||
dependencySet(group: 'org.apache.logging.log4j', version: '2.14.1') {
|
||||
entry 'log4j-api'
|
||||
entry 'log4j-core'
|
||||
entry 'log4j-jul'
|
||||
@@ -53,7 +56,7 @@ configure(allprojects) { project ->
|
||||
entry 'aspectjtools'
|
||||
entry 'aspectjweaver'
|
||||
}
|
||||
dependencySet(group: 'org.codehaus.groovy', version: '3.0.6') {
|
||||
dependencySet(group: 'org.codehaus.groovy', version: '3.0.8') {
|
||||
entry 'groovy'
|
||||
entry 'groovy-jsr223'
|
||||
entry 'groovy-templates' // requires findbugs for warning-free compilation
|
||||
@@ -63,23 +66,23 @@ configure(allprojects) { project ->
|
||||
|
||||
dependency "io.reactivex:rxjava:1.3.8"
|
||||
dependency "io.reactivex:rxjava-reactive-streams:1.2.1"
|
||||
dependency "io.reactivex.rxjava2:rxjava:2.2.19"
|
||||
dependency "io.reactivex.rxjava3:rxjava:3.0.7"
|
||||
dependency "io.reactivex.rxjava2:rxjava:2.2.21"
|
||||
dependency "io.reactivex.rxjava3:rxjava:3.0.13"
|
||||
dependency "io.projectreactor.tools:blockhound:1.0.4.RELEASE"
|
||||
|
||||
dependency "com.caucho:hessian:4.0.63"
|
||||
dependency "com.fasterxml:aalto-xml:1.2.2"
|
||||
dependency("com.fasterxml.woodstox:woodstox-core:6.2.3") {
|
||||
dependency "com.fasterxml:aalto-xml:1.3.0"
|
||||
dependency("com.fasterxml.woodstox:woodstox-core:6.2.6") {
|
||||
exclude group: "stax", name: "stax-api"
|
||||
}
|
||||
dependency "com.google.code.gson:gson:2.8.6"
|
||||
dependency "com.google.protobuf:protobuf-java-util:3.13.0"
|
||||
dependency "com.google.code.gson:gson:2.8.7"
|
||||
dependency "com.google.protobuf:protobuf-java-util:3.17.2"
|
||||
dependency "com.googlecode.protobuf-java-format:protobuf-java-format:1.4"
|
||||
dependency("com.thoughtworks.xstream:xstream:1.4.13") {
|
||||
dependency("com.thoughtworks.xstream:xstream:1.4.17") {
|
||||
exclude group: "xpp3", name: "xpp3_min"
|
||||
exclude group: "xmlpull", name: "xmlpull"
|
||||
}
|
||||
dependency "org.apache.johnzon:johnzon-jsonb:1.2.8"
|
||||
dependency "org.apache.johnzon:johnzon-jsonb:1.2.10"
|
||||
dependency("org.codehaus.jettison:jettison:1.3.8") {
|
||||
exclude group: "stax", name: "stax-api"
|
||||
}
|
||||
@@ -88,20 +91,16 @@ configure(allprojects) { project ->
|
||||
entry 'jibx-run'
|
||||
}
|
||||
dependency "org.ogce:xpp3:1.1.6"
|
||||
dependency "org.yaml:snakeyaml:1.27"
|
||||
dependencySet(group: 'org.jetbrains.kotlinx', version: '1.0.0') {
|
||||
entry 'kotlinx-serialization-core'
|
||||
entry 'kotlinx-serialization-json'
|
||||
}
|
||||
dependency "org.yaml:snakeyaml:1.28"
|
||||
|
||||
dependency "com.h2database:h2:1.4.200"
|
||||
dependency "com.github.ben-manes.caffeine:caffeine:2.8.6"
|
||||
dependency "com.github.librepdf:openpdf:1.3.22"
|
||||
dependency "com.github.ben-manes.caffeine:caffeine:2.9.1"
|
||||
dependency "com.github.librepdf:openpdf:1.3.26"
|
||||
dependency "com.rometools:rome:1.15.0"
|
||||
dependency "commons-io:commons-io:2.5"
|
||||
dependency "io.vavr:vavr:0.10.3"
|
||||
dependency "net.sf.jopt-simple:jopt-simple:5.0.4"
|
||||
dependencySet(group: 'org.apache.activemq', version: '5.16.0') {
|
||||
dependencySet(group: 'org.apache.activemq', version: '5.16.2') {
|
||||
entry 'activemq-broker'
|
||||
entry('activemq-kahadb-store') {
|
||||
exclude group: "org.springframework", name: "spring-context"
|
||||
@@ -116,30 +115,30 @@ configure(allprojects) { project ->
|
||||
}
|
||||
dependency "org.apache.poi:poi-ooxml:4.1.2"
|
||||
dependency "org.apache-extras.beanshell:bsh:2.0b6"
|
||||
dependency "org.freemarker:freemarker:2.3.30"
|
||||
dependency "org.hsqldb:hsqldb:2.5.1"
|
||||
dependency "org.freemarker:freemarker:2.3.31"
|
||||
dependency "org.hsqldb:hsqldb:2.5.2"
|
||||
dependency "org.quartz-scheduler:quartz:2.3.2"
|
||||
dependency "org.codehaus.fabric3.api:commonj:1.1.0"
|
||||
dependency "net.sf.ehcache:ehcache:2.10.6"
|
||||
dependency "org.ehcache:jcache:1.0.1"
|
||||
dependency "org.ehcache:ehcache:3.4.0"
|
||||
dependency "org.hibernate:hibernate-core:5.4.23.Final"
|
||||
dependency "org.hibernate:hibernate-validator:6.1.6.Final"
|
||||
dependency "org.hibernate:hibernate-core:5.4.32.Final"
|
||||
dependency "org.hibernate:hibernate-validator:6.2.0.Final"
|
||||
dependency "org.webjars:webjars-locator-core:0.46"
|
||||
dependency "org.webjars:underscorejs:1.8.3"
|
||||
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.39') {
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.45') {
|
||||
entry 'tomcat-util'
|
||||
entry('tomcat-websocket') {
|
||||
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
|
||||
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
|
||||
}
|
||||
}
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.39') {
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.45') {
|
||||
entry 'tomcat-embed-core'
|
||||
entry 'tomcat-embed-websocket'
|
||||
}
|
||||
dependencySet(group: 'io.undertow', version: '2.2.2.Final') {
|
||||
dependencySet(group: 'io.undertow', version: '2.2.8.Final') {
|
||||
entry 'undertow-core'
|
||||
entry('undertow-websockets-jsr') {
|
||||
exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec"
|
||||
@@ -154,17 +153,17 @@ configure(allprojects) { project ->
|
||||
entry 'okhttp'
|
||||
entry 'mockwebserver'
|
||||
}
|
||||
dependency("org.apache.httpcomponents:httpclient:4.5.12") {
|
||||
dependency("org.apache.httpcomponents:httpclient:4.5.13") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.apache.httpcomponents:httpasyncclient:4.1.4") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency 'org.apache.httpcomponents.client5:httpclient5:5.0.3'
|
||||
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.0.2'
|
||||
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.4"
|
||||
dependency 'org.apache.httpcomponents.client5:httpclient5:5.1'
|
||||
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.1.1'
|
||||
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.8"
|
||||
|
||||
dependency "org.jruby:jruby:9.2.13.0"
|
||||
dependency "org.jruby:jruby:9.2.17.0"
|
||||
dependency "org.python:jython-standalone:2.7.1"
|
||||
dependency "org.mozilla:rhino:1.7.11"
|
||||
|
||||
@@ -181,34 +180,34 @@ configure(allprojects) { project ->
|
||||
exclude group: "dom4j", name: "dom4j"
|
||||
}
|
||||
|
||||
dependency("junit:junit:4.13.1") {
|
||||
dependency("junit:junit:4.13.2") {
|
||||
exclude group: "org.hamcrest", name: "hamcrest-core"
|
||||
}
|
||||
dependency("de.bechte.junit:junit-hierarchicalcontextrunner:4.12.1") {
|
||||
exclude group: "junit", name: "junit"
|
||||
}
|
||||
dependency "org.testng:testng:7.3.0"
|
||||
dependency "org.testng:testng:7.4.0"
|
||||
dependency "org.hamcrest:hamcrest:2.1"
|
||||
dependency "org.awaitility:awaitility:3.1.6"
|
||||
dependency "org.assertj:assertj-core:3.18.0"
|
||||
dependencySet(group: 'org.xmlunit', version: '2.6.2') {
|
||||
dependency "org.assertj:assertj-core:3.19.0"
|
||||
dependencySet(group: 'org.xmlunit', version: '2.8.2') {
|
||||
entry 'xmlunit-assertj'
|
||||
entry('xmlunit-matchers') {
|
||||
exclude group: "org.hamcrest", name: "hamcrest-core"
|
||||
}
|
||||
}
|
||||
dependencySet(group: 'org.mockito', version: '3.6.0') {
|
||||
dependencySet(group: 'org.mockito', version: '3.11.0') {
|
||||
entry('mockito-core') {
|
||||
exclude group: "org.hamcrest", name: "hamcrest-core"
|
||||
}
|
||||
entry 'mockito-junit-jupiter'
|
||||
}
|
||||
dependency "io.mockk:mockk:1.10.0"
|
||||
dependency "io.mockk:mockk:1.10.2"
|
||||
|
||||
dependency("net.sourceforge.htmlunit:htmlunit:2.44.0") {
|
||||
dependency("net.sourceforge.htmlunit:htmlunit:2.50.0") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.seleniumhq.selenium:htmlunit-driver:2.44.0") {
|
||||
dependency("org.seleniumhq.selenium:htmlunit-driver:2.50.0") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
|
||||
@@ -216,7 +215,7 @@ configure(allprojects) { project ->
|
||||
exclude group: "io.netty", name: "netty"
|
||||
}
|
||||
dependency "org.skyscreamer:jsonassert:1.5.0"
|
||||
dependency "com.jayway.jsonpath:json-path:2.4.0"
|
||||
dependency "com.jayway.jsonpath:json-path:2.5.0"
|
||||
dependency "org.bouncycastle:bcpkix-jdk15on:1.66"
|
||||
|
||||
dependencySet(group: 'org.apache.tiles', version: '3.0.8') {
|
||||
@@ -236,8 +235,8 @@ configure(allprojects) { project ->
|
||||
|
||||
dependency "com.ibm.websphere:uow:6.0.2.17"
|
||||
dependency "com.jamonapi:jamon:2.82"
|
||||
dependency "joda-time:joda-time:2.10.6"
|
||||
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.7"
|
||||
dependency "joda-time:joda-time:2.10.10"
|
||||
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.8"
|
||||
dependency "org.javamoney:moneta:1.3"
|
||||
|
||||
dependency "com.sun.activation:javax.activation:1.2.0"
|
||||
@@ -308,23 +307,21 @@ configure([rootProject] + javaProjects) { project ->
|
||||
apply plugin: "java-test-fixtures"
|
||||
apply plugin: "checkstyle"
|
||||
apply plugin: 'org.springframework.build.compile'
|
||||
apply from: "${rootDir}/gradle/custom-java-home.gradle"
|
||||
apply from: "${rootDir}/gradle/toolchains.gradle"
|
||||
apply from: "${rootDir}/gradle/ide.gradle"
|
||||
|
||||
pluginManager.withPlugin("kotlin") {
|
||||
apply plugin: "org.jetbrains.dokka"
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
languageVersion = "1.3"
|
||||
apiVersion = "1.3"
|
||||
freeCompilerArgs = ["-Xjsr305=strict"]
|
||||
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings", "-Xopt-in=kotlin.RequiresOptIn"]
|
||||
allWarningsAsErrors = true
|
||||
}
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
freeCompilerArgs = ["-Xjsr305=strict"]
|
||||
}
|
||||
}
|
||||
@@ -339,7 +336,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "8.36.2"
|
||||
toolVersion = "8.43"
|
||||
configDirectory.set(rootProject.file("src/checkstyle"))
|
||||
}
|
||||
|
||||
@@ -378,10 +375,10 @@ configure([rootProject] + javaProjects) { project ->
|
||||
"https://fasterxml.github.io/jackson-core/javadoc/2.10/",
|
||||
"https://fasterxml.github.io/jackson-databind/javadoc/2.10/",
|
||||
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/",
|
||||
"https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/",
|
||||
"https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/",
|
||||
"https://projectreactor.io/docs/test/release/api/",
|
||||
"https://junit.org/junit4/javadoc/4.13.1/",
|
||||
"https://junit.org/junit5/docs/5.7.0/api/"
|
||||
"https://junit.org/junit4/javadoc/4.13.2/",
|
||||
"https://junit.org/junit5/docs/5.7.2/api/"
|
||||
] as String[]
|
||||
}
|
||||
|
||||
|
||||
+2
-8
@@ -8,16 +8,10 @@ They are declared in the `build.gradle` file in this folder.
|
||||
### Compiler conventions
|
||||
|
||||
The `org.springframework.build.compile` plugin applies the Java compiler conventions to the build.
|
||||
By default, the build compiles sources with Java `1.8` source and target compatibility.
|
||||
You can test a different source compatibility version on the CLI with a project property like:
|
||||
|
||||
```
|
||||
./gradlew test -PjavaSourceVersion=11
|
||||
```
|
||||
|
||||
## Build Plugins
|
||||
|
||||
## Optional dependencies
|
||||
### Optional dependencies
|
||||
|
||||
The `org.springframework.build.optional-dependencies` plugin creates a new `optional`
|
||||
Gradle configuration - it adds the dependencies to the project's compile and runtime classpath
|
||||
@@ -25,7 +19,7 @@ but doesn't affect the classpath of dependent projects.
|
||||
This plugin does not provide a `provided` configuration, as the native `compileOnly` and `testCompileOnly`
|
||||
configurations are preferred.
|
||||
|
||||
## API Diff
|
||||
### API Diff
|
||||
|
||||
This plugin uses the [Gradle JApiCmp](https://github.com/melix/japicmp-gradle-plugin) plugin
|
||||
to generate API Diff reports for each Spring Framework module. This plugin is applied once on the root
|
||||
|
||||
+3
-22
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,31 +20,21 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.gradle.api.JavaVersion;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.plugins.JavaLibraryPlugin;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.plugins.JavaPluginConvention;
|
||||
import org.gradle.api.tasks.compile.JavaCompile;
|
||||
|
||||
/**
|
||||
* {@link Plugin} that applies conventions for compiling Java sources in Spring Framework.
|
||||
* <p>One can override the default Java source compatibility version
|
||||
* with a dedicated property on the CLI: {@code "./gradlew test -PjavaSourceVersion=11"}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class CompilerConventionsPlugin implements Plugin<Project> {
|
||||
|
||||
/**
|
||||
* The project property that can be used to switch the Java source
|
||||
* compatibility version for building source and test classes.
|
||||
*/
|
||||
public static final String JAVA_SOURCE_VERSION_PROPERTY = "javaSourceVersion";
|
||||
|
||||
public static final JavaVersion DEFAULT_COMPILER_VERSION = JavaVersion.VERSION_1_8;
|
||||
|
||||
private static final List<String> COMPILER_ARGS;
|
||||
|
||||
private static final List<String> TEST_COMPILER_ARGS;
|
||||
@@ -69,7 +59,7 @@ public class CompilerConventionsPlugin implements Plugin<Project> {
|
||||
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
project.getPlugins().withType(JavaPlugin.class, javaPlugin -> applyJavaCompileConventions(project));
|
||||
project.getPlugins().withType(JavaLibraryPlugin.class, javaPlugin -> applyJavaCompileConventions(project));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,15 +69,6 @@ public class CompilerConventionsPlugin implements Plugin<Project> {
|
||||
*/
|
||||
private void applyJavaCompileConventions(Project project) {
|
||||
JavaPluginConvention java = project.getConvention().getPlugin(JavaPluginConvention.class);
|
||||
if (project.hasProperty(JAVA_SOURCE_VERSION_PROPERTY)) {
|
||||
JavaVersion javaSourceVersion = JavaVersion.toVersion(project.property(JAVA_SOURCE_VERSION_PROPERTY));
|
||||
java.setSourceCompatibility(javaSourceVersion);
|
||||
}
|
||||
else {
|
||||
java.setSourceCompatibility(DEFAULT_COMPILER_VERSION);
|
||||
}
|
||||
java.setTargetCompatibility(DEFAULT_COMPILER_VERSION);
|
||||
|
||||
project.getTasks().withType(JavaCompile.class)
|
||||
.matching(compileTask -> compileTask.getName().equals(JavaPlugin.COMPILE_JAVA_TASK_NAME))
|
||||
.forEach(compileTask -> {
|
||||
|
||||
+9
-3
@@ -1,7 +1,8 @@
|
||||
== Spring Framework Concourse pipeline
|
||||
|
||||
The Spring Framework is using https://concourse-ci.org/[Concourse] for its CI build and other automated tasks.
|
||||
The Spring team has a dedicated Concourse instance available at https://ci.spring.io.
|
||||
The Spring Framework uses https://concourse-ci.org/[Concourse] for its CI build and other automated tasks.
|
||||
The Spring team has a dedicated Concourse instance available at https://ci.spring.io with a build pipeline
|
||||
for https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.3.x[Spring Framework 5.3.x].
|
||||
|
||||
=== Setting up your development environment
|
||||
|
||||
@@ -25,13 +26,17 @@ spring https://ci.spring.io spring-framework Wed, 25 Mar 20
|
||||
----
|
||||
|
||||
=== Pipeline configuration and structure
|
||||
|
||||
The build pipelines are described in `pipeline.yml` file.
|
||||
|
||||
This file is listing Concourse resources, i.e. build inputs and outputs such as container images, artifact repositories, source repositories, notification services, etc.
|
||||
|
||||
It also describes jobs (a job is a sequence of inputs, tasks and outputs); jobs are organized by groups.
|
||||
|
||||
The `pipeline.yml` definition contains `((parameters))` which are loaded from the `parameters.yml` file or from our https://docs.cloudfoundry.org/credhub/[credhub instance].
|
||||
|
||||
You'll find in this folder the following resources:
|
||||
|
||||
* `pipeline.yml` the build pipeline
|
||||
* `parameters.yml` the build parameters used for the pipeline
|
||||
* `images/` holds the container images definitions used in this pipeline
|
||||
@@ -41,6 +46,7 @@ You'll find in this folder the following resources:
|
||||
=== Updating the build pipeline
|
||||
|
||||
Updating files on the repository is not enough to update the build pipeline, as changes need to be applied.
|
||||
|
||||
The pipeline can be deployed using the following command:
|
||||
|
||||
[source]
|
||||
@@ -48,4 +54,4 @@ The pipeline can be deployed using the following command:
|
||||
$ fly -t spring set-pipeline -p spring-framework-5.3.x -c ci/pipeline.yml -l ci/parameters.yml
|
||||
----
|
||||
|
||||
NOTE: This assumes that you have credhub integration configured with the appropriate secrets.
|
||||
NOTE: This assumes that you have credhub integration configured with the appropriate secrets.
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
logging:
|
||||
level:
|
||||
io.spring.concourse: DEBUG
|
||||
distribute:
|
||||
optional-deployments:
|
||||
- '.*\\.zip'
|
||||
spring:
|
||||
main:
|
||||
banner-mode: off
|
||||
banner-mode: off
|
||||
sonatype:
|
||||
exclude:
|
||||
- 'build-info\.json'
|
||||
- '.*\.zip'
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
FROM ubuntu:focal-20210119
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
RUN ./setup.sh java8
|
||||
|
||||
ENV JAVA_HOME /opt/openjdk/java8
|
||||
ENV JDK11 /opt/openjdk/java11
|
||||
ENV JDK15 /opt/openjdk/java15
|
||||
|
||||
ENV PATH $JAVA_HOME/bin:$PATH
|
||||
@@ -3,16 +3,13 @@ set -e
|
||||
|
||||
case "$1" in
|
||||
java8)
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u265-b01/OpenJDK8U-jdk_x64_linux_hotspot_8u265b01.tar.gz"
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u282-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u282b08.tar.gz"
|
||||
;;
|
||||
java11)
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_linux_hotspot_11.0.8_10.tar.gz"
|
||||
;;
|
||||
java14)
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.2%2B12/OpenJDK14U-jdk_x64_linux_hotspot_14.0.2_12.tar.gz"
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_linux_hotspot_11.0.10_9.tar.gz"
|
||||
;;
|
||||
java15)
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_linux_hotspot_15_36.tar.gz"
|
||||
echo "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.2%2B7/OpenJDK15U-jdk_x64_linux_hotspot_15.0.2_7.tar.gz"
|
||||
;;
|
||||
*)
|
||||
echo $"Unknown java version"
|
||||
|
||||
+18
-8
@@ -5,24 +5,34 @@ set -ex
|
||||
# UTILS
|
||||
###########################################################
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install --no-install-recommends -y ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq fontconfig
|
||||
apt-get install --no-install-recommends -y tzdata ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq fontconfig
|
||||
ln -fs /usr/share/zoneinfo/UTC /etc/localtime
|
||||
dpkg-reconfigure --frontend noninteractive tzdata
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.3/concourse-java.sh > /opt/concourse-java.sh
|
||||
curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/concourse-java.sh > /opt/concourse-java.sh
|
||||
|
||||
curl --output /opt/concourse-release-scripts.jar https://repo.spring.io/release/io/spring/concourse/releasescripts/concourse-release-scripts/0.2.1/concourse-release-scripts-0.2.1.jar
|
||||
curl --output /opt/concourse-release-scripts.jar https://repo.spring.io/release/io/spring/concourse/releasescripts/concourse-release-scripts/0.3.2/concourse-release-scripts-0.3.2.jar
|
||||
|
||||
###########################################################
|
||||
# JAVA
|
||||
###########################################################
|
||||
JDK_URL=$( ./get-jdk-url.sh $1 )
|
||||
|
||||
mkdir -p /opt/openjdk
|
||||
cd /opt/openjdk
|
||||
curl -L ${JDK_URL} | tar zx --strip-components=1
|
||||
test -f /opt/openjdk/bin/java
|
||||
test -f /opt/openjdk/bin/javac
|
||||
pushd /opt/openjdk > /dev/null
|
||||
for jdk in java8 java11 java15
|
||||
do
|
||||
JDK_URL=$( /get-jdk-url.sh $jdk )
|
||||
mkdir $jdk
|
||||
pushd $jdk > /dev/null
|
||||
curl -L ${JDK_URL} | tar zx --strip-components=1
|
||||
test -f bin/java
|
||||
test -f bin/javac
|
||||
popd > /dev/null
|
||||
done
|
||||
popd
|
||||
|
||||
###########################################################
|
||||
# GRADLE ENTERPRISE
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
FROM ubuntu:bionic-20200713
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
RUN ./setup.sh java8
|
||||
|
||||
ENV JAVA_HOME /opt/openjdk
|
||||
ENV PATH $JAVA_HOME/bin:$PATH
|
||||
@@ -1,8 +0,0 @@
|
||||
FROM ubuntu:bionic-20200713
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
RUN ./setup.sh java11
|
||||
|
||||
ENV JAVA_HOME /opt/openjdk
|
||||
ENV PATH $JAVA_HOME/bin:$PATH
|
||||
@@ -1,8 +0,0 @@
|
||||
FROM ubuntu:bionic-20200713
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
RUN ./setup.sh java14
|
||||
|
||||
ENV JAVA_HOME /opt/openjdk
|
||||
ENV PATH $JAVA_HOME/bin:$PATH
|
||||
@@ -1,8 +0,0 @@
|
||||
FROM ubuntu:bionic-20200713
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
RUN ./setup.sh java15
|
||||
|
||||
ENV JAVA_HOME /opt/openjdk
|
||||
ENV PATH $JAVA_HOME/bin:$PATH
|
||||
+3
-4
@@ -5,10 +5,9 @@ github-repo: "https://github.com/spring-projects/spring-framework.git"
|
||||
github-repo-name: "spring-projects/spring-framework"
|
||||
docker-hub-organization: "springci"
|
||||
artifactory-server: "https://repo.spring.io"
|
||||
branch: "master"
|
||||
branch: "main"
|
||||
milestone: "5.3.x"
|
||||
build-name: "spring-framework"
|
||||
pipeline-name: "spring-framework"
|
||||
concourse-url: "https://ci.spring.io"
|
||||
bintray-subject: "spring"
|
||||
bintray-repo: "jars"
|
||||
task-timeout: 1h00m
|
||||
task-timeout: 1h00m
|
||||
|
||||
+116
-141
@@ -1,21 +1,29 @@
|
||||
anchors:
|
||||
artifactory-task-params: &artifactory-task-params
|
||||
ARTIFACTORY_SERVER: ((artifactory-server))
|
||||
ARTIFACTORY_USERNAME: ((artifactory-username))
|
||||
ARTIFACTORY_PASSWORD: ((artifactory-password))
|
||||
bintray-task-params: &bintray-task-params
|
||||
BINTRAY_SUBJECT: ((bintray-subject))
|
||||
BINTRAY_REPO: ((bintray-repo))
|
||||
BINTRAY_USERNAME: ((bintray-username))
|
||||
BINTRAY_API_KEY: ((bintray-api-key))
|
||||
docker-resource-source: &docker-resource-source
|
||||
username: ((docker-hub-username))
|
||||
password: ((docker-hub-password))
|
||||
tag: 5.3.x
|
||||
git-repo-resource-source: &git-repo-resource-source
|
||||
uri: ((github-repo))
|
||||
username: ((github-username))
|
||||
password: ((github-password))
|
||||
branch: ((branch))
|
||||
gradle-enterprise-task-params: &gradle-enterprise-task-params
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
|
||||
sonatype-task-params: &sonatype-task-params
|
||||
SONATYPE_USERNAME: ((sonatype-username))
|
||||
SONATYPE_PASSWORD: ((sonatype-password))
|
||||
SONATYPE_URL: ((sonatype-url))
|
||||
SONATYPE_STAGING_PROFILE_ID: ((sonatype-staging-profile-id))
|
||||
artifactory-task-params: &artifactory-task-params
|
||||
ARTIFACTORY_SERVER: ((artifactory-server))
|
||||
ARTIFACTORY_USERNAME: ((artifactory-username))
|
||||
ARTIFACTORY_PASSWORD: ((artifactory-password))
|
||||
build-project-task-params: &build-project-task-params
|
||||
BRANCH: ((branch))
|
||||
<<: *gradle-enterprise-task-params
|
||||
docker-resource-source: &docker-resource-source
|
||||
username: ((docker-hub-username))
|
||||
password: ((docker-hub-password))
|
||||
tag: ((milestone))
|
||||
slack-fail-params: &slack-fail-params
|
||||
text: >
|
||||
:concourse-failed: <https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!>
|
||||
@@ -24,9 +32,6 @@ anchors:
|
||||
silent: true
|
||||
icon_emoji: ":concourse:"
|
||||
username: concourse-ci
|
||||
sonatype-task-params: &sonatype-task-params
|
||||
SONATYPE_USER_TOKEN: ((sonatype-user-token))
|
||||
SONATYPE_PASSWORD_TOKEN: ((sonatype-user-token-password))
|
||||
changelog-task-params: &changelog-task-params
|
||||
name: generated-changelog/tag
|
||||
tag: generated-changelog/tag
|
||||
@@ -37,30 +42,31 @@ anchors:
|
||||
|
||||
resource_types:
|
||||
- name: artifactory-resource
|
||||
type: docker-image
|
||||
type: registry-image
|
||||
source:
|
||||
repository: springio/artifactory-resource
|
||||
tag: 0.0.12
|
||||
tag: 0.0.13
|
||||
- name: github-status-resource
|
||||
type: docker-image
|
||||
type: registry-image
|
||||
source:
|
||||
repository: dpb587/github-status-resource
|
||||
tag: master
|
||||
- name: pull-request
|
||||
type: registry-image
|
||||
source:
|
||||
repository: teliaoss/github-pr-resource
|
||||
tag: v0.23.0
|
||||
- name: slack-notification
|
||||
type: docker-image
|
||||
type: registry-image
|
||||
source:
|
||||
repository: cfcommunity/slack-notification-resource
|
||||
tag: latest
|
||||
|
||||
resources:
|
||||
- name: git-repo
|
||||
type: git
|
||||
icon: github
|
||||
source:
|
||||
uri: ((github-repo))
|
||||
username: ((github-username))
|
||||
password: ((github-password))
|
||||
branch: ((branch))
|
||||
<<: *git-repo-resource-source
|
||||
- name: every-morning
|
||||
type: time
|
||||
icon: alarm
|
||||
@@ -75,30 +81,12 @@ resources:
|
||||
uri: ((github-repo))
|
||||
branch: ((branch))
|
||||
paths: ["ci/images/*"]
|
||||
- name: spring-framework-ci-image
|
||||
- name: ci-image
|
||||
type: docker-image
|
||||
icon: docker
|
||||
source:
|
||||
<<: *docker-resource-source
|
||||
repository: ((docker-hub-organization))/spring-framework-ci-image
|
||||
- name: spring-framework-jdk11-ci-image
|
||||
type: docker-image
|
||||
icon: docker
|
||||
source:
|
||||
<<: *docker-resource-source
|
||||
repository: ((docker-hub-organization))/spring-framework-jdk11-ci-image
|
||||
- name: spring-framework-jdk14-ci-image
|
||||
type: docker-image
|
||||
icon: docker
|
||||
source:
|
||||
<<: *docker-resource-source
|
||||
repository: ((docker-hub-organization))/spring-framework-jdk14-ci-image
|
||||
- name: spring-framework-jdk15-ci-image
|
||||
type: docker-image
|
||||
icon: docker
|
||||
source:
|
||||
<<: *docker-resource-source
|
||||
repository: ((docker-hub-organization))/spring-framework-jdk15-ci-image
|
||||
repository: ((docker-hub-organization))/spring-framework-ci
|
||||
- name: artifactory-repo
|
||||
type: artifactory-resource
|
||||
icon: package-variant
|
||||
@@ -107,6 +95,14 @@ resources:
|
||||
username: ((artifactory-username))
|
||||
password: ((artifactory-password))
|
||||
build_name: ((build-name))
|
||||
- name: git-pull-request
|
||||
type: pull-request
|
||||
icon: source-pull
|
||||
source:
|
||||
access_token: ((github-ci-pull-request-token))
|
||||
repository: ((github-repo-name))
|
||||
base_branch: ((branch))
|
||||
ignore_paths: ["ci/*"]
|
||||
- name: repo-status-build
|
||||
type: github-status-resource
|
||||
icon: eye-check-outline
|
||||
@@ -123,14 +119,6 @@ resources:
|
||||
access_token: ((github-ci-status-token))
|
||||
branch: ((branch))
|
||||
context: jdk11-build
|
||||
- name: repo-status-jdk14-build
|
||||
type: github-status-resource
|
||||
icon: eye-check-outline
|
||||
source:
|
||||
repository: ((github-repo-name))
|
||||
access_token: ((github-ci-status-token))
|
||||
branch: ((branch))
|
||||
context: jdk14-build
|
||||
- name: repo-status-jdk15-build
|
||||
type: github-status-resource
|
||||
icon: eye-check-outline
|
||||
@@ -161,47 +149,33 @@ resources:
|
||||
repository: spring-framework
|
||||
access_token: ((github-ci-release-token))
|
||||
pre_release: false
|
||||
|
||||
jobs:
|
||||
- name: build-spring-framework-ci-images
|
||||
- name: build-ci-images
|
||||
plan:
|
||||
- get: ci-images-git-repo
|
||||
trigger: true
|
||||
- in_parallel:
|
||||
- put: spring-framework-ci-image
|
||||
- put: ci-image
|
||||
params:
|
||||
build: ci-images-git-repo/ci/images
|
||||
dockerfile: ci-images-git-repo/ci/images/spring-framework-ci-image/Dockerfile
|
||||
- put: spring-framework-jdk11-ci-image
|
||||
params:
|
||||
build: ci-images-git-repo/ci/images
|
||||
dockerfile: ci-images-git-repo/ci/images/spring-framework-jdk11-ci-image/Dockerfile
|
||||
- put: spring-framework-jdk14-ci-image
|
||||
params:
|
||||
build: ci-images-git-repo/ci/images
|
||||
dockerfile: ci-images-git-repo/ci/images/spring-framework-jdk14-ci-image/Dockerfile
|
||||
- put: spring-framework-jdk15-ci-image
|
||||
params:
|
||||
build: ci-images-git-repo/ci/images
|
||||
dockerfile: ci-images-git-repo/ci/images/spring-framework-jdk15-ci-image/Dockerfile
|
||||
dockerfile: ci-images-git-repo/ci/images/ci-image/Dockerfile
|
||||
- name: build
|
||||
serial: true
|
||||
public: true
|
||||
plan:
|
||||
- get: spring-framework-ci-image
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
trigger: true
|
||||
- put: repo-status-build
|
||||
params: { state: "pending", commit: "git-repo" }
|
||||
- do:
|
||||
- task: build-project
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/build-project.yml
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
image: spring-framework-ci-image
|
||||
file: git-repo/ci/tasks/build-project.yml
|
||||
params:
|
||||
BRANCH: ((branch))
|
||||
<<: *gradle-enterprise-task-params
|
||||
<<: *build-project-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-build
|
||||
@@ -213,6 +187,8 @@ jobs:
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- put: artifactory-repo
|
||||
params: &artifactory-params
|
||||
signing_key: ((signing-key))
|
||||
signing_passphrase: ((signing-passphrase))
|
||||
repo: libs-snapshot-local
|
||||
folder: distribution-repository
|
||||
build_uri: "https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}"
|
||||
@@ -244,7 +220,7 @@ jobs:
|
||||
serial: true
|
||||
public: true
|
||||
plan:
|
||||
- get: spring-framework-jdk11-ci-image
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
- get: every-morning
|
||||
trigger: true
|
||||
@@ -252,13 +228,13 @@ jobs:
|
||||
params: { state: "pending", commit: "git-repo" }
|
||||
- do:
|
||||
- task: check-project
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/check-project.yml
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
image: spring-framework-jdk11-ci-image
|
||||
file: git-repo/ci/tasks/check-project.yml
|
||||
params:
|
||||
BRANCH: ((branch))
|
||||
<<: *gradle-enterprise-task-params
|
||||
TEST_TOOLCHAIN: 11
|
||||
<<: *build-project-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-jdk11-build
|
||||
@@ -268,53 +244,25 @@ jobs:
|
||||
<<: *slack-fail-params
|
||||
- put: repo-status-jdk11-build
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- name: jdk14-build
|
||||
serial: true
|
||||
public: true
|
||||
plan:
|
||||
- get: spring-framework-jdk14-ci-image
|
||||
- get: git-repo
|
||||
- get: every-morning
|
||||
trigger: true
|
||||
- put: repo-status-jdk14-build
|
||||
params: { state: "pending", commit: "git-repo" }
|
||||
- do:
|
||||
- task: check-project
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
image: spring-framework-jdk14-ci-image
|
||||
file: git-repo/ci/tasks/check-project.yml
|
||||
params:
|
||||
BRANCH: ((branch))
|
||||
<<: *gradle-enterprise-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-jdk14-build
|
||||
params: { state: "failure", commit: "git-repo" }
|
||||
- put: slack-alert
|
||||
params:
|
||||
<<: *slack-fail-params
|
||||
- put: repo-status-jdk14-build
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- name: jdk15-build
|
||||
serial: true
|
||||
public: true
|
||||
plan:
|
||||
- get: spring-framework-jdk15-ci-image
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
- get: every-morning
|
||||
trigger: true
|
||||
- put: repo-status-jdk15-build
|
||||
params: { state: "pending", commit: "git-repo" }
|
||||
- do:
|
||||
- task: check-project
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
image: spring-framework-jdk15-ci-image
|
||||
file: git-repo/ci/tasks/check-project.yml
|
||||
params:
|
||||
BRANCH: ((branch))
|
||||
<<: *gradle-enterprise-task-params
|
||||
- task: check-project
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/check-project.yml
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
params:
|
||||
TEST_TOOLCHAIN: 15
|
||||
<<: *build-project-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-jdk15-build
|
||||
@@ -324,14 +272,45 @@ jobs:
|
||||
<<: *slack-fail-params
|
||||
- put: repo-status-jdk15-build
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- name: build-pull-requests
|
||||
serial: true
|
||||
public: true
|
||||
plan:
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
resource: git-pull-request
|
||||
trigger: true
|
||||
version: every
|
||||
- do:
|
||||
- put: git-pull-request
|
||||
params:
|
||||
path: git-repo
|
||||
status: pending
|
||||
- task: build-pr
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/build-pr.yml
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
params:
|
||||
<<: *build-project-task-params
|
||||
on_success:
|
||||
put: git-pull-request
|
||||
params:
|
||||
path: git-repo
|
||||
status: success
|
||||
on_failure:
|
||||
put: git-pull-request
|
||||
params:
|
||||
path: git-repo
|
||||
status: failure
|
||||
- name: stage-milestone
|
||||
serial: true
|
||||
plan:
|
||||
- get: spring-framework-ci-image
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
trigger: false
|
||||
- task: stage
|
||||
image: spring-framework-ci-image
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/stage-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: M
|
||||
@@ -346,7 +325,7 @@ jobs:
|
||||
- name: promote-milestone
|
||||
serial: true
|
||||
plan:
|
||||
- get: spring-framework-ci-image
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
trigger: false
|
||||
- get: artifactory-repo
|
||||
@@ -356,7 +335,7 @@ jobs:
|
||||
download_artifacts: false
|
||||
save_build_info: true
|
||||
- task: promote
|
||||
image: spring-framework-ci-image
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/promote-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: M
|
||||
@@ -372,11 +351,11 @@ jobs:
|
||||
- name: stage-rc
|
||||
serial: true
|
||||
plan:
|
||||
- get: spring-framework-ci-image
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
trigger: false
|
||||
- task: stage
|
||||
image: spring-framework-ci-image
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/stage-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: RC
|
||||
@@ -391,7 +370,7 @@ jobs:
|
||||
- name: promote-rc
|
||||
serial: true
|
||||
plan:
|
||||
- get: spring-framework-ci-image
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
trigger: false
|
||||
- get: artifactory-repo
|
||||
@@ -401,7 +380,7 @@ jobs:
|
||||
download_artifacts: false
|
||||
save_build_info: true
|
||||
- task: promote
|
||||
image: spring-framework-ci-image
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/promote-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: RC
|
||||
@@ -417,11 +396,11 @@ jobs:
|
||||
- name: stage-release
|
||||
serial: true
|
||||
plan:
|
||||
- get: spring-framework-ci-image
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
trigger: false
|
||||
- task: stage
|
||||
image: spring-framework-ci-image
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/stage-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: RELEASE
|
||||
@@ -436,26 +415,26 @@ jobs:
|
||||
- name: promote-release
|
||||
serial: true
|
||||
plan:
|
||||
- get: spring-framework-ci-image
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
trigger: false
|
||||
- get: artifactory-repo
|
||||
trigger: false
|
||||
passed: [stage-release]
|
||||
params:
|
||||
download_artifacts: false
|
||||
download_artifacts: true
|
||||
save_build_info: true
|
||||
- task: promote
|
||||
image: spring-framework-ci-image
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/promote-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: RELEASE
|
||||
<<: *artifactory-task-params
|
||||
<<: *bintray-task-params
|
||||
- name: sync-to-maven-central
|
||||
<<: *sonatype-task-params
|
||||
- name: create-github-release
|
||||
serial: true
|
||||
plan:
|
||||
- get: spring-framework-ci-image
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
- get: artifactory-repo
|
||||
trigger: true
|
||||
@@ -463,12 +442,6 @@ jobs:
|
||||
params:
|
||||
download_artifacts: false
|
||||
save_build_info: true
|
||||
- task: sync-to-maven-central
|
||||
image: spring-framework-ci-image
|
||||
file: git-repo/ci/tasks/sync-to-maven-central.yml
|
||||
params:
|
||||
<<: *bintray-task-params
|
||||
<<: *sonatype-task-params
|
||||
- task: generate-changelog
|
||||
file: git-repo/ci/tasks/generate-changelog.yml
|
||||
params:
|
||||
@@ -480,8 +453,10 @@ jobs:
|
||||
|
||||
groups:
|
||||
- name: "builds"
|
||||
jobs: ["build", "jdk11-build", "jdk14-build", "jdk15-build"]
|
||||
jobs: ["build", "jdk11-build", "jdk15-build"]
|
||||
- name: "releases"
|
||||
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone","promote-rc", "promote-release", "sync-to-maven-central"]
|
||||
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
|
||||
- name: "ci-images"
|
||||
jobs: ["build-spring-framework-ci-images"]
|
||||
jobs: ["build-ci-images"]
|
||||
- name: "pull-requests"
|
||||
jobs: [ "build-pull-requests" ]
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
source $(dirname $0)/common.sh
|
||||
|
||||
pushd git-repo > /dev/null
|
||||
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 check
|
||||
popd > /dev/null
|
||||
@@ -4,5 +4,6 @@ set -e
|
||||
source $(dirname $0)/common.sh
|
||||
|
||||
pushd git-repo > /dev/null
|
||||
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 check
|
||||
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK11,JDK15 \
|
||||
-PmainToolchain=${MAIN_TOOLCHAIN} -PtestToolchain=${TEST_TOOLCHAIN} --no-daemon --max-workers=4 check
|
||||
popd > /dev/null
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
set -e
|
||||
|
||||
CONFIG_DIR=git-repo/ci/config
|
||||
version=$( cat version/version )
|
||||
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
|
||||
|
||||
java -jar /github-changelog-generator.jar \
|
||||
--spring.config.location=${CONFIG_DIR}/changelog-generator.yml \
|
||||
|
||||
@@ -6,11 +6,13 @@ CONFIG_DIR=git-repo/ci/config
|
||||
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
|
||||
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
|
||||
|
||||
java -jar /opt/concourse-release-scripts.jar promote $RELEASE_TYPE $BUILD_INFO_LOCATION > /dev/null || { exit 1; }
|
||||
java -jar /opt/concourse-release-scripts.jar \
|
||||
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
|
||||
publishToCentral $RELEASE_TYPE $BUILD_INFO_LOCATION artifactory-repo || { exit 1; }
|
||||
|
||||
java -jar /opt/concourse-release-scripts.jar \
|
||||
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
|
||||
distribute $RELEASE_TYPE $BUILD_INFO_LOCATION > /dev/null || { exit 1; }
|
||||
promote $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; }
|
||||
|
||||
echo "Promotion complete"
|
||||
echo $version > version/version
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
platform: linux
|
||||
inputs:
|
||||
- name: git-repo
|
||||
caches:
|
||||
- path: gradle
|
||||
params:
|
||||
BRANCH:
|
||||
CI: true
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY:
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME:
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD:
|
||||
GRADLE_ENTERPRISE_URL: https://ge.spring.io
|
||||
run:
|
||||
path: bash
|
||||
args:
|
||||
- -ec
|
||||
- |
|
||||
${PWD}/git-repo/ci/scripts/build-pr.sh
|
||||
@@ -10,6 +10,8 @@ caches:
|
||||
params:
|
||||
BRANCH:
|
||||
CI: true
|
||||
MAIN_TOOLCHAIN:
|
||||
TEST_TOOLCHAIN:
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY:
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME:
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD:
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
platform: linux
|
||||
image_resource:
|
||||
type: docker-image
|
||||
type: registry-image
|
||||
source:
|
||||
repository: springio/github-changelog-generator
|
||||
tag: '0.0.4'
|
||||
tag: '0.0.6'
|
||||
inputs:
|
||||
- name: git-repo
|
||||
- name: version
|
||||
- name: artifactory-repo
|
||||
outputs:
|
||||
- name: generated-changelog
|
||||
params:
|
||||
|
||||
@@ -10,9 +10,9 @@ params:
|
||||
ARTIFACTORY_SERVER:
|
||||
ARTIFACTORY_USERNAME:
|
||||
ARTIFACTORY_PASSWORD:
|
||||
BINTRAY_SUBJECT:
|
||||
BINTRAY_REPO:
|
||||
BINTRAY_USERNAME:
|
||||
BINTRAY_API_KEY:
|
||||
SONATYPE_USER:
|
||||
SONATYPE_PASSWORD:
|
||||
SONATYPE_URL:
|
||||
SONATYPE_STAGING_PROFILE_ID:
|
||||
run:
|
||||
path: git-repo/ci/scripts/promote-version.sh
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
platform: linux
|
||||
inputs:
|
||||
- name: git-repo
|
||||
- name: artifactory-repo
|
||||
outputs:
|
||||
- name: version
|
||||
params:
|
||||
BINTRAY_REPO:
|
||||
BINTRAY_SUBJECT:
|
||||
BINTRAY_USERNAME:
|
||||
BINTRAY_API_KEY:
|
||||
SONATYPE_USER_TOKEN:
|
||||
SONATYPE_PASSWORD_TOKEN:
|
||||
run:
|
||||
path: git-repo/ci/scripts/sync-to-maven-central.sh
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=5.3.1-SNAPSHOT
|
||||
version=5.3.8
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This script adds support for the following two JVM system properties
|
||||
// that control the build for alternative JDKs (i.e., a JDK other than
|
||||
// the one used to launch the Gradle process).
|
||||
//
|
||||
// - customJavaHome: absolute path to the alternate JDK installation to
|
||||
// use to compile Java code and execute tests. This system property
|
||||
// is also used in spring-oxm.gradle to determine whether JiBX is
|
||||
// supported.
|
||||
//
|
||||
// - customJavaSourceVersion: Java version supplied to the `--release`
|
||||
// command line flag to control the Java source and target
|
||||
// compatibility version. Supported versions include 9 or higher.
|
||||
// Do not set this system property if Java 8 should be used.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// ./gradlew -DcustomJavaHome=/Library/Java/JavaVirtualMachines/jdk-14.jdk/Contents/Home test
|
||||
//
|
||||
// ./gradlew --no-build-cache -DcustomJavaHome=/Library/Java/JavaVirtualMachines/jdk-14.jdk/Contents/Home test
|
||||
//
|
||||
// ./gradlew -DcustomJavaHome=/Library/Java/JavaVirtualMachines/jdk-14.jdk/Contents/Home -DcustomJavaSourceVersion=14 test
|
||||
//
|
||||
//
|
||||
// Credits: inspired by work from Marc Philipp and Stephane Nicoll
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
import org.gradle.internal.os.OperatingSystem
|
||||
// import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile
|
||||
|
||||
def customJavaHome = System.getProperty("customJavaHome")
|
||||
|
||||
if (customJavaHome) {
|
||||
def customJavaHomeDir = new File(customJavaHome)
|
||||
def customJavaSourceVersion = System.getProperty("customJavaSourceVersion")
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
logger.info("Java home for " + it.name + " task in " + project.name + ": " + customJavaHomeDir)
|
||||
options.forkOptions.javaHome = customJavaHomeDir
|
||||
inputs.property("customJavaHome", customJavaHome)
|
||||
if (customJavaSourceVersion) {
|
||||
options.compilerArgs += [ "--release", customJavaSourceVersion]
|
||||
inputs.property("customJavaSourceVersion", customJavaSourceVersion)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(GroovyCompile) {
|
||||
logger.info("Java home for " + it.name + " task in " + project.name + ": " + customJavaHomeDir)
|
||||
options.forkOptions.javaHome = customJavaHomeDir
|
||||
inputs.property("customJavaHome", customJavaHome)
|
||||
if (customJavaSourceVersion) {
|
||||
options.compilerArgs += [ "--release", customJavaSourceVersion]
|
||||
inputs.property("customJavaSourceVersion", customJavaSourceVersion)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
tasks.withType(KotlinJvmCompile) {
|
||||
logger.info("Java home for " + it.name + " task in " + project.name + ": " + customJavaHome)
|
||||
kotlinOptions.jdkHome = customJavaHomeDir
|
||||
inputs.property("customJavaHome", customJavaHome)
|
||||
}
|
||||
*/
|
||||
|
||||
tasks.withType(Test) {
|
||||
def javaExecutable = customJavaHome + "/bin/java"
|
||||
if (OperatingSystem.current().isWindows()) {
|
||||
javaExecutable += ".exe"
|
||||
}
|
||||
logger.info("Java executable for " + it.name + " task in " + project.name + ": " + javaExecutable)
|
||||
executable = javaExecutable
|
||||
inputs.property("customJavaHome", customJavaHome)
|
||||
if (customJavaSourceVersion) {
|
||||
inputs.property("customJavaSourceVersion", customJavaSourceVersion)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+4
-3
@@ -3,7 +3,7 @@ configurations {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.4.3.RELEASE")
|
||||
asciidoctorExt("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.5.0")
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -113,7 +113,7 @@ dokka {
|
||||
}
|
||||
|
||||
task downloadResources(type: Download) {
|
||||
def version = "0.2.2.RELEASE"
|
||||
def version = "0.2.5"
|
||||
src "https://repo.spring.io/release/io/spring/docresources/" +
|
||||
"spring-doc-resources/$version/spring-doc-resources-${version}.zip"
|
||||
dest project.file("$buildDir/docs/spring-doc-resources.zip")
|
||||
@@ -143,7 +143,8 @@ asciidoctorj {
|
||||
'highlightjs-theme': 'googlecode',
|
||||
stylesdir: 'css/',
|
||||
stylesheet: 'stylesheet.css',
|
||||
'spring-version': project.version
|
||||
'spring-version': project.version,
|
||||
'spring-framework-main-code': 'https://github.com/spring-projects/spring-framework/tree/main'
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
+10
-20
@@ -29,12 +29,11 @@ eclipse.classpath.file.whenMerged { classpath ->
|
||||
classpath.entries.removeAll { entry -> (entry.path =~ /(?!.*?repack.*\.jar).*?\/([^\/]+)\/build\/libs\/[^\/]+\.jar/) }
|
||||
}
|
||||
|
||||
|
||||
// Use separate main/test outputs (prevents WTP from packaging test classes)
|
||||
eclipse.classpath.defaultOutputDir = file(project.name+"/bin/eclipse")
|
||||
eclipse.classpath.file.beforeMerged { classpath ->
|
||||
classpath.entries.findAll{ it instanceof SourceFolder }.each {
|
||||
if(it.output.startsWith("bin/")) {
|
||||
if (it.output.startsWith("bin/")) {
|
||||
it.output = null
|
||||
}
|
||||
}
|
||||
@@ -56,6 +55,15 @@ eclipse.classpath.file.whenMerged { classpath ->
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that JMH sources and resources are treated as test classpath entries
|
||||
// so that they can see test fixtures.
|
||||
// https://github.com/melix/jmh-gradle-plugin/issues/157
|
||||
eclipse.classpath.file.whenMerged {
|
||||
entries.findAll { it.path =~ /src\/jmh\/(java|resources)/ }.each {
|
||||
it.entryAttributes['test'] = 'true'
|
||||
}
|
||||
}
|
||||
|
||||
// Allow projects to be used as WTP modules
|
||||
eclipse.project.natures "org.eclipse.wst.common.project.facet.core.nature"
|
||||
|
||||
@@ -100,21 +108,3 @@ task eclipseBuildship(type: Copy) {
|
||||
tasks["eclipseJdt"].dependsOn(eclipseJdtPrepare)
|
||||
tasks["cleanEclipse"].dependsOn(cleanEclipseJdtUi)
|
||||
tasks["eclipse"].dependsOn(eclipseSettings, eclipseWstComponent)
|
||||
|
||||
|
||||
// Filter 'build' folder
|
||||
eclipse.project.file.withXml {
|
||||
def node = it.asNode()
|
||||
|
||||
def filteredResources = node.get("filteredResources")
|
||||
if(filteredResources) {
|
||||
node.remove(filteredResources)
|
||||
}
|
||||
def filterNode = node.appendNode("filteredResources").appendNode("filter")
|
||||
filterNode.appendNode("id", "1359048889071")
|
||||
filterNode.appendNode("name", "")
|
||||
filterNode.appendNode("type", "30")
|
||||
def matcherNode = filterNode.appendNode("matcher")
|
||||
matcherNode.appendNode("id", "org.eclipse.ui.ide.multiFilter")
|
||||
matcherNode.appendNode("arguments", "1.0-projectRelativePath-matches-false-false-build")
|
||||
}
|
||||
|
||||
@@ -1,17 +1,38 @@
|
||||
apply plugin: 'java-library'
|
||||
apply plugin: 'org.springframework.build.compile'
|
||||
apply plugin: 'org.springframework.build.optional-dependencies'
|
||||
apply plugin: 'me.champeau.gradle.jmh'
|
||||
// Uncomment the following for Shadow support in the jmhJar block.
|
||||
// Currently commented out due to ZipException: archive is not a ZIP archive
|
||||
// apply plugin: 'com.github.johnrengelman.shadow'
|
||||
apply plugin: 'me.champeau.jmh'
|
||||
apply from: "$rootDir/gradle/publications.gradle"
|
||||
|
||||
dependencies {
|
||||
jmh 'org.openjdk.jmh:jmh-core:1.23'
|
||||
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.23'
|
||||
jmh 'org.openjdk.jmh:jmh-core:1.28'
|
||||
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.28'
|
||||
jmh 'net.sf.jopt-simple:jopt-simple:4.6'
|
||||
}
|
||||
|
||||
jmh {
|
||||
duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
|
||||
jmhJar {
|
||||
// Uncomment the following for Shadow's Transformer support.
|
||||
// mergeServiceFiles()
|
||||
// append('META-INF/spring.handlers')
|
||||
// append('META-INF/spring.schemas')
|
||||
// append('META-INF/spring.tooling')
|
||||
exclude 'LICENSE'
|
||||
exclude 'THIRD-PARTY'
|
||||
exclude 'META-INF/license.txt'
|
||||
exclude 'META-INF/notice.txt'
|
||||
exclude 'META-INF/DEPENDENCIES'
|
||||
exclude 'META-INF/LICENSE*'
|
||||
exclude 'META-INF/NOTICE'
|
||||
exclude 'META-INF/THIRD-PARTY'
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest.attributes["Implementation-Title"] = project.name
|
||||
manifest.attributes["Implementation-Version"] = project.version
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* Apply the JVM Toolchain conventions
|
||||
* See https://docs.gradle.org/current/userguide/toolchains.html
|
||||
*
|
||||
* One can choose the toolchain to use for compiling the MAIN sources and/or compiling
|
||||
* and running the TEST sources. These options apply to Java, Kotlin and Groovy sources
|
||||
* when available.
|
||||
* {@code "./gradlew check -PmainToolchain=8 -PtestToolchain=11"} will use:
|
||||
* <ul>
|
||||
* <li>a JDK8 toolchain for compiling the main SourceSet
|
||||
* <li>a JDK11 toolchain for compiling and running the test SourceSet
|
||||
* </ul>
|
||||
*
|
||||
* By default, the build will fall back to using the current JDK and 1.8 language level for all sourceSets.
|
||||
*
|
||||
* Gradle will automatically detect JDK distributions in well-known locations.
|
||||
* The following command will list the detected JDKs on the host.
|
||||
* {@code
|
||||
* $ ./gradlew -q javaToolchains
|
||||
* }
|
||||
*
|
||||
* We can also configure ENV variables and let Gradle know about them:
|
||||
* {@code
|
||||
* $ echo JDK11
|
||||
* /opt/openjdk/java11
|
||||
* $ echo JDK15
|
||||
* /opt/openjdk/java15
|
||||
* $ ./gradlew -Porg.gradle.java.installations.fromEnv=JDK11,JDK15 check
|
||||
* }
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
|
||||
def mainToolchainConfigured() {
|
||||
return project.hasProperty('mainToolchain') && project.mainToolchain
|
||||
}
|
||||
|
||||
def testToolchainConfigured() {
|
||||
return project.hasProperty('testToolchain') && project.testToolchain
|
||||
}
|
||||
|
||||
def mainToolchainLanguageVersion() {
|
||||
if (mainToolchainConfigured()) {
|
||||
return JavaLanguageVersion.of(project.mainToolchain.toString())
|
||||
}
|
||||
return JavaLanguageVersion.of(8)
|
||||
}
|
||||
|
||||
def testToolchainLanguageVersion() {
|
||||
if (testToolchainConfigured()) {
|
||||
return JavaLanguageVersion.of(project.testToolchain.toString())
|
||||
}
|
||||
return mainToolchainLanguageVersion()
|
||||
}
|
||||
|
||||
plugins.withType(JavaPlugin) {
|
||||
// Configure the Java Toolchain if the 'mainToolchain' is configured
|
||||
if (mainToolchainConfigured()) {
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = mainToolchainLanguageVersion()
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Fallback to JDK8
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
// Configure a specific Java Toolchain for compiling and running tests if the 'testToolchain' property is defined
|
||||
if (testToolchainConfigured()) {
|
||||
def testLanguageVersion = testToolchainLanguageVersion()
|
||||
tasks.withType(JavaCompile).matching { it.name.contains("Test") }.configureEach {
|
||||
javaCompiler = javaToolchains.compilerFor {
|
||||
languageVersion = testLanguageVersion
|
||||
}
|
||||
}
|
||||
tasks.withType(Test).configureEach{
|
||||
javaLauncher = javaToolchains.launcherFor {
|
||||
languageVersion = testLanguageVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugins.withType(GroovyPlugin) {
|
||||
// Fallback to JDK8
|
||||
if (!mainToolchainConfigured()) {
|
||||
compileGroovy {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pluginManager.withPlugin("kotlin") {
|
||||
// Configure the Kotlin compiler if the 'mainToolchain' property is defined
|
||||
if (mainToolchainConfigured()) {
|
||||
def mainLanguageVersion = mainToolchainLanguageVersion()
|
||||
def compiler = javaToolchains.compilerFor {
|
||||
languageVersion = mainLanguageVersion
|
||||
}
|
||||
// See https://kotlinlang.org/docs/gradle.html#attributes-specific-for-jvm
|
||||
def javaVersion = mainLanguageVersion.toString() == '8' ? '1.8' : mainLanguageVersion.toString()
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = javaVersion
|
||||
jdkHome = compiler.get().metadata.installationPath.asFile.absolutePath
|
||||
}
|
||||
}
|
||||
// Compile the test classes with the same version, 'testToolchain' will override if defined
|
||||
compileTestKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = javaVersion
|
||||
jdkHome = compiler.get().metadata.installationPath.asFile.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Fallback to JDK8
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (testToolchainConfigured()) {
|
||||
def testLanguageVersion = testToolchainLanguageVersion()
|
||||
def compiler = javaToolchains.compilerFor {
|
||||
languageVersion = testLanguageVersion
|
||||
}
|
||||
// See https://kotlinlang.org/docs/gradle.html#attributes-specific-for-jvm
|
||||
def javaVersion = testLanguageVersion.toString() == '8' ? '1.8' : testLanguageVersion.toString()
|
||||
compileTestKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = javaVersion
|
||||
jdkHome = compiler.get().metadata.installationPath.asFile.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the JMH plugin to use the toolchain for generating and running JMH bytecode
|
||||
pluginManager.withPlugin("me.champeau.jmh") {
|
||||
if (mainToolchainConfigured() || testToolchainConfigured()) {
|
||||
tasks.matching { it.name.contains('jmh') && it.hasProperty('javaLauncher') }.configureEach {
|
||||
javaLauncher.set(javaToolchains.launcherFor {
|
||||
languageVersion.set(testToolchainLanguageVersion())
|
||||
})
|
||||
}
|
||||
tasks.withType(JavaCompile).matching { it.name.contains("Jmh") }.configureEach {
|
||||
javaCompiler = javaToolchains.compilerFor {
|
||||
languageVersion = testToolchainLanguageVersion()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store resolved Toolchain JVM information as custom values in the build scan.
|
||||
rootProject.ext {
|
||||
resolvedMainToolchain = false
|
||||
resolvedTestToolchain = false
|
||||
}
|
||||
gradle.taskGraph.afterTask { Task task, TaskState state ->
|
||||
if (mainToolchainConfigured() && !resolvedMainToolchain && task instanceof JavaCompile && task.javaCompiler.isPresent()) {
|
||||
def metadata = task.javaCompiler.get().metadata
|
||||
task.project.buildScan.value('Main toolchain', "$metadata.vendor $metadata.languageVersion ($metadata.installationPath)")
|
||||
resolvedMainToolchain = true
|
||||
}
|
||||
if (testToolchainConfigured() && !resolvedTestToolchain && task instanceof Test && task.javaLauncher.isPresent()) {
|
||||
def metadata = task.javaLauncher.get().metadata
|
||||
task.project.buildScan.value('Test toolchain', "$metadata.vendor $metadata.languageVersion ($metadata.installationPath)")
|
||||
resolvedTestToolchain = true
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
+2
-8
@@ -6,8 +6,8 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "com.gradle.enterprise" version "3.2"
|
||||
id "io.spring.gradle-enterprise-conventions" version "0.0.2"
|
||||
id "com.gradle.enterprise" version "3.6.1"
|
||||
id "io.spring.ge.conventions" version "0.0.7"
|
||||
}
|
||||
|
||||
include "spring-aop"
|
||||
@@ -45,12 +45,6 @@ rootProject.children.each {project ->
|
||||
settings.gradle.projectsLoaded {
|
||||
gradleEnterprise {
|
||||
buildScan {
|
||||
if (settings.gradle.rootProject.hasProperty('customJavaHome')) {
|
||||
value("Custom JAVA_HOME", settings.gradle.rootProject.getProperty('customJavaHome'))
|
||||
}
|
||||
if (settings.gradle.rootProject.hasProperty('customJavaSourceVersion')) {
|
||||
value("Custom Java Source Version", settings.gradle.rootProject.getProperty('customJavaSourceVersion'))
|
||||
}
|
||||
File buildDir = settings.gradle.rootProject.getBuildDir()
|
||||
buildDir.mkdirs()
|
||||
new File(buildDir, "build-scan-uri.txt").text = "(build scan not generated)"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,7 +26,7 @@ import org.aopalliance.aop.Advice;
|
||||
* <p>Introductions are often <b>mixins</b>, enabling the building of composite
|
||||
* objects that can achieve many of the goals of multiple inheritance in Java.
|
||||
*
|
||||
* <p>Compared to {qlink IntroductionInfo}, this interface allows an advice to
|
||||
* <p>Compared to {@link IntroductionInfo}, this interface allows an advice to
|
||||
* implement a range of interfaces that is not necessarily known in advance.
|
||||
* Thus an {@link IntroductionAdvisor} can be used to specify which interfaces
|
||||
* will be exposed in an advised object.
|
||||
|
||||
+3
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -350,17 +350,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
return this.discoveredThrowingType;
|
||||
}
|
||||
|
||||
private boolean isVariableName(String name) {
|
||||
char[] chars = name.toCharArray();
|
||||
if (!Character.isJavaIdentifierStart(chars[0])) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 1; i < chars.length; i++) {
|
||||
if (!Character.isJavaIdentifierPart(chars[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
private static boolean isVariableName(String name) {
|
||||
return AspectJProxyUtils.isVariableName(name);
|
||||
}
|
||||
|
||||
|
||||
@@ -640,7 +631,6 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
}
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
|
||||
// TODO AopUtils.invokeJoinpointUsingReflection
|
||||
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
|
||||
+2
-14
@@ -470,22 +470,10 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
*/
|
||||
@Nullable
|
||||
private String maybeExtractVariableName(@Nullable String candidateToken) {
|
||||
if (!StringUtils.hasLength(candidateToken)) {
|
||||
return null;
|
||||
}
|
||||
if (Character.isJavaIdentifierStart(candidateToken.charAt(0)) &&
|
||||
Character.isLowerCase(candidateToken.charAt(0))) {
|
||||
char[] tokenChars = candidateToken.toCharArray();
|
||||
for (char tokenChar : tokenChars) {
|
||||
if (!Character.isJavaIdentifierPart(tokenChar)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (AspectJProxyUtils.isVariableName(candidateToken)) {
|
||||
return candidateToken;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,8 @@ import java.util.List;
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.PointcutAdvisor;
|
||||
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Utility methods for working with AspectJ proxies.
|
||||
@@ -73,4 +75,19 @@ public abstract class AspectJProxyUtils {
|
||||
((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
|
||||
}
|
||||
|
||||
static boolean isVariableName(@Nullable String name) {
|
||||
if (!StringUtils.hasLength(name)) {
|
||||
return false;
|
||||
}
|
||||
if (!Character.isJavaIdentifierStart(name.charAt(0))) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 1; i < name.length(); i++) {
|
||||
if (!Character.isJavaIdentifierPart(name.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-10
@@ -51,6 +51,7 @@ import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.ConvertingComparator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.comparator.InstanceComparator;
|
||||
|
||||
@@ -70,7 +71,11 @@ import org.springframework.util.comparator.InstanceComparator;
|
||||
@SuppressWarnings("serial")
|
||||
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
|
||||
|
||||
private static final Comparator<Method> METHOD_COMPARATOR;
|
||||
// Exclude @Pointcut methods
|
||||
private static final MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS
|
||||
.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));
|
||||
|
||||
private static final Comparator<Method> adviceMethodComparator;
|
||||
|
||||
static {
|
||||
// Note: although @After is ordered before @AfterReturning and @AfterThrowing,
|
||||
@@ -86,7 +91,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
return (ann != null ? ann.getAnnotation() : null);
|
||||
});
|
||||
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
|
||||
METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
|
||||
adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
|
||||
}
|
||||
|
||||
|
||||
@@ -160,15 +165,10 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
}
|
||||
|
||||
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
|
||||
final List<Method> methods = new ArrayList<>();
|
||||
ReflectionUtils.doWithMethods(aspectClass, method -> {
|
||||
// Exclude pointcuts
|
||||
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
|
||||
methods.add(method);
|
||||
}
|
||||
}, ReflectionUtils.USER_DECLARED_METHODS);
|
||||
List<Method> methods = new ArrayList<>();
|
||||
ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
|
||||
if (methods.size() > 1) {
|
||||
methods.sort(METHOD_COMPARATOR);
|
||||
methods.sort(adviceMethodComparator);
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
+9
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.core.SmartClassLoader;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
@@ -89,7 +90,13 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSu
|
||||
}
|
||||
proxyFactory.addAdvisor(this.advisor);
|
||||
customizeProxyFactory(proxyFactory);
|
||||
return proxyFactory.getProxy(getProxyClassLoader());
|
||||
|
||||
// Use original ClassLoader if bean class not locally loaded in overriding class loader
|
||||
ClassLoader classLoader = getProxyClassLoader();
|
||||
if (classLoader instanceof SmartClassLoader && classLoader != bean.getClass().getClassLoader()) {
|
||||
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
|
||||
}
|
||||
return proxyFactory.getProxy(classLoader);
|
||||
}
|
||||
|
||||
// No proxy needed.
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodInterceptor;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.cglib.proxy.NoOp;
|
||||
import org.springframework.core.KotlinDetector;
|
||||
import org.springframework.core.SmartClassLoader;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -752,10 +753,17 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
|
||||
if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) ||
|
||||
KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) {
|
||||
// Propagate original exception if declared on the target method
|
||||
// (with callers expecting it). Always propagate it for Kotlin code
|
||||
// since checked exceptions do not have to be explicitly declared there.
|
||||
throw ex;
|
||||
}
|
||||
else {
|
||||
// Checked exception thrown in the interceptor but not declared on the
|
||||
// target method signature -> apply an UndeclaredThrowableException,
|
||||
// aligned with standard JDK dynamic proxy behavior.
|
||||
throw new UndeclaredThrowableException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,6 +20,7 @@ import java.io.Serializable;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.springframework.aop.SpringProxy;
|
||||
import org.springframework.core.NativeDetector;
|
||||
|
||||
/**
|
||||
* Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy
|
||||
@@ -47,17 +48,10 @@ import org.springframework.aop.SpringProxy;
|
||||
@SuppressWarnings("serial")
|
||||
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
|
||||
|
||||
/**
|
||||
* Whether this environment lives within a native image.
|
||||
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
|
||||
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
|
||||
*/
|
||||
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
|
||||
|
||||
|
||||
@Override
|
||||
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
|
||||
if (!IN_NATIVE_IMAGE &&
|
||||
if (!NativeDetector.inNativeImage() &&
|
||||
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
|
||||
Class<?> targetClass = config.getTargetClass();
|
||||
if (targetClass == null) {
|
||||
|
||||
+12
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,6 +46,7 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
|
||||
import org.springframework.core.SmartClassLoader;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -458,7 +459,12 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
proxyFactory.setPreFiltered(true);
|
||||
}
|
||||
|
||||
return proxyFactory.getProxy(getProxyClassLoader());
|
||||
// Use original ClassLoader if bean class not locally loaded in overriding class loader
|
||||
ClassLoader classLoader = getProxyClassLoader();
|
||||
if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
|
||||
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
|
||||
}
|
||||
return proxyFactory.getProxy(classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -503,7 +509,10 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
|
||||
List<Object> allInterceptors = new ArrayList<>();
|
||||
if (specificInterceptors != null) {
|
||||
allInterceptors.addAll(Arrays.asList(specificInterceptors));
|
||||
if (specificInterceptors.length > 0) {
|
||||
// specificInterceptors may equal PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
|
||||
allInterceptors.addAll(Arrays.asList(specificInterceptors));
|
||||
}
|
||||
if (commonInterceptors.length > 0) {
|
||||
if (this.applyCommonInterceptorsFirst) {
|
||||
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -116,7 +116,7 @@ public abstract class AbstractPoolingTargetSource extends AbstractPrototypeBased
|
||||
|
||||
|
||||
/**
|
||||
* Return an IntroductionAdvisor that providing a mixin
|
||||
* Return an IntroductionAdvisor that provides a mixin
|
||||
* exposing statistics about the pool maintained by this object.
|
||||
*/
|
||||
public DefaultIntroductionAdvisor getPoolingConfigMixin() {
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,8 @@ public abstract aspect AbstractTransactionAspect extends TransactionAspectSuppor
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
clearTransactionManagerCache(); // An aspect is basically a singleton
|
||||
// An aspect is basically a singleton -> cleanup on destruction
|
||||
clearTransactionManagerCache();
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
|
||||
@@ -23,8 +23,6 @@ sourceSets {
|
||||
}
|
||||
|
||||
compileGroovy {
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
options.compilerArgs += "-Werror"
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -1,14 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="bean1" class="org.springframework.beans.factory.ConcurrentBeanFactoryTests$ConcurrentBean"
|
||||
<bean id="bean1" class="org.springframework.beans.factory.ConcurrentBeanFactoryBenchmark$ConcurrentBean"
|
||||
scope="prototype">
|
||||
<property name="date" value="2004/08/08"/>
|
||||
</bean>
|
||||
|
||||
<bean id="bean2" class="org.springframework.beans.factory.ConcurrentBeanFactoryTests$ConcurrentBean"
|
||||
<bean id="bean2" class="org.springframework.beans.factory.ConcurrentBeanFactoryBenchmark$ConcurrentBean"
|
||||
scope="prototype">
|
||||
<property name="date" value="2000/02/02"/>
|
||||
</bean>
|
||||
|
||||
+5
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -305,8 +305,10 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
Class<?> componentType = propValue.getClass().getComponentType();
|
||||
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
|
||||
System.arraycopy(propValue, 0, newArray, 0, length);
|
||||
setPropertyValue(tokens.actualName, newArray);
|
||||
propValue = getPropertyValue(tokens.actualName);
|
||||
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
|
||||
String propName = tokens.canonicalName.substring(0, lastKeyIndex);
|
||||
setPropertyValue(propName, newArray);
|
||||
propValue = getPropertyValue(propName);
|
||||
}
|
||||
Array.set(propValue, arrayIndex, convertedValue);
|
||||
}
|
||||
|
||||
@@ -268,10 +268,7 @@ public abstract class BeanUtils {
|
||||
public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(clazz)) {
|
||||
Constructor<T> kotlinPrimaryConstructor = KotlinDelegate.findPrimaryConstructor(clazz);
|
||||
if (kotlinPrimaryConstructor != null) {
|
||||
return kotlinPrimaryConstructor;
|
||||
}
|
||||
return KotlinDelegate.findPrimaryConstructor(clazz);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -543,6 +540,7 @@ public abstract class BeanUtils {
|
||||
if (targetType == null || targetType.isArray() || unknownEditorTypes.contains(targetType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClassLoader cl = targetType.getClassLoader();
|
||||
if (cl == null) {
|
||||
try {
|
||||
@@ -559,28 +557,34 @@ public abstract class BeanUtils {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String targetTypeName = targetType.getName();
|
||||
String editorName = targetTypeName + "Editor";
|
||||
try {
|
||||
Class<?> editorClass = cl.loadClass(editorName);
|
||||
if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Editor class [" + editorName +
|
||||
"] does not implement [java.beans.PropertyEditor] interface");
|
||||
if (editorClass != null) {
|
||||
if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Editor class [" + editorName +
|
||||
"] does not implement [java.beans.PropertyEditor] interface");
|
||||
}
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
}
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
return (PropertyEditor) instantiateClass(editorClass);
|
||||
}
|
||||
return (PropertyEditor) instantiateClass(editorClass);
|
||||
// Misbehaving ClassLoader returned null instead of ClassNotFoundException
|
||||
// - fall back to unknown editor type registration below
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("No property editor [" + editorName + "] found for type " +
|
||||
targetTypeName + " according to 'Editor' suffix convention");
|
||||
}
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
// Ignore - fall back to unknown editor type registration below
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("No property editor [" + editorName + "] found for type " +
|
||||
targetTypeName + " according to 'Editor' suffix convention");
|
||||
}
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -772,7 +776,14 @@ public abstract class BeanUtils {
|
||||
if (readMethod != null) {
|
||||
ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod);
|
||||
ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0);
|
||||
if (targetResolvableType.isAssignableFrom(sourceResolvableType)) {
|
||||
|
||||
// Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
|
||||
boolean isAssignable =
|
||||
(sourceResolvableType.hasUnresolvableGenerics() || targetResolvableType.hasUnresolvableGenerics() ?
|
||||
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) :
|
||||
targetResolvableType.isAssignableFrom(sourceResolvableType));
|
||||
|
||||
if (isAssignable) {
|
||||
try {
|
||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
|
||||
readMethod.setAccessible(true);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,10 +41,10 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
private String propertyName;
|
||||
|
||||
@Nullable
|
||||
private transient Object value;
|
||||
private final transient Object value;
|
||||
|
||||
@Nullable
|
||||
private Class<?> requiredType;
|
||||
private final Class<?> requiredType;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -84,7 +84,7 @@ import org.springframework.lang.Nullable;
|
||||
* (only applicable when running in a web application context)
|
||||
* <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
|
||||
* <li>InitializingBean's {@code afterPropertiesSet}
|
||||
* <li>a custom init-method definition
|
||||
* <li>a custom {@code init-method} definition
|
||||
* <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
|
||||
* </ol>
|
||||
*
|
||||
@@ -92,7 +92,7 @@ import org.springframework.lang.Nullable;
|
||||
* <ol>
|
||||
* <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
|
||||
* <li>DisposableBean's {@code destroy}
|
||||
* <li>a custom destroy-method definition
|
||||
* <li>a custom {@code destroy-method} definition
|
||||
* </ol>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
@@ -102,6 +102,8 @@ import org.springframework.lang.Nullable;
|
||||
* @see BeanNameAware#setBeanName
|
||||
* @see BeanClassLoaderAware#setBeanClassLoader
|
||||
* @see BeanFactoryAware#setBeanFactory
|
||||
* @see org.springframework.context.EnvironmentAware#setEnvironment
|
||||
* @see org.springframework.context.EmbeddedValueResolverAware#setEmbeddedValueResolver
|
||||
* @see org.springframework.context.ResourceLoaderAware#setResourceLoader
|
||||
* @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher
|
||||
* @see org.springframework.context.MessageSourceAware#setMessageSource
|
||||
@@ -111,6 +113,7 @@ import org.springframework.lang.Nullable;
|
||||
* @see InitializingBean#afterPropertiesSet
|
||||
* @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
|
||||
* @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
|
||||
* @see DisposableBean#destroy
|
||||
* @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
|
||||
*/
|
||||
|
||||
+106
-82
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -628,45 +628,58 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
Field field = (Field) this.member;
|
||||
Object value;
|
||||
if (this.cached) {
|
||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
||||
try {
|
||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Unexpected removal of target bean for cached argument -> re-resolve
|
||||
value = resolveFieldValue(field, bean, beanName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
|
||||
desc.setContainingClass(bean.getClass());
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
try {
|
||||
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
Object cachedFieldValue = null;
|
||||
if (value != null || this.required) {
|
||||
cachedFieldValue = desc;
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == 1) {
|
||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
|
||||
cachedFieldValue = new ShortcutDependencyDescriptor(
|
||||
desc, autowiredBeanName, field.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cachedFieldValue = cachedFieldValue;
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
value = resolveFieldValue(field, bean, beanName);
|
||||
}
|
||||
if (value != null) {
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
field.set(bean, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
|
||||
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
|
||||
desc.setContainingClass(bean.getClass());
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
Object value;
|
||||
try {
|
||||
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
Object cachedFieldValue = null;
|
||||
if (value != null || this.required) {
|
||||
cachedFieldValue = desc;
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == 1) {
|
||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
|
||||
cachedFieldValue = new ShortcutDependencyDescriptor(
|
||||
desc, autowiredBeanName, field.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cachedFieldValue = cachedFieldValue;
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -695,58 +708,16 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
Method method = (Method) this.member;
|
||||
Object[] arguments;
|
||||
if (this.cached) {
|
||||
// Shortcut for avoiding synchronization...
|
||||
arguments = resolveCachedArguments(beanName);
|
||||
try {
|
||||
arguments = resolveCachedArguments(beanName);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Unexpected removal of target bean for cached argument -> re-resolve
|
||||
arguments = resolveMethodArguments(method, bean, beanName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int argumentCount = method.getParameterCount();
|
||||
arguments = new Object[argumentCount];
|
||||
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
|
||||
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
|
||||
currDesc.setContainingClass(bean.getClass());
|
||||
descriptors[i] = currDesc;
|
||||
try {
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
|
||||
if (arg == null && !this.required) {
|
||||
arguments = null;
|
||||
break;
|
||||
}
|
||||
arguments[i] = arg;
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
|
||||
}
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
if (arguments != null) {
|
||||
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
|
||||
registerDependentBeans(beanName, autowiredBeans);
|
||||
if (autowiredBeans.size() == argumentCount) {
|
||||
Iterator<String> it = autowiredBeans.iterator();
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
String autowiredBeanName = it.next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
|
||||
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
|
||||
descriptors[i], autowiredBeanName, paramTypes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cachedMethodArguments = cachedMethodArguments;
|
||||
}
|
||||
else {
|
||||
this.cachedMethodArguments = null;
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
arguments = resolveMethodArguments(method, bean, beanName);
|
||||
}
|
||||
if (arguments != null) {
|
||||
try {
|
||||
@@ -771,6 +742,59 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
|
||||
int argumentCount = method.getParameterCount();
|
||||
Object[] arguments = new Object[argumentCount];
|
||||
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
|
||||
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
|
||||
currDesc.setContainingClass(bean.getClass());
|
||||
descriptors[i] = currDesc;
|
||||
try {
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
|
||||
if (arg == null && !this.required) {
|
||||
arguments = null;
|
||||
break;
|
||||
}
|
||||
arguments[i] = arg;
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
|
||||
}
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
if (arguments != null) {
|
||||
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
|
||||
registerDependentBeans(beanName, autowiredBeans);
|
||||
if (autowiredBeans.size() == argumentCount) {
|
||||
Iterator<String> it = autowiredBeans.iterator();
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
String autowiredBeanName = it.next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
|
||||
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
|
||||
descriptors[i], autowiredBeanName, paramTypes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cachedMethodArguments = cachedMethodArguments;
|
||||
}
|
||||
else {
|
||||
this.cachedMethodArguments = null;
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-2
@@ -141,8 +141,7 @@ public class InjectionMetadata {
|
||||
* Return an {@code InjectionMetadata} instance, possibly for empty elements.
|
||||
* @param elements the elements to inject (possibly empty)
|
||||
* @param clazz the target class
|
||||
* @return a new {@link #InjectionMetadata(Class, Collection)} instance,
|
||||
* or {@link #EMPTY} in case of no elements
|
||||
* @return a new {@link #InjectionMetadata(Class, Collection)} instance
|
||||
* @since 5.2
|
||||
*/
|
||||
public static InjectionMetadata forElements(Collection<InjectedElement> elements, Class<?> clazz) {
|
||||
|
||||
+11
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,15 +36,16 @@ import org.springframework.util.StringValueResolver;
|
||||
* Example XML bean definition:
|
||||
*
|
||||
* <pre class="code">
|
||||
* <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>
|
||||
* <property name="driverClassName" value="${driver}"/>
|
||||
* <property name="url" value="jdbc:${dbname}"/>
|
||||
* <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
* <property name="driverClassName" value="${driver}" />
|
||||
* <property name="url" value="jdbc:${dbname}" />
|
||||
* </bean>
|
||||
* </pre>
|
||||
*
|
||||
* Example properties file:
|
||||
*
|
||||
* <pre class="code">driver=com.mysql.jdbc.Driver
|
||||
* <pre class="code">
|
||||
* driver=com.mysql.jdbc.Driver
|
||||
* dbname=mysql:mydb</pre>
|
||||
*
|
||||
* Annotated bean definitions may take advantage of property replacement using
|
||||
@@ -56,7 +57,8 @@ import org.springframework.util.StringValueResolver;
|
||||
* in bean references. Furthermore, placeholder values can also cross-reference
|
||||
* other placeholders, like:
|
||||
*
|
||||
* <pre class="code">rootPath=myrootdir
|
||||
* <pre class="code">
|
||||
* rootPath=myrootdir
|
||||
* subPath=${rootPath}/subdir</pre>
|
||||
*
|
||||
* In contrast to {@link PropertyOverrideConfigurer}, subclasses of this type allow
|
||||
@@ -71,13 +73,13 @@ import org.springframework.util.StringValueResolver;
|
||||
*
|
||||
* <p>Default property values can be defined globally for each configurer instance
|
||||
* via the {@link #setProperties properties} property, or on a property-by-property basis
|
||||
* using the default value separator which is {@code ":"} by default and
|
||||
* customizable via {@link #setValueSeparator(String)}.
|
||||
* using the value separator which is {@code ":"} by default and customizable via
|
||||
* {@link #setValueSeparator(String)}.
|
||||
*
|
||||
* <p>Example XML property with default value:
|
||||
*
|
||||
* <pre class="code">
|
||||
* <property name="url" value="jdbc:${dbname:defaultdb}"/>
|
||||
* <property name="url" value="jdbc:${dbname:defaultdb}" />
|
||||
* </pre>
|
||||
*
|
||||
* @author Chris Beams
|
||||
|
||||
+9
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -52,6 +52,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @author Brian Clozel
|
||||
* @since 4.1
|
||||
*/
|
||||
public abstract class YamlProcessor {
|
||||
@@ -128,10 +129,11 @@ public abstract class YamlProcessor {
|
||||
|
||||
/**
|
||||
* Set the supported types that can be loaded from YAML documents.
|
||||
* <p>If no supported types are configured, all types encountered in YAML
|
||||
* documents will be supported. If an unsupported type is encountered, an
|
||||
* {@link IllegalStateException} will be thrown when the corresponding YAML
|
||||
* node is processed.
|
||||
* <p>If no supported types are configured, only Java standard classes
|
||||
* (as defined in {@link org.yaml.snakeyaml.constructor.SafeConstructor})
|
||||
* encountered in YAML documents will be supported.
|
||||
* If an unsupported type is encountered, an {@link IllegalStateException}
|
||||
* will be thrown when the corresponding YAML node is processed.
|
||||
* @param supportedTypes the supported types, or an empty array to clear the
|
||||
* supported types
|
||||
* @since 5.1.16
|
||||
@@ -182,12 +184,8 @@ public abstract class YamlProcessor {
|
||||
protected Yaml createYaml() {
|
||||
LoaderOptions loaderOptions = new LoaderOptions();
|
||||
loaderOptions.setAllowDuplicateKeys(false);
|
||||
|
||||
if (!this.supportedTypes.isEmpty()) {
|
||||
return new Yaml(new FilteringConstructor(loaderOptions), new Representer(),
|
||||
new DumperOptions(), loaderOptions);
|
||||
}
|
||||
return new Yaml(loaderOptions);
|
||||
return new Yaml(new FilteringConstructor(loaderOptions), new Representer(),
|
||||
new DumperOptions(), loaderOptions);
|
||||
}
|
||||
|
||||
private boolean process(MatchCallback callback, Yaml yaml, Resource resource) {
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -489,8 +489,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length);
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class<?>) args[1], constructorArgs);
|
||||
Map<?, ?> namedArgs = (Map<?, ?>) args[0];
|
||||
for (Object o : namedArgs.keySet()) {
|
||||
String propName = (String) o;
|
||||
for (Object key : namedArgs.keySet()) {
|
||||
String propName = (String) key;
|
||||
setProperty(propName, namedArgs.get(propName));
|
||||
}
|
||||
}
|
||||
|
||||
+8
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -73,6 +73,7 @@ import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
import org.springframework.core.NativeDetector;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.ResolvableType;
|
||||
@@ -123,14 +124,6 @@ import org.springframework.util.StringUtils;
|
||||
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
|
||||
implements AutowireCapableBeanFactory {
|
||||
|
||||
/**
|
||||
* Whether this environment lives within a native image.
|
||||
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
|
||||
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
|
||||
*/
|
||||
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
|
||||
|
||||
|
||||
/** Strategy for creating bean instances. */
|
||||
private InstantiationStrategy instantiationStrategy;
|
||||
|
||||
@@ -184,7 +177,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
ignoreDependencyInterface(BeanNameAware.class);
|
||||
ignoreDependencyInterface(BeanFactoryAware.class);
|
||||
ignoreDependencyInterface(BeanClassLoaderAware.class);
|
||||
if (IN_NATIVE_IMAGE) {
|
||||
if (NativeDetector.inNativeImage()) {
|
||||
this.instantiationStrategy = new SimpleInstantiationStrategy();
|
||||
}
|
||||
else {
|
||||
@@ -1022,6 +1015,11 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
throw ex;
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
// Don't swallow a linkage error since it contains a full stacktrace on
|
||||
// first occurrence... and just a plain NoClassDefFoundError afterwards.
|
||||
if (ex.contains(LinkageError.class)) {
|
||||
throw ex;
|
||||
}
|
||||
// Instantiation failure, maybe too early...
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Bean creation exception on singleton FactoryBean type check: " + ex);
|
||||
|
||||
+24
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -894,7 +894,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if there are property values values defined for this bean.
|
||||
* Return if there are property values defined for this bean.
|
||||
* @since 5.0.2
|
||||
*/
|
||||
@Override
|
||||
@@ -1194,8 +1194,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
this.primary == that.primary &&
|
||||
this.nonPublicAccessAllowed == that.nonPublicAccessAllowed &&
|
||||
this.lenientConstructorResolution == that.lenientConstructorResolution &&
|
||||
ObjectUtils.nullSafeEquals(this.constructorArgumentValues, that.constructorArgumentValues) &&
|
||||
ObjectUtils.nullSafeEquals(this.propertyValues, that.propertyValues) &&
|
||||
equalsConstructorArgumentValues(that) &&
|
||||
equalsPropertyValues(that) &&
|
||||
ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides) &&
|
||||
ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName) &&
|
||||
ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName) &&
|
||||
@@ -1208,12 +1208,30 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
super.equals(other));
|
||||
}
|
||||
|
||||
private boolean equalsConstructorArgumentValues(AbstractBeanDefinition other) {
|
||||
if (!hasConstructorArgumentValues()) {
|
||||
return !other.hasConstructorArgumentValues();
|
||||
}
|
||||
return ObjectUtils.nullSafeEquals(this.constructorArgumentValues, other.constructorArgumentValues);
|
||||
}
|
||||
|
||||
private boolean equalsPropertyValues(AbstractBeanDefinition other) {
|
||||
if (!hasPropertyValues()) {
|
||||
return !other.hasPropertyValues();
|
||||
}
|
||||
return ObjectUtils.nullSafeEquals(this.propertyValues, other.propertyValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = ObjectUtils.nullSafeHashCode(getBeanClassName());
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.scope);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.constructorArgumentValues);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.propertyValues);
|
||||
if (hasConstructorArgumentValues()) {
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.constructorArgumentValues);
|
||||
}
|
||||
if (hasPropertyValues()) {
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.propertyValues);
|
||||
}
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryBeanName);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryMethodName);
|
||||
hashCode = 29 * hashCode + super.hashCode();
|
||||
|
||||
+12
-7
@@ -250,7 +250,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
throws BeansException {
|
||||
|
||||
String beanName = transformedBeanName(name);
|
||||
Object bean;
|
||||
Object beanInstance;
|
||||
|
||||
// Eagerly check singleton cache for manually registered singletons.
|
||||
Object sharedInstance = getSingleton(beanName);
|
||||
@@ -264,7 +264,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
|
||||
}
|
||||
}
|
||||
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
|
||||
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
|
||||
}
|
||||
|
||||
else {
|
||||
@@ -342,7 +342,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
throw ex;
|
||||
}
|
||||
});
|
||||
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
|
||||
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
|
||||
}
|
||||
|
||||
else if (mbd.isPrototype()) {
|
||||
@@ -355,7 +355,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
finally {
|
||||
afterPrototypeCreation(beanName);
|
||||
}
|
||||
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
|
||||
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
|
||||
}
|
||||
|
||||
else {
|
||||
@@ -377,7 +377,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
afterPrototypeCreation(beanName);
|
||||
}
|
||||
});
|
||||
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
|
||||
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw new ScopeNotActiveException(beanName, scopeName, ex);
|
||||
@@ -395,14 +395,19 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
}
|
||||
}
|
||||
|
||||
return adaptBeanInstance(name, beanInstance, requiredType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> T adaptBeanInstance(String name, Object bean, @Nullable Class<?> requiredType) {
|
||||
// Check if required type matches the type of the actual bean instance.
|
||||
if (requiredType != null && !requiredType.isInstance(bean)) {
|
||||
try {
|
||||
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
|
||||
Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
|
||||
if (convertedBean == null) {
|
||||
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
|
||||
}
|
||||
return convertedBean;
|
||||
return (T) convertedBean;
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
|
||||
+6
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,6 +35,7 @@ import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodInterceptor;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.cglib.proxy.NoOp;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -244,8 +245,10 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
return (bean.equals(null) ? null : bean);
|
||||
}
|
||||
else {
|
||||
return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
|
||||
this.owner.getBean(method.getReturnType()));
|
||||
// Find target bean matching the (potentially generic) method return type
|
||||
ResolvableType genericReturnType = ResolvableType.forMethodReturnType(method);
|
||||
return (argsToUse != null ? this.owner.getBeanProvider(genericReturnType).getObject(argsToUse) :
|
||||
this.owner.getBeanProvider(genericReturnType).getObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -67,6 +67,7 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Delegate for resolving constructors and factory methods.
|
||||
*
|
||||
* <p>Performs constructor resolution through argument matching.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
@@ -85,7 +86,7 @@ class ConstructorResolver {
|
||||
private static final Object[] EMPTY_ARGS = new Object[0];
|
||||
|
||||
/**
|
||||
* Marker for autowired arguments in a cached argument array, to be later replaced
|
||||
* Marker for autowired arguments in a cached argument array, to be replaced
|
||||
* by a {@linkplain #resolveAutowiredArgument resolved autowired argument}.
|
||||
*/
|
||||
private static final Object autowiredArgumentMarker = new Object();
|
||||
@@ -149,7 +150,7 @@ class ConstructorResolver {
|
||||
}
|
||||
}
|
||||
if (argsToResolve != null) {
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,6 +411,7 @@ class ConstructorResolver {
|
||||
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
|
||||
throw new ImplicitlyAppearedSingletonException();
|
||||
}
|
||||
this.beanFactory.registerDependentBean(factoryBeanName, beanName);
|
||||
factoryClass = factoryBean.getClass();
|
||||
isStatic = false;
|
||||
}
|
||||
@@ -444,7 +446,7 @@ class ConstructorResolver {
|
||||
}
|
||||
}
|
||||
if (argsToResolve != null) {
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -816,7 +818,7 @@ class ConstructorResolver {
|
||||
* Resolve the prepared arguments stored in the given bean definition.
|
||||
*/
|
||||
private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
|
||||
Executable executable, Object[] argsToResolve, boolean fallback) {
|
||||
Executable executable, Object[] argsToResolve) {
|
||||
|
||||
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
|
||||
TypeConverter converter = (customConverter != null ? customConverter : bw);
|
||||
@@ -829,7 +831,7 @@ class ConstructorResolver {
|
||||
Object argValue = argsToResolve[argIndex];
|
||||
MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex);
|
||||
if (argValue == autowiredArgumentMarker) {
|
||||
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, fallback);
|
||||
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, true);
|
||||
}
|
||||
else if (argValue instanceof BeanMetadataElement) {
|
||||
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
|
||||
|
||||
+17
-4
@@ -1231,8 +1231,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
|
||||
if (candidateNames.length == 1) {
|
||||
String beanName = candidateNames[0];
|
||||
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
|
||||
return resolveNamedBean(candidateNames[0], requiredType, args);
|
||||
}
|
||||
else if (candidateNames.length > 1) {
|
||||
Map<String, Object> candidates = CollectionUtils.newLinkedHashMap(candidateNames.length);
|
||||
@@ -1251,8 +1250,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
if (candidateName != null) {
|
||||
Object beanInstance = candidates.get(candidateName);
|
||||
if (beanInstance == null || beanInstance instanceof Class) {
|
||||
beanInstance = getBean(candidateName, requiredType.toClass(), args);
|
||||
if (beanInstance == null) {
|
||||
return null;
|
||||
}
|
||||
if (beanInstance instanceof Class) {
|
||||
return resolveNamedBean(candidateName, requiredType, args);
|
||||
}
|
||||
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
|
||||
}
|
||||
@@ -1264,6 +1266,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T> NamedBeanHolder<T> resolveNamedBean(
|
||||
String beanName, ResolvableType requiredType, @Nullable Object[] args) throws BeansException {
|
||||
|
||||
Object bean = getBean(beanName, null, args);
|
||||
if (bean instanceof NullBean) {
|
||||
return null;
|
||||
}
|
||||
return new NamedBeanHolder<T>(beanName, adaptBeanInstance(beanName, bean, requiredType.toClass()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
|
||||
|
||||
+75
-74
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -119,14 +119,16 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
}
|
||||
}
|
||||
else {
|
||||
Class<?>[] paramTypes = destroyMethod.getParameterTypes();
|
||||
if (paramTypes.length > 1) {
|
||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||
beanName + "' has more than one parameter - not supported as destroy method");
|
||||
}
|
||||
else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
|
||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||
beanName + "' has a non-boolean parameter - not supported as destroy method");
|
||||
if (destroyMethod.getParameterCount() > 0) {
|
||||
Class<?>[] paramTypes = destroyMethod.getParameterTypes();
|
||||
if (paramTypes.length > 1) {
|
||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||
beanName + "' has more than one parameter - not supported as destroy method");
|
||||
}
|
||||
else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
|
||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||
beanName + "' has a non-boolean parameter - not supported as destroy method");
|
||||
}
|
||||
}
|
||||
destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);
|
||||
}
|
||||
@@ -170,66 +172,6 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the current value of the given beanDefinition's "destroyMethodName" property is
|
||||
* {@link AbstractBeanDefinition#INFER_METHOD}, then attempt to infer a destroy method.
|
||||
* Candidate methods are currently limited to public, no-arg methods named "close" or
|
||||
* "shutdown" (whether declared locally or inherited). The given BeanDefinition's
|
||||
* "destroyMethodName" is updated to be null if no such method is found, otherwise set
|
||||
* to the name of the inferred method. This constant serves as the default for the
|
||||
* {@code @Bean#destroyMethod} attribute and the value of the constant may also be
|
||||
* used in XML within the {@code <bean destroy-method="">} or {@code
|
||||
* <beans default-destroy-method="">} attributes.
|
||||
* <p>Also processes the {@link java.io.Closeable} and {@link java.lang.AutoCloseable}
|
||||
* interfaces, reflectively calling the "close" method on implementing beans as well.
|
||||
*/
|
||||
@Nullable
|
||||
private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
|
||||
String destroyMethodName = beanDefinition.getDestroyMethodName();
|
||||
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
|
||||
(destroyMethodName == null && bean instanceof AutoCloseable)) {
|
||||
// Only perform destroy method inference or Closeable detection
|
||||
// in case of the bean not explicitly implementing DisposableBean
|
||||
if (!(bean instanceof DisposableBean)) {
|
||||
try {
|
||||
return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
try {
|
||||
return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
|
||||
}
|
||||
catch (NoSuchMethodException ex2) {
|
||||
// no candidate destroy method found
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for all DestructionAwareBeanPostProcessors in the List.
|
||||
* @param processors the List to search
|
||||
* @return the filtered List of DestructionAwareBeanPostProcessors
|
||||
*/
|
||||
@Nullable
|
||||
private List<DestructionAwareBeanPostProcessor> filterPostProcessors(
|
||||
List<DestructionAwareBeanPostProcessor> processors, Object bean) {
|
||||
|
||||
List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
|
||||
if (!CollectionUtils.isEmpty(processors)) {
|
||||
filteredPostProcessors = new ArrayList<>(processors.size());
|
||||
for (DestructionAwareBeanPostProcessor processor : processors) {
|
||||
if (processor.requiresDestruction(bean)) {
|
||||
filteredPostProcessors.add(processor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return filteredPostProcessors;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
destroy();
|
||||
@@ -384,12 +326,50 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
|
||||
return true;
|
||||
}
|
||||
String destroyMethodName = beanDefinition.getDestroyMethodName();
|
||||
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) {
|
||||
return (ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME) ||
|
||||
ClassUtils.hasMethod(bean.getClass(), SHUTDOWN_METHOD_NAME));
|
||||
return inferDestroyMethodIfNecessary(bean, beanDefinition) != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the current value of the given beanDefinition's "destroyMethodName" property is
|
||||
* {@link AbstractBeanDefinition#INFER_METHOD}, then attempt to infer a destroy method.
|
||||
* Candidate methods are currently limited to public, no-arg methods named "close" or
|
||||
* "shutdown" (whether declared locally or inherited). The given BeanDefinition's
|
||||
* "destroyMethodName" is updated to be null if no such method is found, otherwise set
|
||||
* to the name of the inferred method. This constant serves as the default for the
|
||||
* {@code @Bean#destroyMethod} attribute and the value of the constant may also be
|
||||
* used in XML within the {@code <bean destroy-method="">} or {@code
|
||||
* <beans default-destroy-method="">} attributes.
|
||||
* <p>Also processes the {@link java.io.Closeable} and {@link java.lang.AutoCloseable}
|
||||
* interfaces, reflectively calling the "close" method on implementing beans as well.
|
||||
*/
|
||||
@Nullable
|
||||
private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
|
||||
String destroyMethodName = beanDefinition.resolvedDestroyMethodName;
|
||||
if (destroyMethodName == null) {
|
||||
destroyMethodName = beanDefinition.getDestroyMethodName();
|
||||
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
|
||||
(destroyMethodName == null && bean instanceof AutoCloseable)) {
|
||||
// Only perform destroy method inference or Closeable detection
|
||||
// in case of the bean not explicitly implementing DisposableBean
|
||||
destroyMethodName = null;
|
||||
if (!(bean instanceof DisposableBean)) {
|
||||
try {
|
||||
destroyMethodName = bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
try {
|
||||
destroyMethodName = bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
|
||||
}
|
||||
catch (NoSuchMethodException ex2) {
|
||||
// no candidate destroy method found
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : "");
|
||||
}
|
||||
return StringUtils.hasLength(destroyMethodName);
|
||||
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -408,4 +388,25 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for all DestructionAwareBeanPostProcessors in the List.
|
||||
* @param processors the List to search
|
||||
* @return the filtered List of DestructionAwareBeanPostProcessors
|
||||
*/
|
||||
@Nullable
|
||||
private static List<DestructionAwareBeanPostProcessor> filterPostProcessors(
|
||||
List<DestructionAwareBeanPostProcessor> processors, Object bean) {
|
||||
|
||||
List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
|
||||
if (!CollectionUtils.isEmpty(processors)) {
|
||||
filteredPostProcessors = new ArrayList<>(processors.size());
|
||||
for (DestructionAwareBeanPostProcessor processor : processors) {
|
||||
if (processor.requiresDestruction(bean)) {
|
||||
filteredPostProcessors.add(processor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return filteredPostProcessors;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2021 the original author 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,17 +19,25 @@ package org.springframework.beans.factory.support;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Represents an override of a method that looks up an object in the same IoC context.
|
||||
* Represents an override of a method that looks up an object in the same IoC context,
|
||||
* either by bean name or by bean type (based on the declared method return type).
|
||||
*
|
||||
* <p>Methods eligible for lookup override must not have arguments.
|
||||
* <p>Methods eligible for lookup override may declare arguments in which case the
|
||||
* given arguments are passed to the bean retrieval operation.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean(String)
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean(Class)
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean(String, Object...)
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean(Class, Object...)
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBeanProvider(ResolvableType)
|
||||
*/
|
||||
public class LookupOverride extends MethodOverride {
|
||||
|
||||
@@ -43,8 +51,8 @@ public class LookupOverride extends MethodOverride {
|
||||
/**
|
||||
* Construct a new LookupOverride.
|
||||
* @param methodName the name of the method to override
|
||||
* @param beanName the name of the bean in the current {@code BeanFactory}
|
||||
* that the overridden method should return (may be {@code null})
|
||||
* @param beanName the name of the bean in the current {@code BeanFactory} that the
|
||||
* overridden method should return (may be {@code null} for type-based bean retrieval)
|
||||
*/
|
||||
public LookupOverride(String methodName, @Nullable String beanName) {
|
||||
super(methodName);
|
||||
@@ -53,9 +61,9 @@ public class LookupOverride extends MethodOverride {
|
||||
|
||||
/**
|
||||
* Construct a new LookupOverride.
|
||||
* @param method the method to override
|
||||
* @param beanName the name of the bean in the current {@code BeanFactory}
|
||||
* that the overridden method should return (may be {@code null})
|
||||
* @param method the method declaration to override
|
||||
* @param beanName the name of the bean in the current {@code BeanFactory} that the
|
||||
* overridden method should return (may be {@code null} for type-based bean retrieval)
|
||||
*/
|
||||
public LookupOverride(Method method, @Nullable String beanName) {
|
||||
super(method.getName());
|
||||
|
||||
+3
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2021 the original author 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,9 +19,8 @@ package org.springframework.beans.factory.support;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by classes that can reimplement any method
|
||||
* on an IoC-managed object: the <b>Method Injection</b> form of
|
||||
* Dependency Injection.
|
||||
* Interface to be implemented by classes that can reimplement any method on an
|
||||
* IoC-managed object: the <b>Method Injection</b> form of Dependency Injection.
|
||||
*
|
||||
* <p>Such methods may be (but need not be) abstract, in which case the
|
||||
* container will create a concrete subclass to instantiate.
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,7 +25,7 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Extension of MethodOverride that represents an arbitrary
|
||||
* Extension of {@link MethodOverride} that represents an arbitrary
|
||||
* override of a method by the IoC container.
|
||||
*
|
||||
* <p>Any non-final method can be overridden, irrespective of its
|
||||
@@ -45,7 +45,7 @@ public class ReplaceOverride extends MethodOverride {
|
||||
/**
|
||||
* Construct a new ReplaceOverride.
|
||||
* @param methodName the name of the method to override
|
||||
* @param methodReplacerBeanName the bean name of the MethodReplacer
|
||||
* @param methodReplacerBeanName the bean name of the {@link MethodReplacer}
|
||||
*/
|
||||
public ReplaceOverride(String methodName, String methodReplacerBeanName) {
|
||||
super(methodName);
|
||||
|
||||
+5
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -86,6 +86,10 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
@Nullable
|
||||
volatile Method factoryMethodToIntrospect;
|
||||
|
||||
/** Package-visible field for caching a resolved destroy method name (also for inferred). */
|
||||
@Nullable
|
||||
volatile String resolvedDestroyMethodName;
|
||||
|
||||
/** Common lock for the four constructor fields below. */
|
||||
final Object constructorArgumentLock = new Object();
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,9 +23,9 @@ import org.springframework.util.StringUtils;
|
||||
/**
|
||||
* Editor for {@code java.util.Locale}, to directly populate a Locale property.
|
||||
*
|
||||
* <p>Expects the same syntax as Locale's {@code toString}, i.e. language +
|
||||
* <p>Expects the same syntax as Locale's {@code toString()}, i.e. language +
|
||||
* optionally country + optionally variant, separated by "_" (e.g. "en", "en_US").
|
||||
* Also accepts spaces as separators, as alternative to underscores.
|
||||
* Also accepts spaces as separators, as an alternative to underscores.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 26.05.2003
|
||||
|
||||
+11
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,8 +26,8 @@ import java.nio.file.Paths;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceEditor;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
/**
|
||||
* Editor for {@code java.nio.file.Path}, to directly populate a Path
|
||||
@@ -74,7 +74,7 @@ public class PathEditor extends PropertyEditorSupport {
|
||||
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
boolean nioPathCandidate = !text.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX);
|
||||
boolean nioPathCandidate = !text.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX);
|
||||
if (nioPathCandidate && !text.startsWith("/")) {
|
||||
try {
|
||||
URI uri = new URI(text);
|
||||
@@ -85,9 +85,13 @@ public class PathEditor extends PropertyEditorSupport {
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (URISyntaxException | FileSystemNotFoundException ex) {
|
||||
// Not a valid URI (let's try as Spring resource location),
|
||||
// or a URI scheme not registered for NIO (let's try URL
|
||||
catch (URISyntaxException ex) {
|
||||
// Not a valid URI; potentially a Windows-style path after
|
||||
// a file prefix (let's try as Spring resource location)
|
||||
nioPathCandidate = !text.startsWith(ResourceUtils.FILE_URL_PREFIX);
|
||||
}
|
||||
catch (FileSystemNotFoundException ex) {
|
||||
// URI scheme not registered for NIO (let's try URL
|
||||
// protocol handlers via Spring's resource mechanism).
|
||||
}
|
||||
}
|
||||
@@ -97,7 +101,7 @@ public class PathEditor extends PropertyEditorSupport {
|
||||
if (resource == null) {
|
||||
setValue(null);
|
||||
}
|
||||
else if (!resource.exists() && nioPathCandidate) {
|
||||
else if (nioPathCandidate && !resource.exists()) {
|
||||
setValue(Paths.get(text).normalize());
|
||||
}
|
||||
else {
|
||||
|
||||
+4
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,8 +44,6 @@ public class PropertyComparator<T> implements Comparator<T> {
|
||||
|
||||
private final SortDefinition sortDefinition;
|
||||
|
||||
private final BeanWrapperImpl beanWrapper = new BeanWrapperImpl(false);
|
||||
|
||||
|
||||
/**
|
||||
* Create a new PropertyComparator for the given SortDefinition.
|
||||
@@ -115,8 +113,9 @@ public class PropertyComparator<T> implements Comparator<T> {
|
||||
// (similar to JSTL EL). If the property doesn't exist in the
|
||||
// first place, let the exception through.
|
||||
try {
|
||||
this.beanWrapper.setWrappedInstance(obj);
|
||||
return this.beanWrapper.getPropertyValue(this.sortDefinition.getProperty());
|
||||
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(false);
|
||||
beanWrapper.setWrappedInstance(obj);
|
||||
return beanWrapper.getPropertyValue(this.sortDefinition.getProperty());
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
logger.debug("PropertyComparator could not access property - treating as null for sorting", ex);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author 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,12 +19,16 @@ package org.springframework.beans;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -196,6 +200,29 @@ class BeanUtilsTests {
|
||||
assertThat(longListHolder.getList()).isEmpty();
|
||||
}
|
||||
|
||||
@Test // gh-26531
|
||||
void copyPropertiesIgnoresGenericsIfSourceOrTargetHasUnresolvableGenerics() throws Exception {
|
||||
Order original = new Order("test", Arrays.asList("foo", "bar"));
|
||||
|
||||
// Create a Proxy that loses the generic type information for the getLineItems() method.
|
||||
OrderSummary proxy = proxyOrder(original);
|
||||
assertThat(OrderSummary.class.getDeclaredMethod("getLineItems").toGenericString())
|
||||
.contains("java.util.List<java.lang.String>");
|
||||
assertThat(proxy.getClass().getDeclaredMethod("getLineItems").toGenericString())
|
||||
.contains("java.util.List")
|
||||
.doesNotContain("<java.lang.String>");
|
||||
|
||||
// Ensure that our custom Proxy works as expected.
|
||||
assertThat(proxy.getId()).isEqualTo("test");
|
||||
assertThat(proxy.getLineItems()).containsExactly("foo", "bar");
|
||||
|
||||
// Copy from proxy to target.
|
||||
Order target = new Order();
|
||||
BeanUtils.copyProperties(proxy, target);
|
||||
assertThat(target.getId()).isEqualTo("test");
|
||||
assertThat(target.getLineItems()).containsExactly("foo", "bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void copyPropertiesWithEditable() throws Exception {
|
||||
TestBean tb = new TestBean();
|
||||
@@ -633,4 +660,77 @@ class BeanUtilsTests {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class Order {
|
||||
|
||||
private String id;
|
||||
private List<String> lineItems;
|
||||
|
||||
|
||||
Order() {
|
||||
}
|
||||
|
||||
Order(String id, List<String> lineItems) {
|
||||
this.id = id;
|
||||
this.lineItems = lineItems;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<String> getLineItems() {
|
||||
return this.lineItems;
|
||||
}
|
||||
|
||||
public void setLineItems(List<String> lineItems) {
|
||||
this.lineItems = lineItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Order [id=" + this.id + ", lineItems=" + this.lineItems + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private interface OrderSummary {
|
||||
|
||||
String getId();
|
||||
|
||||
List<String> getLineItems();
|
||||
}
|
||||
|
||||
|
||||
private OrderSummary proxyOrder(Order order) {
|
||||
return (OrderSummary) Proxy.newProxyInstance(getClass().getClassLoader(),
|
||||
new Class<?>[] { OrderSummary.class }, new OrderInvocationHandler(order));
|
||||
}
|
||||
|
||||
|
||||
private static class OrderInvocationHandler implements InvocationHandler {
|
||||
|
||||
private final Order order;
|
||||
|
||||
|
||||
OrderInvocationHandler(Order order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
try {
|
||||
// Ignore args since OrderSummary doesn't declare any methods with arguments,
|
||||
// and we're not supporting equals(Object), etc.
|
||||
return Order.class.getDeclaredMethod(method.getName()).invoke(this.order);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw ex.getTargetException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+46
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,6 +28,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
/**
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class BeanWrapperAutoGrowingTests {
|
||||
|
||||
@@ -66,11 +67,6 @@ public class BeanWrapperAutoGrowingTests {
|
||||
assertThat(bean.getArray()[0]).isInstanceOf(Bean.class);
|
||||
}
|
||||
|
||||
private void assertNotNull(Object propertyValue) {
|
||||
assertThat(propertyValue).isNotNull();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void setPropertyValueAutoGrowArray() {
|
||||
wrapper.setPropertyValue("array[0].prop", "test");
|
||||
@@ -93,12 +89,39 @@ public class BeanWrapperAutoGrowingTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPropertyValueAutoGrowMultiDimensionalArray() {
|
||||
public void getPropertyValueAutoGrow2dArray() {
|
||||
assertNotNull(wrapper.getPropertyValue("multiArray[0][0]"));
|
||||
assertThat(bean.getMultiArray()[0].length).isEqualTo(1);
|
||||
assertThat(bean.getMultiArray()[0][0]).isInstanceOf(Bean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPropertyValueAutoGrow3dArray() {
|
||||
assertNotNull(wrapper.getPropertyValue("threeDimensionalArray[1][2][3]"));
|
||||
assertThat(bean.getThreeDimensionalArray()[1].length).isEqualTo(3);
|
||||
assertThat(bean.getThreeDimensionalArray()[1][2][3]).isInstanceOf(Bean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPropertyValueAutoGrow2dArray() {
|
||||
Bean newBean = new Bean();
|
||||
newBean.setProp("enigma");
|
||||
wrapper.setPropertyValue("multiArray[2][3]", newBean);
|
||||
assertThat(bean.getMultiArray()[2][3])
|
||||
.isInstanceOf(Bean.class)
|
||||
.extracting(Bean::getProp).isEqualTo("enigma");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPropertyValueAutoGrow3dArray() {
|
||||
Bean newBean = new Bean();
|
||||
newBean.setProp("enigma");
|
||||
wrapper.setPropertyValue("threeDimensionalArray[2][3][4]", newBean);
|
||||
assertThat(bean.getThreeDimensionalArray()[2][3][4])
|
||||
.isInstanceOf(Bean.class)
|
||||
.extracting(Bean::getProp).isEqualTo("enigma");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPropertyValueAutoGrowList() {
|
||||
assertNotNull(wrapper.getPropertyValue("list[0]"));
|
||||
@@ -131,7 +154,7 @@ public class BeanWrapperAutoGrowingTests {
|
||||
public void getPropertyValueAutoGrowListFailsAgainstLimit() {
|
||||
wrapper.setAutoGrowCollectionLimit(2);
|
||||
assertThatExceptionOfType(InvalidPropertyException.class).isThrownBy(() ->
|
||||
assertNotNull(wrapper.getPropertyValue("list[4]")))
|
||||
wrapper.getPropertyValue("list[4]"))
|
||||
.withRootCauseInstanceOf(IndexOutOfBoundsException.class);
|
||||
}
|
||||
|
||||
@@ -161,6 +184,11 @@ public class BeanWrapperAutoGrowingTests {
|
||||
}
|
||||
|
||||
|
||||
private static void assertNotNull(Object propertyValue) {
|
||||
assertThat(propertyValue).isNotNull();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static class Bean {
|
||||
|
||||
@@ -174,6 +202,8 @@ public class BeanWrapperAutoGrowingTests {
|
||||
|
||||
private Bean[][] multiArray;
|
||||
|
||||
private Bean[][][] threeDimensionalArray;
|
||||
|
||||
private List<Bean> list;
|
||||
|
||||
private List<List<Bean>> multiList;
|
||||
@@ -214,6 +244,14 @@ public class BeanWrapperAutoGrowingTests {
|
||||
this.multiArray = multiArray;
|
||||
}
|
||||
|
||||
public Bean[][][] getThreeDimensionalArray() {
|
||||
return threeDimensionalArray;
|
||||
}
|
||||
|
||||
public void setThreeDimensionalArray(Bean[][][] threeDimensionalArray) {
|
||||
this.threeDimensionalArray = threeDimensionalArray;
|
||||
}
|
||||
|
||||
public List<Bean> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
+11
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,14 +18,14 @@ package org.springframework.beans;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.RepeatedTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -36,23 +36,21 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Chris Beams
|
||||
* @since 08.03.2004
|
||||
*/
|
||||
public class ConcurrentBeanWrapperTests {
|
||||
class ConcurrentBeanWrapperTests {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private Set<TestRun> set = Collections.synchronizedSet(new HashSet<TestRun>());
|
||||
private final Set<TestRun> set = ConcurrentHashMap.newKeySet();
|
||||
|
||||
private Throwable ex = null;
|
||||
|
||||
@Test
|
||||
public void testSingleThread() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
performSet();
|
||||
}
|
||||
@RepeatedTest(100)
|
||||
void testSingleThread() {
|
||||
performSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcurrent() {
|
||||
void testConcurrent() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
TestRun run = new TestRun(this);
|
||||
set.add(run);
|
||||
@@ -82,7 +80,7 @@ public class ConcurrentBeanWrapperTests {
|
||||
|
||||
Properties p = (Properties) System.getProperties().clone();
|
||||
|
||||
assertThat(p.size() != 0).as("The System properties must not be empty").isTrue();
|
||||
assertThat(p).as("The System properties must not be empty").isNotEmpty();
|
||||
|
||||
for (Iterator<?> i = p.entrySet().iterator(); i.hasNext();) {
|
||||
i.next();
|
||||
@@ -111,7 +109,7 @@ public class ConcurrentBeanWrapperTests {
|
||||
|
||||
private ConcurrentBeanWrapperTests test;
|
||||
|
||||
public TestRun(ConcurrentBeanWrapperTests test) {
|
||||
TestRun(ConcurrentBeanWrapperTests test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
|
||||
+16
-11
@@ -63,9 +63,8 @@ public class BeanFactoryUtilsTests {
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
public void setup() {
|
||||
// Interesting hierarchical factory to test counts.
|
||||
// Slow to read so we cache it.
|
||||
|
||||
DefaultListableBeanFactory grandParent = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(grandParent).loadBeanDefinitions(ROOT_CONTEXT);
|
||||
@@ -93,7 +92,7 @@ public class BeanFactoryUtilsTests {
|
||||
* Check that override doesn't count as two separate beans.
|
||||
*/
|
||||
@Test
|
||||
public void testHierarchicalCountBeansWithOverride() throws Exception {
|
||||
public void testHierarchicalCountBeansWithOverride() {
|
||||
// Leaf count
|
||||
assertThat(this.listableBeanFactory.getBeanDefinitionCount() == 1).isTrue();
|
||||
// Count minus duplicate
|
||||
@@ -101,14 +100,14 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesWithNoMatch() throws Exception {
|
||||
public void testHierarchicalNamesWithNoMatch() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, NoOp.class));
|
||||
assertThat(names.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesWithMatchOnlyInRoot() throws Exception {
|
||||
public void testHierarchicalNamesWithMatchOnlyInRoot() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, IndexedTestBean.class));
|
||||
assertThat(names.size()).isEqualTo(1);
|
||||
@@ -118,7 +117,7 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanNamesForTypeWithOverride() throws Exception {
|
||||
public void testGetBeanNamesForTypeWithOverride() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class));
|
||||
// includes 2 TestBeans from FactoryBeans (DummyFactory definitions)
|
||||
@@ -236,7 +235,7 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalResolutionWithOverride() throws Exception {
|
||||
public void testHierarchicalResolutionWithOverride() {
|
||||
Object test3 = this.listableBeanFactory.getBean("test3");
|
||||
Object test = this.listableBeanFactory.getBean("test");
|
||||
|
||||
@@ -276,14 +275,14 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesForAnnotationWithNoMatch() throws Exception {
|
||||
public void testHierarchicalNamesForAnnotationWithNoMatch() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, Override.class));
|
||||
assertThat(names.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() throws Exception {
|
||||
public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, TestAnnotation.class));
|
||||
assertThat(names.size()).isEqualTo(1);
|
||||
@@ -293,7 +292,7 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanNamesForAnnotationWithOverride() throws Exception {
|
||||
public void testGetBeanNamesForAnnotationWithOverride() {
|
||||
AnnotatedBean annotatedBean = new AnnotatedBean();
|
||||
this.listableBeanFactory.registerSingleton("anotherAnnotatedBean", annotatedBean);
|
||||
List<String> names = Arrays.asList(
|
||||
@@ -433,6 +432,7 @@ public class BeanFactoryUtilsTests {
|
||||
String basePackage() default "";
|
||||
}
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@ControllerAdvice
|
||||
@interface RestControllerAdvice {
|
||||
@@ -444,18 +444,23 @@ public class BeanFactoryUtilsTests {
|
||||
String basePackage() default "";
|
||||
}
|
||||
|
||||
|
||||
@ControllerAdvice("com.example")
|
||||
static class ControllerAdviceClass {
|
||||
}
|
||||
|
||||
|
||||
@RestControllerAdvice("com.example")
|
||||
static class RestControllerAdviceClass {
|
||||
}
|
||||
|
||||
|
||||
static class TestBeanSmartFactoryBean implements SmartFactoryBean<TestBean> {
|
||||
|
||||
private final TestBean testBean = new TestBean("enigma", 42);
|
||||
|
||||
private final boolean singleton;
|
||||
|
||||
private final boolean prototype;
|
||||
|
||||
TestBeanSmartFactoryBean(boolean singleton, boolean prototype) {
|
||||
@@ -478,7 +483,7 @@ public class BeanFactoryUtilsTests {
|
||||
return TestBean.class;
|
||||
}
|
||||
|
||||
public TestBean getObject() throws Exception {
|
||||
public TestBean getObject() {
|
||||
// We don't really care if the actual instance is a singleton or prototype
|
||||
// for the tests that use this factory.
|
||||
return this.testBean;
|
||||
|
||||
+16
-22
@@ -785,12 +785,13 @@ class DefaultListableBeanFactoryTests {
|
||||
factory.registerBeanDefinition("child", childDefinition);
|
||||
factory.registerAlias("parent", "alias");
|
||||
|
||||
TestBean child = (TestBean) factory.getBean("child");
|
||||
TestBean child = factory.getBean("child", TestBean.class);
|
||||
assertThat(child.getName()).isEqualTo(EXPECTED_NAME);
|
||||
assertThat(child.getAge()).isEqualTo(EXPECTED_AGE);
|
||||
Object mergedBeanDefinition2 = factory.getMergedBeanDefinition("child");
|
||||
BeanDefinition mergedBeanDefinition1 = factory.getMergedBeanDefinition("child");
|
||||
BeanDefinition mergedBeanDefinition2 = factory.getMergedBeanDefinition("child");
|
||||
|
||||
assertThat(mergedBeanDefinition2).as("Use cached merged bean definition").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(mergedBeanDefinition1).as("Use cached merged bean definition").isSameAs(mergedBeanDefinition2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1838,8 +1839,7 @@ class DefaultListableBeanFactoryTests {
|
||||
assertThat(factoryBean).as("The FactoryBean should have been registered.").isNotNull();
|
||||
FactoryBeanDependentBean bean = (FactoryBeanDependentBean) lbf.autowire(FactoryBeanDependentBean.class,
|
||||
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
|
||||
Object mergedBeanDefinition2 = bean.getFactoryBean();
|
||||
assertThat(mergedBeanDefinition2).as("The FactoryBeanDependentBean should have been autowired 'by type' with the LazyInitFactory.").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(bean.getFactoryBean()).as("The FactoryBeanDependentBean should have been autowired 'by type' with the LazyInitFactory.").isEqualTo(factoryBean);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2388,8 +2388,7 @@ class DefaultListableBeanFactoryTests {
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount;
|
||||
assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2403,8 +2402,7 @@ class DefaultListableBeanFactoryTests {
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount;
|
||||
assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2419,8 +2417,7 @@ class DefaultListableBeanFactoryTests {
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount;
|
||||
assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2542,14 +2539,15 @@ class DefaultListableBeanFactoryTests {
|
||||
factory.registerBeanDefinition("child", child);
|
||||
|
||||
AbstractBeanDefinition def = (AbstractBeanDefinition) factory.getBeanDefinition("child");
|
||||
Object mergedBeanDefinition2 = def.getScope();
|
||||
assertThat(mergedBeanDefinition2).as("Child 'scope' not overriding parent scope (it must).").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(def.getScope()).as("Child 'scope' not overriding parent scope (it must).").isEqualTo(theChildScope);
|
||||
}
|
||||
|
||||
@Test
|
||||
void scopeInheritanceForChildBeanDefinitions() {
|
||||
String theParentScope = "bonanza!";
|
||||
|
||||
RootBeanDefinition parent = new RootBeanDefinition();
|
||||
parent.setScope("bonanza!");
|
||||
parent.setScope(theParentScope);
|
||||
|
||||
AbstractBeanDefinition child = new ChildBeanDefinition("parent");
|
||||
child.setBeanClass(TestBean.class);
|
||||
@@ -2559,8 +2557,7 @@ class DefaultListableBeanFactoryTests {
|
||||
factory.registerBeanDefinition("child", child);
|
||||
|
||||
BeanDefinition def = factory.getMergedBeanDefinition("child");
|
||||
Object mergedBeanDefinition2 = def.getScope();
|
||||
assertThat(mergedBeanDefinition2).as("Child 'scope' not inherited").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(def.getScope()).as("Child 'scope' not inherited").isEqualTo(theParentScope);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2596,15 +2593,12 @@ class DefaultListableBeanFactoryTests {
|
||||
});
|
||||
lbf.preInstantiateSingletons();
|
||||
TestBean tb = (TestBean) lbf.getBean("test");
|
||||
Object mergedBeanDefinition2 = tb.getName();
|
||||
assertThat(mergedBeanDefinition2).as("Name was set on field by IAPP").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(tb.getName()).as("Name was set on field by IAPP").isEqualTo(nameSetOnField);
|
||||
if (!skipPropertyPopulation) {
|
||||
Object mergedBeanDefinition21 = tb.getAge();
|
||||
assertThat(mergedBeanDefinition21).as("Property value still set").isEqualTo(mergedBeanDefinition21);
|
||||
assertThat(tb.getAge()).as("Property value still set").isEqualTo(ageSetByPropertyValue);
|
||||
}
|
||||
else {
|
||||
Object mergedBeanDefinition21 = tb.getAge();
|
||||
assertThat(mergedBeanDefinition21).as("Property value was NOT set and still has default value").isEqualTo(mergedBeanDefinition21);
|
||||
assertThat(tb.getAge()).as("Property value was NOT set and still has default value").isEqualTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+193
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -297,6 +297,121 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalResourceInjectionWithSingletonRemoval() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(OptionalResourceInjectionBean.class);
|
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", rbd);
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
IndexedTestBean itb = new IndexedTestBean();
|
||||
bf.registerSingleton("indexedTestBean", itb);
|
||||
NestedTestBean ntb1 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean1", ntb1);
|
||||
NestedTestBean ntb2 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
|
||||
bf.destroySingleton("testBean");
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
assertThat(bean.getTestBean4()).isNull();
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
|
||||
bf.registerSingleton("testBean", tb);
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalResourceInjectionWithBeanDefinitionRemoval() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(OptionalResourceInjectionBean.class);
|
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", rbd);
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
IndexedTestBean itb = new IndexedTestBean();
|
||||
bf.registerSingleton("indexedTestBean", itb);
|
||||
NestedTestBean ntb1 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean1", ntb1);
|
||||
NestedTestBean ntb2 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean4()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
|
||||
bf.removeBeanDefinition("testBean");
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
assertThat(bean.getTestBean4()).isNull();
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean4()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalCollectionResourceInjection() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(OptionalCollectionResourceInjectionBean.class);
|
||||
@@ -533,6 +648,83 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorResourceInjectionWithSingletonRemoval() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class);
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
NestedTestBean ntb = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bf.destroySingleton("nestedTestBean");
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isNull();
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorResourceInjectionWithBeanDefinitionRemoval() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class);
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NestedTestBean.class));
|
||||
|
||||
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(bf.getBean("nestedTestBean"));
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bf.removeBeanDefinition("nestedTestBean");
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isNull();
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NestedTestBean.class));
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(bf.getBean("nestedTestBean"));
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorResourceInjectionWithNullFromFactoryBean() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class);
|
||||
|
||||
+35
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -121,6 +121,18 @@ public class LookupAnnotationTests {
|
||||
assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithGenericBean() {
|
||||
beanFactory.registerBeanDefinition("numberBean", new RootBeanDefinition(NumberBean.class));
|
||||
beanFactory.registerBeanDefinition("doubleStore", new RootBeanDefinition(DoubleStore.class));
|
||||
beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
|
||||
|
||||
NumberBean bean = (NumberBean) beanFactory.getBean("numberBean");
|
||||
assertThat(bean).isNotNull();
|
||||
assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
|
||||
assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
|
||||
}
|
||||
|
||||
|
||||
public static abstract class AbstractBean {
|
||||
|
||||
@@ -147,4 +159,26 @@ public class LookupAnnotationTests {
|
||||
AbstractBean abstractBean;
|
||||
}
|
||||
|
||||
|
||||
public static class NumberStore<T extends Number> {
|
||||
}
|
||||
|
||||
|
||||
public static class DoubleStore extends NumberStore<Double> {
|
||||
}
|
||||
|
||||
|
||||
public static class FloatStore extends NumberStore<Float> {
|
||||
}
|
||||
|
||||
|
||||
public static abstract class NumberBean {
|
||||
|
||||
@Lookup
|
||||
public abstract NumberStore<Double> getDoubleStore();
|
||||
|
||||
@Lookup
|
||||
public abstract NumberStore<Float> getFloatStore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+28
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author 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,9 +17,11 @@
|
||||
package org.springframework.beans.factory.config;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.yaml.snakeyaml.constructor.ConstructorException;
|
||||
@@ -28,7 +30,6 @@ import org.yaml.snakeyaml.scanner.ScannerException;
|
||||
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
@@ -39,10 +40,12 @@ import static org.assertj.core.api.Assertions.entry;
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class YamlProcessorTests {
|
||||
|
||||
private final YamlProcessor processor = new YamlProcessor() {};
|
||||
private final YamlProcessor processor = new YamlProcessor() {
|
||||
};
|
||||
|
||||
|
||||
@Test
|
||||
@@ -79,8 +82,8 @@ class YamlProcessorTests {
|
||||
void badResource() {
|
||||
setYaml("foo: bar\ncd\nspam:\n foo: baz");
|
||||
assertThatExceptionOfType(ScannerException.class)
|
||||
.isThrownBy(() -> this.processor.process((properties, map) -> {}))
|
||||
.withMessageContaining("line 3, column 1");
|
||||
.isThrownBy(() -> this.processor.process((properties, map) -> {}))
|
||||
.withMessageContaining("line 3, column 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -127,8 +130,8 @@ class YamlProcessorTests {
|
||||
Map<String, Object> bar = (Map<String, Object>) map.get("bar");
|
||||
assertThat(bar.get("spam")).isEqualTo("bucket");
|
||||
|
||||
List<Object> keysFromProperties = properties.keySet().stream().collect(toList());
|
||||
List<String> keysFromFlattenedMap = flattenedMap.keySet().stream().collect(toList());
|
||||
List<Object> keysFromProperties = new ArrayList<>(properties.keySet());
|
||||
List<String> keysFromFlattenedMap = new ArrayList<>(flattenedMap.keySet());
|
||||
assertThat(keysFromProperties).containsExactlyInAnyOrderElementsOf(keysFromFlattenedMap);
|
||||
// Keys in the Properties object are sorted.
|
||||
assertThat(keysFromProperties).containsExactly("bar.spam", "cat", "foo");
|
||||
@@ -138,14 +141,24 @@ class YamlProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void customTypeSupportedByDefault() throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
void standardTypesSupportedByDefault() throws Exception {
|
||||
setYaml("value: !!set\n ? first\n ? second");
|
||||
this.processor.process((properties, map) -> {
|
||||
assertThat(properties).containsExactly(entry("value[0]", "first"), entry("value[1]", "second"));
|
||||
assertThat(map.get("value")).isInstanceOf(Set.class);
|
||||
Set<String> set = (Set<String>) map.get("value");
|
||||
assertThat(set).containsExactly("first", "second");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customTypeNotSupportedByDefault() throws Exception {
|
||||
URL url = new URL("https://localhost:9000/");
|
||||
setYaml("value: !!java.net.URL [\"" + url + "\"]");
|
||||
|
||||
this.processor.process((properties, map) -> {
|
||||
assertThat(properties).containsExactly(entry("value", url));
|
||||
assertThat(map).containsExactly(entry("value", url));
|
||||
});
|
||||
assertThatExceptionOfType(ConstructorException.class)
|
||||
.isThrownBy(() -> this.processor.process((properties, map) -> {}))
|
||||
.withMessageContaining("Unsupported type encountered in YAML document: java.net.URL");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -168,8 +181,8 @@ class YamlProcessorTests {
|
||||
setYaml("value: !!java.net.URL [\"https://localhost:9000/\"]");
|
||||
|
||||
assertThatExceptionOfType(ConstructorException.class)
|
||||
.isThrownBy(() -> this.processor.process((properties, map) -> {}))
|
||||
.withMessageContaining("Unsupported type encountered in YAML document: java.net.URL");
|
||||
.isThrownBy(() -> this.processor.process((properties, map) -> {}))
|
||||
.withMessageContaining("Unsupported type encountered in YAML document: java.net.URL");
|
||||
}
|
||||
|
||||
private void setYaml(String yaml) {
|
||||
|
||||
+11
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -133,6 +133,16 @@ public class BeanDefinitionTests {
|
||||
assertThat(bd.equals(otherBd)).isTrue();
|
||||
assertThat(otherBd.equals(bd)).isTrue();
|
||||
assertThat(bd.hashCode() == otherBd.hashCode()).isTrue();
|
||||
|
||||
bd.getPropertyValues();
|
||||
assertThat(bd.equals(otherBd)).isTrue();
|
||||
assertThat(otherBd.equals(bd)).isTrue();
|
||||
assertThat(bd.hashCode() == otherBd.hashCode()).isTrue();
|
||||
|
||||
bd.getConstructorArgumentValues();
|
||||
assertThat(bd.equals(otherBd)).isTrue();
|
||||
assertThat(otherBd.equals(bd)).isTrue();
|
||||
assertThat(bd.hashCode() == otherBd.hashCode()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+39
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,7 +36,7 @@ public class LookupMethodTests {
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
public void setup() {
|
||||
beanFactory = new DefaultListableBeanFactory();
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
|
||||
reader.loadBeanDefinitions(new ClassPathResource("lookupMethodTests.xml", getClass()));
|
||||
@@ -83,8 +83,8 @@ public class LookupMethodTests {
|
||||
public void testWithThreeArgsShouldFail() {
|
||||
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
|
||||
assertThat(bean).isNotNull();
|
||||
assertThatExceptionOfType(AbstractMethodError.class).as("does not have a three arg constructor").isThrownBy(() ->
|
||||
bean.getThreeArguments("name", 1, 2));
|
||||
assertThatExceptionOfType(AbstractMethodError.class).as("does not have a three arg constructor")
|
||||
.isThrownBy(() -> bean.getThreeArguments("name", 1, 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -97,6 +97,21 @@ public class LookupMethodTests {
|
||||
assertThat(expected.isJedi()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithGenericBean() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(NumberBean.class);
|
||||
bd.getMethodOverrides().addOverride(new LookupOverride("getDoubleStore", null));
|
||||
bd.getMethodOverrides().addOverride(new LookupOverride("getFloatStore", null));
|
||||
beanFactory.registerBeanDefinition("numberBean", bd);
|
||||
beanFactory.registerBeanDefinition("doubleStore", new RootBeanDefinition(DoubleStore.class));
|
||||
beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
|
||||
|
||||
NumberBean bean = (NumberBean) beanFactory.getBean("numberBean");
|
||||
assertThat(bean).isNotNull();
|
||||
assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
|
||||
assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
|
||||
}
|
||||
|
||||
|
||||
public static abstract class AbstractBean {
|
||||
|
||||
@@ -111,4 +126,24 @@ public class LookupMethodTests {
|
||||
public abstract TestBean getThreeArguments(String name, int age, int anotherArg);
|
||||
}
|
||||
|
||||
|
||||
public static class NumberStore<T extends Number> {
|
||||
}
|
||||
|
||||
|
||||
public static class DoubleStore extends NumberStore<Double> {
|
||||
}
|
||||
|
||||
|
||||
public static class FloatStore extends NumberStore<Float> {
|
||||
}
|
||||
|
||||
|
||||
public static abstract class NumberBean {
|
||||
|
||||
public abstract NumberStore<Double> getDoubleStore();
|
||||
|
||||
public abstract NumberStore<Float> getFloatStore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+41
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author 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,57 +34,78 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
public class PathEditorTests {
|
||||
|
||||
@Test
|
||||
public void testClasspathPathName() throws Exception {
|
||||
public void testClasspathPathName() {
|
||||
PropertyEditor pathEditor = new PathEditor();
|
||||
pathEditor.setAsText("classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + "/" +
|
||||
ClassUtils.getShortName(getClass()) + ".class");
|
||||
Object value = pathEditor.getValue();
|
||||
boolean condition = value instanceof Path;
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(value instanceof Path).isTrue();
|
||||
Path path = (Path) value;
|
||||
assertThat(path.toFile().exists()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithNonExistentResource() throws Exception {
|
||||
public void testWithNonExistentResource() {
|
||||
PropertyEditor propertyEditor = new PathEditor();
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
propertyEditor.setAsText("classpath:/no_way_this_file_is_found.doc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithNonExistentPath() throws Exception {
|
||||
public void testWithNonExistentPath() {
|
||||
PropertyEditor pathEditor = new PathEditor();
|
||||
pathEditor.setAsText("file:/no_way_this_file_is_found.doc");
|
||||
Object value = pathEditor.getValue();
|
||||
boolean condition1 = value instanceof Path;
|
||||
assertThat(condition1).isTrue();
|
||||
assertThat(value instanceof Path).isTrue();
|
||||
Path path = (Path) value;
|
||||
boolean condition = !path.toFile().exists();
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(!path.toFile().exists()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbsolutePath() throws Exception {
|
||||
public void testAbsolutePath() {
|
||||
PropertyEditor pathEditor = new PathEditor();
|
||||
pathEditor.setAsText("/no_way_this_file_is_found.doc");
|
||||
Object value = pathEditor.getValue();
|
||||
boolean condition1 = value instanceof Path;
|
||||
assertThat(condition1).isTrue();
|
||||
assertThat(value instanceof Path).isTrue();
|
||||
Path path = (Path) value;
|
||||
boolean condition = !path.toFile().exists();
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(!path.toFile().exists()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnqualifiedPathNameFound() throws Exception {
|
||||
public void testWindowsAbsolutePath() {
|
||||
PropertyEditor pathEditor = new PathEditor();
|
||||
pathEditor.setAsText("C:\\no_way_this_file_is_found.doc");
|
||||
Object value = pathEditor.getValue();
|
||||
assertThat(value instanceof Path).isTrue();
|
||||
Path path = (Path) value;
|
||||
assertThat(!path.toFile().exists()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindowsAbsoluteFilePath() {
|
||||
PropertyEditor pathEditor = new PathEditor();
|
||||
try {
|
||||
pathEditor.setAsText("file://C:\\no_way_this_file_is_found.doc");
|
||||
Object value = pathEditor.getValue();
|
||||
assertThat(value instanceof Path).isTrue();
|
||||
Path path = (Path) value;
|
||||
assertThat(!path.toFile().exists()).isTrue();
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
if (File.separatorChar == '\\') { // on Windows, otherwise silently ignore
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnqualifiedPathNameFound() {
|
||||
PropertyEditor pathEditor = new PathEditor();
|
||||
String fileName = ClassUtils.classPackageAsResourcePath(getClass()) + "/" +
|
||||
ClassUtils.getShortName(getClass()) + ".class";
|
||||
pathEditor.setAsText(fileName);
|
||||
Object value = pathEditor.getValue();
|
||||
boolean condition = value instanceof Path;
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(value instanceof Path).isTrue();
|
||||
Path path = (Path) value;
|
||||
File file = path.toFile();
|
||||
assertThat(file.exists()).isTrue();
|
||||
@@ -96,14 +117,13 @@ public class PathEditorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnqualifiedPathNameNotFound() throws Exception {
|
||||
public void testUnqualifiedPathNameNotFound() {
|
||||
PropertyEditor pathEditor = new PathEditor();
|
||||
String fileName = ClassUtils.classPackageAsResourcePath(getClass()) + "/" +
|
||||
ClassUtils.getShortName(getClass()) + ".clazz";
|
||||
pathEditor.setAsText(fileName);
|
||||
Object value = pathEditor.getValue();
|
||||
boolean condition = value instanceof Path;
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(value instanceof Path).isTrue();
|
||||
Path path = (Path) value;
|
||||
File file = path.toFile();
|
||||
assertThat(file.exists()).isFalse();
|
||||
|
||||
+4
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,6 @@ package org.springframework.context.index.processor;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -37,7 +36,7 @@ import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
|
||||
/**
|
||||
* Annotation {@link Processor} that writes {@link CandidateComponentsMetadata}
|
||||
* Annotation {@link Processor} that writes a {@link CandidateComponentsMetadata}
|
||||
* file for spring components.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
@@ -46,9 +45,6 @@ import javax.lang.model.element.TypeElement;
|
||||
*/
|
||||
public class CandidateComponentsIndexer implements Processor {
|
||||
|
||||
private static final Set<ElementKind> TYPE_KINDS =
|
||||
Collections.unmodifiableSet(EnumSet.of(ElementKind.CLASS, ElementKind.INTERFACE));
|
||||
|
||||
private MetadataStore metadataStore;
|
||||
|
||||
private MetadataCollector metadataCollector;
|
||||
@@ -136,7 +132,8 @@ public class CandidateComponentsIndexer implements Processor {
|
||||
private static List<TypeElement> staticTypesIn(Iterable<? extends Element> elements) {
|
||||
List<TypeElement> list = new ArrayList<>();
|
||||
for (Element element : elements) {
|
||||
if (TYPE_KINDS.contains(element.getKind()) && element.getModifiers().contains(Modifier.STATIC)) {
|
||||
if ((element.getKind().isClass() || element.getKind() == ElementKind.INTERFACE) &&
|
||||
element.getModifiers().contains(Modifier.STATIC) && element instanceof TypeElement) {
|
||||
list.add((TypeElement) element);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,7 +26,7 @@ import javax.lang.model.element.ElementKind;
|
||||
|
||||
/**
|
||||
* A {@link StereotypesProvider} implementation that extracts the stereotypes
|
||||
* flagged by the {@value INDEXED_ANNOTATION} annotation. This implementation
|
||||
* flagged by the {@value #INDEXED_ANNOTATION} annotation. This implementation
|
||||
* honors stereotypes defined this way on meta-annotations.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
@@ -48,7 +48,7 @@ class IndexedStereotypesProvider implements StereotypesProvider {
|
||||
public Set<String> getStereotypes(Element element) {
|
||||
Set<String> stereotypes = new LinkedHashSet<>();
|
||||
ElementKind kind = element.getKind();
|
||||
if (kind != ElementKind.CLASS && kind != ElementKind.INTERFACE) {
|
||||
if (!kind.isClass() && kind != ElementKind.INTERFACE) {
|
||||
return stereotypes;
|
||||
}
|
||||
Set<Element> seen = new HashSet<>();
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import javax.lang.model.element.ElementKind;
|
||||
|
||||
/**
|
||||
* A {@link StereotypesProvider} implementation that provides the
|
||||
* {@value STEREOTYPE} stereotype for each package-info.
|
||||
* {@value #STEREOTYPE} stereotype for each package-info.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 5.0
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,8 +24,8 @@ import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
|
||||
/**
|
||||
* A {@link StereotypesProvider} that extract a stereotype for each
|
||||
* {@code javax.*} annotation placed on a class or interface.
|
||||
* A {@link StereotypesProvider} that extracts a stereotype for each
|
||||
* {@code javax.*} annotation <i>present</i> on a class or interface.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 5.0
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,7 @@ import javax.lang.model.element.Element;
|
||||
|
||||
/**
|
||||
* Provide the list of stereotypes that match an {@link Element}.
|
||||
* If an element has one more stereotypes, it is referenced in the index
|
||||
* <p>If an element has one or more stereotypes, it is referenced in the index
|
||||
* of candidate components and each stereotype can be queried individually.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -130,8 +130,8 @@ public class EhCacheManagerFactoryBean implements FactoryBean<CacheManager>, Ini
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws CacheException {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Initializing EhCache CacheManager" +
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Initializing EhCache CacheManager" +
|
||||
(this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : ""));
|
||||
}
|
||||
|
||||
@@ -188,8 +188,8 @@ public class EhCacheManagerFactoryBean implements FactoryBean<CacheManager>, Ini
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (this.cacheManager != null && this.locallyManaged) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Shutting down EhCache CacheManager" +
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Shutting down EhCache CacheManager" +
|
||||
(this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : ""));
|
||||
}
|
||||
this.cacheManager.shutdown();
|
||||
|
||||
+8
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2021 the original author 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,7 +31,8 @@ import org.springframework.core.annotation.AliasFor;
|
||||
*
|
||||
* <p>In contrast to the {@link Cacheable @Cacheable} annotation, this annotation
|
||||
* does not cause the advised method to be skipped. Rather, it always causes the
|
||||
* method to be invoked and its result to be stored in the associated cache. Note
|
||||
* method to be invoked and its result to be stored in the associated cache if the
|
||||
* {@link #condition()} and {@link #unless()} expressions match accordingly. Note
|
||||
* that Java8's {@code Optional} return types are automatically handled and its
|
||||
* content is stored in the cache if present.
|
||||
*
|
||||
@@ -118,10 +119,15 @@ public @interface CachePut {
|
||||
/**
|
||||
* Spring Expression Language (SpEL) expression used for making the cache
|
||||
* put operation conditional.
|
||||
* <p>This expression is evaluated after the method has been called due to the
|
||||
* nature of the put operation and can therefore refer to the {@code result}.
|
||||
* <p>Default is {@code ""}, meaning the method result is always cached.
|
||||
* <p>The SpEL expression evaluates against a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #result} for a reference to the result of the method invocation. For
|
||||
* supported wrappers such as {@code Optional}, {@code #result} refers to the actual
|
||||
* object, not the wrapper</li>
|
||||
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
|
||||
* references to the {@link java.lang.reflect.Method method}, target object, and
|
||||
* affected cache(s) respectively.</li>
|
||||
@@ -136,8 +142,6 @@ public @interface CachePut {
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) expression used to veto the cache put operation.
|
||||
* <p>Unlike {@link #condition}, this expression is evaluated after the method
|
||||
* has been called and can therefore refer to the {@code result}.
|
||||
* <p>Default is {@code ""}, meaning that caching is never vetoed.
|
||||
* <p>The SpEL expression evaluates against a dedicated context that provides the
|
||||
* following meta-data:
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -221,11 +221,11 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
}
|
||||
catch (NoUniqueBeanDefinitionException ex) {
|
||||
throw new IllegalStateException("No CacheResolver specified, and no unique bean of type " +
|
||||
"CacheManager found. Mark one as primary or declare a specific CacheManager to use.");
|
||||
"CacheManager found. Mark one as primary or declare a specific CacheManager to use.", ex);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
throw new IllegalStateException("No CacheResolver specified, and no bean of type CacheManager found. " +
|
||||
"Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.");
|
||||
"Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.", ex);
|
||||
}
|
||||
}
|
||||
this.initialized = true;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author 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.context;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
@@ -37,18 +38,37 @@ public abstract class ApplicationEvent extends EventObject {
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code ApplicationEvent}.
|
||||
* Create a new {@code ApplicationEvent} with its {@link #getTimestamp() timestamp}
|
||||
* set to {@link System#currentTimeMillis()}.
|
||||
* @param source the object on which the event initially occurred or with
|
||||
* which the event is associated (never {@code null})
|
||||
* @see #ApplicationEvent(Object, Clock)
|
||||
*/
|
||||
public ApplicationEvent(Object source) {
|
||||
super(source);
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code ApplicationEvent} with its {@link #getTimestamp() timestamp}
|
||||
* set to the value returned by {@link Clock#millis()} in the provided {@link Clock}.
|
||||
* <p>This constructor is typically used in testing scenarios.
|
||||
* @param source the object on which the event initially occurred or with
|
||||
* which the event is associated (never {@code null})
|
||||
* @param clock a clock which will provide the timestamp
|
||||
* @since 5.3.8
|
||||
* @see #ApplicationEvent(Object)
|
||||
*/
|
||||
public ApplicationEvent(Object source, Clock clock) {
|
||||
super(source);
|
||||
this.timestamp = clock.millis();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the system time in milliseconds when the event occurred.
|
||||
* Return the time in milliseconds when the event occurred.
|
||||
* @see #ApplicationEvent(Object)
|
||||
* @see #ApplicationEvent(Object, Clock)
|
||||
*/
|
||||
public final long getTimestamp() {
|
||||
return this.timestamp;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,6 +35,8 @@ import java.util.function.Consumer;
|
||||
* @param <E> the specific {@code ApplicationEvent} subclass to listen to
|
||||
* @see org.springframework.context.ApplicationEvent
|
||||
* @see org.springframework.context.event.ApplicationEventMulticaster
|
||||
* @see org.springframework.context.event.SmartApplicationListener
|
||||
* @see org.springframework.context.event.GenericApplicationListener
|
||||
* @see org.springframework.context.event.EventListener
|
||||
*/
|
||||
@FunctionalInterface
|
||||
|
||||
+6
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.context;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.ResolvableTypeProvider;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -23,11 +25,12 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* An {@link ApplicationEvent} that carries an arbitrary payload.
|
||||
*
|
||||
* <p>Mainly intended for internal use within the framework.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
* @param <T> the payload type of the event
|
||||
* @see ApplicationEventPublisher#publishEvent(Object)
|
||||
* @see ApplicationListener#forPayload(Consumer)
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class PayloadApplicationEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,10 +26,10 @@ import org.springframework.core.io.ResourceLoader;
|
||||
* the {@link org.springframework.context.ApplicationContextAware} interface.
|
||||
*
|
||||
* <p>Note that {@link org.springframework.core.io.Resource} dependencies can also
|
||||
* be exposed as bean properties of type {@code Resource}, populated via Strings
|
||||
* with automatic type conversion by the bean factory. This removes the need for
|
||||
* implementing any callback interface just for the purpose of accessing a
|
||||
* specific file resource.
|
||||
* be exposed as bean properties of type {@code Resource} or {@code Resource[]},
|
||||
* populated via Strings with automatic type conversion by the bean factory. This
|
||||
* removes the need for implementing any callback interface just for the purpose
|
||||
* of accessing specific file resources.
|
||||
*
|
||||
* <p>You typically need a {@link ResourceLoader} when your application object has to
|
||||
* access a variety of file resources whose names are calculated. A good strategy is
|
||||
@@ -48,7 +48,7 @@ import org.springframework.core.io.ResourceLoader;
|
||||
* default; see also the {@code ResourcePatternUtils.getResourcePatternResolver} method.
|
||||
*
|
||||
* <p>As an alternative to a {@code ResourcePatternResolver} dependency, consider
|
||||
* exposing bean properties of type {@code Resource} array, populated via pattern
|
||||
* exposing bean properties of type {@code Resource[]} array, populated via pattern
|
||||
* Strings with automatic type conversion by the bean factory at binding time.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
|
||||
+24
-24
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -52,6 +52,7 @@ import org.springframework.context.ApplicationStartupAware;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration;
|
||||
import org.springframework.core.NativeDetector;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.env.Environment;
|
||||
@@ -74,16 +75,17 @@ import org.springframework.util.ClassUtils;
|
||||
*
|
||||
* <p>Registered by default when using {@code <context:annotation-config/>} or
|
||||
* {@code <context:component-scan/>}. Otherwise, may be declared manually as
|
||||
* with any other BeanFactoryPostProcessor.
|
||||
* with any other {@link BeanFactoryPostProcessor}.
|
||||
*
|
||||
* <p>This post processor is priority-ordered as it is important that any
|
||||
* {@link Bean} methods declared in {@code @Configuration} classes have
|
||||
* {@link Bean @Bean} methods declared in {@code @Configuration} classes have
|
||||
* their corresponding bean definitions registered before any other
|
||||
* {@link BeanFactoryPostProcessor} executes.
|
||||
* {@code BeanFactoryPostProcessor} executes.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
|
||||
@@ -104,13 +106,6 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
private static final String IMPORT_REGISTRY_BEAN_NAME =
|
||||
ConfigurationClassPostProcessor.class.getName() + ".importRegistry";
|
||||
|
||||
/**
|
||||
* Whether this environment lives within a native image.
|
||||
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
|
||||
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
|
||||
*/
|
||||
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
|
||||
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@@ -395,21 +390,30 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
for (String beanName : beanFactory.getBeanDefinitionNames()) {
|
||||
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
|
||||
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
|
||||
AnnotationMetadata annotationMetadata = null;
|
||||
MethodMetadata methodMetadata = null;
|
||||
if (beanDef instanceof AnnotatedBeanDefinition) {
|
||||
methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
|
||||
AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDef;
|
||||
annotationMetadata = annotatedBeanDefinition.getMetadata();
|
||||
methodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
|
||||
}
|
||||
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
|
||||
// Configuration class (full or lite) or a configuration-derived @Bean method
|
||||
// -> resolve bean class at this point...
|
||||
// -> eagerly resolve bean class at this point, unless it's a 'lite' configuration
|
||||
// or component class without @Bean methods.
|
||||
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
|
||||
if (!abd.hasBeanClass()) {
|
||||
try {
|
||||
abd.resolveBeanClass(this.beanClassLoader);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
|
||||
boolean liteConfigurationCandidateWithoutBeanMethods =
|
||||
(ConfigurationClassUtils.CONFIGURATION_CLASS_LITE.equals(configClassAttr) &&
|
||||
annotationMetadata != null && !ConfigurationClassUtils.hasBeanMethods(annotationMetadata));
|
||||
if (!liteConfigurationCandidateWithoutBeanMethods) {
|
||||
try {
|
||||
abd.resolveBeanClass(this.beanClassLoader);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -427,15 +431,11 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
|
||||
}
|
||||
}
|
||||
if (configBeanDefs.isEmpty()) {
|
||||
if (configBeanDefs.isEmpty() || NativeDetector.inNativeImage()) {
|
||||
// nothing to enhance -> return immediately
|
||||
enhanceConfigClasses.end();
|
||||
return;
|
||||
}
|
||||
if (IN_NATIVE_IMAGE) {
|
||||
throw new BeanDefinitionStoreException("@Configuration classes need to be marked as " +
|
||||
"proxyBeanMethods=false. Found: " + configBeanDefs.keySet());
|
||||
}
|
||||
|
||||
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
|
||||
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
|
||||
|
||||
+6
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,6 +46,7 @@ import org.springframework.stereotype.Component;
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
*/
|
||||
abstract class ConfigurationClassUtils {
|
||||
@@ -162,6 +163,10 @@ abstract class ConfigurationClassUtils {
|
||||
}
|
||||
|
||||
// Finally, let's look for @Bean methods...
|
||||
return hasBeanMethods(metadata);
|
||||
}
|
||||
|
||||
static boolean hasBeanMethods(AnnotationMetadata metadata) {
|
||||
try {
|
||||
return metadata.hasAnnotatedMethods(Bean.class.getName());
|
||||
}
|
||||
|
||||
+18
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.aop.framework.AopProxyUtils;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
@@ -137,6 +138,22 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
this.defaultRetriever.applicationListeners.removeIf(predicate);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeApplicationListenerBeans(Predicate<String> predicate) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
this.defaultRetriever.applicationListenerBeans.removeIf(predicate);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllListeners() {
|
||||
synchronized (this.defaultRetriever) {
|
||||
|
||||
+40
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.context.event;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.core.ResolvableType;
|
||||
@@ -39,31 +41,68 @@ public interface ApplicationEventMulticaster {
|
||||
/**
|
||||
* Add a listener to be notified of all events.
|
||||
* @param listener the listener to add
|
||||
* @see #removeApplicationListener(ApplicationListener)
|
||||
* @see #removeApplicationListeners(Predicate)
|
||||
*/
|
||||
void addApplicationListener(ApplicationListener<?> listener);
|
||||
|
||||
/**
|
||||
* Add a listener bean to be notified of all events.
|
||||
* @param listenerBeanName the name of the listener bean to add
|
||||
* @see #removeApplicationListenerBean(String)
|
||||
* @see #removeApplicationListenerBeans(Predicate)
|
||||
*/
|
||||
void addApplicationListenerBean(String listenerBeanName);
|
||||
|
||||
/**
|
||||
* Remove a listener from the notification list.
|
||||
* @param listener the listener to remove
|
||||
* @see #addApplicationListener(ApplicationListener)
|
||||
* @see #removeApplicationListeners(Predicate)
|
||||
*/
|
||||
void removeApplicationListener(ApplicationListener<?> listener);
|
||||
|
||||
/**
|
||||
* Remove a listener bean from the notification list.
|
||||
* @param listenerBeanName the name of the listener bean to remove
|
||||
* @see #addApplicationListenerBean(String)
|
||||
* @see #removeApplicationListenerBeans(Predicate)
|
||||
*/
|
||||
void removeApplicationListenerBean(String listenerBeanName);
|
||||
|
||||
/**
|
||||
* Remove all matching listeners from the set of registered
|
||||
* {@code ApplicationListener} instances (which includes adapter classes
|
||||
* such as {@link ApplicationListenerMethodAdapter}, e.g. for annotated
|
||||
* {@link EventListener} methods).
|
||||
* <p>Note: This just applies to instance registrations, not to listeners
|
||||
* registered by bean name.
|
||||
* @param predicate the predicate to identify listener instances to remove,
|
||||
* e.g. checking {@link SmartApplicationListener#getListenerId()}
|
||||
* @since 5.3.5
|
||||
* @see #addApplicationListener(ApplicationListener)
|
||||
* @see #removeApplicationListener(ApplicationListener)
|
||||
*/
|
||||
void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate);
|
||||
|
||||
/**
|
||||
* Remove all matching listener beans from the set of registered
|
||||
* listener bean names (referring to bean classes which in turn
|
||||
* implement the {@link ApplicationListener} interface directly).
|
||||
* <p>Note: This just applies to bean name registrations, not to
|
||||
* programmatically registered {@code ApplicationListener} instances.
|
||||
* @param predicate the predicate to identify listener bean names to remove
|
||||
* @since 5.3.5
|
||||
* @see #addApplicationListenerBean(String)
|
||||
* @see #removeApplicationListenerBean(String)
|
||||
*/
|
||||
void removeApplicationListenerBeans(Predicate<String> predicate);
|
||||
|
||||
/**
|
||||
* Remove all listeners registered with this multicaster.
|
||||
* <p>After a remove call, the multicaster will perform no action
|
||||
* on event notification until new listeners are registered.
|
||||
* @see #removeApplicationListeners(Predicate)
|
||||
*/
|
||||
void removeAllListeners();
|
||||
|
||||
|
||||
+33
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -89,6 +90,9 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
||||
|
||||
private final int order;
|
||||
|
||||
@Nullable
|
||||
private volatile String listenerId;
|
||||
|
||||
@Nullable
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@@ -113,6 +117,8 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
||||
this.declaredEventTypes = resolveDeclaredEventTypes(method, ann);
|
||||
this.condition = (ann != null ? ann.condition() : null);
|
||||
this.order = resolveOrder(this.targetMethod);
|
||||
String id = (ann != null ? ann.id() : "");
|
||||
this.listenerId = (!id.isEmpty() ? id : null);
|
||||
}
|
||||
|
||||
private static List<ResolvableType> resolveDeclaredEventTypes(Method method, @Nullable EventListener ann) {
|
||||
@@ -186,6 +192,32 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
||||
return this.order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getListenerId() {
|
||||
String id = this.listenerId;
|
||||
if (id == null) {
|
||||
id = getDefaultListenerId();
|
||||
this.listenerId = id;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the default id for the target listener, to be applied in case of
|
||||
* no {@link EventListener#id() annotation-specified id value}.
|
||||
* <p>The default implementation builds a method name with parameter types.
|
||||
* @since 5.3.5
|
||||
* @see #getListenerId()
|
||||
*/
|
||||
protected String getDefaultListenerId() {
|
||||
Method method = getTargetMethod();
|
||||
StringJoiner sj = new StringJoiner(",", "(", ")");
|
||||
for (Class<?> paramType : method.getParameterTypes()) {
|
||||
sj.add(paramType.getName());
|
||||
}
|
||||
return ClassUtils.getQualifiedMethodName(method) + sj.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the specified {@link ApplicationEvent}, checking if the condition
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
@@ -83,6 +84,7 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* @author Sam Brannen
|
||||
* @since 4.2
|
||||
* @see EventListenerMethodProcessor
|
||||
* @see org.springframework.transaction.event.TransactionalEventListener
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -128,4 +130,13 @@ public @interface EventListener {
|
||||
*/
|
||||
String condition() default "";
|
||||
|
||||
/**
|
||||
* An optional identifier for the listener, defaulting to the fully-qualified
|
||||
* signature of the declaring method (e.g. "mypackage.MyClass.myMethod()").
|
||||
* @since 5.3.5
|
||||
* @see SmartApplicationListener#getListenerId()
|
||||
* @see ApplicationEventMulticaster#removeApplicationListeners(Predicate)
|
||||
*/
|
||||
String id() default "";
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user