mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
378 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8242d02f9d | |||
| 8b9e9202f1 | |||
| afe11e7919 | |||
| 665e6cf6ca | |||
| fd1d8aeeb4 | |||
| 9b2f9e655e | |||
| 6c370ed28d | |||
| a2b356162e | |||
| 71f7fdd632 | |||
| c35ddf905a | |||
| d866715556 | |||
| a9a1f783c5 | |||
| 65d52a4b97 | |||
| 3c8fc46568 | |||
| 421fabb2c4 | |||
| 811d523211 | |||
| 40232f4e22 | |||
| 80fa3ac907 | |||
| 54180f90e2 | |||
| 865953f145 | |||
| 93fac8882f | |||
| a3d199f4dd | |||
| 597fe0720f | |||
| 8321f01bf8 | |||
| 7e736b69b7 | |||
| 8b054840fc | |||
| 7f3d0b3e6e | |||
| 546d7ddd07 | |||
| 95099fd709 | |||
| f65e1edd58 | |||
| 0a9f98f0df | |||
| 46cf4f9ba1 | |||
| 2b930e3858 | |||
| bde2ddbeb1 | |||
| 4eb929c105 | |||
| d0d7a88233 | |||
| f7548a87ed | |||
| e0fe7cdc44 | |||
| 8289bf0aff | |||
| 79d747410d | |||
| 70bca99da8 | |||
| 83617f382c | |||
| 21ac764e5c | |||
| c4fda0e811 | |||
| 66670cfd56 | |||
| c31bfe65aa | |||
| 22ddb35258 | |||
| d0177b0f55 | |||
| 2233ec04ff | |||
| e9ff3bb4e3 | |||
| 57c8c759ae | |||
| cfd9b3461f | |||
| d3324c8d4f | |||
| ffe9bae138 | |||
| 020e51cb96 | |||
| a78066830b | |||
| 77c771e874 | |||
| 227ac3faa4 | |||
| 98dbc17591 | |||
| e58b17a3a1 | |||
| 9de97614a0 | |||
| 015e00b5dd | |||
| 0bc59225d8 | |||
| d8acc27afb | |||
| a1e4afe338 | |||
| 3b9faee335 | |||
| 0048ff84ea | |||
| c3f131325d | |||
| b945e0f202 | |||
| ce3cf3251d | |||
| d69fb06852 | |||
| e9de3bb85b | |||
| e6a51e3d29 | |||
| c734c3a3fe | |||
| a48a956c0c | |||
| e5010a823b | |||
| 1db42081e5 | |||
| 34a0857628 | |||
| ba0484fcac | |||
| f1133a8e56 | |||
| 35e37f6b60 | |||
| f117b804a8 | |||
| 278199d467 | |||
| fd568f3e96 | |||
| 45b27a85f4 | |||
| 0f71f58616 | |||
| 9834c42b5c | |||
| 7879bdfc1d | |||
| dfa8a7c358 | |||
| 427fd9b19a | |||
| 6417ed47ab | |||
| b0ef80c3ff | |||
| 7ed4884eaa | |||
| c3cc42d4d3 | |||
| 860e2bcc2d | |||
| 06231721c3 | |||
| 4d2360e5b5 | |||
| 4f52174674 | |||
| 7d7c5c9d9c | |||
| 08b9e7b83e | |||
| e24c530705 | |||
| 5017c05c23 | |||
| 6e93834e27 | |||
| 5f90a7eee9 | |||
| eff285eb3b | |||
| da7d79b3a1 | |||
| d6216fb74a | |||
| 941f3e7166 | |||
| e80c251c7a | |||
| 56abc4a429 | |||
| dde9e27630 | |||
| 15b174a522 | |||
| 1fcb2608fb | |||
| c15d687bf0 | |||
| e038631a6d | |||
| d5daa8e3a7 | |||
| 6014ca9140 | |||
| d4010573af | |||
| e3cd5c8ef0 | |||
| dec1c93b24 | |||
| 3ef6697536 | |||
| 8207c53b9a | |||
| e3be94c961 | |||
| b40f016de2 | |||
| 28849e0987 | |||
| b386be1529 | |||
| a98a61852f | |||
| 3304efd64d | |||
| b97e7d53bc | |||
| 4af6d58d8d | |||
| e2d06eaae5 | |||
| fcfacd9f83 | |||
| bddcc669b3 | |||
| 2024b37e65 | |||
| fb3191904a | |||
| 9e4d74c502 | |||
| 9b221f58b9 | |||
| f7c3b814e3 | |||
| 155bbb8466 | |||
| 4f690eea2a | |||
| 70a1ecba7f | |||
| c8b0ff2fca | |||
| f9a4856c3b | |||
| 35b67a54d2 | |||
| 78a23be9bc | |||
| 09c5958608 | |||
| ffb295971a | |||
| 77bb7e6030 | |||
| 75daf781c2 | |||
| fcead670f0 | |||
| 801b93a078 | |||
| 4beeeb8118 | |||
| 64d4afad9f | |||
| 48f57e3bb2 | |||
| d92f69747b | |||
| 315698b50e | |||
| 6deccf123d | |||
| 391ebc8eda | |||
| 28c7f65a25 | |||
| caebe72083 | |||
| f79baec5ff | |||
| d1c0ea7d74 | |||
| 53e2d7d160 | |||
| 8c62a2f11a | |||
| 8656e30550 | |||
| 0655d73f8e | |||
| 24ebd15f9c | |||
| cce84711c6 | |||
| 7f127300f9 | |||
| 1521094c5b | |||
| 0b8134049c | |||
| 70a980db58 | |||
| 8b960099f1 | |||
| cc53d597c0 | |||
| 5982f732b4 | |||
| c5500b2332 | |||
| de611cb3a9 | |||
| 72a76367f2 | |||
| 5afc3a3a50 | |||
| 2f2ef00d1f | |||
| de7eea4498 | |||
| e9a87de965 | |||
| db7b74feac | |||
| f7d126043b | |||
| 55b44b4f86 | |||
| 523370b6f2 | |||
| 131d2c2051 | |||
| 7f05c2a18c | |||
| 8fc65ab0a5 | |||
| b6108e3b2d | |||
| 26a4aef417 | |||
| 050f2c746d | |||
| fd21e0e69a | |||
| 794580ffcd | |||
| d44bc27c9a | |||
| 243e21a3ea | |||
| 20aaa8841c | |||
| d77ab67c56 | |||
| dd2b6a0fc5 | |||
| f949461297 | |||
| 9a39a25bb5 | |||
| 4b018407c1 | |||
| 28e114b569 | |||
| 99226e0fa6 | |||
| 4a84ee07be | |||
| 505480cf63 | |||
| fa2bfdd326 | |||
| afe022853c | |||
| 41b834f76e | |||
| a88436c806 | |||
| e2d6e709c3 | |||
| bd7fee5a77 | |||
| 709d4ba6e7 | |||
| 8d55c7d60a | |||
| 9cb4de8b5e | |||
| 8662c61a17 | |||
| 935671ae32 | |||
| a5ce965d22 | |||
| 1e58c80fe7 | |||
| a92ae4ba30 | |||
| b5f2e56e38 | |||
| 594f4d56b8 | |||
| 2d83ca61e7 | |||
| 307e37a69f | |||
| 8310eb3b1f | |||
| b9c4f1fa95 | |||
| faab4f9e28 | |||
| 271b0abc45 | |||
| f0c3d50408 | |||
| f0fdff1f07 | |||
| d15df3489e | |||
| f3cc4ab09d | |||
| 442d8a68a6 | |||
| 934fffec68 | |||
| 8190e7838f | |||
| 4571975414 | |||
| 5115c61b03 | |||
| 54c7a9ee95 | |||
| 0296c7c5b6 | |||
| 84d8135cbb | |||
| dd3c370bca | |||
| 4e41f74925 | |||
| c6663f59b8 | |||
| ced7503d95 | |||
| 04af30daed | |||
| 5ccc8e341c | |||
| 71977e8f9d | |||
| 5e774e0b44 | |||
| e16d753439 | |||
| b14d189db9 | |||
| 14de29c031 | |||
| b59455b63c | |||
| 1a6dc86fed | |||
| 35b0c8b577 | |||
| 75034c3710 | |||
| 305cea28c5 | |||
| 69ba85b051 | |||
| 5700d65a53 | |||
| e707c40e0b | |||
| 9d37472f23 | |||
| eb97335c6f | |||
| 0028b29760 | |||
| 1ded1e38e8 | |||
| 149acdae7d | |||
| 5fee5f39ea | |||
| f16d453805 | |||
| 2b0293578f | |||
| 66aeeedaef | |||
| af41dd1ed6 | |||
| 17f7f1fc15 | |||
| cbc512f3be | |||
| 7ac9f92bc2 | |||
| a7ba63d425 | |||
| 5ca10b1d67 | |||
| f22a4a4e80 | |||
| b53ee13662 | |||
| 8de100b116 | |||
| ac30bcb0eb | |||
| 872d6ef55a | |||
| dd3b9c7c35 | |||
| 9755ae3cbe | |||
| bc29fb5a09 | |||
| 646a574b9c | |||
| 8f19650fd7 | |||
| f08980967b | |||
| 5285f5300a | |||
| 1608d0596d | |||
| 62631bfe33 | |||
| 7ffed858f0 | |||
| 3a1334e0d4 | |||
| 37f4f43726 | |||
| db1a84ede1 | |||
| 3d2e4c338c | |||
| b42d731fc8 | |||
| fd7045adac | |||
| e26d3505f7 | |||
| fe0249bf8f | |||
| 2ac682e125 | |||
| 9be1710dca | |||
| 7e7504f5ea | |||
| e83c11667f | |||
| 05547979de | |||
| 9e67ba83a5 | |||
| 2bb3522bbb | |||
| 8f4ec35697 | |||
| 17863dfbda | |||
| 56bb20d489 | |||
| 5baf32cd81 | |||
| 38cd1ecff4 | |||
| 77e00f1926 | |||
| ade139f2d0 | |||
| 653f35a3d8 | |||
| baa7aecf60 | |||
| d859826be6 | |||
| d759c96a98 | |||
| 7cbab0efe3 | |||
| b6b536682e | |||
| edf1df33cc | |||
| bf0df54136 | |||
| 7e80d2de79 | |||
| 144f687ee9 | |||
| 0ee8322947 | |||
| 997fb5fb48 | |||
| 2b459881bd | |||
| e18e7eca47 | |||
| 1c80d2ac2f | |||
| 62918ca779 | |||
| 3cca57a801 | |||
| 5578a2e46d | |||
| fe19cfde28 | |||
| fbad637235 | |||
| 01e9307fb7 | |||
| 5697cb6c95 | |||
| 05ff83f95a | |||
| 1e3012cb49 | |||
| 45b8cf350e | |||
| 2c2c6f8e02 | |||
| 4e3a6b9404 | |||
| 76bbccb4dc | |||
| 1c4433555a | |||
| faaced1d86 | |||
| 1a1d17e13a | |||
| 4254b6d0e2 | |||
| a211c2a955 | |||
| 196200bcc0 | |||
| c062835702 | |||
| 664ef756c2 | |||
| 9de28d640e | |||
| adb9dc7ede | |||
| f9fcd24315 | |||
| 6d95b999ad | |||
| 6731e52280 | |||
| 970358b2af | |||
| 3d68950037 | |||
| d50b2a4804 | |||
| 29a946163b | |||
| 9472025da7 | |||
| f5cd5387da | |||
| 7a8bf8e9a5 | |||
| f5ecdda400 | |||
| c2031aa651 | |||
| 8751c9931e | |||
| adbf9922f4 | |||
| b3a1e5f9e9 | |||
| 22f70f9ac9 | |||
| d2079f32d8 | |||
| f2ac416f66 | |||
| 642fbfba9f | |||
| c98cdd4f4c | |||
| d04567b99c | |||
| f2e1e1b890 | |||
| 6c764f6b8a | |||
| 49929f1e56 | |||
| acdf139137 | |||
| 3346c594e4 | |||
| 0bb2cfe440 | |||
| 11573b4ea4 | |||
| 5934959b62 |
+55
-50
@@ -32,51 +32,52 @@ configure(allprojects) { project ->
|
||||
version = qualifyVersionIfNecessary(version)
|
||||
|
||||
ext.aspectjVersion = "1.8.9"
|
||||
ext.caffeineVersion = "2.3.3"
|
||||
ext.caffeineVersion = "2.3.5"
|
||||
ext.eclipselinkVersion = "2.4.2"
|
||||
ext.ehcacheVersion = "2.10.2"
|
||||
ext.ehcacheVersion = "2.10.3"
|
||||
ext.ehcachejcacheVersion = "1.0.1"
|
||||
ext.ehcache3Version = "3.1.2"
|
||||
ext.ehcache3Version = "3.1.3"
|
||||
ext.ejbVersion = "3.0"
|
||||
ext.fileuploadVersion = "1.3.2"
|
||||
ext.freemarkerVersion = "2.3.23"
|
||||
ext.groovyVersion = "2.4.7"
|
||||
ext.gsonVersion = "2.7"
|
||||
ext.guavaVersion = "19.0"
|
||||
ext.groovyVersion = "2.4.9"
|
||||
ext.gsonVersion = "2.8.0"
|
||||
ext.guavaVersion = "20.0"
|
||||
ext.hamcrestVersion = "1.3"
|
||||
ext.hibernate3Version = "3.6.10.Final"
|
||||
ext.hibernate4Version = "4.3.11.Final"
|
||||
ext.hibernate5Version = "5.2.2.Final"
|
||||
ext.hibernate5Version = "5.2.10.Final"
|
||||
ext.hibval4Version = "4.3.2.Final"
|
||||
ext.hibval5Version = "5.2.4.Final"
|
||||
ext.hibval5Version = "5.2.5.Final"
|
||||
ext.hsqldbVersion = "2.3.4"
|
||||
ext.httpasyncVersion = "4.1.2"
|
||||
ext.httpclientVersion = "4.5.2"
|
||||
ext.jackson2Version = "2.8.2"
|
||||
ext.httpasyncVersion = "4.1.3"
|
||||
ext.httpclientVersion = "4.5.3"
|
||||
ext.jackson2Version = "2.8.7"
|
||||
ext.jasperreportsVersion = "6.2.1" // our tests fail with JR-internal NPEs against 6.2.2 and higher
|
||||
ext.javamailVersion = "1.5.5"
|
||||
ext.jettyVersion = "9.3.11.v20160721"
|
||||
ext.jodaVersion = "2.9.4"
|
||||
ext.jrubyVersion = "1.7.25" // JRuby 9000 only supported through JSR-223 (StandardScriptFactory)
|
||||
ext.javamailVersion = "1.5.6"
|
||||
ext.jettyVersion = "9.3.14.v20161028" // as of 9.3.15, Jetty has hard Servlet 3.1 requirement
|
||||
ext.jetty94Version = "9.4.3.v20170317" // for spring-websocket support, optimized for Jetty 9.4
|
||||
ext.jodaVersion = "2.9.9"
|
||||
ext.jrubyVersion = "1.7.26" // JRuby 9000 primarily supported through JSR-223 (StandardScriptFactory)
|
||||
ext.jtaVersion = "1.2"
|
||||
ext.junitVersion = "4.12"
|
||||
ext.log4jVersion = "1.2.17"
|
||||
ext.nettyVersion = "4.1.5.Final"
|
||||
ext.nettyVersion = "4.1.8.Final"
|
||||
ext.okhttpVersion = "2.7.5"
|
||||
ext.okhttp3Version = "3.4.1"
|
||||
ext.okhttp3Version = "3.6.0"
|
||||
ext.openjpaVersion = "2.4.1"
|
||||
ext.poiVersion = "3.14"
|
||||
ext.reactorVersion = "2.0.8.RELEASE"
|
||||
ext.romeVersion = "1.7.0"
|
||||
ext.romeVersion = "1.7.1"
|
||||
ext.slf4jVersion = "1.7.21"
|
||||
ext.snakeyamlVersion = "1.17"
|
||||
ext.snifferVersion = "1.15"
|
||||
ext.testngVersion = "6.9.10"
|
||||
ext.tiles2Version = "2.2.2"
|
||||
ext.tiles3Version = "3.0.5"
|
||||
ext.tomcatVersion = "8.5.5"
|
||||
ext.tiles3Version = "3.0.7"
|
||||
ext.tomcatVersion = "8.5.11"
|
||||
ext.tyrusVersion = "1.3.5" // constrained by WebLogic 12.1.3 support
|
||||
ext.undertowVersion = "1.3.24.Final"
|
||||
ext.undertowVersion = "1.3.28.Final"
|
||||
ext.xmlunitVersion = "1.6"
|
||||
ext.xstreamVersion = "1.4.9"
|
||||
|
||||
@@ -216,7 +217,6 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
|
||||
configurations {
|
||||
jacoco
|
||||
}
|
||||
|
||||
dependencies {
|
||||
jacoco("org.jacoco:org.jacoco.agent:0.7.5.201505241946:runtime")
|
||||
}
|
||||
@@ -250,16 +250,16 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
|
||||
options.links(project.ext.javadocLinks)
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
|
||||
// suppress warnings due to cross-module @see and @link references;
|
||||
// note that global 'api' task does display all warnings.
|
||||
// Suppress warnings due to cross-module @see and @link references.
|
||||
// Note that global 'api' task does display all warnings.
|
||||
logging.captureStandardError LogLevel.INFO
|
||||
logging.captureStandardOutput LogLevel.INFO // suppress "## warnings" message
|
||||
logging.captureStandardOutput LogLevel.INFO // suppress "## warnings" message
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||
classifier = 'sources'
|
||||
from sourceSets.main.allSource
|
||||
// don't include or exclude anything explicitly by default. See SPR-12085.
|
||||
// Don't include or exclude anything explicitly by default. See SPR-12085.
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
@@ -275,6 +275,7 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
|
||||
|
||||
project("spring-build-src") {
|
||||
description = "Exposes gradle buildSrc for IDE support"
|
||||
|
||||
apply plugin: "groovy"
|
||||
|
||||
dependencies {
|
||||
@@ -292,8 +293,8 @@ project("spring-core") {
|
||||
// both into the spring-core jar. cglib 3.2 itself depends on asm 5.x and is therefore
|
||||
// further transformed by the JarJar task to depend on org.springframework.asm; this
|
||||
// avoids including two different copies of asm unnecessarily.
|
||||
def cglibVersion = "3.2.4"
|
||||
def objenesisVersion = "2.4"
|
||||
def cglibVersion = "3.2.5"
|
||||
def objenesisVersion = "2.5.1"
|
||||
|
||||
configurations {
|
||||
jarjar
|
||||
@@ -313,9 +314,9 @@ project("spring-core") {
|
||||
configurations.cglib.each { originalJar ->
|
||||
zipfileset(src: originalJar)
|
||||
}
|
||||
// repackage net.sf.cglib => org.springframework.cglib
|
||||
// Repackage net.sf.cglib => org.springframework.cglib
|
||||
rule(pattern: "net.sf.cglib.**", result: "org.springframework.cglib.@1")
|
||||
// as mentioned above, transform cglib"s internal asm dependencies from
|
||||
// As mentioned above, transform cglib"s internal asm dependencies from
|
||||
// org.objectweb.asm => org.springframework.asm. Doing this counts on the
|
||||
// the fact that Spring and cglib depend on the same version of asm!
|
||||
rule(pattern: "org.objectweb.asm.**", result: "org.springframework.asm.@1")
|
||||
@@ -336,7 +337,7 @@ project("spring-core") {
|
||||
configurations.objenesis.each { originalJar ->
|
||||
zipfileset(src: originalJar)
|
||||
}
|
||||
// repackage org.objenesis => org.springframework.objenesis
|
||||
// Repackage org.objenesis => org.springframework.objenesis
|
||||
rule(pattern: "org.objenesis.**", result: "org.springframework.objenesis.@1")
|
||||
}
|
||||
}
|
||||
@@ -353,7 +354,7 @@ project("spring-core") {
|
||||
compile("commons-logging:commons-logging:1.2")
|
||||
optional("commons-codec:commons-codec:1.10")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("net.sf.jopt-simple:jopt-simple:5.0.2")
|
||||
optional("net.sf.jopt-simple:jopt-simple:5.0.3")
|
||||
optional("log4j:log4j:${log4jVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
testCompile("xmlunit:xmlunit:${xmlunitVersion}")
|
||||
@@ -363,7 +364,7 @@ project("spring-core") {
|
||||
}
|
||||
|
||||
jar {
|
||||
// inline repackaged cglib classes directly into the spring-core jar
|
||||
// Inline repackaged cglib classes directly into spring-core jar
|
||||
dependsOn cglibRepackJar
|
||||
from(zipTree(cglibRepackJar.archivePath)) {
|
||||
include "org/springframework/cglib/**"
|
||||
@@ -392,6 +393,7 @@ project("spring-beans") {
|
||||
|
||||
project("spring-beans-groovy") {
|
||||
description "Groovy Bean Definitions"
|
||||
|
||||
merge.into = project(":spring-beans")
|
||||
apply plugin: "groovy"
|
||||
|
||||
@@ -400,8 +402,8 @@ project("spring-beans-groovy") {
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
}
|
||||
|
||||
// this module's Java and Groovy sources need to be compiled together
|
||||
compileJava.enabled=false
|
||||
// This module's Java and Groovy sources need to be compiled together.
|
||||
compileJava.enabled = false
|
||||
sourceSets {
|
||||
main {
|
||||
groovy {
|
||||
@@ -467,6 +469,7 @@ project("spring-instrument-tomcat") {
|
||||
|
||||
project("spring-context") {
|
||||
description = "Spring Context"
|
||||
|
||||
apply plugin: "groovy"
|
||||
|
||||
dependencies {
|
||||
@@ -486,7 +489,7 @@ project("spring-context") {
|
||||
optional("joda-time:joda-time:${jodaVersion}")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("org.beanshell:bsh:2.0b4")
|
||||
optional("org.beanshell:bsh:2.0b5")
|
||||
optional("org.jruby:jruby:${jrubyVersion}")
|
||||
testCompile("javax.inject:javax.inject-tck:1")
|
||||
testCompile("org.javamoney:moneta:1.1")
|
||||
@@ -614,9 +617,9 @@ project("spring-jdbc") {
|
||||
optional("javax.transaction:javax.transaction-api:${jtaVersion}")
|
||||
optional("com.mchange:c3p0:0.9.5.2")
|
||||
optional("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
optional("com.h2database:h2:1.4.192")
|
||||
optional("org.apache.derby:derby:10.12.1.1")
|
||||
optional("org.apache.derby:derbyclient:10.12.1.1")
|
||||
optional("com.h2database:h2:1.4.193")
|
||||
optional("org.apache.derby:derby:10.13.1.1")
|
||||
optional("org.apache.derby:derbyclient:10.13.1.1")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,6 +663,7 @@ project("spring-context-support") {
|
||||
|
||||
project("spring-web") {
|
||||
description = "Spring Web"
|
||||
|
||||
apply plugin: "groovy"
|
||||
|
||||
// Re-generate Protobuf classes from *.proto files and move them in test sources
|
||||
@@ -720,6 +724,7 @@ project("spring-web") {
|
||||
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-joda:${jackson2Version}")
|
||||
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:${jackson2Version}")
|
||||
testCompile("com.fasterxml.jackson.module:jackson-module-kotlin:${jackson2Version}")
|
||||
testCompile("com.squareup.okhttp3:mockwebserver:${okhttp3Version}")
|
||||
testRuntime("com.sun.mail:javax.mail:${javamailVersion}")
|
||||
}
|
||||
}
|
||||
@@ -869,7 +874,7 @@ project("spring-webmvc") {
|
||||
testCompile("org.hibernate:hibernate-validator:${hibval4Version}")
|
||||
testCompile("org.apache.httpcomponents:httpclient:${httpclientVersion}")
|
||||
testCompile("commons-fileupload:commons-fileupload:${fileuploadVersion}")
|
||||
testCompile("commons-io:commons-io:1.3")
|
||||
testCompile("commons-io:commons-io:1.4")
|
||||
testCompile("joda-time:joda-time:${jodaVersion}")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("org.mozilla:rhino:1.7.7.1")
|
||||
@@ -948,11 +953,11 @@ project("spring-websocket") {
|
||||
optional("org.eclipse.jetty:jetty-webapp:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet"
|
||||
}
|
||||
optional("org.eclipse.jetty.websocket:websocket-server:${jettyVersion}") {
|
||||
optional("org.eclipse.jetty.websocket:websocket-server:${jetty94Version}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet"
|
||||
}
|
||||
optional("org.eclipse.jetty.websocket:websocket-client:${jettyVersion}")
|
||||
optional("org.eclipse.jetty:jetty-client:${jettyVersion}")
|
||||
optional("org.eclipse.jetty.websocket:websocket-client:${jetty94Version}")
|
||||
optional("org.eclipse.jetty:jetty-client:${jetty94Version}")
|
||||
optional("io.undertow:undertow-core:${undertowVersion}")
|
||||
optional("io.undertow:undertow-servlet:${undertowVersion}") {
|
||||
exclude group: "org.jboss.spec.javax.servlet", module: "jboss-servlet-api_3.1_spec"
|
||||
@@ -1001,10 +1006,10 @@ project("spring-test") {
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("org.hamcrest:hamcrest-core:${hamcrestVersion}")
|
||||
optional("xmlunit:xmlunit:${xmlunitVersion}")
|
||||
optional("net.sourceforge.htmlunit:htmlunit:2.22")
|
||||
optional("org.seleniumhq.selenium:htmlunit-driver:2.21")
|
||||
optional("net.sourceforge.htmlunit:htmlunit:2.23")
|
||||
optional("org.seleniumhq.selenium:htmlunit-driver:2.23.2")
|
||||
optional("org.seleniumhq.selenium:selenium-java:2.53.1")
|
||||
optional("org.skyscreamer:jsonassert:1.3.0")
|
||||
optional("org.skyscreamer:jsonassert:1.4.0")
|
||||
optional("com.jayway.jsonpath:json-path:2.2.0")
|
||||
testCompile(project(":spring-context-support"))
|
||||
testCompile(project(":spring-oxm"))
|
||||
@@ -1029,7 +1034,7 @@ project("spring-test") {
|
||||
testCompile("javax.cache:cache-api:1.0.0")
|
||||
testRuntime("log4j:log4j:${log4jVersion}")
|
||||
testRuntime("org.ehcache:ehcache:${ehcache3Version}")
|
||||
testRuntime("org.terracotta:management-model:2.0.0")
|
||||
testRuntime("org.terracotta:management-model:2.3.0")
|
||||
}
|
||||
|
||||
task testNG(type: Test) {
|
||||
@@ -1174,7 +1179,7 @@ configure(rootProject) {
|
||||
// don't publish the default jar for the root project
|
||||
configurations.archives.artifacts.clear()
|
||||
|
||||
dependencies { // for integration tests
|
||||
dependencies { // for integration tests
|
||||
testCompile(project(":spring-aop"))
|
||||
testCompile(project(":spring-beans"))
|
||||
testCompile(project(":spring-context"))
|
||||
@@ -1223,11 +1228,11 @@ configure(rootProject) {
|
||||
|
||||
doFirst {
|
||||
classpath = files(
|
||||
// ensure Servlet 3.x and Hibernate 4.x have precedence on the javadoc
|
||||
// Ensure Servlet 3.x and Hibernate 4.x have precedence on the javadoc
|
||||
// classpath over their respective 2.5 and 3.x variants
|
||||
project(":spring-webmvc").sourceSets.main.compileClasspath.files.find { it =~ "servlet-api" },
|
||||
rootProject.sourceSets.test.compileClasspath.files.find { it =~ "hibernate-core" },
|
||||
// ensure the javadoc process can resolve types compiled from .aj sources
|
||||
// Ensure the javadoc process can resolve types compiled from .aj sources
|
||||
project(":spring-aspects").sourceSets.main.output
|
||||
)
|
||||
classpath += files(subprojects.collect { it.sourceSets.main.compileClasspath })
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
version=4.3.3.BUILD-SNAPSHOT
|
||||
version=4.3.8.RELEASE
|
||||
|
||||
@@ -29,8 +29,8 @@ def customizePom(pom, gradleProject) {
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name "The Apache Software License, Version 2.0"
|
||||
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
name "Apache License, Version 2.0"
|
||||
url "http://www.apache.org/licenses/LICENSE-2.0"
|
||||
distribution "repo"
|
||||
}
|
||||
}
|
||||
|
||||
+44
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,7 +28,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.aspectj.weaver.BCException;
|
||||
import org.aspectj.weaver.patterns.NamePattern;
|
||||
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
|
||||
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
||||
@@ -187,13 +186,24 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
throw new IllegalStateException("Must set property 'expression' before attempting to match");
|
||||
}
|
||||
if (this.pointcutExpression == null) {
|
||||
this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
this.pointcutClassLoader = determinePointcutClassLoader();
|
||||
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the ClassLoader to use for pointcut evaluation.
|
||||
*/
|
||||
private ClassLoader determinePointcutClassLoader() {
|
||||
if (this.beanFactory instanceof ConfigurableBeanFactory) {
|
||||
return ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader();
|
||||
}
|
||||
if (this.pointcutDeclarationScope != null) {
|
||||
return this.pointcutDeclarationScope.getClassLoader();
|
||||
}
|
||||
return ClassUtils.getDefaultClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
@@ -258,7 +268,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (BCException ex) {
|
||||
catch (Throwable ex) {
|
||||
logger.debug("PointcutExpression matching rejected target class", ex);
|
||||
}
|
||||
return false;
|
||||
@@ -326,7 +336,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// No current invocation...
|
||||
// TODO: Should we really proceed here?
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not access current invocation - matching with limited context: " + ex);
|
||||
}
|
||||
@@ -413,39 +422,46 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
shadowMatch = this.shadowMatchCache.get(targetMethod);
|
||||
if (shadowMatch == null) {
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorldException ex) {
|
||||
// Failed to introspect target method, probably because it has been loaded
|
||||
// in a special ClassLoader. Let's try the declaring ClassLoader instead...
|
||||
try {
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex2) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
if (shadowMatch == null && targetMethod != originalMethod) {
|
||||
methodToMatch = originalMethod;
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorldException ex3) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's try the original method's declaring class before we give up...
|
||||
catch (ReflectionWorldException ex) {
|
||||
// Failed to introspect target method, probably because it has been loaded
|
||||
// in a special ClassLoader. Let's try the declaring ClassLoader instead...
|
||||
try {
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex4) {
|
||||
catch (ReflectionWorldException ex2) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
if (shadowMatch == null && targetMethod != originalMethod) {
|
||||
methodToMatch = originalMethod;
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorldException ex3) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's try the original method's declaring class before we give up...
|
||||
try {
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex4) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Possibly AspectJ 1.8.10 encountering an invalid signature
|
||||
logger.debug("PointcutExpression matching rejected target method", ex);
|
||||
fallbackExpression = null;
|
||||
}
|
||||
if (shadowMatch == null) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
|
||||
+18
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,8 @@ package org.springframework.aop.aspectj;
|
||||
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.support.AbstractGenericPointcutAdvisor;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
|
||||
/**
|
||||
* Spring AOP Advisor that can be used for any AspectJ pointcut expression.
|
||||
@@ -26,16 +28,11 @@ import org.springframework.aop.support.AbstractGenericPointcutAdvisor;
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor {
|
||||
public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor implements BeanFactoryAware {
|
||||
|
||||
private final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
|
||||
|
||||
@Override
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
public void setExpression(String expression) {
|
||||
this.pointcut.setExpression(expression);
|
||||
}
|
||||
@@ -52,12 +49,22 @@ public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdv
|
||||
return this.pointcut.getLocation();
|
||||
}
|
||||
|
||||
public void setParameterTypes(Class<?>[] types) {
|
||||
this.pointcut.setParameterTypes(types);
|
||||
}
|
||||
|
||||
public void setParameterNames(String... names) {
|
||||
this.pointcut.setParameterNames(names);
|
||||
}
|
||||
|
||||
public void setParameterTypes(Class<?>... types) {
|
||||
this.pointcut.setParameterTypes(types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.pointcut.setBeanFactory(beanFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,6 +27,7 @@ import org.springframework.util.StringUtils;
|
||||
* Spring AOP {@link ClassFilter} implementation using AspectJ type matching.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class TypePatternClassFilter implements ClassFilter {
|
||||
@@ -76,17 +77,21 @@ public class TypePatternClassFilter implements ClassFilter {
|
||||
* or is recognized as invalid
|
||||
*/
|
||||
public void setTypePattern(String typePattern) {
|
||||
Assert.notNull(typePattern);
|
||||
Assert.notNull(typePattern, "Type pattern must not be null");
|
||||
this.typePattern = typePattern;
|
||||
this.aspectJTypePatternMatcher =
|
||||
PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution().
|
||||
parseTypePattern(replaceBooleanOperators(typePattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the AspectJ type pattern to match.
|
||||
*/
|
||||
public String getTypePattern() {
|
||||
return typePattern;
|
||||
return this.typePattern;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Should the pointcut apply to the given interface or target class?
|
||||
* @param clazz candidate target class
|
||||
@@ -95,9 +100,7 @@ public class TypePatternClassFilter implements ClassFilter {
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(Class<?> clazz) {
|
||||
if (this.aspectJTypePatternMatcher == null) {
|
||||
throw new IllegalStateException("No 'typePattern' has been set via ctor/setter.");
|
||||
}
|
||||
Assert.state(this.aspectJTypePatternMatcher != null, "No type pattern has been set");
|
||||
return this.aspectJTypePatternMatcher.matches(clazz);
|
||||
}
|
||||
|
||||
@@ -108,9 +111,8 @@ public class TypePatternClassFilter implements ClassFilter {
|
||||
* <p>This method converts back to {@code &&} for the AspectJ pointcut parser.
|
||||
*/
|
||||
private String replaceBooleanOperators(String pcExpr) {
|
||||
pcExpr = StringUtils.replace(pcExpr," and "," && ");
|
||||
pcExpr = StringUtils.replace(pcExpr, " or ", " || ");
|
||||
pcExpr = StringUtils.replace(pcExpr, " not ", " ! ");
|
||||
return pcExpr;
|
||||
String result = StringUtils.replace(pcExpr," and "," && ");
|
||||
result = StringUtils.replace(result, " or ", " || ");
|
||||
return StringUtils.replace(result, " not ", " ! ");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-45
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,7 +38,6 @@ import org.aspectj.lang.reflect.AjType;
|
||||
import org.aspectj.lang.reflect.AjTypeSystem;
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
@@ -121,49 +120,6 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The pointcut and advice annotations both have an "argNames" member which contains a
|
||||
* comma-separated list of the argument names. We use this (if non-empty) to build the
|
||||
* formal parameters for the pointcut.
|
||||
*/
|
||||
protected AspectJExpressionPointcut createPointcutExpression(
|
||||
Method annotatedMethod, Class<?> declarationScope, String[] pointcutParameterNames) {
|
||||
|
||||
Class<?> [] pointcutParameterTypes = new Class<?>[0];
|
||||
if (pointcutParameterNames != null) {
|
||||
pointcutParameterTypes = extractPointcutParameterTypes(pointcutParameterNames,annotatedMethod);
|
||||
}
|
||||
|
||||
AspectJExpressionPointcut ajexp =
|
||||
new AspectJExpressionPointcut(declarationScope,pointcutParameterNames,pointcutParameterTypes);
|
||||
ajexp.setLocation(annotatedMethod.toString());
|
||||
return ajexp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the pointcut parameters needed by aspectj based on the given argument names
|
||||
* and the argument types that are available from the adviceMethod. Needs to take into
|
||||
* account (ignore) any JoinPoint based arguments as these are not pointcut context but
|
||||
* rather part of the advice execution context (thisJoinPoint, thisJoinPointStaticPart)
|
||||
*/
|
||||
private Class<?>[] extractPointcutParameterTypes(String[] argNames, Method adviceMethod) {
|
||||
Class<?>[] ret = new Class<?>[argNames.length];
|
||||
Class<?>[] paramTypes = adviceMethod.getParameterTypes();
|
||||
if (argNames.length > paramTypes.length) {
|
||||
throw new IllegalStateException("Expecting at least " + argNames.length +
|
||||
" arguments in the advice declaration, but only found " + paramTypes.length);
|
||||
}
|
||||
|
||||
// Make the simplifying assumption for now that all of the JoinPoint based arguments
|
||||
// come first in the advice declaration.
|
||||
int typeOffset = paramTypes.length - argNames.length;
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = paramTypes[i + typeOffset];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find and return the first AspectJ annotation on the given method
|
||||
* (there <i>should</i> only be one anyway...)
|
||||
|
||||
+6
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,7 +50,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
|
||||
private List<Pattern> includePatterns;
|
||||
|
||||
private AspectJAdvisorFactory aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory();
|
||||
private AspectJAdvisorFactory aspectJAdvisorFactory;
|
||||
|
||||
private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;
|
||||
|
||||
@@ -74,6 +74,9 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
@Override
|
||||
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
super.initBeanFactory(beanFactory);
|
||||
if (this.aspectJAdvisorFactory == null) {
|
||||
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
|
||||
}
|
||||
this.aspectJAdvisorsBuilder =
|
||||
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
|
||||
}
|
||||
@@ -130,6 +133,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
|
||||
public BeanFactoryAspectJAdvisorsBuilderAdapter(
|
||||
ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
|
||||
|
||||
super(beanFactory, advisorFactory);
|
||||
}
|
||||
|
||||
|
||||
+25
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
@@ -50,7 +50,7 @@ import org.springframework.util.ClassUtils;
|
||||
public class AspectJProxyFactory extends ProxyCreatorSupport {
|
||||
|
||||
/** Cache for singleton aspect instances */
|
||||
private static final Map<Class<?>, Object> aspectCache = new HashMap<Class<?>, Object>();
|
||||
private static final Map<Class<?>, Object> aspectCache = new ConcurrentHashMap<Class<?>, Object>();
|
||||
|
||||
private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory();
|
||||
|
||||
@@ -144,7 +144,7 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
|
||||
private MetadataAwareAspectInstanceFactory createAspectInstanceFactory(
|
||||
AspectMetadata am, Class<?> aspectClass, String aspectName) {
|
||||
|
||||
MetadataAwareAspectInstanceFactory instanceFactory = null;
|
||||
MetadataAwareAspectInstanceFactory instanceFactory;
|
||||
if (am.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
|
||||
// Create a shared aspect instance.
|
||||
Object instance = getSingletonAspectInstance(aspectClass);
|
||||
@@ -162,23 +162,29 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
|
||||
* is created if one cannot be found in the instance cache.
|
||||
*/
|
||||
private Object getSingletonAspectInstance(Class<?> aspectClass) {
|
||||
synchronized (aspectCache) {
|
||||
Object instance = aspectCache.get(aspectClass);
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
}
|
||||
try {
|
||||
instance = aspectClass.newInstance();
|
||||
aspectCache.put(aspectClass, instance);
|
||||
return instance;
|
||||
}
|
||||
catch (InstantiationException ex) {
|
||||
throw new AopConfigException("Unable to instantiate aspect class [" + aspectClass.getName() + "]", ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new AopConfigException("Cannot access aspect class [" + aspectClass.getName() + "]", ex);
|
||||
// Quick check without a lock...
|
||||
Object instance = aspectCache.get(aspectClass);
|
||||
if (instance == null) {
|
||||
synchronized (aspectCache) {
|
||||
// To be safe, check within full lock now...
|
||||
instance = aspectCache.get(aspectClass);
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
}
|
||||
try {
|
||||
instance = aspectClass.newInstance();
|
||||
aspectCache.put(aspectClass, instance);
|
||||
return instance;
|
||||
}
|
||||
catch (InstantiationException ex) {
|
||||
throw new AopConfigException("Unable to instantiate aspect class [" + aspectClass.getName() + "]", ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new AopConfigException("Cannot access aspect class [" + aspectClass.getName() + "]", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+10
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,9 +35,8 @@ import org.springframework.aop.support.ComposablePointcut;
|
||||
* Metadata for an AspectJ aspect class, with an additional Spring AOP pointcut
|
||||
* for the per clause.
|
||||
*
|
||||
* <p>Uses AspectJ 5 AJType reflection API, so is only supported on Java 5.
|
||||
* Enables us to work with different AspectJ instantiation models such as
|
||||
* "singleton", "pertarget" and "perthis".
|
||||
* <p>Uses AspectJ 5 AJType reflection API, enabling us to work with different
|
||||
* AspectJ instantiation models such as "singleton", "pertarget" and "perthis".
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -102,20 +101,22 @@ public class AspectMetadata implements Serializable {
|
||||
this.ajType = ajType;
|
||||
|
||||
switch (this.ajType.getPerClause().getKind()) {
|
||||
case SINGLETON :
|
||||
case SINGLETON:
|
||||
this.perClausePointcut = Pointcut.TRUE;
|
||||
return;
|
||||
case PERTARGET : case PERTHIS :
|
||||
case PERTARGET:
|
||||
case PERTHIS:
|
||||
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
|
||||
ajexp.setLocation("@Aspect annotation on " + aspectClass.getName());
|
||||
ajexp.setLocation(aspectClass.getName());
|
||||
ajexp.setExpression(findPerClause(aspectClass));
|
||||
ajexp.setPointcutDeclarationScope(aspectClass);
|
||||
this.perClausePointcut = ajexp;
|
||||
return;
|
||||
case PERTYPEWITHIN :
|
||||
case PERTYPEWITHIN:
|
||||
// Works with a type pattern
|
||||
this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));
|
||||
return;
|
||||
default :
|
||||
default:
|
||||
throw new AopConfigException(
|
||||
"PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass);
|
||||
}
|
||||
@@ -125,8 +126,6 @@ public class AspectMetadata implements Serializable {
|
||||
* Extract contents from String of form {@code pertarget(contents)}.
|
||||
*/
|
||||
private String findPerClause(Class<?> aspectClass) {
|
||||
// TODO when AspectJ provides this, we can remove this hack. Hence we don't
|
||||
// bother to make it elegant. Or efficient. Or robust :-)
|
||||
String str = aspectClass.getAnnotation(Aspect.class).value();
|
||||
str = str.substring(str.indexOf("(") + 1);
|
||||
str = str.substring(0, str.length() - 1);
|
||||
|
||||
+13
-2
@@ -97,8 +97,19 @@ public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInst
|
||||
|
||||
@Override
|
||||
public Object getAspectCreationMutex() {
|
||||
return (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex() : this);
|
||||
if (this.beanFactory != null) {
|
||||
if (this.beanFactory.isSingleton(name)) {
|
||||
// Rely on singleton semantics provided by the factory -> no local lock.
|
||||
return null;
|
||||
}
|
||||
else if (this.beanFactory instanceof ConfigurableBeanFactory) {
|
||||
// No singleton guarantees from the factory -> let's lock locally but
|
||||
// reuse the factory's singleton lock, just in case a lazy dependency
|
||||
// of our advice bean happens to trigger the singleton lock implicitly...
|
||||
return ((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex();
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+49
-48
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,10 +17,10 @@
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
@@ -43,12 +43,12 @@ public class BeanFactoryAspectJAdvisorsBuilder {
|
||||
|
||||
private final AspectJAdvisorFactory advisorFactory;
|
||||
|
||||
private List<String> aspectBeanNames;
|
||||
private volatile List<String> aspectBeanNames;
|
||||
|
||||
private final Map<String, List<Advisor>> advisorsCache = new HashMap<String, List<Advisor>>();
|
||||
private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<String, List<Advisor>>();
|
||||
|
||||
private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache =
|
||||
new HashMap<String, MetadataAwareAspectInstanceFactory>();
|
||||
new ConcurrentHashMap<String, MetadataAwareAspectInstanceFactory>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -56,7 +56,7 @@ public class BeanFactoryAspectJAdvisorsBuilder {
|
||||
* @param beanFactory the ListableBeanFactory to scan
|
||||
*/
|
||||
public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory) {
|
||||
this(beanFactory, new ReflectiveAspectJAdvisorFactory());
|
||||
this(beanFactory, new ReflectiveAspectJAdvisorFactory(beanFactory));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,56 +80,57 @@ public class BeanFactoryAspectJAdvisorsBuilder {
|
||||
* @see #isEligibleBean
|
||||
*/
|
||||
public List<Advisor> buildAspectJAdvisors() {
|
||||
List<String> aspectNames = null;
|
||||
List<String> aspectNames = this.aspectBeanNames;
|
||||
|
||||
synchronized (this) {
|
||||
aspectNames = this.aspectBeanNames;
|
||||
if (aspectNames == null) {
|
||||
List<Advisor> advisors = new LinkedList<Advisor>();
|
||||
aspectNames = new LinkedList<String>();
|
||||
String[] beanNames =
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
|
||||
for (String beanName : beanNames) {
|
||||
if (!isEligibleBean(beanName)) {
|
||||
continue;
|
||||
}
|
||||
// We must be careful not to instantiate beans eagerly as in this
|
||||
// case they would be cached by the Spring container but would not
|
||||
// have been weaved
|
||||
Class<?> beanType = this.beanFactory.getType(beanName);
|
||||
if (beanType == null) {
|
||||
continue;
|
||||
}
|
||||
if (this.advisorFactory.isAspect(beanType)) {
|
||||
aspectNames.add(beanName);
|
||||
AspectMetadata amd = new AspectMetadata(beanType, beanName);
|
||||
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
|
||||
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
this.advisorsCache.put(beanName, classAdvisors);
|
||||
if (aspectNames == null) {
|
||||
synchronized (this) {
|
||||
aspectNames = this.aspectBeanNames;
|
||||
if (aspectNames == null) {
|
||||
List<Advisor> advisors = new LinkedList<Advisor>();
|
||||
aspectNames = new LinkedList<String>();
|
||||
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
|
||||
this.beanFactory, Object.class, true, false);
|
||||
for (String beanName : beanNames) {
|
||||
if (!isEligibleBean(beanName)) {
|
||||
continue;
|
||||
}
|
||||
// We must be careful not to instantiate beans eagerly as in this case they
|
||||
// would be cached by the Spring container but would not have been weaved.
|
||||
Class<?> beanType = this.beanFactory.getType(beanName);
|
||||
if (beanType == null) {
|
||||
continue;
|
||||
}
|
||||
if (this.advisorFactory.isAspect(beanType)) {
|
||||
aspectNames.add(beanName);
|
||||
AspectMetadata amd = new AspectMetadata(beanType, beanName);
|
||||
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
|
||||
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
this.advisorsCache.put(beanName, classAdvisors);
|
||||
}
|
||||
else {
|
||||
this.aspectFactoryCache.put(beanName, factory);
|
||||
}
|
||||
advisors.addAll(classAdvisors);
|
||||
}
|
||||
else {
|
||||
// Per target or per this.
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
throw new IllegalArgumentException("Bean with name '" + beanName +
|
||||
"' is a singleton, but aspect instantiation model is not singleton");
|
||||
}
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
|
||||
this.aspectFactoryCache.put(beanName, factory);
|
||||
advisors.addAll(this.advisorFactory.getAdvisors(factory));
|
||||
}
|
||||
advisors.addAll(classAdvisors);
|
||||
}
|
||||
else {
|
||||
// Per target or per this.
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
throw new IllegalArgumentException("Bean with name '" + beanName +
|
||||
"' is a singleton, but aspect instantiation model is not singleton");
|
||||
}
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
|
||||
this.aspectFactoryCache.put(beanName, factory);
|
||||
advisors.addAll(this.advisorFactory.getAdvisors(factory));
|
||||
}
|
||||
}
|
||||
this.aspectBeanNames = aspectNames;
|
||||
return advisors;
|
||||
}
|
||||
this.aspectBeanNames = aspectNames;
|
||||
return advisors;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-3
@@ -48,9 +48,15 @@ public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwar
|
||||
@Override
|
||||
public Object getAspectInstance() {
|
||||
if (this.materialized == null) {
|
||||
synchronized (this.maaif.getAspectCreationMutex()) {
|
||||
if (this.materialized == null) {
|
||||
this.materialized = this.maaif.getAspectInstance();
|
||||
Object mutex = this.maaif.getAspectCreationMutex();
|
||||
if (mutex == null) {
|
||||
this.materialized = this.maaif.getAspectInstance();
|
||||
}
|
||||
else {
|
||||
synchronized (mutex) {
|
||||
if (this.materialized == null) {
|
||||
this.materialized = this.maaif.getAspectInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactor
|
||||
|
||||
/**
|
||||
* Return the best possible creation mutex for this factory.
|
||||
* @return the mutex object (never {@code null})
|
||||
* @return the mutex object (may be {@code null} for no mutex to use)
|
||||
* @since 4.3
|
||||
*/
|
||||
Object getAspectCreationMutex();
|
||||
|
||||
+28
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,6 +46,7 @@ import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
|
||||
import org.springframework.aop.aspectj.DeclareParentsAdvisor;
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.ConvertingComparator;
|
||||
@@ -95,6 +96,30 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
}
|
||||
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code ReflectiveAspectJAdvisorFactory}.
|
||||
*/
|
||||
public ReflectiveAspectJAdvisorFactory() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code ReflectiveAspectJAdvisorFactory}, propagating the given
|
||||
* {@link BeanFactory} to the created {@link AspectJExpressionPointcut} instances,
|
||||
* for bean pointcut handling as well as consistent {@link ClassLoader} resolution.
|
||||
* @param beanFactory the BeanFactory to propagate (may be {@code null}}
|
||||
* @since 4.3.6
|
||||
* @see AspectJExpressionPointcut#setBeanFactory
|
||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#getBeanClassLoader()
|
||||
*/
|
||||
public ReflectiveAspectJAdvisorFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
|
||||
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
|
||||
@@ -161,9 +186,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
}
|
||||
|
||||
if (DeclareParents.class == declareParents.defaultImpl()) {
|
||||
// This is what comes back if it wasn't set. This seems bizarre...
|
||||
// TODO this restriction possibly should be relaxed
|
||||
throw new IllegalStateException("defaultImpl must be set on DeclareParents");
|
||||
throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
|
||||
}
|
||||
|
||||
return new DeclareParentsAdvisor(
|
||||
@@ -197,6 +220,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
AspectJExpressionPointcut ajexp =
|
||||
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
|
||||
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
|
||||
ajexp.setBeanFactory(this.beanFactory);
|
||||
return ajexp;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -71,7 +71,7 @@ public abstract class AbstractInterceptorDrivenBeanDefinitionDecorator implement
|
||||
BeanDefinition interceptorDefinition = createInterceptorDefinition(node);
|
||||
|
||||
// generate name and register the interceptor
|
||||
String interceptorName = existingBeanName + "." + getInterceptorNameSuffix(interceptorDefinition);
|
||||
String interceptorName = existingBeanName + '.' + getInterceptorNameSuffix(interceptorDefinition);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(
|
||||
new BeanDefinitionHolder(interceptorDefinition, interceptorName), registry);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,6 +43,25 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
public abstract class AopProxyUtils {
|
||||
|
||||
/**
|
||||
* Obtain the singleton target object behind the given proxy, if any.
|
||||
* @param candidate the (potential) proxy to check
|
||||
* @return the singleton target object managed in a {@link SingletonTargetSource},
|
||||
* or {@code null} in any other case (not a proxy, not an existing singleton target)
|
||||
* @since 4.3.8
|
||||
* @see Advised#getTargetSource()
|
||||
* @see SingletonTargetSource#getTarget()
|
||||
*/
|
||||
public static Object getSingletonTarget(Object candidate) {
|
||||
if (candidate instanceof Advised) {
|
||||
TargetSource targetSource = ((Advised) candidate).getTargetSource();
|
||||
if (targetSource instanceof SingletonTargetSource) {
|
||||
return ((SingletonTargetSource) targetSource).getTarget();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the ultimate target class of the given bean instance, traversing
|
||||
* not only a top-level proxy but any number of nested proxies as well —
|
||||
@@ -59,14 +78,7 @@ public abstract class AopProxyUtils {
|
||||
Class<?> result = null;
|
||||
while (current instanceof TargetClassAware) {
|
||||
result = ((TargetClassAware) current).getTargetClass();
|
||||
Object nested = null;
|
||||
if (current instanceof Advised) {
|
||||
TargetSource targetSource = ((Advised) current).getTargetSource();
|
||||
if (targetSource instanceof SingletonTargetSource) {
|
||||
nested = ((SingletonTargetSource) targetSource).getTarget();
|
||||
}
|
||||
}
|
||||
current = nested;
|
||||
current = getSingletonTarget(current);
|
||||
}
|
||||
if (result == null) {
|
||||
result = (AopUtils.isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,7 @@ import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
@@ -56,9 +57,6 @@ import org.springframework.util.ObjectUtils;
|
||||
/**
|
||||
* CGLIB-based {@link AopProxy} implementation for the Spring AOP framework.
|
||||
*
|
||||
* <p>Formerly named {@code Cglib2AopProxy}, as of Spring 3.2, this class depends on
|
||||
* Spring's own internally repackaged version of CGLIB 3.</i>.
|
||||
*
|
||||
* <p>Objects of this type should be obtained through proxy factories,
|
||||
* configured by an {@link AdvisedSupport} object. This class is internal
|
||||
* to Spring's AOP framework and need not be used directly by client code.
|
||||
@@ -214,7 +212,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
"Common causes of this problem include using a final class or a non-visible class",
|
||||
ex);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
catch (Throwable ex) {
|
||||
// TargetSource.getTarget() failed
|
||||
throw new AopConfigException("Unexpected AOP exception", ex);
|
||||
}
|
||||
@@ -241,10 +239,11 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
* validates it if not.
|
||||
*/
|
||||
private void validateClassIfNecessary(Class<?> proxySuperClass, ClassLoader proxyClassLoader) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
synchronized (validatedClasses) {
|
||||
if (!validatedClasses.containsKey(proxySuperClass)) {
|
||||
doValidateClass(proxySuperClass, proxyClassLoader);
|
||||
doValidateClass(proxySuperClass, proxyClassLoader,
|
||||
ClassUtils.getAllInterfacesForClassAsSet(proxySuperClass));
|
||||
validatedClasses.put(proxySuperClass, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
@@ -255,30 +254,35 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
* Checks for final methods on the given {@code Class}, as well as package-visible
|
||||
* methods across ClassLoaders, and writes warnings to the log for each one found.
|
||||
*/
|
||||
private void doValidateClass(Class<?> proxySuperClass, ClassLoader proxyClassLoader) {
|
||||
if (Object.class != proxySuperClass) {
|
||||
private void doValidateClass(Class<?> proxySuperClass, ClassLoader proxyClassLoader, Set<Class<?>> ifcs) {
|
||||
if (proxySuperClass != Object.class) {
|
||||
Method[] methods = proxySuperClass.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
int mod = method.getModifiers();
|
||||
if (!Modifier.isStatic(mod)) {
|
||||
if (Modifier.isFinal(mod)) {
|
||||
logger.info("Unable to proxy method [" + method + "] because it is final: " +
|
||||
"All calls to this method via a proxy will NOT be routed to the target instance.");
|
||||
if (implementsInterface(method, ifcs)) {
|
||||
logger.warn("Unable to proxy interface-implementing method [" + method + "] because " +
|
||||
"it is marked as final: Consider using interface-based JDK proxies instead!");
|
||||
}
|
||||
logger.info("Final method [" + method + "] cannot get proxied via CGLIB: " +
|
||||
"Calls to this method will NOT be routed to the target instance and " +
|
||||
"might lead to NPEs against uninitialized fields in the proxy instance.");
|
||||
}
|
||||
else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) && !Modifier.isPrivate(mod) &&
|
||||
proxyClassLoader != null && proxySuperClass.getClassLoader() != proxyClassLoader) {
|
||||
logger.info("Unable to proxy method [" + method + "] because it is package-visible " +
|
||||
"across different ClassLoaders: All calls to this method via a proxy will " +
|
||||
"NOT be routed to the target instance.");
|
||||
logger.info("Method [" + method + "] is package-visible across different ClassLoaders " +
|
||||
"and cannot get proxied via CGLIB: Declare this method as public or protected " +
|
||||
"if you need to support invocations through the proxy.");
|
||||
}
|
||||
}
|
||||
}
|
||||
doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader);
|
||||
doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader, ifcs);
|
||||
}
|
||||
}
|
||||
|
||||
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
|
||||
// Parameters used for optimisation choices...
|
||||
// Parameters used for optimization choices...
|
||||
boolean exposeProxy = this.advised.isExposeProxy();
|
||||
boolean isFrozen = this.advised.isFrozen();
|
||||
boolean isStatic = this.advised.getTargetSource().isStatic();
|
||||
@@ -317,14 +321,14 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
Callback[] callbacks;
|
||||
|
||||
// If the target is a static one and the advice chain is frozen,
|
||||
// then we can make some optimisations by sending the AOP calls
|
||||
// then we can make some optimizations by sending the AOP calls
|
||||
// direct to the target using the fixed chain for that method.
|
||||
if (isStatic && isFrozen) {
|
||||
Method[] methods = rootClass.getMethods();
|
||||
Callback[] fixedCallbacks = new Callback[methods.length];
|
||||
this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
|
||||
|
||||
// TODO: small memory optimisation here (can skip creation for methods with no advice)
|
||||
// TODO: small memory optimization here (can skip creation for methods with no advice)
|
||||
for (int x = 0; x < methods.length; x++) {
|
||||
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
|
||||
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
|
||||
@@ -345,25 +349,6 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a return value. Wraps a return of {@code this} if necessary to be the
|
||||
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
|
||||
*/
|
||||
private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) {
|
||||
// Massage return value if necessary
|
||||
if (retVal != null && retVal == target && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this". Note that we can't help
|
||||
// if the target sets a reference to itself in another returned object.
|
||||
retVal = proxy;
|
||||
}
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
|
||||
throw new AopInvocationException(
|
||||
"Null return value from advice does not match primitive return type for: " + method);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
@@ -377,6 +362,39 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the given method is declared on any of the given interfaces.
|
||||
*/
|
||||
private static boolean implementsInterface(Method method, Set<Class<?>> ifcs) {
|
||||
for (Class<?> ifc : ifcs) {
|
||||
if (ClassUtils.hasMethod(ifc, method.getName(), method.getParameterTypes())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a return value. Wraps a return of {@code this} if necessary to be the
|
||||
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
|
||||
*/
|
||||
private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) {
|
||||
// Massage return value if necessary
|
||||
if (retVal != null && retVal == target &&
|
||||
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this". Note that we can't help
|
||||
// if the target sets a reference to itself in another returned object.
|
||||
retVal = proxy;
|
||||
}
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
|
||||
throw new AopInvocationException(
|
||||
"Null return value from advice does not match primitive return type for: " + method);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializable replacement for CGLIB's NoOp interface.
|
||||
* Public to allow use elsewhere in the framework.
|
||||
@@ -822,51 +840,42 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
// Else use the AOP_PROXY.
|
||||
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method has advice and optimisations are enabled: " + method);
|
||||
logger.debug("Method has advice and optimizations are enabled: " + method);
|
||||
}
|
||||
// We know that we are optimising so we can use the FixedStaticChainInterceptors.
|
||||
// We know that we are optimizing so we can use the FixedStaticChainInterceptors.
|
||||
int index = this.fixedInterceptorMap.get(key);
|
||||
return (index + this.fixedInterceptorOffset);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Unable to apply any optimisations to advised method: " + method);
|
||||
logger.debug("Unable to apply any optimizations to advised method: " + method);
|
||||
}
|
||||
return AOP_PROXY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// See if the return type of the method is outside the class hierarchy
|
||||
// of the target type. If so we know it never needs to have return type
|
||||
// massage and can use a dispatcher.
|
||||
// If the proxy is being exposed, then must use the interceptor the
|
||||
// correct one is already configured. If the target is not static, then
|
||||
// cannot use a dispatcher because the target cannot be released.
|
||||
// See if the return type of the method is outside the class hierarchy of the target type.
|
||||
// If so we know it never needs to have return type massage and can use a dispatcher.
|
||||
// If the proxy is being exposed, then must use the interceptor the correct one is already
|
||||
// configured. If the target is not static, then we cannot use a dispatcher because the
|
||||
// target needs to be explicitly released after the invocation.
|
||||
if (exposeProxy || !isStatic) {
|
||||
return INVOKE_TARGET;
|
||||
}
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (targetClass == returnType) {
|
||||
if (returnType.isAssignableFrom(targetClass)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method " + method +
|
||||
"has return type same as target type (may return this) - using INVOKE_TARGET");
|
||||
logger.debug("Method return type is assignable from target type and " +
|
||||
"may therefore return 'this' - using INVOKE_TARGET: " + method);
|
||||
}
|
||||
return INVOKE_TARGET;
|
||||
}
|
||||
else if (returnType.isPrimitive() || !returnType.isAssignableFrom(targetClass)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method " + method +
|
||||
" has return type that ensures this cannot be returned- using DISPATCH_TARGET");
|
||||
}
|
||||
return DISPATCH_TARGET;
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method " + method +
|
||||
"has return type that is assignable from the target type (may return this) - " +
|
||||
"using INVOKE_TARGET");
|
||||
logger.debug("Method return type ensures 'this' cannot be returned - " +
|
||||
"using DISPATCH_TARGET: " + method);
|
||||
}
|
||||
return INVOKE_TARGET;
|
||||
return DISPATCH_TARGET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,8 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
|
||||
|
||||
// Massage return value if necessary.
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
|
||||
if (retVal != null && retVal == target &&
|
||||
returnType != Object.class && returnType.isInstance(proxy) &&
|
||||
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this" and the return type of the method
|
||||
// is type-compatible. Note that we can't help if the target sets
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,7 +26,7 @@ import org.springframework.aop.AfterReturningAdvice;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Interceptor to wrap am {@link org.springframework.aop.AfterReturningAdvice}.
|
||||
* Interceptor to wrap an {@link org.springframework.aop.AfterReturningAdvice}.
|
||||
* Used internally by the AOP framework; application developers should not need
|
||||
* to use this class directly.
|
||||
*
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,7 +54,8 @@ public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyC
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
super.setBeanFactory(beanFactory);
|
||||
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
|
||||
throw new IllegalStateException("Cannot use AdvisorAutoProxyCreator without a ConfigurableListableBeanFactory");
|
||||
throw new IllegalArgumentException(
|
||||
"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
|
||||
}
|
||||
initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
|
||||
}
|
||||
|
||||
+24
-25
@@ -55,26 +55,25 @@ import org.springframework.util.StringUtils;
|
||||
* before invoking the bean itself.
|
||||
*
|
||||
* <p>This class distinguishes between "common" interceptors: shared for all proxies it
|
||||
* creates, and "specific" interceptors: unique per bean instance. There need not
|
||||
* be any common interceptors. If there are, they are set using the interceptorNames
|
||||
* property. As with ProxyFactoryBean, interceptors names in the current factory
|
||||
* are used rather than bean references to allow correct handling of prototype
|
||||
* advisors and interceptors: for example, to support stateful mixins.
|
||||
* Any advice type is supported for "interceptorNames" entries.
|
||||
* creates, and "specific" interceptors: unique per bean instance. There need not be any
|
||||
* common interceptors. If there are, they are set using the interceptorNames property.
|
||||
* As with {@link org.springframework.aop.framework.ProxyFactoryBean}, interceptors names
|
||||
* in the current factory are used rather than bean references to allow correct handling
|
||||
* of prototype advisors and interceptors: for example, to support stateful mixins.
|
||||
* Any advice type is supported for {@link #setInterceptorNames "interceptorNames"} entries.
|
||||
*
|
||||
* <p>Such auto-proxying is particularly useful if there's a large number of beans that
|
||||
* need to be wrapped with similar proxies, i.e. delegating to the same interceptors.
|
||||
* Instead of x repetitive proxy definitions for x target beans, you can register
|
||||
* one single such post processor with the bean factory to achieve the same effect.
|
||||
*
|
||||
* <p>Subclasses can apply any strategy to decide if a bean is to be proxied,
|
||||
* e.g. by type, by name, by definition details, etc. They can also return
|
||||
* additional interceptors that should just be applied to the specific bean
|
||||
* instance. The default concrete implementation is BeanNameAutoProxyCreator,
|
||||
* identifying the beans to be proxied via a list of bean names.
|
||||
* <p>Subclasses can apply any strategy to decide if a bean is to be proxied, e.g. by type,
|
||||
* by name, by definition details, etc. They can also return additional interceptors that
|
||||
* should just be applied to the specific bean instance. A simple concrete implementation is
|
||||
* {@link BeanNameAutoProxyCreator}, identifying the beans to be proxied via given names.
|
||||
*
|
||||
* <p>Any number of {@link TargetSourceCreator} implementations can be used to create
|
||||
* a custom target source - for example, to pool prototype objects. Auto-proxying will
|
||||
* a custom target source: for example, to pool prototype objects. Auto-proxying will
|
||||
* occur even if there is no advice, as long as a TargetSourceCreator specifies a custom
|
||||
* {@link org.springframework.aop.TargetSource}. If there are no TargetSourceCreators set,
|
||||
* or if none matches, a {@link org.springframework.aop.target.SingletonTargetSource}
|
||||
@@ -156,8 +155,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the AdvisorAdapterRegistry to use.
|
||||
* Default is the global AdvisorAdapterRegistry.
|
||||
* Specify the {@link AdvisorAdapterRegistry} to use.
|
||||
* <p>Default is the global {@link AdvisorAdapterRegistry}.
|
||||
* @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry
|
||||
*/
|
||||
public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
|
||||
@@ -165,18 +164,18 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom TargetSourceCreators to be applied in this order.
|
||||
* If the list is empty, or they all return null, a SingletonTargetSource
|
||||
* Set custom {@code TargetSourceCreators} to be applied in this order.
|
||||
* If the list is empty, or they all return null, a {@link SingletonTargetSource}
|
||||
* will be created for each bean.
|
||||
* <p>Note that TargetSourceCreators will kick in even for target beans
|
||||
* where no advices or advisors have been found. If a TargetSourceCreator
|
||||
* returns a TargetSource for a specific bean, that bean will be proxied
|
||||
* where no advices or advisors have been found. If a {@code TargetSourceCreator}
|
||||
* returns a {@link TargetSource} for a specific bean, that bean will be proxied
|
||||
* in any case.
|
||||
* <p>TargetSourceCreators can only be invoked if this post processor is used
|
||||
* in a BeanFactory, and its BeanFactoryAware callback is used.
|
||||
* @param targetSourceCreators list of TargetSourceCreator.
|
||||
* Ordering is significant: The TargetSource returned from the first matching
|
||||
* TargetSourceCreator (that is, the first that returns non-null) will be used.
|
||||
* <p>{@code TargetSourceCreators} can only be invoked if this post processor is used
|
||||
* in a {@link BeanFactory} and its {@link BeanFactoryAware} callback is triggered.
|
||||
* @param targetSourceCreators the list of {@code TargetSourceCreators}.
|
||||
* Ordering is significant: The {@code TargetSource} returned from the first matching
|
||||
* {@code TargetSourceCreator} (that is, the first that returns non-null) will be used.
|
||||
*/
|
||||
public void setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators) {
|
||||
this.customTargetSourceCreators = targetSourceCreators;
|
||||
@@ -207,8 +206,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the owning BeanFactory.
|
||||
* May be {@code null}, as this object doesn't need to belong to a bean factory.
|
||||
* Return the owning {@link BeanFactory}.
|
||||
* May be {@code null}, as this post-processor doesn't need to belong to a bean factory.
|
||||
*/
|
||||
protected BeanFactory getBeanFactory() {
|
||||
return this.beanFactory;
|
||||
|
||||
+15
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,15 +19,16 @@ package org.springframework.aop.framework.autoproxy;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
|
||||
/**
|
||||
* BeanPostProcessor implementation that creates AOP proxies based on all candidate
|
||||
* Advisors in the current BeanFactory. This class is completely generic; it contains
|
||||
* no special code to handle any particular aspects, such as pooling aspects.
|
||||
* {@code BeanPostProcessor} implementation that creates AOP proxies based on all
|
||||
* candidate {@code Advisor}s in the current {@code BeanFactory}. This class is
|
||||
* completely generic; it contains no special code to handle any particular aspects,
|
||||
* such as pooling aspects.
|
||||
*
|
||||
* <p>It's possible to filter out advisors - for example, to use multiple post processors
|
||||
* of this type in the same factory - by setting the {@code usePrefix} property
|
||||
* to true, in which case only advisors beginning with the DefaultAdvisorAutoProxyCreator's
|
||||
* bean name followed by a dot (like "aapc.") will be used. This default prefix can be
|
||||
* changed from the bean name by setting the {@code advisorBeanNamePrefix} property.
|
||||
* of this type in the same factory - by setting the {@code usePrefix} property to true,
|
||||
* in which case only advisors beginning with the DefaultAdvisorAutoProxyCreator's bean
|
||||
* name followed by a dot (like "aapc.") will be used. This default prefix can be changed
|
||||
* from the bean name by setting the {@code advisorBeanNamePrefix} property.
|
||||
* The separator (.) will also be used in this case.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
@@ -40,22 +41,22 @@ public class DefaultAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCrea
|
||||
public final static String SEPARATOR = ".";
|
||||
|
||||
|
||||
private boolean usePrefix;
|
||||
private boolean usePrefix = false;
|
||||
|
||||
private String advisorBeanNamePrefix;
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to exclude advisors with a certain prefix
|
||||
* in the bean name.
|
||||
* Set whether to only include advisors with a certain prefix in the bean name.
|
||||
* <p>Default is {@code false}, including all beans of type {@code Advisor}.
|
||||
* @see #setAdvisorBeanNamePrefix
|
||||
*/
|
||||
public void setUsePrefix(boolean usePrefix) {
|
||||
this.usePrefix = usePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to exclude advisors with a certain prefix
|
||||
* in the bean name.
|
||||
* Return whether to only include advisors with a certain prefix in the bean name.
|
||||
*/
|
||||
public boolean isUsePrefix() {
|
||||
return this.usePrefix;
|
||||
@@ -89,7 +90,7 @@ public class DefaultAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCrea
|
||||
|
||||
|
||||
/**
|
||||
* Consider Advisor beans with the specified prefix as eligible, if activated.
|
||||
* Consider {@code Advisor} beans with the specified prefix as eligible, if activated.
|
||||
* @see #setUsePrefix
|
||||
* @see #setAdvisorBeanNamePrefix
|
||||
*/
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -246,7 +246,7 @@ public class CustomizableTraceInterceptor extends AbstractTraceInterceptor {
|
||||
*/
|
||||
@Override
|
||||
protected Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable {
|
||||
String name = invocation.getMethod().getDeclaringClass().getName() + "." + invocation.getMethod().getName();
|
||||
String name = ClassUtils.getQualifiedMethodName(invocation.getMethod());
|
||||
StopWatch stopWatch = new StopWatch(name);
|
||||
Object returnValue = null;
|
||||
boolean exitThroughException = false;
|
||||
|
||||
+22
-6
@@ -46,7 +46,7 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private transient Advice advice;
|
||||
private transient volatile Advice advice;
|
||||
|
||||
private transient volatile Object adviceMonitor = new Object();
|
||||
|
||||
@@ -98,12 +98,28 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
|
||||
|
||||
@Override
|
||||
public Advice getAdvice() {
|
||||
synchronized (this.adviceMonitor) {
|
||||
if (this.advice == null && this.adviceBeanName != null) {
|
||||
Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
|
||||
this.advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
|
||||
Advice advice = this.advice;
|
||||
if (advice != null || this.adviceBeanName == null) {
|
||||
return advice;
|
||||
}
|
||||
|
||||
Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
|
||||
if (this.beanFactory.isSingleton(this.adviceBeanName)) {
|
||||
// Rely on singleton semantics provided by the factory.
|
||||
advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
|
||||
this.advice = advice;
|
||||
return advice;
|
||||
}
|
||||
else {
|
||||
// No singleton guarantees from the factory -> let's lock locally but
|
||||
// reuse the factory's singleton lock, just in case a lazy dependency
|
||||
// of our advice bean happens to trigger the singleton lock implicitly...
|
||||
synchronized (this.adviceMonitor) {
|
||||
if (this.advice == null) {
|
||||
this.advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
|
||||
}
|
||||
return this.advice;
|
||||
}
|
||||
return this.advice;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -129,8 +130,8 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return ((targetClass != null && matchesPattern(targetClass.getName() + "." + method.getName())) ||
|
||||
matchesPattern(method.getDeclaringClass().getName() + "." + method.getName()));
|
||||
return ((targetClass != null && matchesPattern(ClassUtils.getQualifiedMethodName(method, targetClass))) ||
|
||||
matchesPattern(ClassUtils.getQualifiedMethodName(method)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,8 +22,6 @@ import java.lang.reflect.Method;
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.core.ControlFlow;
|
||||
import org.springframework.core.ControlFlowFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -34,7 +32,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
* @see org.springframework.core.ControlFlow
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable {
|
||||
@@ -43,7 +41,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
|
||||
|
||||
private String methodName;
|
||||
|
||||
private int evaluations;
|
||||
private volatile int evaluations;
|
||||
|
||||
|
||||
/**
|
||||
@@ -55,11 +53,11 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new pointcut that matches all calls below the
|
||||
* given method in the given class. If the method name is null,
|
||||
* matches all control flows below that class.
|
||||
* Construct a new pointcut that matches all calls below the given method
|
||||
* in the given class. If no method name is given, matches all control flows
|
||||
* below the given class.
|
||||
* @param clazz the clazz
|
||||
* @param methodName the name of the method
|
||||
* @param methodName the name of the method (may be {@code null})
|
||||
*/
|
||||
public ControlFlowPointcut(Class<?> clazz, String methodName) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
@@ -93,8 +91,14 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass, Object... args) {
|
||||
this.evaluations++;
|
||||
ControlFlow cflow = ControlFlowFactory.createControlFlow();
|
||||
return (this.methodName != null ? cflow.under(this.clazz, this.methodName) : cflow.under(this.clazz));
|
||||
|
||||
for (StackTraceElement element : new Throwable().getStackTrace()) {
|
||||
if (element.getClassName().equals(this.clazz.getName()) &&
|
||||
(this.methodName == null || element.getMethodName().equals(this.methodName))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,8 +134,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = 17;
|
||||
code = 37 * code + this.clazz.hashCode();
|
||||
int code = this.clazz.hashCode();
|
||||
if (this.methodName != null) {
|
||||
code = 37 * code + this.methodName.hashCode();
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,7 +39,7 @@ import org.springframework.aop.TargetSource;
|
||||
public abstract class AbstractRefreshableTargetSource implements TargetSource, Refreshable {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected Log logger = LogFactory.getLog(getClass());
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected Object targetObject;
|
||||
|
||||
|
||||
+15
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.aop.scope;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
@@ -27,19 +29,24 @@ import static org.springframework.tests.TestResourceUtils.*;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public final class ScopedProxyAutowireTests {
|
||||
public class ScopedProxyAutowireTests {
|
||||
|
||||
private static final Class<?> CLASS = ScopedProxyAutowireTests.class;
|
||||
private static final Resource SCOPED_AUTOWIRE_FALSE_CONTEXT =
|
||||
qualifiedResource(ScopedProxyAutowireTests.class, "scopedAutowireFalse.xml");
|
||||
private static final Resource SCOPED_AUTOWIRE_TRUE_CONTEXT =
|
||||
qualifiedResource(ScopedProxyAutowireTests.class, "scopedAutowireTrue.xml");
|
||||
|
||||
private static final Resource SCOPED_AUTOWIRE_TRUE_CONTEXT = qualifiedResource(CLASS, "scopedAutowireTrue.xml");
|
||||
private static final Resource SCOPED_AUTOWIRE_FALSE_CONTEXT = qualifiedResource(CLASS, "scopedAutowireFalse.xml");
|
||||
|
||||
@Test
|
||||
public void testScopedProxyInheritsAutowireCandidateFalse() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(SCOPED_AUTOWIRE_FALSE_CONTEXT);
|
||||
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, false, false)).contains("scoped"));
|
||||
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, true, false)).contains("scoped"));
|
||||
assertFalse(bf.containsSingleton("scoped"));
|
||||
TestBean autowired = (TestBean) bf.getBean("autowired");
|
||||
TestBean unscoped = (TestBean) bf.getBean("unscoped");
|
||||
assertSame(unscoped, autowired.getChild());
|
||||
@@ -49,6 +56,9 @@ public final class ScopedProxyAutowireTests {
|
||||
public void testScopedProxyReplacesAutowireCandidateTrue() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(SCOPED_AUTOWIRE_TRUE_CONTEXT);
|
||||
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, true, false)).contains("scoped"));
|
||||
assertTrue(Arrays.asList(bf.getBeanNamesForType(TestBean.class, false, false)).contains("scoped"));
|
||||
assertFalse(bf.containsSingleton("scoped"));
|
||||
TestBean autowired = (TestBean) bf.getBean("autowired");
|
||||
TestBean scoped = (TestBean) bf.getBean("scoped");
|
||||
assertSame(scoped, autowired.getChild());
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
<config xmlns="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
|
||||
|
||||
<pointcut id="testPointcut" expression="execution(* foo(..)) and within(springbank.dao.AccountDao+)"/>
|
||||
<pointcut id="testPointcut1" expression="execution(* springbank.dao.AccountDao.foo(..))"/>
|
||||
@@ -9,4 +9,4 @@
|
||||
<after method="foo" pointcut-ref="testPointcut"/>
|
||||
</aspect>
|
||||
|
||||
</config>
|
||||
</config>
|
||||
|
||||
+9
-9
@@ -1,16 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
|
||||
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" scope="prototype" autowire-candidate="false">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
|
||||
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true"/>
|
||||
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true"/>
|
||||
|
||||
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
|
||||
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
|
||||
|
||||
</beans>
|
||||
|
||||
+9
-9
@@ -1,16 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
|
||||
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" scope="singleton" autowire-candidate="true">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
|
||||
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false"/>
|
||||
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false"/>
|
||||
|
||||
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
|
||||
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
|
||||
|
||||
</beans>
|
||||
|
||||
+42
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,55 +18,45 @@ package org.springframework.transaction.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.tests.transaction.CallCountingTransactionManager;
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class TransactionAspectTests extends org.springframework.test.AbstractDependencyInjectionSpringContextTests {
|
||||
public class TransactionAspectTests {
|
||||
|
||||
private CallCountingTransactionManager txManager;
|
||||
private final CallCountingTransactionManager txManager = new CallCountingTransactionManager();
|
||||
|
||||
private TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface;
|
||||
private final TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface =
|
||||
new TransactionalAnnotationOnlyOnClassWithNoInterface();
|
||||
|
||||
private ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod;
|
||||
private final ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod =
|
||||
new ClassWithProtectedAnnotatedMember();
|
||||
|
||||
private ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod;
|
||||
private final ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod =
|
||||
new ClassWithPrivateAnnotatedMember();
|
||||
|
||||
private MethodAnnotationOnClassWithNoInterface methodAnnotationOnly = new MethodAnnotationOnClassWithNoInterface();
|
||||
private final MethodAnnotationOnClassWithNoInterface methodAnnotationOnly =
|
||||
new MethodAnnotationOnClassWithNoInterface();
|
||||
|
||||
|
||||
public void setAnnotationOnlyOnClassWithNoInterface(
|
||||
TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface) {
|
||||
this.annotationOnlyOnClassWithNoInterface = annotationOnlyOnClassWithNoInterface;
|
||||
}
|
||||
|
||||
public void setClassWithAnnotatedProtectedMethod(ClassWithProtectedAnnotatedMember aBean) {
|
||||
this.beanWithAnnotatedProtectedMethod = aBean;
|
||||
}
|
||||
|
||||
public void setClassWithAnnotatedPrivateMethod(ClassWithPrivateAnnotatedMember aBean) {
|
||||
this.beanWithAnnotatedPrivateMethod = aBean;
|
||||
}
|
||||
|
||||
public void setTransactionAspect(TransactionAspectSupport transactionAspect) {
|
||||
this.txManager = (CallCountingTransactionManager) transactionAspect.getTransactionManager();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String[] getConfigPaths() {
|
||||
return new String[] { "TransactionAspectTests-context.xml" };
|
||||
@Before
|
||||
public void initContext() {
|
||||
AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCommitOnAnnotatedClass() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -74,6 +64,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommitOnAnnotatedProtectedMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -81,6 +72,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommitOnAnnotatedPrivateMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -88,6 +80,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoCommitOnNonAnnotatedNonPublicMethodInTransactionalType() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0,txManager.begun);
|
||||
@@ -95,6 +88,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(0,txManager.begun);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommitOnAnnotatedMethod() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -102,6 +96,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(1, txManager.commits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotTransactional() throws Throwable {
|
||||
txManager.clear();
|
||||
assertEquals(0, txManager.begun);
|
||||
@@ -109,6 +104,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
assertEquals(0, txManager.begun);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommitOnAnnotatedClass() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
try {
|
||||
@@ -125,6 +121,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultRollbackOnAnnotatedClass() throws Throwable {
|
||||
final RuntimeException ex = new RuntimeException();
|
||||
try {
|
||||
@@ -141,10 +138,11 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommitOnSubclassOfAnnotatedClass() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
try {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
testRollback(new TransactionOperationCallback() {
|
||||
@Override
|
||||
public Object performTransactionalOperation() throws Throwable {
|
||||
return new SubclassOfClassWithTransactionalAnnotation().echo(ex);
|
||||
@@ -157,6 +155,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
try {
|
||||
@@ -173,6 +172,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommitOnImplementationOfAnnotatedInterface() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
testNotTransactional(new TransactionOperationCallback() {
|
||||
@@ -185,16 +185,19 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
|
||||
/**
|
||||
* Note: resolution does not occur. Thus we can't make a class transactional if
|
||||
* it implements a transactionally annotated interface. This behaviour could only
|
||||
* it implements a transactionally annotated interface. This behavior could only
|
||||
* be changed in AbstractFallbackTransactionAttributeSource in Spring proper.
|
||||
* See SPR-14322.
|
||||
*/
|
||||
@Test
|
||||
public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws Exception {
|
||||
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
|
||||
Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
|
||||
TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class);
|
||||
Method method = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
|
||||
TransactionAttribute ta = atas.getTransactionAttribute(method, ImplementsAnnotatedInterface.class);
|
||||
assertNull(ta);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultRollbackOnImplementationOfAnnotatedInterface() throws Throwable {
|
||||
final Exception rollbackProvokingException = new RuntimeException();
|
||||
testNotTransactional(new TransactionOperationCallback() {
|
||||
@@ -237,15 +240,19 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
|
||||
|
||||
private interface TransactionOperationCallback {
|
||||
|
||||
Object performTransactionalOperation() throws Throwable;
|
||||
}
|
||||
|
||||
|
||||
public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface {
|
||||
}
|
||||
|
||||
|
||||
public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface {
|
||||
}
|
||||
|
||||
|
||||
public static class ImplementsAnnotatedInterface implements ITransactional {
|
||||
|
||||
@Override
|
||||
@@ -257,6 +264,7 @@ public class TransactionAspectTests extends org.springframework.test.AbstractDep
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class NotTransactional {
|
||||
|
||||
public void noop() {
|
||||
|
||||
+10
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -303,7 +303,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
Collection constructorArgs = null;
|
||||
if (!ObjectUtils.isEmpty(args)) {
|
||||
int index = args.length;
|
||||
Object lastArg = args[index-1];
|
||||
Object lastArg = args[index - 1];
|
||||
if (lastArg instanceof Closure) {
|
||||
callable = (Closure) lastArg;
|
||||
index--;
|
||||
@@ -456,14 +456,14 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
* @return the bean definition wrapper
|
||||
*/
|
||||
private GroovyBeanDefinitionWrapper invokeBeanDefiningMethod(String beanName, Object[] args) {
|
||||
boolean hasClosureArgument = args[args.length - 1] instanceof Closure;
|
||||
boolean hasClosureArgument = (args[args.length - 1] instanceof Closure);
|
||||
if (args[0] instanceof Class) {
|
||||
Class<?> beanClass = (args[0] instanceof Class ? (Class) args[0] : args[0].getClass());
|
||||
Class<?> beanClass = (Class<?>) args[0];
|
||||
if (args.length >= 1) {
|
||||
if (hasClosureArgument) {
|
||||
if (args.length-1 != 1) {
|
||||
if (args.length - 1 != 1) {
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(
|
||||
beanName, beanClass, resolveConstructorArguments(args,1,args.length-1));
|
||||
beanName, beanClass, resolveConstructorArguments(args, 1, args.length - 1));
|
||||
}
|
||||
else {
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, beanClass);
|
||||
@@ -471,7 +471,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
else {
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(
|
||||
beanName, beanClass, resolveConstructorArguments(args,1,args.length));
|
||||
beanName, beanClass, resolveConstructorArguments(args, 1, args.length));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -483,7 +483,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
else if (args[0] instanceof Map) {
|
||||
// named constructor arguments
|
||||
if (args.length > 1 && args[1] instanceof Class) {
|
||||
List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length-1 : args.length);
|
||||
List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length);
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class)args[1], constructorArgs);
|
||||
Map namedArgs = (Map)args[0];
|
||||
for (Object o : namedArgs.keySet()) {
|
||||
@@ -519,12 +519,12 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
this.currentBeanDefinition.getBeanDefinition().setAbstract(true);
|
||||
}
|
||||
else {
|
||||
List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length-1 : args.length);
|
||||
List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length - 1 : args.length);
|
||||
currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, null, constructorArgs);
|
||||
}
|
||||
|
||||
if (hasClosureArgument) {
|
||||
Closure callable = (Closure)args[args.length-1];
|
||||
Closure callable = (Closure) args[args.length - 1];
|
||||
callable.setDelegate(this);
|
||||
callable.setResolveStrategy(Closure.DELEGATE_FIRST);
|
||||
callable.call(new Object[]{currentBeanDefinition});
|
||||
|
||||
+182
-171
@@ -284,198 +284,212 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
|
||||
String propertyName = tokens.canonicalName;
|
||||
String actualName = tokens.actualName;
|
||||
|
||||
if (tokens.keys != null) {
|
||||
// Apply indexes and map keys: fetch value for all keys but the last one.
|
||||
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
|
||||
getterTokens.canonicalName = tokens.canonicalName;
|
||||
getterTokens.actualName = tokens.actualName;
|
||||
getterTokens.keys = new String[tokens.keys.length - 1];
|
||||
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);
|
||||
Object propValue;
|
||||
processKeyedProperty(tokens, pv);
|
||||
}
|
||||
else {
|
||||
processLocalProperty(tokens, pv);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) {
|
||||
Object propValue = getPropertyHoldingValue(tokens);
|
||||
String lastKey = tokens.keys[tokens.keys.length - 1];
|
||||
|
||||
if (propValue.getClass().isArray()) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
|
||||
Class<?> requiredType = propValue.getClass().getComponentType();
|
||||
int arrayIndex = Integer.parseInt(lastKey);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
propValue = getPropertyValue(getterTokens);
|
||||
}
|
||||
catch (NotReadablePropertyException ex) {
|
||||
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + propertyName + "'", ex);
|
||||
}
|
||||
// Set value for last key.
|
||||
String key = tokens.keys[tokens.keys.length - 1];
|
||||
if (propValue == null) {
|
||||
// null map value case
|
||||
if (isAutoGrowNestedPaths()) {
|
||||
// TODO: cleanup, this is pretty hacky
|
||||
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
|
||||
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
|
||||
propValue = setDefaultValue(getterTokens);
|
||||
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
|
||||
oldValue = Array.get(propValue, arrayIndex);
|
||||
}
|
||||
else {
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + propertyName + "': returned null");
|
||||
}
|
||||
}
|
||||
if (propValue.getClass().isArray()) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(actualName);
|
||||
Class<?> requiredType = propValue.getClass().getComponentType();
|
||||
int arrayIndex = Integer.parseInt(key);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
|
||||
oldValue = Array.get(propValue, arrayIndex);
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
requiredType, ph.nested(tokens.keys.length));
|
||||
int length = Array.getLength(propValue);
|
||||
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
|
||||
Class<?> componentType = propValue.getClass().getComponentType();
|
||||
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
|
||||
System.arraycopy(propValue, 0, newArray, 0, length);
|
||||
setPropertyValue(actualName, newArray);
|
||||
propValue = getPropertyValue(actualName);
|
||||
}
|
||||
Array.set(propValue, arrayIndex, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Invalid array index in property path '" + propertyName + "'", ex);
|
||||
}
|
||||
}
|
||||
else if (propValue instanceof List) {
|
||||
PropertyHandler ph = getPropertyHandler(actualName);
|
||||
Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
|
||||
List<Object> list = (List<Object>) propValue;
|
||||
int index = Integer.parseInt(key);
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor() && index < list.size()) {
|
||||
oldValue = list.get(index);
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
|
||||
requiredType, ph.nested(tokens.keys.length));
|
||||
int size = list.size();
|
||||
if (index >= size && index < this.autoGrowCollectionLimit) {
|
||||
for (int i = size; i < index; i++) {
|
||||
try {
|
||||
list.add(null);
|
||||
}
|
||||
catch (NullPointerException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot set element with index " + index + " in List of size " +
|
||||
size + ", accessed using property path '" + propertyName +
|
||||
"': List does not support filling up gaps with null elements");
|
||||
}
|
||||
}
|
||||
list.add(convertedValue);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
list.set(index, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Invalid list index in property path '" + propertyName + "'", ex);
|
||||
}
|
||||
int length = Array.getLength(propValue);
|
||||
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
|
||||
Class<?> componentType = propValue.getClass().getComponentType();
|
||||
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
|
||||
System.arraycopy(propValue, 0, newArray, 0, length);
|
||||
setPropertyValue(tokens.actualName, newArray);
|
||||
propValue = getPropertyValue(tokens.actualName);
|
||||
}
|
||||
Array.set(propValue, arrayIndex, convertedValue);
|
||||
}
|
||||
else if (propValue instanceof Map) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(actualName);
|
||||
Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
|
||||
Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);
|
||||
Map<Object, Object> map = (Map<Object, Object>) propValue;
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
|
||||
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor()) {
|
||||
oldValue = map.get(convertedMapKey);
|
||||
}
|
||||
// Pass full property name and old value in here, since we want full
|
||||
// conversion ability for map values.
|
||||
Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
mapValueType, ph.nested(tokens.keys.length));
|
||||
map.put(convertedMapKey, convertedMapValue);
|
||||
}
|
||||
else {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Property referenced in indexed property path '" + propertyName +
|
||||
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Invalid array index in property path '" + tokens.canonicalName + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
PropertyHandler ph = getLocalPropertyHandler(actualName);
|
||||
if (ph == null || !ph.isWritable()) {
|
||||
if (pv.isOptional()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Ignoring optional value for property '" + actualName +
|
||||
"' - property not found on bean class [" + getRootClass().getName() + "]");
|
||||
else if (propValue instanceof List) {
|
||||
PropertyHandler ph = getPropertyHandler(tokens.actualName);
|
||||
Class<?> requiredType = ph.getCollectionType(tokens.keys.length);
|
||||
List<Object> list = (List<Object>) propValue;
|
||||
int index = Integer.parseInt(lastKey);
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor() && index < list.size()) {
|
||||
oldValue = list.get(index);
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
|
||||
requiredType, ph.nested(tokens.keys.length));
|
||||
int size = list.size();
|
||||
if (index >= size && index < this.autoGrowCollectionLimit) {
|
||||
for (int i = size; i < index; i++) {
|
||||
try {
|
||||
list.add(null);
|
||||
}
|
||||
catch (NullPointerException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Cannot set element with index " + index + " in List of size " +
|
||||
size + ", accessed using property path '" + tokens.canonicalName +
|
||||
"': List does not support filling up gaps with null elements");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw createNotWritablePropertyException(propertyName);
|
||||
list.add(convertedValue);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
list.set(index, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Invalid list index in property path '" + tokens.canonicalName + "'", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (propValue instanceof Map) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
|
||||
Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length);
|
||||
Class<?> mapValueType = ph.getMapValueType(tokens.keys.length);
|
||||
Map<Object, Object> map = (Map<Object, Object>) propValue;
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
|
||||
Object convertedMapKey = convertIfNecessary(null, null, lastKey, mapKeyType, typeDescriptor);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
Object originalValue = pv.getValue();
|
||||
Object valueToApply = originalValue;
|
||||
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
|
||||
if (pv.isConverted()) {
|
||||
valueToApply = pv.getConvertedValue();
|
||||
}
|
||||
else {
|
||||
if (isExtractOldValueForEditor() && ph.isReadable()) {
|
||||
try {
|
||||
oldValue = ph.getValue();
|
||||
if (isExtractOldValueForEditor()) {
|
||||
oldValue = map.get(convertedMapKey);
|
||||
}
|
||||
// Pass full property name and old value in here, since we want full
|
||||
// conversion ability for map values.
|
||||
Object convertedMapValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
|
||||
mapValueType, ph.nested(tokens.keys.length));
|
||||
map.put(convertedMapKey, convertedMapValue);
|
||||
}
|
||||
|
||||
else {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Property referenced in indexed property path '" + tokens.canonicalName +
|
||||
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private Object getPropertyHoldingValue(PropertyTokenHolder tokens) {
|
||||
// Apply indexes and map keys: fetch value for all keys but the last one.
|
||||
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
|
||||
getterTokens.canonicalName = tokens.canonicalName;
|
||||
getterTokens.actualName = tokens.actualName;
|
||||
getterTokens.keys = new String[tokens.keys.length - 1];
|
||||
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);
|
||||
|
||||
Object propValue;
|
||||
try {
|
||||
propValue = getPropertyValue(getterTokens);
|
||||
}
|
||||
catch (NotReadablePropertyException ex) {
|
||||
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + tokens.canonicalName + "'", ex);
|
||||
}
|
||||
|
||||
if (propValue == null) {
|
||||
// null map value case
|
||||
if (isAutoGrowNestedPaths()) {
|
||||
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
|
||||
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
|
||||
propValue = setDefaultValue(getterTokens);
|
||||
}
|
||||
else {
|
||||
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + tokens.canonicalName,
|
||||
"Cannot access indexed value in property referenced " +
|
||||
"in indexed property path '" + tokens.canonicalName + "': returned null");
|
||||
}
|
||||
}
|
||||
return propValue;
|
||||
}
|
||||
|
||||
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
|
||||
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
|
||||
if (ph == null || !ph.isWritable()) {
|
||||
if (pv.isOptional()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Ignoring optional value for property '" + tokens.actualName +
|
||||
"' - property not found on bean class [" + getRootClass().getName() + "]");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw createNotWritablePropertyException(tokens.canonicalName);
|
||||
}
|
||||
}
|
||||
|
||||
Object oldValue = null;
|
||||
try {
|
||||
Object originalValue = pv.getValue();
|
||||
Object valueToApply = originalValue;
|
||||
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
|
||||
if (pv.isConverted()) {
|
||||
valueToApply = pv.getConvertedValue();
|
||||
}
|
||||
else {
|
||||
if (isExtractOldValueForEditor() && ph.isReadable()) {
|
||||
try {
|
||||
oldValue = ph.getValue();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex instanceof PrivilegedActionException) {
|
||||
ex = ((PrivilegedActionException) ex).getException();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex instanceof PrivilegedActionException) {
|
||||
ex = ((PrivilegedActionException) ex).getException();
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not read previous value of property '" +
|
||||
this.nestedPath + propertyName + "'", ex);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not read previous value of property '" +
|
||||
this.nestedPath + tokens.canonicalName + "'", ex);
|
||||
}
|
||||
}
|
||||
valueToApply = convertForProperty(
|
||||
propertyName, oldValue, originalValue, ph.toTypeDescriptor());
|
||||
}
|
||||
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
|
||||
valueToApply = convertForProperty(
|
||||
tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
|
||||
}
|
||||
ph.setValue(this.wrappedObject, valueToApply);
|
||||
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
throw ex;
|
||||
ph.setValue(this.wrappedObject, valueToApply);
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
|
||||
this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
|
||||
if (ex.getTargetException() instanceof ClassCastException) {
|
||||
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
PropertyChangeEvent propertyChangeEvent =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
if (ex.getTargetException() instanceof ClassCastException) {
|
||||
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
|
||||
}
|
||||
else {
|
||||
Throwable cause = ex.getTargetException();
|
||||
if (cause instanceof UndeclaredThrowableException) {
|
||||
// May happen e.g. with Groovy-generated methods
|
||||
cause = cause.getCause();
|
||||
}
|
||||
throw new MethodInvocationException(propertyChangeEvent, cause);
|
||||
else {
|
||||
Throwable cause = ex.getTargetException();
|
||||
if (cause instanceof UndeclaredThrowableException) {
|
||||
// May happen e.g. with Groovy-generated methods
|
||||
cause = cause.getCause();
|
||||
}
|
||||
throw new MethodInvocationException(propertyChangeEvent, cause);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
PropertyChangeEvent pce =
|
||||
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
|
||||
throw new MethodInvocationException(pce, ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
PropertyChangeEvent pce = new PropertyChangeEvent(
|
||||
this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
|
||||
throw new MethodInvocationException(pce, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -973,9 +987,6 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle a given property.
|
||||
*/
|
||||
protected abstract static class PropertyHandler {
|
||||
|
||||
private final Class<?> propertyType;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,8 +18,6 @@ package org.springframework.beans;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
|
||||
import org.springframework.core.ErrorCoded;
|
||||
|
||||
/**
|
||||
* Superclass for exceptions related to a property access,
|
||||
* such as type mismatch or invocation target exception.
|
||||
@@ -27,8 +25,8 @@ import org.springframework.core.ErrorCoded;
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class PropertyAccessException extends BeansException implements ErrorCoded {
|
||||
@SuppressWarnings({"serial", "deprecation"})
|
||||
public abstract class PropertyAccessException extends BeansException implements org.springframework.core.ErrorCoded {
|
||||
|
||||
private transient PropertyChangeEvent propertyChangeEvent;
|
||||
|
||||
@@ -77,4 +75,10 @@ public abstract class PropertyAccessException extends BeansException implements
|
||||
return (this.propertyChangeEvent != null ? this.propertyChangeEvent.getNewValue() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a corresponding error code for this type of exception.
|
||||
*/
|
||||
@Override
|
||||
public abstract String getErrorCode();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,8 +30,8 @@ import org.springframework.util.StringUtils;
|
||||
* Helper class for calculating property matches, according to a configurable
|
||||
* distance. Provide the list of potential matches and an easy way to generate
|
||||
* an error message. Works for both java bean properties and fields.
|
||||
* <p>
|
||||
* Mainly for use within the framework and in particular the binding facility
|
||||
*
|
||||
* <p>Mainly for use within the framework and in particular the binding facility.
|
||||
*
|
||||
* @author Alef Arendsen
|
||||
* @author Arjen Poutsma
|
||||
@@ -43,14 +43,12 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class PropertyMatches {
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Static section
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/** Default maximum property distance: 2 */
|
||||
public static final int DEFAULT_MAX_DISTANCE = 2;
|
||||
|
||||
|
||||
// Static factory methods
|
||||
|
||||
/**
|
||||
* Create PropertyMatches for the given bean property.
|
||||
* @param propertyName the name of the property to find possible matches for
|
||||
@@ -90,9 +88,7 @@ public abstract class PropertyMatches {
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Instance section
|
||||
//---------------------------------------------------------------------
|
||||
// Instance state
|
||||
|
||||
private final String propertyName;
|
||||
|
||||
@@ -107,18 +103,19 @@ public abstract class PropertyMatches {
|
||||
this.possibleMatches = possibleMatches;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of the requested property.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
return this.propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the calculated possible matches.
|
||||
*/
|
||||
public String[] getPossibleMatches() {
|
||||
return possibleMatches;
|
||||
return this.possibleMatches;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,6 +124,9 @@ public abstract class PropertyMatches {
|
||||
*/
|
||||
public abstract String buildErrorMessage();
|
||||
|
||||
|
||||
// Implementation support for subclasses
|
||||
|
||||
protected void appendHintMessage(StringBuilder msg) {
|
||||
msg.append("Did you mean ");
|
||||
for (int i = 0; i < this.possibleMatches.length; i++) {
|
||||
@@ -150,10 +150,10 @@ public abstract class PropertyMatches {
|
||||
* @return the distance value
|
||||
*/
|
||||
private static int calculateStringDistance(String s1, String s2) {
|
||||
if (s1.length() == 0) {
|
||||
if (s1.isEmpty()) {
|
||||
return s2.length();
|
||||
}
|
||||
if (s2.length() == 0) {
|
||||
if (s2.isEmpty()) {
|
||||
return s1.length();
|
||||
}
|
||||
int d[][] = new int[s1.length() + 1][s2.length() + 1];
|
||||
@@ -184,9 +184,12 @@ public abstract class PropertyMatches {
|
||||
return d[s1.length()][s2.length()];
|
||||
}
|
||||
|
||||
|
||||
// Concrete subclasses
|
||||
|
||||
private static class BeanPropertyMatches extends PropertyMatches {
|
||||
|
||||
private BeanPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
public BeanPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
super(propertyName, calculateMatches(propertyName,
|
||||
BeanUtils.getPropertyDescriptors(beanClass), maxDistance));
|
||||
}
|
||||
@@ -231,12 +234,12 @@ public abstract class PropertyMatches {
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class FieldPropertyMatches extends PropertyMatches {
|
||||
|
||||
private FieldPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
public FieldPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
super(propertyName, calculateMatches(propertyName, beanClass, maxDistance));
|
||||
}
|
||||
|
||||
@@ -255,7 +258,6 @@ public abstract class PropertyMatches {
|
||||
return StringUtils.toStringArray(candidates);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String buildErrorMessage() {
|
||||
String propertyName = getPropertyName();
|
||||
@@ -270,7 +272,6 @@ public abstract class PropertyMatches {
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -290,15 +290,15 @@ class TypeConverterDelegate {
|
||||
|
||||
// Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Cannot convert value of type [").append(ClassUtils.getDescriptiveType(newValue));
|
||||
msg.append("] to required type [").append(ClassUtils.getQualifiedName(requiredType)).append("]");
|
||||
msg.append("Cannot convert value of type '").append(ClassUtils.getDescriptiveType(newValue));
|
||||
msg.append("' to required type '").append(ClassUtils.getQualifiedName(requiredType)).append("'");
|
||||
if (propertyName != null) {
|
||||
msg.append(" for property '").append(propertyName).append("'");
|
||||
}
|
||||
if (editor != null) {
|
||||
msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
|
||||
"] returned inappropriate value of type [").append(
|
||||
ClassUtils.getDescriptiveType(convertedValue)).append("]");
|
||||
"] returned inappropriate value of type '").append(
|
||||
ClassUtils.getDescriptiveType(convertedValue)).append("'");
|
||||
throw new IllegalArgumentException(msg.toString());
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -57,10 +57,10 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
*/
|
||||
public TypeMismatchException(PropertyChangeEvent propertyChangeEvent, Class<?> requiredType, Throwable cause) {
|
||||
super(propertyChangeEvent,
|
||||
"Failed to convert property value of type [" +
|
||||
ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "]" +
|
||||
"Failed to convert property value of type '" +
|
||||
ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "'" +
|
||||
(requiredType != null ?
|
||||
" to required type [" + ClassUtils.getQualifiedName(requiredType) + "]" : "") +
|
||||
" to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : "") +
|
||||
(propertyChangeEvent.getPropertyName() != null ?
|
||||
" for property '" + propertyChangeEvent.getPropertyName() + "'" : ""),
|
||||
cause);
|
||||
@@ -84,8 +84,8 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
* @param cause the root cause (may be {@code null})
|
||||
*/
|
||||
public TypeMismatchException(Object value, Class<?> requiredType, Throwable cause) {
|
||||
super("Failed to convert value of type [" + ClassUtils.getDescriptiveType(value) + "]" +
|
||||
(requiredType != null ? " to required type [" + ClassUtils.getQualifiedName(requiredType) + "]" : ""),
|
||||
super("Failed to convert value of type '" + ClassUtils.getDescriptiveType(value) + "'" +
|
||||
(requiredType != null ? " to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : ""),
|
||||
cause);
|
||||
this.value = value;
|
||||
this.requiredType = requiredType;
|
||||
|
||||
@@ -63,31 +63,35 @@ import org.springframework.core.ResolvableType;
|
||||
* are supposed to override beans of the same name in any parent factory.
|
||||
*
|
||||
* <p>Bean factory implementations should support the standard bean lifecycle interfaces
|
||||
* as far as possible. The full set of initialization methods and their standard order is:<br>
|
||||
* 1. BeanNameAware's {@code setBeanName}<br>
|
||||
* 2. BeanClassLoaderAware's {@code setBeanClassLoader}<br>
|
||||
* 3. BeanFactoryAware's {@code setBeanFactory}<br>
|
||||
* 4. EnvironmentAware's {@code setEnvironment}
|
||||
* 5. EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
|
||||
* 6. ResourceLoaderAware's {@code setResourceLoader}
|
||||
* (only applicable when running in an application context)<br>
|
||||
* 7. ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
|
||||
* (only applicable when running in an application context)<br>
|
||||
* 8. MessageSourceAware's {@code setMessageSource}
|
||||
* (only applicable when running in an application context)<br>
|
||||
* 9. ApplicationContextAware's {@code setApplicationContext}
|
||||
* (only applicable when running in an application context)<br>
|
||||
* 10. ServletContextAware's {@code setServletContext}
|
||||
* (only applicable when running in a web application context)<br>
|
||||
* 11. {@code postProcessBeforeInitialization} methods of BeanPostProcessors<br>
|
||||
* 12. InitializingBean's {@code afterPropertiesSet}<br>
|
||||
* 13. a custom init-method definition<br>
|
||||
* 14. {@code postProcessAfterInitialization} methods of BeanPostProcessors
|
||||
* as far as possible. The full set of initialization methods and their standard order is:
|
||||
* <ol>
|
||||
* <li>BeanNameAware's {@code setBeanName}
|
||||
* <li>BeanClassLoaderAware's {@code setBeanClassLoader}
|
||||
* <li>BeanFactoryAware's {@code setBeanFactory}
|
||||
* <li>EnvironmentAware's {@code setEnvironment}
|
||||
* <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
|
||||
* <li>ResourceLoaderAware's {@code setResourceLoader}
|
||||
* (only applicable when running in an application context)
|
||||
* <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
|
||||
* (only applicable when running in an application context)
|
||||
* <li>MessageSourceAware's {@code setMessageSource}
|
||||
* (only applicable when running in an application context)
|
||||
* <li>ApplicationContextAware's {@code setApplicationContext}
|
||||
* (only applicable when running in an application context)
|
||||
* <li>ServletContextAware's {@code setServletContext}
|
||||
* (only applicable when running in a web application context)
|
||||
* <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
|
||||
* <li>InitializingBean's {@code afterPropertiesSet}
|
||||
* <li>a custom init-method definition
|
||||
* <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
|
||||
* </ol>
|
||||
*
|
||||
* <p>On shutdown of a bean factory, the following lifecycle methods apply:<br>
|
||||
* 1. {@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
|
||||
* 2. DisposableBean's {@code destroy}<br>
|
||||
* 3. a custom destroy-method definition
|
||||
* <p>On shutdown of a bean factory, the following lifecycle methods apply:
|
||||
* <ol>
|
||||
* <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
|
||||
* <li>DisposableBean's {@code destroy}
|
||||
* <li>a custom destroy-method definition
|
||||
* </ol>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
|
||||
+3
-2
@@ -17,6 +17,7 @@
|
||||
package org.springframework.beans.factory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Thrown when a bean doesn't match the expected type.
|
||||
@@ -45,8 +46,8 @@ public class BeanNotOfRequiredTypeException extends BeansException {
|
||||
* the expected type
|
||||
*/
|
||||
public BeanNotOfRequiredTypeException(String beanName, Class<?> requiredType, Class<?> actualType) {
|
||||
super("Bean named '" + beanName + "' is expected to be of type [" + requiredType.getName() +
|
||||
"] but was actually of type [" + actualType.getName() + "]");
|
||||
super("Bean named '" + beanName + "' is expected to be of type '" + ClassUtils.getQualifiedName(requiredType) +
|
||||
"' but was actually of type '" + ClassUtils.getQualifiedName(actualType) + "'");
|
||||
this.beanName = beanName;
|
||||
this.requiredType = requiredType;
|
||||
this.actualType = actualType;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,31 +17,34 @@
|
||||
package org.springframework.beans.factory;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by objects used within a {@link BeanFactory}
|
||||
* which are themselves factories. If a bean implements this interface,
|
||||
* it is used as a factory for an object to expose, not directly as a bean
|
||||
* instance that will be exposed itself.
|
||||
* Interface to be implemented by objects used within a {@link BeanFactory} which
|
||||
* are themselves factories for individual objects. If a bean implements this
|
||||
* interface, it is used as a factory for an object to expose, not directly as a
|
||||
* bean instance that will be exposed itself.
|
||||
*
|
||||
* <p><b>NB: A bean that implements this interface cannot be used as a
|
||||
* normal bean.</b> A FactoryBean is defined in a bean style, but the
|
||||
* object exposed for bean references ({@link #getObject()} is always
|
||||
* the object that it creates.
|
||||
* <p><b>NB: A bean that implements this interface cannot be used as a normal bean.</b>
|
||||
* A FactoryBean is defined in a bean style, but the object exposed for bean
|
||||
* references ({@link #getObject()}) is always the object that it creates.
|
||||
*
|
||||
* <p>FactoryBeans can support singletons and prototypes, and can
|
||||
* either create objects lazily on demand or eagerly on startup.
|
||||
* The {@link SmartFactoryBean} interface allows for exposing
|
||||
* more fine-grained behavioral metadata.
|
||||
* <p>FactoryBeans can support singletons and prototypes, and can either create
|
||||
* objects lazily on demand or eagerly on startup. The {@link SmartFactoryBean}
|
||||
* interface allows for exposing more fine-grained behavioral metadata.
|
||||
*
|
||||
* <p>This interface is heavily used within the framework itself, for
|
||||
* example for the AOP {@link org.springframework.aop.framework.ProxyFactoryBean}
|
||||
* or the {@link org.springframework.jndi.JndiObjectFactoryBean}.
|
||||
* It can be used for application components as well; however,
|
||||
* this is not common outside of infrastructure code.
|
||||
* <p>This interface is heavily used within the framework itself, for example for
|
||||
* the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the
|
||||
* {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for
|
||||
* custom components as well; however, this is only common for infrastructure code.
|
||||
*
|
||||
* <p><b>NOTE:</b> FactoryBean objects participate in the containing
|
||||
* BeanFactory's synchronization of bean creation. There is usually no
|
||||
* need for internal synchronization other than for purposes of lazy
|
||||
* initialization within the FactoryBean itself (or the like).
|
||||
* <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not
|
||||
* supposed to rely on annotation-driven injection or other reflective facilities.</b>
|
||||
* {@link #getObjectType()} {@link #getObject()} invocations may arrive early in
|
||||
* the bootstrap process, even ahead of any post-processor setup. If you need access
|
||||
* other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
|
||||
*
|
||||
* <p>Finally, FactoryBean objects participate in the containing BeanFactory's
|
||||
* synchronization of bean creation. There is usually no need for internal
|
||||
* synchronization other than for purposes of lazy initialization within the
|
||||
* FactoryBean itself (or the like).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
|
||||
+44
-13
@@ -17,6 +17,7 @@
|
||||
package org.springframework.beans.factory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -27,6 +28,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @see BeanFactory#getBean(String)
|
||||
* @see BeanFactory#getBean(Class)
|
||||
* @see NoUniqueBeanDefinitionException
|
||||
@@ -34,11 +36,9 @@ import org.springframework.util.StringUtils;
|
||||
@SuppressWarnings("serial")
|
||||
public class NoSuchBeanDefinitionException extends BeansException {
|
||||
|
||||
/** Name of the missing bean */
|
||||
private String beanName;
|
||||
|
||||
/** Required type of the missing bean */
|
||||
private Class<?> beanType;
|
||||
private ResolvableType resolvableType;
|
||||
|
||||
|
||||
/**
|
||||
@@ -46,7 +46,7 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
||||
* @param name the name of the missing bean
|
||||
*/
|
||||
public NoSuchBeanDefinitionException(String name) {
|
||||
super("No bean named '" + name + "' is defined");
|
||||
super("No bean named '" + name + "' available");
|
||||
this.beanName = name;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
||||
* @param message detailed message describing the problem
|
||||
*/
|
||||
public NoSuchBeanDefinitionException(String name, String message) {
|
||||
super("No bean named '" + name + "' is defined: " + message);
|
||||
super("No bean named '" + name + "' available: " + message);
|
||||
this.beanName = name;
|
||||
}
|
||||
|
||||
@@ -65,8 +65,7 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
||||
* @param type required type of the missing bean
|
||||
*/
|
||||
public NoSuchBeanDefinitionException(Class<?> type) {
|
||||
super("No qualifying bean of type [" + type.getName() + "] is defined");
|
||||
this.beanType = type;
|
||||
this(ResolvableType.forClass(type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,8 +74,28 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
||||
* @param message detailed message describing the problem
|
||||
*/
|
||||
public NoSuchBeanDefinitionException(Class<?> type, String message) {
|
||||
super("No qualifying bean of type [" + ClassUtils.getQualifiedName(type) + "] is defined: " + message);
|
||||
this.beanType = type;
|
||||
this(ResolvableType.forClass(type), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code NoSuchBeanDefinitionException}.
|
||||
* @param type full type declaration of the missing bean
|
||||
* @since 4.3.4
|
||||
*/
|
||||
public NoSuchBeanDefinitionException(ResolvableType type) {
|
||||
super("No qualifying bean of type '" + type + "' available");
|
||||
this.resolvableType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code NoSuchBeanDefinitionException}.
|
||||
* @param type full type declaration of the missing bean
|
||||
* @param message detailed message describing the problem
|
||||
* @since 4.3.4
|
||||
*/
|
||||
public NoSuchBeanDefinitionException(ResolvableType type, String message) {
|
||||
super("No qualifying bean of type '" + type + "' available: " + message);
|
||||
this.resolvableType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,13 +103,15 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
||||
* @param type required type of the missing bean
|
||||
* @param dependencyDescription a description of the originating dependency
|
||||
* @param message detailed message describing the problem
|
||||
* @deprecated as of 4.3.4, in favor of {@link #NoSuchBeanDefinitionException(ResolvableType, String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public NoSuchBeanDefinitionException(Class<?> type, String dependencyDescription, String message) {
|
||||
super("No qualifying bean" + (!StringUtils.hasLength(dependencyDescription) ?
|
||||
" of type [" + ClassUtils.getQualifiedName(type) + "]" : "") + " found for dependency" +
|
||||
" of type '" + ClassUtils.getQualifiedName(type) + "'" : "") + " found for dependency" +
|
||||
(StringUtils.hasLength(dependencyDescription) ? " [" + dependencyDescription + "]" : "") +
|
||||
": " + message);
|
||||
this.beanType = type;
|
||||
this.resolvableType = ResolvableType.forClass(type);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,10 +123,20 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the required type of the missing bean, if it was a lookup <em>by type</em> that failed.
|
||||
* Return the required type of the missing bean, if it was a lookup <em>by type</em>
|
||||
* that failed.
|
||||
*/
|
||||
public Class<?> getBeanType() {
|
||||
return this.beanType;
|
||||
return (this.resolvableType != null ? this.resolvableType.resolve() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the required {@link ResolvableType} of the missing bean, if it was a lookup
|
||||
* <em>by type</em> that failed.
|
||||
* @since 4.3.4
|
||||
*/
|
||||
public ResolvableType getResolvableType() {
|
||||
return this.resolvableType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+60
-41
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -220,10 +220,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
|
||||
throw new IllegalArgumentException(
|
||||
"AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory");
|
||||
"AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory: " + beanFactory);
|
||||
}
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
@@ -238,35 +238,56 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
|
||||
@Override
|
||||
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeansException {
|
||||
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
|
||||
throws BeanCreationException {
|
||||
|
||||
// Let's check for lookup methods here..
|
||||
if (!this.lookupMethodsChecked.contains(beanName)) {
|
||||
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
Lookup lookup = method.getAnnotation(Lookup.class);
|
||||
if (lookup != null) {
|
||||
LookupOverride override = new LookupOverride(method, lookup.value());
|
||||
try {
|
||||
RootBeanDefinition mbd = (RootBeanDefinition) beanFactory.getMergedBeanDefinition(beanName);
|
||||
mbd.getMethodOverrides().addOverride(override);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Cannot apply @Lookup to beans without corresponding bean definition");
|
||||
try {
|
||||
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
Lookup lookup = method.getAnnotation(Lookup.class);
|
||||
if (lookup != null) {
|
||||
LookupOverride override = new LookupOverride(method, lookup.value());
|
||||
try {
|
||||
RootBeanDefinition mbd = (RootBeanDefinition) beanFactory.getMergedBeanDefinition(beanName);
|
||||
mbd.getMethodOverrides().addOverride(override);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Cannot apply @Lookup to beans without corresponding bean definition");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
|
||||
}
|
||||
catch (NoClassDefFoundError err) {
|
||||
throw new BeanCreationException(beanName, "Failed to introspect bean class [" + beanClass.getName() +
|
||||
"] for lookup method metadata: could not find class that it depends on", err);
|
||||
}
|
||||
this.lookupMethodsChecked.add(beanName);
|
||||
}
|
||||
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
|
||||
if (candidateConstructors == null) {
|
||||
// Fully synchronized resolution now...
|
||||
synchronized (this.candidateConstructorsCache) {
|
||||
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
|
||||
if (candidateConstructors == null) {
|
||||
Constructor<?>[] rawCandidates = beanClass.getDeclaredConstructors();
|
||||
Constructor<?>[] rawCandidates;
|
||||
try {
|
||||
rawCandidates = beanClass.getDeclaredConstructors();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
|
||||
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
|
||||
}
|
||||
List<Constructor<?>> candidates = new ArrayList<Constructor<?>>(rawCandidates.length);
|
||||
Constructor<?> requiredConstructor = null;
|
||||
Constructor<?> defaultConstructor = null;
|
||||
@@ -292,10 +313,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
". Found constructor with 'required' Autowired annotation already: " +
|
||||
requiredConstructor);
|
||||
}
|
||||
if (candidate.getParameterTypes().length == 0) {
|
||||
throw new IllegalStateException(
|
||||
"Autowired annotation requires at least one argument: " + candidate);
|
||||
}
|
||||
boolean required = determineRequiredStatus(ann);
|
||||
if (required) {
|
||||
if (!candidates.isEmpty()) {
|
||||
@@ -320,9 +337,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
else if (candidates.size() == 1 && logger.isWarnEnabled()) {
|
||||
logger.warn("Inconsistent constructor declaration on bean with name '" + beanName +
|
||||
"': single autowire-marked constructor flagged as optional - this constructor " +
|
||||
"is effectively required since there is no default constructor to fall back to: " +
|
||||
candidates.get(0));
|
||||
"': single autowire-marked constructor flagged as optional - " +
|
||||
"this constructor is effectively required since there is no " +
|
||||
"default constructor to fall back to: " + candidates.get(0));
|
||||
}
|
||||
}
|
||||
candidateConstructors = candidates.toArray(new Constructor<?>[candidates.size()]);
|
||||
@@ -342,7 +359,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
@Override
|
||||
public PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
|
||||
|
||||
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
|
||||
try {
|
||||
@@ -361,9 +378,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
* 'Native' processing method for direct calls with an arbitrary target instance,
|
||||
* resolving all of its fields and methods which are annotated with {@code @Autowired}.
|
||||
* @param bean the target instance to process
|
||||
* @throws BeansException if autowiring failed
|
||||
* @throws BeanCreationException if autowiring failed
|
||||
*/
|
||||
public void processInjection(Object bean) throws BeansException {
|
||||
public void processInjection(Object bean) throws BeanCreationException {
|
||||
Class<?> clazz = bean.getClass();
|
||||
InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);
|
||||
try {
|
||||
@@ -373,7 +390,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
throw ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);
|
||||
throw new BeanCreationException(
|
||||
"Injection of autowired dependencies failed for class [" + clazz + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,7 +464,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
if (method.getParameterTypes().length == 0) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Autowired annotation should be used on methods with parameters: " + method);
|
||||
logger.warn("Autowired annotation should only be used on methods with parameters: " +
|
||||
method);
|
||||
}
|
||||
}
|
||||
boolean required = determineRequiredStatus(ann);
|
||||
@@ -629,7 +648,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
arguments = new Object[paramTypes.length];
|
||||
DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(paramTypes.length);
|
||||
Set<String> autowiredBeans = new LinkedHashSet<String>(paramTypes.length);
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
@@ -637,7 +656,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
currDesc.setContainingClass(bean.getClass());
|
||||
descriptors[i] = currDesc;
|
||||
try {
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeanNames, typeConverter);
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
|
||||
if (arg == null && !this.required) {
|
||||
arguments = null;
|
||||
break;
|
||||
@@ -655,9 +674,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
this.cachedMethodArguments[i] = descriptors[i];
|
||||
}
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == paramTypes.length) {
|
||||
Iterator<String> it = autowiredBeanNames.iterator();
|
||||
registerDependentBeans(beanName, autowiredBeans);
|
||||
if (autowiredBeans.size() == paramTypes.length) {
|
||||
Iterator<String> it = autowiredBeans.iterator();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
String autowiredBeanName = it.next();
|
||||
if (beanFactory.containsBean(autowiredBeanName)) {
|
||||
@@ -706,19 +725,19 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
@SuppressWarnings("serial")
|
||||
private static class ShortcutDependencyDescriptor extends DependencyDescriptor {
|
||||
|
||||
private final String shortcutName;
|
||||
private final String shortcut;
|
||||
|
||||
private final Class<?> requiredType;
|
||||
|
||||
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcutName, Class<?> requiredType) {
|
||||
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) {
|
||||
super(original);
|
||||
this.shortcutName = shortcutName;
|
||||
this.shortcut = shortcut;
|
||||
this.requiredType = requiredType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveShortcut(BeanFactory beanFactory) {
|
||||
return resolveCandidate(this.shortcutName, this.requiredType, beanFactory);
|
||||
return resolveCandidate(this.shortcut, this.requiredType, beanFactory);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -40,6 +40,7 @@ import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcess
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -349,7 +350,7 @@ public class InitDestroyAnnotationBeanPostProcessor
|
||||
}
|
||||
this.method = method;
|
||||
this.identifier = (Modifier.isPrivate(method.getModifiers()) ?
|
||||
method.getDeclaringClass() + "." + method.getName() : method.getName());
|
||||
ClassUtils.getQualifiedMethodName(method) : method.getName());
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -141,8 +141,7 @@ public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanP
|
||||
|
||||
@Override
|
||||
public PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
|
||||
throws BeansException {
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
|
||||
|
||||
if (!this.validatedBeanNames.contains(beanName)) {
|
||||
if (!shouldSkip(this.beanFactory, beanName)) {
|
||||
|
||||
+72
-58
@@ -79,10 +79,7 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
int ROLE_INFRASTRUCTURE = 2;
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of the parent definition of this bean definition, if any.
|
||||
*/
|
||||
String getParentName();
|
||||
// Modifiable attributes
|
||||
|
||||
/**
|
||||
* Set the name of the parent definition of this bean definition, if any.
|
||||
@@ -90,52 +87,33 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
void setParentName(String parentName);
|
||||
|
||||
/**
|
||||
* Return the current bean class name of this bean definition.
|
||||
* <p>Note that this does not have to be the actual class name used at runtime, in
|
||||
* case of a child definition overriding/inheriting the class name from its parent.
|
||||
* Hence, do <i>not</i> consider this to be the definitive bean type at runtime but
|
||||
* rather only use it for parsing purposes at the individual bean definition level.
|
||||
* Return the name of the parent definition of this bean definition, if any.
|
||||
*/
|
||||
String getBeanClassName();
|
||||
String getParentName();
|
||||
|
||||
/**
|
||||
* Override the bean class name of this bean definition.
|
||||
* Specify the bean class name of this bean definition.
|
||||
* <p>The class name can be modified during bean factory post-processing,
|
||||
* typically replacing the original class name with a parsed variant of it.
|
||||
* @see #setParentName
|
||||
* @see #setFactoryBeanName
|
||||
* @see #setFactoryMethodName
|
||||
*/
|
||||
void setBeanClassName(String beanClassName);
|
||||
|
||||
/**
|
||||
* Return the factory bean name, if any.
|
||||
* Return the current bean class name of this bean definition.
|
||||
* <p>Note that this does not have to be the actual class name used at runtime, in
|
||||
* case of a child definition overriding/inheriting the class name from its parent.
|
||||
* Also, this may just be the class that a factory method is called on, or it may
|
||||
* even be empty in case of a factory bean reference that a method is called on.
|
||||
* Hence, do <i>not</i> consider this to be the definitive bean type at runtime but
|
||||
* rather only use it for parsing purposes at the individual bean definition level.
|
||||
* @see #getParentName()
|
||||
* @see #getFactoryBeanName()
|
||||
* @see #getFactoryMethodName()
|
||||
*/
|
||||
String getFactoryBeanName();
|
||||
|
||||
/**
|
||||
* Specify the factory bean to use, if any.
|
||||
*/
|
||||
void setFactoryBeanName(String factoryBeanName);
|
||||
|
||||
/**
|
||||
* Return a factory method, if any.
|
||||
*/
|
||||
String getFactoryMethodName();
|
||||
|
||||
/**
|
||||
* Specify a factory method, if any. This method will be invoked with
|
||||
* constructor arguments, or with no arguments if none are specified.
|
||||
* The method will be invoked on the specified factory bean, if any,
|
||||
* or otherwise as a static method on the local bean class.
|
||||
* @param factoryMethodName static factory method name,
|
||||
* or {@code null} if normal constructor creation should be used
|
||||
* @see #getBeanClassName()
|
||||
*/
|
||||
void setFactoryMethodName(String factoryMethodName);
|
||||
|
||||
/**
|
||||
* Return the name of the current target scope for this bean,
|
||||
* or {@code null} if not known yet.
|
||||
*/
|
||||
String getScope();
|
||||
String getBeanClassName();
|
||||
|
||||
/**
|
||||
* Override the target scope of this bean, specifying a new scope name.
|
||||
@@ -145,10 +123,10 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
void setScope(String scope);
|
||||
|
||||
/**
|
||||
* Return whether this bean should be lazily initialized, i.e. not
|
||||
* eagerly instantiated on startup. Only applicable to a singleton bean.
|
||||
* Return the name of the current target scope for this bean,
|
||||
* or {@code null} if not known yet.
|
||||
*/
|
||||
boolean isLazyInit();
|
||||
String getScope();
|
||||
|
||||
/**
|
||||
* Set whether this bean should be lazily initialized.
|
||||
@@ -158,9 +136,10 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
void setLazyInit(boolean lazyInit);
|
||||
|
||||
/**
|
||||
* Return the bean names that this bean depends on.
|
||||
* Return whether this bean should be lazily initialized, i.e. not
|
||||
* eagerly instantiated on startup. Only applicable to a singleton bean.
|
||||
*/
|
||||
String[] getDependsOn();
|
||||
boolean isLazyInit();
|
||||
|
||||
/**
|
||||
* Set the names of the beans that this bean depends on being initialized.
|
||||
@@ -168,30 +147,63 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
*/
|
||||
void setDependsOn(String... dependsOn);
|
||||
|
||||
/**
|
||||
* Return the bean names that this bean depends on.
|
||||
*/
|
||||
String[] getDependsOn();
|
||||
|
||||
/**
|
||||
* Set whether this bean is a candidate for getting autowired into some other bean.
|
||||
* <p>Note that this flag is designed to only affect type-based autowiring.
|
||||
* It does not affect explicit references by name, which will get resolved even
|
||||
* if the specified bean is not marked as an autowire candidate. As a consequence,
|
||||
* autowiring by name will nevertheless inject a bean if the name matches.
|
||||
*/
|
||||
void setAutowireCandidate(boolean autowireCandidate);
|
||||
|
||||
/**
|
||||
* Return whether this bean is a candidate for getting autowired into some other bean.
|
||||
*/
|
||||
boolean isAutowireCandidate();
|
||||
|
||||
/**
|
||||
* Set whether this bean is a candidate for getting autowired into some other bean.
|
||||
*/
|
||||
void setAutowireCandidate(boolean autowireCandidate);
|
||||
|
||||
/**
|
||||
* Return whether this bean is a primary autowire candidate.
|
||||
* If this value is true for exactly one bean among multiple
|
||||
* matching candidates, it will serve as a tie-breaker.
|
||||
*/
|
||||
boolean isPrimary();
|
||||
|
||||
/**
|
||||
* Set whether this bean is a primary autowire candidate.
|
||||
* <p>If this value is true for exactly one bean among multiple
|
||||
* <p>If this value is {@code true} for exactly one bean among multiple
|
||||
* matching candidates, it will serve as a tie-breaker.
|
||||
*/
|
||||
void setPrimary(boolean primary);
|
||||
|
||||
/**
|
||||
* Return whether this bean is a primary autowire candidate.
|
||||
*/
|
||||
boolean isPrimary();
|
||||
|
||||
/**
|
||||
* Specify the factory bean to use, if any.
|
||||
* This the name of the bean to call the specified factory method on.
|
||||
* @see #setFactoryMethodName
|
||||
*/
|
||||
void setFactoryBeanName(String factoryBeanName);
|
||||
|
||||
/**
|
||||
* Return the factory bean name, if any.
|
||||
*/
|
||||
String getFactoryBeanName();
|
||||
|
||||
/**
|
||||
* Specify a factory method, if any. This method will be invoked with
|
||||
* constructor arguments, or with no arguments if none are specified.
|
||||
* The method will be invoked on the specified factory bean, if any,
|
||||
* or otherwise as a static method on the local bean class.
|
||||
* @see #setFactoryBeanName
|
||||
* @see #setBeanClassName
|
||||
*/
|
||||
void setFactoryMethodName(String factoryMethodName);
|
||||
|
||||
/**
|
||||
* Return a factory method, if any.
|
||||
*/
|
||||
String getFactoryMethodName();
|
||||
|
||||
/**
|
||||
* Return the constructor argument values for this bean.
|
||||
@@ -208,6 +220,8 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
|
||||
MutablePropertyValues getPropertyValues();
|
||||
|
||||
|
||||
// Read-only attributes
|
||||
|
||||
/**
|
||||
* Return whether this a <b>Singleton</b>, with a single, shared instance
|
||||
* returned on all calls.
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -102,12 +102,12 @@ public class CustomScopeConfigurer implements BeanFactoryPostProcessor, BeanClas
|
||||
}
|
||||
else if (value instanceof Class) {
|
||||
Class<?> scopeClass = (Class<?>) value;
|
||||
Assert.isAssignable(Scope.class, scopeClass);
|
||||
Assert.isAssignable(Scope.class, scopeClass, "Invalid scope class");
|
||||
beanFactory.registerScope(scopeKey, (Scope) BeanUtils.instantiateClass(scopeClass));
|
||||
}
|
||||
else if (value instanceof String) {
|
||||
Class<?> scopeClass = ClassUtils.resolveClassName((String) value, this.beanClassLoader);
|
||||
Assert.isAssignable(Scope.class, scopeClass);
|
||||
Assert.isAssignable(Scope.class, scopeClass, "Invalid scope class");
|
||||
beanFactory.registerScope(scopeKey, (Scope) BeanUtils.instantiateClass(scopeClass));
|
||||
}
|
||||
else {
|
||||
|
||||
+23
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,7 +28,6 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.InjectionPoint;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
@@ -63,6 +62,8 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
|
||||
private Class<?> containingClass;
|
||||
|
||||
private volatile ResolvableType resolvableType;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new descriptor for a method or constructor parameter.
|
||||
@@ -214,6 +215,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
*/
|
||||
public void increaseNestingLevel() {
|
||||
this.nestingLevel++;
|
||||
this.resolvableType = null;
|
||||
if (this.methodParameter != null) {
|
||||
this.methodParameter.increaseNestingLevel();
|
||||
}
|
||||
@@ -227,6 +229,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
*/
|
||||
public void setContainingClass(Class<?> containingClass) {
|
||||
this.containingClass = containingClass;
|
||||
this.resolvableType = null;
|
||||
if (this.methodParameter != null) {
|
||||
GenericTypeResolver.resolveParameterType(this.methodParameter, containingClass);
|
||||
}
|
||||
@@ -237,8 +240,12 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
* @since 4.0
|
||||
*/
|
||||
public ResolvableType getResolvableType() {
|
||||
return (this.field != null ? ResolvableType.forField(this.field, this.nestingLevel, this.containingClass) :
|
||||
ResolvableType.forMethodParameter(this.methodParameter));
|
||||
if (this.resolvableType == null) {
|
||||
this.resolvableType = (this.field != null ?
|
||||
ResolvableType.forField(this.field, this.nestingLevel, this.containingClass) :
|
||||
ResolvableType.forMethodParameter(this.methodParameter));
|
||||
}
|
||||
return this.resolvableType;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,31 +331,37 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
/**
|
||||
* Determine the generic element type of the wrapped Collection parameter/field, if any.
|
||||
* @return the generic type, or {@code null} if none
|
||||
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
|
||||
*/
|
||||
@Deprecated
|
||||
public Class<?> getCollectionType() {
|
||||
return (this.field != null ?
|
||||
GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
|
||||
GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
|
||||
org.springframework.core.GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
|
||||
org.springframework.core.GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the generic key type of the wrapped Map parameter/field, if any.
|
||||
* @return the generic type, or {@code null} if none
|
||||
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
|
||||
*/
|
||||
@Deprecated
|
||||
public Class<?> getMapKeyType() {
|
||||
return (this.field != null ?
|
||||
GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
|
||||
GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
|
||||
org.springframework.core.GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
|
||||
org.springframework.core.GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the generic value type of the wrapped Map parameter/field, if any.
|
||||
* @return the generic type, or {@code null} if none
|
||||
* @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
|
||||
*/
|
||||
@Deprecated
|
||||
public Class<?> getMapValueType() {
|
||||
return (this.field != null ?
|
||||
GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
|
||||
GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
|
||||
org.springframework.core.GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
|
||||
org.springframework.core.GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -103,7 +103,6 @@ public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
|
||||
* @see org.springframework.beans.MutablePropertyValues
|
||||
*/
|
||||
PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
|
||||
throws BeansException;
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;
|
||||
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -66,8 +66,7 @@ public abstract class InstantiationAwareBeanPostProcessorAdapter implements Smar
|
||||
|
||||
@Override
|
||||
public PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
|
||||
throws BeansException {
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
|
||||
|
||||
return pvs;
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
/**
|
||||
* Simple factory for shared List instances. Allows for central setup
|
||||
@@ -86,7 +86,7 @@ public class ListFactoryBean extends AbstractFactoryBean<List<Object>> {
|
||||
}
|
||||
Class<?> valueType = null;
|
||||
if (this.targetListClass != null) {
|
||||
valueType = GenericCollectionTypeResolver.getCollectionType(this.targetListClass);
|
||||
valueType = ResolvableType.forClass(this.targetListClass).asCollection().resolveGeneric();
|
||||
}
|
||||
if (valueType != null) {
|
||||
TypeConverter converter = getBeanTypeConverter();
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,7 @@ import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
/**
|
||||
* Simple factory for shared Map instances. Allows for central setup
|
||||
@@ -87,8 +87,9 @@ public class MapFactoryBean extends AbstractFactoryBean<Map<Object, Object>> {
|
||||
Class<?> keyType = null;
|
||||
Class<?> valueType = null;
|
||||
if (this.targetMapClass != null) {
|
||||
keyType = GenericCollectionTypeResolver.getMapKeyType(this.targetMapClass);
|
||||
valueType = GenericCollectionTypeResolver.getMapValueType(this.targetMapClass);
|
||||
ResolvableType mapType = ResolvableType.forClass(this.targetMapClass).asMap();
|
||||
keyType = mapType.resolveGeneric(0);
|
||||
valueType = mapType.resolveGeneric(1);
|
||||
}
|
||||
if (keyType != null || valueType != null) {
|
||||
TypeConverter converter = getBeanTypeConverter();
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -69,7 +69,7 @@ import org.springframework.beans.factory.FactoryBeanNotInitializedException;
|
||||
* </bean>
|
||||
*
|
||||
* <bean id="javaVersion" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
|
||||
* <property name="targetObject" value="sysProps"/>
|
||||
* <property name="targetObject" ref="sysProps"/>
|
||||
* <property name="targetMethod" value="getProperty"/>
|
||||
* <property name="arguments" value="java.version"/>
|
||||
* </bean></pre>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -68,6 +68,7 @@ public interface Scope {
|
||||
* @param objectFactory the {@link ObjectFactory} to use to create the scoped
|
||||
* object if it is not present in the underlying storage mechanism
|
||||
* @return the desired object (never {@code null})
|
||||
* @throws IllegalStateException if the underlying scope is not currently active
|
||||
*/
|
||||
Object get(String name, ObjectFactory<?> objectFactory);
|
||||
|
||||
@@ -84,6 +85,7 @@ public interface Scope {
|
||||
* removing an object.
|
||||
* @param name the name of the object to remove
|
||||
* @return the removed object, or {@code null} if no object was present
|
||||
* @throws IllegalStateException if the underlying scope is not currently active
|
||||
* @see #registerDestructionCallback
|
||||
*/
|
||||
Object remove(String name);
|
||||
@@ -112,6 +114,7 @@ public interface Scope {
|
||||
* so it can safely be executed without an enclosing try-catch block.
|
||||
* Furthermore, the Runnable will usually be serializable, provided
|
||||
* that its target object is serializable as well.
|
||||
* @throws IllegalStateException if the underlying scope is not currently active
|
||||
* @see org.springframework.beans.factory.DisposableBean
|
||||
* @see org.springframework.beans.factory.support.AbstractBeanDefinition#getDestroyMethodName()
|
||||
* @see DestructionAwareBeanPostProcessor
|
||||
@@ -123,6 +126,7 @@ public interface Scope {
|
||||
* E.g. the HttpServletRequest object for key "request".
|
||||
* @param key the contextual key
|
||||
* @return the corresponding object, or {@code null} if none found
|
||||
* @throws IllegalStateException if the underlying scope is not currently active
|
||||
*/
|
||||
Object resolveContextualObject(String key);
|
||||
|
||||
@@ -139,6 +143,7 @@ public interface Scope {
|
||||
* underlying storage mechanism has no obvious candidate for such an ID.
|
||||
* @return the conversation ID, or {@code null} if there is no
|
||||
* conversation ID for the current scope
|
||||
* @throws IllegalStateException if the underlying scope is not currently active
|
||||
*/
|
||||
String getConversationId();
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,7 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
/**
|
||||
* Simple factory for shared Set instances. Allows for central setup
|
||||
@@ -86,7 +86,7 @@ public class SetFactoryBean extends AbstractFactoryBean<Set<Object>> {
|
||||
}
|
||||
Class<?> valueType = null;
|
||||
if (this.targetSetClass != null) {
|
||||
valueType = GenericCollectionTypeResolver.getCollectionType(this.targetSetClass);
|
||||
valueType = ResolvableType.forClass(this.targetSetClass).asCollection().resolveGeneric();
|
||||
}
|
||||
if (valueType != null) {
|
||||
TypeConverter converter = getBeanTypeConverter();
|
||||
|
||||
+14
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,12 +25,16 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Factory for a Map that reads from a YAML source. YAML is a nice human-readable
|
||||
* format for configuration, and it has some useful hierarchical properties. It's
|
||||
* more or less a superset of JSON, so it has a lot of similar features. If
|
||||
* multiple resources are provided the later ones will override entries in the
|
||||
* earlier ones hierarchically - that is all entries with the same nested key of
|
||||
* type Map at any depth are merged. For example:
|
||||
* Factory for a {@code Map} that reads from a YAML source, preserving the
|
||||
* YAML-declared value types and their structure.
|
||||
*
|
||||
* <p>YAML is a nice human-readable format for configuration, and it has some
|
||||
* useful hierarchical properties. It's more or less a superset of JSON, so it
|
||||
* has a lot of similar features.
|
||||
*
|
||||
* <p>If multiple resources are provided the later ones will override entries in
|
||||
* the earlier ones hierarchically; that is, all entries with the same nested key
|
||||
* of type {@code Map} at any depth are merged. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* foo:
|
||||
@@ -62,6 +66,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
* with the value in the second, but its nested values are merged.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
*/
|
||||
public class YamlMapFactoryBean extends YamlProcessor implements FactoryBean<Map<String, Object>>, InitializingBean {
|
||||
@@ -104,10 +109,10 @@ public class YamlMapFactoryBean extends YamlProcessor implements FactoryBean<Map
|
||||
|
||||
/**
|
||||
* Template method that subclasses may override to construct the object
|
||||
* returned by this factory. The default implementation returns the
|
||||
* merged Map instance.
|
||||
* returned by this factory.
|
||||
* <p>Invoked lazily the first time {@link #getObject()} is invoked in
|
||||
* case of a shared singleton; else, on each {@link #getObject()} call.
|
||||
* <p>The default implementation returns the merged {@code Map} instance.
|
||||
* @return the object returned by this factory
|
||||
* @see #process(java.util.Map, MatchCallback)
|
||||
*/
|
||||
|
||||
+12
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,6 +37,7 @@ import org.yaml.snakeyaml.nodes.MappingNode;
|
||||
import org.yaml.snakeyaml.parser.ParserException;
|
||||
import org.yaml.snakeyaml.reader.UnicodeReader;
|
||||
|
||||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -45,6 +46,7 @@ import org.springframework.util.StringUtils;
|
||||
* Base class for YAML factories.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
*/
|
||||
public abstract class YamlProcessor {
|
||||
@@ -217,7 +219,7 @@ public abstract class YamlProcessor {
|
||||
}
|
||||
|
||||
private boolean process(Map<String, Object> map, MatchCallback callback) {
|
||||
Properties properties = new Properties();
|
||||
Properties properties = CollectionFactory.createStringAdaptingProperties();
|
||||
properties.putAll(getFlattenedMap(map));
|
||||
|
||||
if (this.documentMatchers.isEmpty()) {
|
||||
@@ -278,7 +280,7 @@ public abstract class YamlProcessor {
|
||||
key = path + key;
|
||||
}
|
||||
else {
|
||||
key = path + "." + key;
|
||||
key = path + '.' + key;
|
||||
}
|
||||
}
|
||||
Object value = entry.getValue();
|
||||
@@ -302,21 +304,23 @@ public abstract class YamlProcessor {
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.put(key, value != null ? value : "");
|
||||
result.put(key, (value != null ? value : ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback interface used to process properties in a resulting map.
|
||||
* Callback interface used to process the YAML parsing results.
|
||||
*/
|
||||
public interface MatchCallback {
|
||||
|
||||
/**
|
||||
* Process the properties.
|
||||
* @param properties the properties to process
|
||||
* @param map a mutable result map
|
||||
* Process the given representation of the parsing results.
|
||||
* @param properties the properties to process (as a flattened
|
||||
* representation with indexed keys in case of a collection or map)
|
||||
* @param map the result map (preserving the original value structure
|
||||
* in the YAML document)
|
||||
*/
|
||||
void process(Properties properties, Map<String, Object> map);
|
||||
}
|
||||
|
||||
+20
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,13 +21,23 @@ import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.CollectionFactory;
|
||||
|
||||
/**
|
||||
* Factory for Java Properties that reads from a YAML source. YAML is a nice
|
||||
* human-readable format for configuration, and it has some useful hierarchical
|
||||
* properties. It's more or less a superset of JSON, so it has a lot of similar
|
||||
* features. The Properties created by this factory have nested paths for
|
||||
* hierarchical objects, so for instance this YAML
|
||||
* Factory for {@link java.util.Properties} that reads from a YAML source,
|
||||
* exposing a flat structure of String property values.
|
||||
*
|
||||
* <p>YAML is a nice human-readable format for configuration, and it has some
|
||||
* useful hierarchical properties. It's more or less a superset of JSON, so it
|
||||
* has a lot of similar features.
|
||||
*
|
||||
* <p><b>Note: All exposed values are of type {@code String}</b> for access through
|
||||
* the common {@link Properties#getProperty} method (e.g. in configuration property
|
||||
* resolution through {@link PropertyResourceConfigurer#setProperties(Properties)}).
|
||||
* If this is not desirable, use {@link YamlMapFactoryBean} instead.
|
||||
*
|
||||
* <p>The Properties created by this factory have nested paths for hierarchical
|
||||
* objects, so for instance this YAML
|
||||
*
|
||||
* <pre class="code">
|
||||
* environments:
|
||||
@@ -39,7 +49,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
* name: My Cool App
|
||||
* </pre>
|
||||
*
|
||||
* is transformed into these Properties:
|
||||
* is transformed into these properties:
|
||||
*
|
||||
* <pre class="code">
|
||||
* environments.dev.url=http://dev.bar.com
|
||||
@@ -57,7 +67,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
* - foo.bar.com
|
||||
* </pre>
|
||||
*
|
||||
* becomes Java Properties like this:
|
||||
* becomes properties like this:
|
||||
*
|
||||
* <pre class="code">
|
||||
* servers[0]=dev.bar.com
|
||||
@@ -66,6 +76,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Stephane Nicoll
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
*/
|
||||
public class YamlPropertiesFactoryBean extends YamlProcessor implements FactoryBean<Properties>, InitializingBean {
|
||||
@@ -116,7 +127,7 @@ public class YamlPropertiesFactoryBean extends YamlProcessor implements FactoryB
|
||||
* @see #process(MatchCallback) ()
|
||||
*/
|
||||
protected Properties createProperties() {
|
||||
final Properties result = new Properties();
|
||||
final Properties result = CollectionFactory.createStringAdaptingProperties();
|
||||
process(new MatchCallback() {
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
|
||||
+109
-62
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -74,6 +74,7 @@ import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
@@ -500,7 +501,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @see #instantiateUsingFactoryMethod
|
||||
* @see #autowireConstructor
|
||||
*/
|
||||
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
|
||||
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
|
||||
throws BeanCreationException {
|
||||
|
||||
// Instantiate the bean.
|
||||
BeanWrapper instanceWrapper = null;
|
||||
if (mbd.isSingleton()) {
|
||||
@@ -511,11 +514,18 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
}
|
||||
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
|
||||
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
|
||||
mbd.resolvedTargetType = beanType;
|
||||
|
||||
// Allow post-processors to modify the merged bean definition.
|
||||
synchronized (mbd.postProcessingLock) {
|
||||
if (!mbd.postProcessed) {
|
||||
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
|
||||
try {
|
||||
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Post-processing of merged bean definition failed", ex);
|
||||
}
|
||||
mbd.postProcessed = true;
|
||||
}
|
||||
}
|
||||
@@ -550,7 +560,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
throw (BeanCreationException) ex;
|
||||
}
|
||||
else {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
|
||||
throw new BeanCreationException(
|
||||
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,7 +597,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
registerDisposableBeanIfNecessary(beanName, bean, mbd);
|
||||
}
|
||||
catch (BeanDefinitionValidationException ex) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
|
||||
throw new BeanCreationException(
|
||||
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
|
||||
}
|
||||
|
||||
return exposedObject;
|
||||
@@ -649,9 +661,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @see #createBean
|
||||
*/
|
||||
protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
|
||||
Class<?> preResolved = mbd.resolvedFactoryMethodReturnType;
|
||||
if (preResolved != null) {
|
||||
return preResolved;
|
||||
ResolvableType cachedReturnType = mbd.factoryMethodReturnType;
|
||||
if (cachedReturnType != null) {
|
||||
return cachedReturnType.resolve();
|
||||
}
|
||||
|
||||
Class<?> factoryClass;
|
||||
@@ -675,11 +687,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
if (factoryClass == null) {
|
||||
return null;
|
||||
}
|
||||
factoryClass = ClassUtils.getUserClass(factoryClass);
|
||||
|
||||
// If all factory methods have the same return type, return that type.
|
||||
// Can't clearly figure out exact method due to type converting / autowiring!
|
||||
Class<?> commonType = null;
|
||||
boolean cache = false;
|
||||
Method uniqueCandidate = null;
|
||||
int minNrOfArgs = mbd.getConstructorArgumentValues().getArgumentCount();
|
||||
Method[] candidates = ReflectionUtils.getUniqueDeclaredMethods(factoryClass);
|
||||
for (Method factoryMethod : candidates) {
|
||||
@@ -714,8 +727,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
|
||||
factoryMethod, args, getBeanClassLoader());
|
||||
if (returnType != null) {
|
||||
cache = true;
|
||||
uniqueCandidate = (commonType == null ? factoryMethod : null);
|
||||
commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
|
||||
if (commonType == null) {
|
||||
// Ambiguous return types found: return null to indicate "not determinable".
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
@@ -725,22 +742,22 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
}
|
||||
}
|
||||
else {
|
||||
uniqueCandidate = (commonType == null ? factoryMethod : null);
|
||||
commonType = ClassUtils.determineCommonAncestor(factoryMethod.getReturnType(), commonType);
|
||||
if (commonType == null) {
|
||||
// Ambiguous return types found: return null to indicate "not determinable".
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (commonType != null) {
|
||||
// Clear return type found: all factory methods return same type.
|
||||
if (cache) {
|
||||
mbd.resolvedFactoryMethodReturnType = commonType;
|
||||
}
|
||||
return commonType;
|
||||
}
|
||||
else {
|
||||
// Ambiguous return types found: return null to indicate "not determinable".
|
||||
return null;
|
||||
mbd.factoryMethodReturnType = (uniqueCandidate != null ?
|
||||
ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType));
|
||||
}
|
||||
return commonType;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -756,32 +773,21 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
|
||||
class Holder { Class<?> value = null; }
|
||||
final Holder objectType = new Holder();
|
||||
String factoryBeanName = mbd.getFactoryBeanName();
|
||||
final String factoryMethodName = mbd.getFactoryMethodName();
|
||||
String factoryMethodName = mbd.getFactoryMethodName();
|
||||
|
||||
if (factoryBeanName != null) {
|
||||
if (factoryMethodName != null) {
|
||||
// Try to obtain the FactoryBean's object type without instantiating it at all.
|
||||
// Try to obtain the FactoryBean's object type from its factory method declaration
|
||||
// without instantiating the containing bean at all.
|
||||
BeanDefinition fbDef = getBeanDefinition(factoryBeanName);
|
||||
if (fbDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) fbDef).hasBeanClass()) {
|
||||
// CGLIB subclass methods hide generic parameters; look at the original user class.
|
||||
Class<?> fbClass = ClassUtils.getUserClass(((AbstractBeanDefinition) fbDef).getBeanClass());
|
||||
// Find the given factory method, taking into account that in the case of
|
||||
// @Bean methods, there may be parameters present.
|
||||
ReflectionUtils.doWithMethods(fbClass,
|
||||
new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
if (method.getName().equals(factoryMethodName) &&
|
||||
FactoryBean.class.isAssignableFrom(method.getReturnType())) {
|
||||
objectType.value = GenericTypeResolver.resolveReturnTypeArgument(method, FactoryBean.class);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (objectType.value != null && Object.class != objectType.value) {
|
||||
return objectType.value;
|
||||
if (fbDef instanceof AbstractBeanDefinition) {
|
||||
AbstractBeanDefinition afbDef = (AbstractBeanDefinition) fbDef;
|
||||
if (afbDef.hasBeanClass()) {
|
||||
Class<?> result = getTypeForFactoryBeanFromMethod(afbDef.getBeanClass(), factoryMethodName);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -793,15 +799,16 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
}
|
||||
}
|
||||
|
||||
// Let's obtain a shortcut instance for an early getObjectType() call...
|
||||
FactoryBean<?> fb = (mbd.isSingleton() ?
|
||||
getSingletonFactoryBeanForTypeCheck(beanName, mbd) :
|
||||
getNonSingletonFactoryBeanForTypeCheck(beanName, mbd));
|
||||
|
||||
if (fb != null) {
|
||||
// Try to obtain the FactoryBean's object type from this early stage of the instance.
|
||||
objectType.value = getTypeForFactoryBean(fb);
|
||||
if (objectType.value != null) {
|
||||
return objectType.value;
|
||||
Class<?> result = getTypeForFactoryBean(fb);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
// No type found for shortcut FactoryBean instance:
|
||||
@@ -810,9 +817,54 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
}
|
||||
}
|
||||
|
||||
if (factoryBeanName == null && mbd.hasBeanClass()) {
|
||||
// No early bean instantiation possible: determine FactoryBean's type from
|
||||
// static factory method signature or from class inheritance hierarchy...
|
||||
if (factoryMethodName != null) {
|
||||
return getTypeForFactoryBeanFromMethod(mbd.getBeanClass(), factoryMethodName);
|
||||
}
|
||||
else {
|
||||
return GenericTypeResolver.resolveTypeArgument(mbd.getBeanClass(), FactoryBean.class);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Introspect the factory method signatures on the given bean class,
|
||||
* trying to find a common {@code FactoryBean} object type declared there.
|
||||
* @param beanClass the bean class to find the factory method on
|
||||
* @param factoryMethodName the name of the factory method
|
||||
* @return the common {@code FactoryBean} object type, or {@code null} if none
|
||||
*/
|
||||
private Class<?> getTypeForFactoryBeanFromMethod(Class<?> beanClass, final String factoryMethodName) {
|
||||
class Holder { Class<?> value = null; }
|
||||
final Holder objectType = new Holder();
|
||||
|
||||
// CGLIB subclass methods hide generic parameters; look at the original user class.
|
||||
Class<?> fbClass = ClassUtils.getUserClass(beanClass);
|
||||
|
||||
// Find the given factory method, taking into account that in the case of
|
||||
// @Bean methods, there may be parameters present.
|
||||
ReflectionUtils.doWithMethods(fbClass,
|
||||
new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) {
|
||||
if (method.getName().equals(factoryMethodName) &&
|
||||
FactoryBean.class.isAssignableFrom(method.getReturnType())) {
|
||||
Class<?> currentType = GenericTypeResolver.resolveReturnTypeArgument(
|
||||
method, FactoryBean.class);
|
||||
if (currentType != null) {
|
||||
objectType.value = ClassUtils.determineCommonAncestor(currentType, objectType.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return (objectType.value != null && Object.class != objectType.value ? objectType.value : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a reference for early access to the specified bean,
|
||||
* typically for the purpose of resolving a circular reference.
|
||||
@@ -860,6 +912,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
(mbd.getFactoryBeanName() != null && isSingletonCurrentlyInCreation(mbd.getFactoryBeanName()))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object instance = null;
|
||||
try {
|
||||
// Mark this bean as currently in creation, even if just partially.
|
||||
@@ -875,6 +928,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
// Finished partial creation of this bean.
|
||||
afterSingletonCreation(beanName);
|
||||
}
|
||||
|
||||
FactoryBean<?> fb = getFactoryBean(beanName, instance);
|
||||
if (bw != null) {
|
||||
this.factoryBeanInstanceCache.put(beanName, bw);
|
||||
@@ -895,6 +949,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
if (isPrototypeCurrentlyInCreation(beanName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object instance = null;
|
||||
try {
|
||||
// Mark this bean as currently in creation, even if just partially.
|
||||
@@ -918,6 +973,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
// Finished partial creation of this bean.
|
||||
afterPrototypeCreation(beanName);
|
||||
}
|
||||
|
||||
return getFactoryBean(beanName, instance);
|
||||
}
|
||||
|
||||
@@ -927,24 +983,15 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @param mbd the merged bean definition for the bean
|
||||
* @param beanType the actual type of the managed bean instance
|
||||
* @param beanName the name of the bean
|
||||
* @throws BeansException if any post-processing failed
|
||||
* @see MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
|
||||
*/
|
||||
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName)
|
||||
throws BeansException {
|
||||
|
||||
try {
|
||||
for (BeanPostProcessor bp : getBeanPostProcessors()) {
|
||||
if (bp instanceof MergedBeanDefinitionPostProcessor) {
|
||||
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
|
||||
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
|
||||
}
|
||||
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
|
||||
for (BeanPostProcessor bp : getBeanPostProcessors()) {
|
||||
if (bp instanceof MergedBeanDefinitionPostProcessor) {
|
||||
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
|
||||
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Post-processing failed of bean type [" + beanType + "] failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -981,12 +1028,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @param beanClass the class of the bean to be instantiated
|
||||
* @param beanName the name of the bean
|
||||
* @return the bean object to use instead of a default instance of the target bean, or {@code null}
|
||||
* @throws BeansException if any post-processing failed
|
||||
* @see InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
|
||||
*/
|
||||
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)
|
||||
throws BeansException {
|
||||
|
||||
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
|
||||
for (BeanPostProcessor bp : getBeanPostProcessors()) {
|
||||
if (bp instanceof InstantiationAwareBeanPostProcessor) {
|
||||
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
|
||||
@@ -1107,7 +1151,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
return bw;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
|
||||
throw new BeanCreationException(
|
||||
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1659,7 +1704,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* methods with arguments.
|
||||
* @see #invokeInitMethods
|
||||
*/
|
||||
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
|
||||
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
|
||||
throws Throwable {
|
||||
|
||||
String initMethodName = mbd.getInitMethodName();
|
||||
final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
|
||||
BeanUtils.findMethod(bean.getClass(), initMethodName) :
|
||||
|
||||
+102
-66
@@ -48,6 +48,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Mark Fisher
|
||||
* @see GenericBeanDefinition
|
||||
* @see RootBeanDefinition
|
||||
* @see ChildBeanDefinition
|
||||
*/
|
||||
@@ -159,16 +160,16 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
|
||||
private boolean lenientConstructorResolution = true;
|
||||
|
||||
private String factoryBeanName;
|
||||
|
||||
private String factoryMethodName;
|
||||
|
||||
private ConstructorArgumentValues constructorArgumentValues;
|
||||
|
||||
private MutablePropertyValues propertyValues;
|
||||
|
||||
private MethodOverrides methodOverrides = new MethodOverrides();
|
||||
|
||||
private String factoryBeanName;
|
||||
|
||||
private String factoryMethodName;
|
||||
|
||||
private String initMethodName;
|
||||
|
||||
private String destroyMethodName;
|
||||
@@ -210,14 +211,14 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
protected AbstractBeanDefinition(BeanDefinition original) {
|
||||
setParentName(original.getParentName());
|
||||
setBeanClassName(original.getBeanClassName());
|
||||
setFactoryBeanName(original.getFactoryBeanName());
|
||||
setFactoryMethodName(original.getFactoryMethodName());
|
||||
setScope(original.getScope());
|
||||
setAbstract(original.isAbstract());
|
||||
setLazyInit(original.isLazyInit());
|
||||
setRole(original.getRole());
|
||||
setFactoryBeanName(original.getFactoryBeanName());
|
||||
setFactoryMethodName(original.getFactoryMethodName());
|
||||
setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues()));
|
||||
setPropertyValues(new MutablePropertyValues(original.getPropertyValues()));
|
||||
setRole(original.getRole());
|
||||
setSource(original.getSource());
|
||||
copyAttributesFrom(original);
|
||||
|
||||
@@ -230,15 +231,15 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
setDependencyCheck(originalAbd.getDependencyCheck());
|
||||
setDependsOn(originalAbd.getDependsOn());
|
||||
setAutowireCandidate(originalAbd.isAutowireCandidate());
|
||||
copyQualifiersFrom(originalAbd);
|
||||
setPrimary(originalAbd.isPrimary());
|
||||
copyQualifiersFrom(originalAbd);
|
||||
setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed());
|
||||
setLenientConstructorResolution(originalAbd.isLenientConstructorResolution());
|
||||
setMethodOverrides(new MethodOverrides(originalAbd.getMethodOverrides()));
|
||||
setInitMethodName(originalAbd.getInitMethodName());
|
||||
setEnforceInitMethod(originalAbd.isEnforceInitMethod());
|
||||
setDestroyMethodName(originalAbd.getDestroyMethodName());
|
||||
setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod());
|
||||
setMethodOverrides(new MethodOverrides(originalAbd.getMethodOverrides()));
|
||||
setSynthetic(originalAbd.isSynthetic());
|
||||
setResource(originalAbd.getResource());
|
||||
}
|
||||
@@ -268,20 +269,20 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
if (StringUtils.hasLength(other.getBeanClassName())) {
|
||||
setBeanClassName(other.getBeanClassName());
|
||||
}
|
||||
if (StringUtils.hasLength(other.getScope())) {
|
||||
setScope(other.getScope());
|
||||
}
|
||||
setAbstract(other.isAbstract());
|
||||
setLazyInit(other.isLazyInit());
|
||||
if (StringUtils.hasLength(other.getFactoryBeanName())) {
|
||||
setFactoryBeanName(other.getFactoryBeanName());
|
||||
}
|
||||
if (StringUtils.hasLength(other.getFactoryMethodName())) {
|
||||
setFactoryMethodName(other.getFactoryMethodName());
|
||||
}
|
||||
if (StringUtils.hasLength(other.getScope())) {
|
||||
setScope(other.getScope());
|
||||
}
|
||||
setAbstract(other.isAbstract());
|
||||
setLazyInit(other.isLazyInit());
|
||||
setRole(other.getRole());
|
||||
getConstructorArgumentValues().addArgumentValues(other.getConstructorArgumentValues());
|
||||
getPropertyValues().addPropertyValues(other.getPropertyValues());
|
||||
setRole(other.getRole());
|
||||
setSource(other.getSource());
|
||||
copyAttributesFrom(other);
|
||||
|
||||
@@ -290,14 +291,15 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
if (otherAbd.hasBeanClass()) {
|
||||
setBeanClass(otherAbd.getBeanClass());
|
||||
}
|
||||
setAutowireCandidate(otherAbd.isAutowireCandidate());
|
||||
setAutowireMode(otherAbd.getAutowireMode());
|
||||
copyQualifiersFrom(otherAbd);
|
||||
setPrimary(otherAbd.isPrimary());
|
||||
setDependencyCheck(otherAbd.getDependencyCheck());
|
||||
setDependsOn(otherAbd.getDependsOn());
|
||||
setAutowireCandidate(otherAbd.isAutowireCandidate());
|
||||
setPrimary(otherAbd.isPrimary());
|
||||
copyQualifiersFrom(otherAbd);
|
||||
setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed());
|
||||
setLenientConstructorResolution(otherAbd.isLenientConstructorResolution());
|
||||
getMethodOverrides().addOverrides(otherAbd.getMethodOverrides());
|
||||
if (StringUtils.hasLength(otherAbd.getInitMethodName())) {
|
||||
setInitMethodName(otherAbd.getInitMethodName());
|
||||
setEnforceInitMethod(otherAbd.isEnforceInitMethod());
|
||||
@@ -306,7 +308,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
setDestroyMethodName(otherAbd.getDestroyMethodName());
|
||||
setEnforceDestroyMethod(otherAbd.isEnforceDestroyMethod());
|
||||
}
|
||||
getMethodOverrides().addOverrides(otherAbd.getMethodOverrides());
|
||||
setSynthetic(otherAbd.isSynthetic());
|
||||
setResource(otherAbd.getResource());
|
||||
}
|
||||
@@ -331,10 +332,25 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
|
||||
|
||||
/**
|
||||
* Return whether this definition specifies a bean class.
|
||||
* Specify the bean class name of this bean definition.
|
||||
*/
|
||||
public boolean hasBeanClass() {
|
||||
return (this.beanClass instanceof Class);
|
||||
@Override
|
||||
public void setBeanClassName(String beanClassName) {
|
||||
this.beanClass = beanClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current bean class name of this bean definition.
|
||||
*/
|
||||
@Override
|
||||
public String getBeanClassName() {
|
||||
Object beanClassObject = this.beanClass;
|
||||
if (beanClassObject instanceof Class) {
|
||||
return ((Class<?>) beanClassObject).getName();
|
||||
}
|
||||
else {
|
||||
return (String) beanClassObject;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,20 +378,11 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
return (Class<?>) beanClassObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassName(String beanClassName) {
|
||||
this.beanClass = beanClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBeanClassName() {
|
||||
Object beanClassObject = this.beanClass;
|
||||
if (beanClassObject instanceof Class) {
|
||||
return ((Class<?>) beanClassObject).getName();
|
||||
}
|
||||
else {
|
||||
return (String) beanClassObject;
|
||||
}
|
||||
/**
|
||||
* Return whether this definition specifies a bean class.
|
||||
*/
|
||||
public boolean hasBeanClass() {
|
||||
return (this.beanClass instanceof Class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -396,7 +403,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
return resolvedClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the target scope for the bean.
|
||||
* <p>The default is singleton status, although this is only applied once
|
||||
@@ -478,7 +484,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
return this.lazyInit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the autowire mode. This determines whether any automagical detection
|
||||
* and setting of bean references will happen. Default is AUTOWIRE_NO,
|
||||
@@ -569,6 +574,12 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
|
||||
/**
|
||||
* Set whether this bean is a candidate for getting autowired into some other bean.
|
||||
* <p>Note that this flag is designed to only affect type-based autowiring.
|
||||
* It does not affect explicit references by name, which will get resolved even
|
||||
* if the specified bean is not marked as an autowire candidate. As a consequence,
|
||||
* autowiring by name will nevertheless inject a bean if the name matches.
|
||||
* @see #AUTOWIRE_BY_TYPE
|
||||
* @see #AUTOWIRE_BY_NAME
|
||||
*/
|
||||
@Override
|
||||
public void setAutowireCandidate(boolean autowireCandidate) {
|
||||
@@ -585,7 +596,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
|
||||
/**
|
||||
* Set whether this bean is a primary autowire candidate.
|
||||
* If this value is true for exactly one bean among multiple
|
||||
* <p>If this value is {@code true} for exactly one bean among multiple
|
||||
* matching candidates, it will serve as a tie-breaker.
|
||||
*/
|
||||
@Override
|
||||
@@ -595,8 +606,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
|
||||
/**
|
||||
* Return whether this bean is a primary autowire candidate.
|
||||
* If this value is true for exactly one bean among multiple
|
||||
* matching candidates, it will serve as a tie-breaker.
|
||||
*/
|
||||
@Override
|
||||
public boolean isPrimary() {
|
||||
@@ -643,7 +652,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
this.qualifiers.putAll(source.qualifiers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify whether to allow access to non-public constructors and methods,
|
||||
* for the case of externalized metadata pointing to those. The default is
|
||||
@@ -683,6 +691,45 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
return this.lenientConstructorResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the factory bean to use, if any.
|
||||
* This the name of the bean to call the specified factory method on.
|
||||
* @see #setFactoryMethodName
|
||||
*/
|
||||
@Override
|
||||
public void setFactoryBeanName(String factoryBeanName) {
|
||||
this.factoryBeanName = factoryBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the factory bean name, if any.
|
||||
*/
|
||||
@Override
|
||||
public String getFactoryBeanName() {
|
||||
return this.factoryBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a factory method, if any. This method will be invoked with
|
||||
* constructor arguments, or with no arguments if none are specified.
|
||||
* The method will be invoked on the specified factory bean, if any,
|
||||
* or otherwise as a static method on the local bean class.
|
||||
* @see #setFactoryBeanName
|
||||
* @see #setBeanClassName
|
||||
*/
|
||||
@Override
|
||||
public void setFactoryMethodName(String factoryMethodName) {
|
||||
this.factoryMethodName = factoryMethodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a factory method, if any.
|
||||
*/
|
||||
@Override
|
||||
public String getFactoryMethodName() {
|
||||
return this.factoryMethodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify constructor argument values for this bean.
|
||||
*/
|
||||
@@ -737,27 +784,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
return this.methodOverrides;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setFactoryBeanName(String factoryBeanName) {
|
||||
this.factoryBeanName = factoryBeanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFactoryBeanName() {
|
||||
return this.factoryBeanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFactoryMethodName(String factoryMethodName) {
|
||||
this.factoryMethodName = factoryMethodName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFactoryMethodName() {
|
||||
return this.factoryMethodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the initializer method. The default is {@code null}
|
||||
* in which case there is no initializer method.
|
||||
@@ -822,7 +848,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
return this.enforceDestroyMethod;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether this bean definition is 'synthetic', that is, not defined
|
||||
* by the application itself (for example, an infrastructure bean such
|
||||
@@ -855,7 +880,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
return this.role;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a human-readable description of this bean definition.
|
||||
*/
|
||||
@@ -863,6 +887,9 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a human-readable description of this bean definition.
|
||||
*/
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
@@ -891,6 +918,10 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
this.resource = new DescriptiveResource(resourceDescription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description of the resource that this bean definition
|
||||
* came from (for the purpose of showing context in case of errors).
|
||||
*/
|
||||
@Override
|
||||
public String getResourceDescription() {
|
||||
return (this.resource != null ? this.resource.getDescription() : null);
|
||||
@@ -903,6 +934,12 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
this.resource = new BeanDefinitionResource(originatingBd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the originating BeanDefinition, or {@code null} if none.
|
||||
* Allows for retrieving the decorated bean definition, if any.
|
||||
* <p>Note that this method returns the immediate originator. Iterate through the
|
||||
* originator chain to find the original BeanDefinition as defined by the user.
|
||||
*/
|
||||
@Override
|
||||
public BeanDefinition getOriginatingBeanDefinition() {
|
||||
return (this.resource instanceof BeanDefinitionResource ?
|
||||
@@ -981,7 +1018,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
*/
|
||||
public abstract AbstractBeanDefinition cloneBeanDefinition();
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
|
||||
+178
-144
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -134,13 +134,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
private final Set<PropertyEditorRegistrar> propertyEditorRegistrars =
|
||||
new LinkedHashSet<PropertyEditorRegistrar>(4);
|
||||
|
||||
/** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */
|
||||
private TypeConverter typeConverter;
|
||||
|
||||
/** Custom PropertyEditors to apply to the beans of this factory */
|
||||
private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
|
||||
new HashMap<Class<?>, Class<? extends PropertyEditor>>(4);
|
||||
|
||||
/** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */
|
||||
private TypeConverter typeConverter;
|
||||
|
||||
/** String resolvers to apply e.g. to annotation attribute values */
|
||||
private final List<StringValueResolver> embeddedValueResolvers = new LinkedList<StringValueResolver>();
|
||||
|
||||
@@ -287,13 +287,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
// Guarantee initialization of beans that the current bean depends on.
|
||||
String[] dependsOn = mbd.getDependsOn();
|
||||
if (dependsOn != null) {
|
||||
for (String dependsOnBean : dependsOn) {
|
||||
if (isDependent(beanName, dependsOnBean)) {
|
||||
for (String dep : dependsOn) {
|
||||
if (isDependent(beanName, dep)) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
|
||||
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
|
||||
}
|
||||
registerDependentBean(dependsOnBean, beanName);
|
||||
getBean(dependsOnBean);
|
||||
registerDependentBean(dep, beanName);
|
||||
getBean(dep);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,8 +372,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to convert bean '" + name + "' to required type [" +
|
||||
ClassUtils.getQualifiedName(requiredType) + "]", ex);
|
||||
logger.debug("Failed to convert bean '" + name + "' to required type '" +
|
||||
ClassUtils.getQualifiedName(requiredType) + "'", ex);
|
||||
}
|
||||
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
|
||||
}
|
||||
@@ -409,33 +409,31 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
return true;
|
||||
}
|
||||
|
||||
else {
|
||||
// No singleton instance found -> check bean definition.
|
||||
BeanFactory parentBeanFactory = getParentBeanFactory();
|
||||
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
|
||||
// No bean definition found in this factory -> delegate to parent.
|
||||
return parentBeanFactory.isSingleton(originalBeanName(name));
|
||||
}
|
||||
// No singleton instance found -> check bean definition.
|
||||
BeanFactory parentBeanFactory = getParentBeanFactory();
|
||||
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
|
||||
// No bean definition found in this factory -> delegate to parent.
|
||||
return parentBeanFactory.isSingleton(originalBeanName(name));
|
||||
}
|
||||
|
||||
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||
|
||||
// In case of FactoryBean, return singleton status of created object if not a dereference.
|
||||
if (mbd.isSingleton()) {
|
||||
if (isFactoryBean(beanName, mbd)) {
|
||||
if (BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
return true;
|
||||
}
|
||||
FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
|
||||
return factoryBean.isSingleton();
|
||||
}
|
||||
else {
|
||||
return !BeanFactoryUtils.isFactoryDereference(name);
|
||||
// In case of FactoryBean, return singleton status of created object if not a dereference.
|
||||
if (mbd.isSingleton()) {
|
||||
if (isFactoryBean(beanName, mbd)) {
|
||||
if (BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
return true;
|
||||
}
|
||||
FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
|
||||
return factoryBean.isSingleton();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
return !BeanFactoryUtils.isFactoryDereference(name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -453,32 +451,31 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
// In case of FactoryBean, return singleton status of created object if not a dereference.
|
||||
return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName, mbd));
|
||||
}
|
||||
else {
|
||||
// Singleton or scoped - not a prototype.
|
||||
// However, FactoryBean may still produce a prototype object...
|
||||
if (BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
return false;
|
||||
}
|
||||
if (isFactoryBean(beanName, mbd)) {
|
||||
final FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
|
||||
if (System.getSecurityManager() != null) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||
@Override
|
||||
public Boolean run() {
|
||||
return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factoryBean).isPrototype()) ||
|
||||
!factoryBean.isSingleton());
|
||||
}
|
||||
}, getAccessControlContext());
|
||||
}
|
||||
else {
|
||||
return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factoryBean).isPrototype()) ||
|
||||
!factoryBean.isSingleton());
|
||||
}
|
||||
|
||||
// Singleton or scoped - not a prototype.
|
||||
// However, FactoryBean may still produce a prototype object...
|
||||
if (BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
return false;
|
||||
}
|
||||
if (isFactoryBean(beanName, mbd)) {
|
||||
final FactoryBean<?> fb = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
|
||||
if (System.getSecurityManager() != null) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||
@Override
|
||||
public Boolean run() {
|
||||
return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
|
||||
!fb.isSingleton());
|
||||
}
|
||||
}, getAccessControlContext());
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
|
||||
!fb.isSingleton());
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -497,68 +494,91 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
return typeToMatch.isInstance(beanInstance);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return (!BeanFactoryUtils.isFactoryDereference(name) && typeToMatch.isInstance(beanInstance));
|
||||
else if (!BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
if (typeToMatch.isInstance(beanInstance)) {
|
||||
// Direct match for exposed instance?
|
||||
return true;
|
||||
}
|
||||
else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) {
|
||||
// Generics potentially only match on the target class, not on the proxy...
|
||||
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||
Class<?> targetType = mbd.getTargetType();
|
||||
if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance) &&
|
||||
typeToMatch.isAssignableFrom(targetType)) {
|
||||
// Check raw class match as well, making sure it's exposed on the proxy.
|
||||
Class<?> classToMatch = typeToMatch.resolve();
|
||||
return (classToMatch == null || classToMatch.isInstance(beanInstance));
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
|
||||
// null instance registered
|
||||
return false;
|
||||
}
|
||||
|
||||
else {
|
||||
// No singleton instance found -> check bean definition.
|
||||
BeanFactory parentBeanFactory = getParentBeanFactory();
|
||||
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
|
||||
// No bean definition found in this factory -> delegate to parent.
|
||||
return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
|
||||
// No singleton instance found -> check bean definition.
|
||||
BeanFactory parentBeanFactory = getParentBeanFactory();
|
||||
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
|
||||
// No bean definition found in this factory -> delegate to parent.
|
||||
return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
|
||||
}
|
||||
|
||||
// Retrieve corresponding bean definition.
|
||||
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||
|
||||
Class<?> classToMatch = typeToMatch.resolve();
|
||||
if (classToMatch == null) {
|
||||
classToMatch = FactoryBean.class;
|
||||
}
|
||||
Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
|
||||
new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
|
||||
|
||||
// Check decorated bean definition, if any: We assume it'll be easier
|
||||
// to determine the decorated bean's type than the proxy's type.
|
||||
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
|
||||
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
|
||||
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
|
||||
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
|
||||
return typeToMatch.isAssignableFrom(targetClass);
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve corresponding bean definition.
|
||||
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||
Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
|
||||
if (beanType == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Class<?> classToMatch = typeToMatch.getRawClass();
|
||||
Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
|
||||
new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
|
||||
|
||||
// Check decorated bean definition, if any: We assume it'll be easier
|
||||
// to determine the decorated bean's type than the proxy's type.
|
||||
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
|
||||
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
|
||||
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
|
||||
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
|
||||
return typeToMatch.isAssignableFrom(targetClass);
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
|
||||
if (beanType == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check bean class whether we're dealing with a FactoryBean.
|
||||
if (FactoryBean.class.isAssignableFrom(beanType)) {
|
||||
if (!BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
|
||||
beanType = getTypeForFactoryBean(beanName, mbd);
|
||||
if (beanType == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
|
||||
// type but we nevertheless are being asked to dereference a FactoryBean...
|
||||
// Let's check the original bean class and proceed with it if it is a FactoryBean.
|
||||
beanType = predictBeanType(beanName, mbd, FactoryBean.class);
|
||||
if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
|
||||
// Check bean class whether we're dealing with a FactoryBean.
|
||||
if (FactoryBean.class.isAssignableFrom(beanType)) {
|
||||
if (!BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
|
||||
beanType = getTypeForFactoryBean(beanName, mbd);
|
||||
if (beanType == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return typeToMatch.isAssignableFrom(beanType);
|
||||
}
|
||||
else if (BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
|
||||
// type but we nevertheless are being asked to dereference a FactoryBean...
|
||||
// Let's check the original bean class and proceed with it if it is a FactoryBean.
|
||||
beanType = predictBeanType(beanName, mbd, FactoryBean.class);
|
||||
if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ResolvableType resolvableType = mbd.targetType;
|
||||
if (resolvableType == null) {
|
||||
resolvableType = mbd.factoryMethodReturnType;
|
||||
}
|
||||
if (resolvableType != null && resolvableType.resolve() == beanType) {
|
||||
return typeToMatch.isAssignableFrom(resolvableType);
|
||||
}
|
||||
return typeToMatch.isAssignableFrom(beanType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -585,43 +605,41 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
return null;
|
||||
}
|
||||
|
||||
else {
|
||||
// No singleton instance found -> check bean definition.
|
||||
BeanFactory parentBeanFactory = getParentBeanFactory();
|
||||
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
|
||||
// No bean definition found in this factory -> delegate to parent.
|
||||
return parentBeanFactory.getType(originalBeanName(name));
|
||||
// No singleton instance found -> check bean definition.
|
||||
BeanFactory parentBeanFactory = getParentBeanFactory();
|
||||
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
|
||||
// No bean definition found in this factory -> delegate to parent.
|
||||
return parentBeanFactory.getType(originalBeanName(name));
|
||||
}
|
||||
|
||||
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||
|
||||
// Check decorated bean definition, if any: We assume it'll be easier
|
||||
// to determine the decorated bean's type than the proxy's type.
|
||||
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
|
||||
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
|
||||
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd);
|
||||
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
|
||||
return targetClass;
|
||||
}
|
||||
}
|
||||
|
||||
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||
Class<?> beanClass = predictBeanType(beanName, mbd);
|
||||
|
||||
// Check decorated bean definition, if any: We assume it'll be easier
|
||||
// to determine the decorated bean's type than the proxy's type.
|
||||
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
|
||||
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
|
||||
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd);
|
||||
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
|
||||
return targetClass;
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> beanClass = predictBeanType(beanName, mbd);
|
||||
|
||||
// Check bean class whether we're dealing with a FactoryBean.
|
||||
if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
|
||||
if (!BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
// If it's a FactoryBean, we want to look at what it creates, not at the factory class.
|
||||
return getTypeForFactoryBean(beanName, mbd);
|
||||
}
|
||||
else {
|
||||
return beanClass;
|
||||
}
|
||||
// Check bean class whether we're dealing with a FactoryBean.
|
||||
if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
|
||||
if (!BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
// If it's a FactoryBean, we want to look at what it creates, not at the factory class.
|
||||
return getTypeForFactoryBean(beanName, mbd);
|
||||
}
|
||||
else {
|
||||
return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null);
|
||||
return beanClass;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -748,7 +766,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
@Override
|
||||
public void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass) {
|
||||
Assert.notNull(requiredType, "Required type must not be null");
|
||||
Assert.isAssignable(PropertyEditor.class, propertyEditorClass);
|
||||
Assert.notNull(propertyEditorClass, "PropertyEditor class must not be null");
|
||||
this.customEditors.put(requiredType, propertyEditorClass);
|
||||
}
|
||||
|
||||
@@ -805,12 +823,15 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
|
||||
@Override
|
||||
public String resolveEmbeddedValue(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String result = value;
|
||||
for (StringValueResolver resolver : this.embeddedValueResolvers) {
|
||||
result = resolver.resolveStringValue(result);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
result = resolver.resolveStringValue(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -918,10 +939,12 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
setBeanClassLoader(otherFactory.getBeanClassLoader());
|
||||
setCacheBeanMetadata(otherFactory.isCacheBeanMetadata());
|
||||
setBeanExpressionResolver(otherFactory.getBeanExpressionResolver());
|
||||
setConversionService(otherFactory.getConversionService());
|
||||
if (otherFactory instanceof AbstractBeanFactory) {
|
||||
AbstractBeanFactory otherAbstractFactory = (AbstractBeanFactory) otherFactory;
|
||||
this.customEditors.putAll(otherAbstractFactory.customEditors);
|
||||
this.propertyEditorRegistrars.addAll(otherAbstractFactory.propertyEditorRegistrars);
|
||||
this.customEditors.putAll(otherAbstractFactory.customEditors);
|
||||
this.typeConverter = otherAbstractFactory.typeConverter;
|
||||
this.beanPostProcessors.addAll(otherAbstractFactory.beanPostProcessors);
|
||||
this.hasInstantiationAwareBeanPostProcessors = this.hasInstantiationAwareBeanPostProcessors ||
|
||||
otherAbstractFactory.hasInstantiationAwareBeanPostProcessors;
|
||||
@@ -932,6 +955,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
}
|
||||
else {
|
||||
setTypeConverter(otherFactory.getTypeConverter());
|
||||
String[] otherScopeNames = otherFactory.getRegisteredScopeNames();
|
||||
for (String scopeName : otherScopeNames) {
|
||||
this.scopes.put(scopeName, otherFactory.getRegisteredScope(scopeName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1050,11 +1077,11 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
* Destroy the given bean instance (usually a prototype instance
|
||||
* obtained from this factory) according to the given bean definition.
|
||||
* @param beanName the name of the bean definition
|
||||
* @param beanInstance the bean instance to destroy
|
||||
* @param bean the bean instance to destroy
|
||||
* @param mbd the merged bean definition
|
||||
*/
|
||||
protected void destroyBean(String beanName, Object beanInstance, RootBeanDefinition mbd) {
|
||||
new DisposableBeanAdapter(beanInstance, beanName, mbd, getBeanPostProcessors(), getAccessControlContext()).destroy();
|
||||
protected void destroyBean(String beanName, Object bean, RootBeanDefinition mbd) {
|
||||
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), getAccessControlContext()).destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1235,12 +1262,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
pbd = getMergedBeanDefinition(parentBeanName);
|
||||
}
|
||||
else {
|
||||
if (getParentBeanFactory() instanceof ConfigurableBeanFactory) {
|
||||
pbd = ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(parentBeanName);
|
||||
BeanFactory parent = getParentBeanFactory();
|
||||
if (parent instanceof ConfigurableBeanFactory) {
|
||||
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
|
||||
}
|
||||
else {
|
||||
throw new NoSuchBeanDefinitionException(bd.getParentName(),
|
||||
"Parent name '" + bd.getParentName() + "' is equal to bean name '" + beanName +
|
||||
throw new NoSuchBeanDefinitionException(parentBeanName,
|
||||
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
|
||||
"': cannot be resolved without an AbstractBeanFactory parent");
|
||||
}
|
||||
}
|
||||
@@ -1356,12 +1384,14 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
|
||||
}
|
||||
catch (LinkageError err) {
|
||||
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
|
||||
catch (LinkageError ex) {
|
||||
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch) throws ClassNotFoundException {
|
||||
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
|
||||
throws ClassNotFoundException {
|
||||
|
||||
ClassLoader beanClassLoader = getBeanClassLoader();
|
||||
ClassLoader classLoaderToUse = beanClassLoader;
|
||||
if (!ObjectUtils.isEmpty(typesToMatch)) {
|
||||
@@ -1435,6 +1465,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
* @return the type of the bean, or {@code null} if not predictable
|
||||
*/
|
||||
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
|
||||
Class<?> targetType = mbd.getTargetType();
|
||||
if (targetType != null) {
|
||||
return targetType;
|
||||
}
|
||||
if (mbd.getFactoryMethodName() != null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -162,8 +162,8 @@ abstract class AutowireUtils {
|
||||
* Determine the target type for the generic return type of the given
|
||||
* <em>generic factory method</em>, where formal type variables are declared
|
||||
* on the given method itself.
|
||||
* <p>For example, given a factory method with the following signature,
|
||||
* if {@code resolveReturnTypeForFactoryMethod()} is invoked with the reflected
|
||||
* <p>For example, given a factory method with the following signature, if
|
||||
* {@code resolveReturnTypeForFactoryMethod()} is invoked with the reflected
|
||||
* method for {@code creatProxy()} and an {@code Object[]} array containing
|
||||
* {@code MyService.class}, {@code resolveReturnTypeForFactoryMethod()} will
|
||||
* infer that the target return type is {@code MyService}.
|
||||
@@ -184,9 +184,9 @@ abstract class AutowireUtils {
|
||||
* @param method the method to introspect (never {@code null})
|
||||
* @param args the arguments that will be supplied to the method when it is
|
||||
* invoked (never {@code null})
|
||||
* @param classLoader the ClassLoader to resolve class names against, if necessary
|
||||
* (never {@code null})
|
||||
* @return the resolved target return type, the standard return type, or {@code null}
|
||||
* @param classLoader the ClassLoader to resolve class names against,
|
||||
* if necessary (never {@code null})
|
||||
* @return the resolved target return type or the standard method return type
|
||||
* @since 3.2.5
|
||||
*/
|
||||
public static Class<?> resolveReturnTypeForFactoryMethod(Method method, Object[] args, ClassLoader classLoader) {
|
||||
|
||||
+14
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -159,13 +159,25 @@ public class BeanDefinitionBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the factory method to use for this definition.
|
||||
* Set the name of a static factory method to use for this definition,
|
||||
* to be called on this bean's class.
|
||||
*/
|
||||
public BeanDefinitionBuilder setFactoryMethod(String factoryMethod) {
|
||||
this.beanDefinition.setFactoryMethodName(factoryMethod);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of a non-static factory method to use for this definition,
|
||||
* including the bean name of the factory instance to call the method on.
|
||||
* @since 4.3.6
|
||||
*/
|
||||
public BeanDefinitionBuilder setFactoryMethodOnBean(String factoryMethod, String factoryBean) {
|
||||
this.beanDefinition.setFactoryMethodName(factoryMethod);
|
||||
this.beanDefinition.setFactoryBeanName(factoryBean);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an indexed constructor arg value. The current index is tracked internally
|
||||
* and all additions are at the present point.
|
||||
|
||||
+18
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -69,6 +69,23 @@ public class BeanDefinitionReaderUtils {
|
||||
return bd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a bean name for the given top-level bean definition,
|
||||
* unique within the given bean factory.
|
||||
* @param beanDefinition the bean definition to generate a bean name for
|
||||
* @param registry the bean factory that the definition is going to be
|
||||
* registered with (to check for existing bean names)
|
||||
* @return the generated bean name
|
||||
* @throws BeanDefinitionStoreException if no unique name can be generated
|
||||
* for the given bean definition
|
||||
* @see #generateBeanName(BeanDefinition, BeanDefinitionRegistry, boolean)
|
||||
*/
|
||||
public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry)
|
||||
throws BeanDefinitionStoreException {
|
||||
|
||||
return generateBeanName(beanDefinition, registry, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a bean name for the given bean definition, unique within the
|
||||
* given bean factory.
|
||||
@@ -117,22 +134,6 @@ public class BeanDefinitionReaderUtils {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a bean name for the given top-level bean definition,
|
||||
* unique within the given bean factory.
|
||||
* @param beanDefinition the bean definition to generate a bean name for
|
||||
* @param registry the bean factory that the definition is going to be
|
||||
* registered with (to check for existing bean names)
|
||||
* @return the generated bean name
|
||||
* @throws BeanDefinitionStoreException if no unique name can be generated
|
||||
* for the given bean definition
|
||||
*/
|
||||
public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry)
|
||||
throws BeanDefinitionStoreException {
|
||||
|
||||
return generateBeanName(beanDefinition, registry, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given bean definition with the given bean factory.
|
||||
* @param definitionHolder the bean definition including name and aliases
|
||||
|
||||
+2
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -53,10 +53,7 @@ public class ChildBeanDefinition extends AbstractBeanDefinition {
|
||||
* configured through its bean properties and configuration methods.
|
||||
* @param parentName the name of the parent bean
|
||||
* @see #setBeanClass
|
||||
* @see #setBeanClassName
|
||||
* @see #setScope
|
||||
* @see #setAutowireMode
|
||||
* @see #setDependencyCheck
|
||||
* @see #setConstructorArgumentValues
|
||||
* @see #setPropertyValues
|
||||
*/
|
||||
@@ -174,9 +171,7 @@ public class ChildBeanDefinition extends AbstractBeanDefinition {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("Child bean with parent '");
|
||||
sb.append(this.parentName).append("': ").append(super.toString());
|
||||
return sb.toString();
|
||||
return "Child bean with parent '" + this.parentName + "': " + super.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+56
-33
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,6 +43,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
@@ -266,6 +267,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
|
||||
/**
|
||||
* Set a {@link java.util.Comparator} for dependency Lists and arrays.
|
||||
* @since 4.0
|
||||
* @see org.springframework.core.OrderComparator
|
||||
* @see org.springframework.core.annotation.AnnotationAwareOrderComparator
|
||||
*/
|
||||
@@ -275,6 +277,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
|
||||
/**
|
||||
* Return the dependency comparator for this BeanFactory (may be {@code null}.
|
||||
* @since 4.0
|
||||
*/
|
||||
public Comparator<Object> getDependencyComparator() {
|
||||
return this.dependencyComparator;
|
||||
@@ -289,11 +292,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
Assert.notNull(autowireCandidateResolver, "AutowireCandidateResolver must not be null");
|
||||
if (autowireCandidateResolver instanceof BeanFactoryAware) {
|
||||
if (System.getSecurityManager() != null) {
|
||||
final BeanFactory target = this;
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
@Override
|
||||
public Object run() {
|
||||
((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(target);
|
||||
((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(DefaultListableBeanFactory.this);
|
||||
return null;
|
||||
}
|
||||
}, getAccessControlContext());
|
||||
@@ -320,7 +322,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
DefaultListableBeanFactory otherListableFactory = (DefaultListableBeanFactory) otherFactory;
|
||||
this.allowBeanDefinitionOverriding = otherListableFactory.allowBeanDefinitionOverriding;
|
||||
this.allowEagerClassLoading = otherListableFactory.allowEagerClassLoading;
|
||||
this.autowireCandidateResolver = otherListableFactory.autowireCandidateResolver;
|
||||
this.dependencyComparator = otherListableFactory.dependencyComparator;
|
||||
// A clone of the AutowireCandidateResolver since it is potentially BeanFactoryAware...
|
||||
setAutowireCandidateResolver(BeanUtils.instantiateClass(getAutowireCandidateResolver().getClass()));
|
||||
// Make resolvable dependencies (e.g. ResourceLoader) available here as well...
|
||||
this.resolvableDependencies.putAll(otherListableFactory.resolvableDependencies);
|
||||
}
|
||||
}
|
||||
@@ -367,7 +372,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
@Override
|
||||
public String[] getBeanDefinitionNames() {
|
||||
if (this.frozenBeanDefinitionNames != null) {
|
||||
return this.frozenBeanDefinitionNames;
|
||||
return this.frozenBeanDefinitionNames.clone();
|
||||
}
|
||||
else {
|
||||
return StringUtils.toStringArray(this.beanDefinitionNames);
|
||||
@@ -418,8 +423,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
|
||||
// In case of FactoryBean, match object created by FactoryBean.
|
||||
boolean isFactoryBean = isFactoryBean(beanName, mbd);
|
||||
boolean matchFound = (allowEagerInit || !isFactoryBean || containsSingleton(beanName)) &&
|
||||
(includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type);
|
||||
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
|
||||
boolean matchFound =
|
||||
(allowEagerInit || !isFactoryBean ||
|
||||
(dbd != null && !mbd.isLazyInit()) || containsSingleton(beanName)) &&
|
||||
(includeNonSingletons ||
|
||||
(dbd != null ? mbd.isSingleton() : isSingleton(beanName))) &&
|
||||
isTypeMatch(beanName, type);
|
||||
if (!matchFound && isFactoryBean) {
|
||||
// In case of FactoryBean, try to match FactoryBean instance itself next.
|
||||
beanName = FACTORY_BEAN_PREFIX + beanName;
|
||||
@@ -983,7 +993,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (parent instanceof AutowireCapableBeanFactory) {
|
||||
return ((AutowireCapableBeanFactory) parent).resolveNamedBean(requiredType);
|
||||
}
|
||||
return null;
|
||||
throw new NoSuchBeanDefinitionException(requiredType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -1091,7 +1101,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
|
||||
if (matchingBeans.isEmpty()) {
|
||||
if (descriptor.isRequired()) {
|
||||
raiseNoMatchingBeanFound(type, descriptor.getResolvableType().toString(), descriptor);
|
||||
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1138,8 +1148,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
Class<?> type = descriptor.getDependencyType();
|
||||
if (type.isArray()) {
|
||||
Class<?> componentType = type.getComponentType();
|
||||
ResolvableType resolvableType = descriptor.getResolvableType();
|
||||
Class<?> resolvedArrayType = resolvableType.resolve();
|
||||
if (resolvedArrayType != null && resolvedArrayType != type) {
|
||||
type = resolvedArrayType;
|
||||
componentType = resolvableType.getComponentType().resolve();
|
||||
}
|
||||
if (componentType == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
|
||||
new MultiElementDependencyDescriptor(descriptor));
|
||||
new MultiElementDescriptor(descriptor));
|
||||
if (matchingBeans.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -1154,12 +1173,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
return result;
|
||||
}
|
||||
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
|
||||
Class<?> elementType = descriptor.getCollectionType();
|
||||
Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
|
||||
if (elementType == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
|
||||
new MultiElementDependencyDescriptor(descriptor));
|
||||
new MultiElementDescriptor(descriptor));
|
||||
if (matchingBeans.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -1173,17 +1192,18 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
|
||||
Class<?> keyType = descriptor.getMapKeyType();
|
||||
else if (Map.class == type) {
|
||||
ResolvableType mapType = descriptor.getResolvableType().asMap();
|
||||
Class<?> keyType = mapType.resolveGeneric(0);
|
||||
if (String.class != keyType) {
|
||||
return null;
|
||||
}
|
||||
Class<?> valueType = descriptor.getMapValueType();
|
||||
Class<?> valueType = mapType.resolveGeneric(1);
|
||||
if (valueType == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
|
||||
new MultiElementDependencyDescriptor(descriptor));
|
||||
new MultiElementDescriptor(descriptor));
|
||||
if (matchingBeans.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -1250,24 +1270,27 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
}
|
||||
}
|
||||
for (String candidateName : candidateNames) {
|
||||
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
|
||||
addCandidateEntry(result, candidateName, descriptor, requiredType);
|
||||
for (String candidate : candidateNames) {
|
||||
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
|
||||
addCandidateEntry(result, candidate, descriptor, requiredType);
|
||||
}
|
||||
}
|
||||
if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
|
||||
// Consider fallback matches if the first pass failed to find anything...
|
||||
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
|
||||
for (String candidateName : candidateNames) {
|
||||
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
|
||||
addCandidateEntry(result, candidateName, descriptor, requiredType);
|
||||
for (String candidate : candidateNames) {
|
||||
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor)) {
|
||||
addCandidateEntry(result, candidate, descriptor, requiredType);
|
||||
}
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
// Consider self references before as a final pass
|
||||
for (String candidateName : candidateNames) {
|
||||
if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
|
||||
addCandidateEntry(result, candidateName, descriptor, requiredType);
|
||||
// Consider self references as a final pass...
|
||||
// but in the case of a dependency collection, not the very same bean itself.
|
||||
for (String candidate : candidateNames) {
|
||||
if (isSelfReference(beanName, candidate) &&
|
||||
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
|
||||
isAutowireCandidate(candidate, fallbackDescriptor)) {
|
||||
addCandidateEntry(result, candidate, descriptor, requiredType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1282,7 +1305,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
|
||||
DependencyDescriptor descriptor, Class<?> requiredType) {
|
||||
|
||||
if (descriptor instanceof MultiElementDependencyDescriptor || containsSingleton(candidateName)) {
|
||||
if (descriptor instanceof MultiElementDescriptor || containsSingleton(candidateName)) {
|
||||
candidates.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this));
|
||||
}
|
||||
else {
|
||||
@@ -1454,11 +1477,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
* for an unresolvable dependency.
|
||||
*/
|
||||
private void raiseNoMatchingBeanFound(
|
||||
Class<?> type, String dependencyDescription, DependencyDescriptor descriptor) throws BeansException {
|
||||
Class<?> type, ResolvableType resolvableType, DependencyDescriptor descriptor) throws BeansException {
|
||||
|
||||
checkBeanNotOfRequiredType(type, descriptor);
|
||||
|
||||
throw new NoSuchBeanDefinitionException(type, dependencyDescription,
|
||||
throw new NoSuchBeanDefinitionException(resolvableType,
|
||||
"expected at least 1 bean which qualifies as autowire candidate. " +
|
||||
"Dependency annotations: " + ObjectUtils.nullSafeToString(descriptor.getAnnotations()));
|
||||
}
|
||||
@@ -1473,10 +1496,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
Class<?> targetType = mbd.getTargetType();
|
||||
if (targetType != null && type.isAssignableFrom(targetType) &&
|
||||
isAutowireCandidate(beanName, mbd, descriptor, getAutowireCandidateResolver())) {
|
||||
// Probably a poxy interfering with target type match -> throw meaningful exception.
|
||||
// Probably a proxy interfering with target type match -> throw meaningful exception.
|
||||
Object beanInstance = getSingleton(beanName, false);
|
||||
Class<?> beanType = (beanInstance != null ? beanInstance.getClass() : predictBeanType(beanName, mbd));
|
||||
if (type != beanType) {
|
||||
if (!type.isAssignableFrom((beanType))) {
|
||||
throw new BeanNotOfRequiredTypeException(beanName, type, beanType);
|
||||
}
|
||||
}
|
||||
@@ -1736,9 +1759,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
|
||||
|
||||
private static class MultiElementDependencyDescriptor extends NestedDependencyDescriptor {
|
||||
private static class MultiElementDescriptor extends NestedDependencyDescriptor {
|
||||
|
||||
public MultiElementDependencyDescriptor(DependencyDescriptor original) {
|
||||
public MultiElementDescriptor(DependencyDescriptor original) {
|
||||
super(original);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -214,7 +214,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
if (singletonObject == null) {
|
||||
if (this.singletonsCurrentlyInDestruction) {
|
||||
throw new BeanCreationNotAllowedException(beanName,
|
||||
"Singleton bean creation not allowed while the singletons of this factory are in destruction " +
|
||||
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
|
||||
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
||||
+1
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -45,10 +45,7 @@ public class GenericBeanDefinition extends AbstractBeanDefinition {
|
||||
* Create a new GenericBeanDefinition, to be configured through its bean
|
||||
* properties and configuration methods.
|
||||
* @see #setBeanClass
|
||||
* @see #setBeanClassName
|
||||
* @see #setScope
|
||||
* @see #setAutowireMode
|
||||
* @see #setDependencyCheck
|
||||
* @see #setConstructorArgumentValues
|
||||
* @see #setPropertyValues
|
||||
*/
|
||||
|
||||
+15
-14
@@ -147,22 +147,23 @@ public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandid
|
||||
protected ResolvableType getReturnTypeForFactoryMethod(RootBeanDefinition rbd, DependencyDescriptor descriptor) {
|
||||
// Should typically be set for any kind of factory method, since the BeanFactory
|
||||
// pre-resolves them before reaching out to the AutowireCandidateResolver...
|
||||
Class<?> preResolved = rbd.resolvedFactoryMethodReturnType;
|
||||
if (preResolved != null) {
|
||||
return ResolvableType.forClass(preResolved);
|
||||
}
|
||||
else {
|
||||
Method resolvedFactoryMethod = rbd.getResolvedFactoryMethod();
|
||||
if (resolvedFactoryMethod != null) {
|
||||
if (descriptor.getDependencyType().isAssignableFrom(resolvedFactoryMethod.getReturnType())) {
|
||||
// Only use factory method metadata if the return type is actually expressive enough
|
||||
// for our dependency. Otherwise, the returned instance type may have matched instead
|
||||
// in case of a singleton instance having been registered with the container already.
|
||||
return ResolvableType.forMethodReturnType(resolvedFactoryMethod);
|
||||
}
|
||||
ResolvableType returnType = rbd.factoryMethodReturnType;
|
||||
if (returnType == null) {
|
||||
Method factoryMethod = rbd.getResolvedFactoryMethod();
|
||||
if (factoryMethod != null) {
|
||||
returnType = ResolvableType.forMethodReturnType(factoryMethod);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (returnType != null) {
|
||||
Class<?> resolvedClass = returnType.resolve();
|
||||
if (resolvedClass != null && descriptor.getDependencyType().isAssignableFrom(resolvedClass)) {
|
||||
// Only use factory method metadata if the return type is actually expressive enough
|
||||
// for our dependency. Otherwise, the returned instance type may have matched instead
|
||||
// in case of a singleton instance having been registered with the container already.
|
||||
return returnType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+9
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,20 +20,20 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
|
||||
/**
|
||||
* Post-processor callback interface for <i>merged</i> bean definitions at runtime.
|
||||
* {@link BeanPostProcessor} implementations may implement this sub-interface in
|
||||
* order to post-process the merged bean definition that the Spring BeanFactory
|
||||
* uses to create a specific bean instance.
|
||||
* {@link BeanPostProcessor} implementations may implement this sub-interface in order
|
||||
* to post-process the merged bean definition (a processed copy of the original bean
|
||||
* definition) that the Spring {@code BeanFactory} uses to create a bean instance.
|
||||
*
|
||||
* <p>The {@link #postProcessMergedBeanDefinition} method may for example introspect
|
||||
* the bean definition in order to prepare some cached metadata before post-processing
|
||||
* actual instances of a bean. It is also allowed to modify the bean definition
|
||||
* but <i>only</i> for bean definition properties which are actually intended
|
||||
* for concurrent modification. Basically, this only applies to operations
|
||||
* defined on the {@link RootBeanDefinition} itself but not to the properties
|
||||
* of its base classes.
|
||||
* actual instances of a bean. It is also allowed to modify the bean definition but
|
||||
* <i>only</i> for definition properties which are actually intended for concurrent
|
||||
* modification. Essentially, this only applies to operations defined on the
|
||||
* {@link RootBeanDefinition} itself but not to the properties of its base classes.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#getMergedBeanDefinition
|
||||
*/
|
||||
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {
|
||||
|
||||
|
||||
+2
-4
@@ -64,7 +64,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
volatile Class<?> resolvedTargetType;
|
||||
|
||||
/** Package-visible field for caching the return type of a generically typed factory method */
|
||||
volatile Class<?> resolvedFactoryMethodReturnType;
|
||||
volatile ResolvableType factoryMethodReturnType;
|
||||
|
||||
/** Common lock for the four constructor fields below */
|
||||
final Object constructorArgumentLock = new Object();
|
||||
@@ -101,10 +101,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
* Create a new RootBeanDefinition, to be configured through its bean
|
||||
* properties and configuration methods.
|
||||
* @see #setBeanClass
|
||||
* @see #setBeanClassName
|
||||
* @see #setScope
|
||||
* @see #setAutowireMode
|
||||
* @see #setDependencyCheck
|
||||
* @see #setConstructorArgumentValues
|
||||
* @see #setPropertyValues
|
||||
*/
|
||||
@@ -115,6 +112,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
/**
|
||||
* Create a new RootBeanDefinition for a singleton.
|
||||
* @param beanClass the class of the bean to instantiate
|
||||
* @see #setBeanClass
|
||||
*/
|
||||
public RootBeanDefinition(Class<?> beanClass) {
|
||||
super();
|
||||
|
||||
+7
-1
@@ -248,7 +248,13 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||
|
||||
@Override
|
||||
public String[] getBeanNamesForType(ResolvableType type) {
|
||||
boolean isFactoryType = (type != null && FactoryBean.class.isAssignableFrom(type.getRawClass()));
|
||||
boolean isFactoryType = false;
|
||||
if (type != null) {
|
||||
Class<?> resolved = type.resolve();
|
||||
if (resolved != null && FactoryBean.class.isAssignableFrom(resolved)) {
|
||||
isFactoryType = true;
|
||||
}
|
||||
}
|
||||
List<String> matches = new ArrayList<String>();
|
||||
for (Map.Entry<String, Object> entry : this.beans.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
|
||||
+9
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -1478,8 +1478,10 @@ public class BeanDefinitionParserDelegate {
|
||||
|
||||
|
||||
/**
|
||||
* Get the namespace URI for the supplied node. The default implementation uses {@link Node#getNamespaceURI}.
|
||||
* Subclasses may override the default implementation to provide a different namespace identification mechanism.
|
||||
* Get the namespace URI for the supplied node.
|
||||
* <p>The default implementation uses {@link Node#getNamespaceURI}.
|
||||
* Subclasses may override the default implementation to provide a
|
||||
* different namespace identification mechanism.
|
||||
* @param node the node
|
||||
*/
|
||||
public String getNamespaceURI(Node node) {
|
||||
@@ -1487,8 +1489,10 @@ public class BeanDefinitionParserDelegate {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ges the local name for the supplied {@link Node}. The default implementation calls {@link Node#getLocalName}.
|
||||
* Subclasses may override the default implementation to provide a different mechanism for getting the local name.
|
||||
* Get the local name for the supplied {@link Node}.
|
||||
* <p>The default implementation calls {@link Node#getLocalName}.
|
||||
* Subclasses may override the default implementation to provide a
|
||||
* different mechanism for getting the local name.
|
||||
* @param node the {@code Node}
|
||||
*/
|
||||
public String getLocalName(Node node) {
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -200,6 +200,7 @@ public class UtilNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
String location = element.getAttribute("location");
|
||||
if (StringUtils.hasLength(location)) {
|
||||
location = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(location);
|
||||
String[] locations = StringUtils.commaDelimitedListToStringArray(location);
|
||||
builder.addPropertyValue("locations", locations);
|
||||
}
|
||||
|
||||
+3
-2
@@ -776,6 +776,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
private void testSingleTestBean(ListableBeanFactory lbf) {
|
||||
assertTrue("1 beans defined", lbf.getBeanDefinitionCount() == 1);
|
||||
String[] names = lbf.getBeanDefinitionNames();
|
||||
assertTrue(names != lbf.getBeanDefinitionNames());
|
||||
assertTrue("Array length == 1", names.length == 1);
|
||||
assertTrue("0th element == test", names[0].equals("test"));
|
||||
TestBean tb = (TestBean) lbf.getBean("test");
|
||||
@@ -2200,7 +2201,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
@Test
|
||||
public void testPrototypeWithArrayConversionForConstructor() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
List<String> list = new ManagedList<String>();
|
||||
List<String> list = new ManagedList<>();
|
||||
list.add("myName");
|
||||
list.add("myBeanName");
|
||||
RootBeanDefinition bd = new RootBeanDefinition(DerivedTestBean.class);
|
||||
@@ -2219,7 +2220,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
@Test
|
||||
public void testPrototypeWithArrayConversionForFactoryMethod() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
List<String> list = new ManagedList<String>();
|
||||
List<String> list = new ManagedList<>();
|
||||
list.add("myName");
|
||||
list.add("myBeanName");
|
||||
RootBeanDefinition bd = new RootBeanDefinition(DerivedTestBean.class);
|
||||
|
||||
+528
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,6 +29,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
@@ -920,7 +921,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
RootBeanDefinition tbm = new RootBeanDefinition(CollectionFactoryMethods.class);
|
||||
tbm.setUniqueFactoryMethodName("testBeanMap");
|
||||
bf.registerBeanDefinition("myTestBeanMap", tbm);
|
||||
bf.registerSingleton("otherMap", new HashMap<Object, Object>());
|
||||
bf.registerSingleton("otherMap", new HashMap<>());
|
||||
|
||||
MapConstructorInjectionBean bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bf.getBean("myTestBeanMap"), bean.getTestBeanMap());
|
||||
@@ -928,6 +929,28 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertSame(bf.getBean("myTestBeanMap"), bean.getTestBeanMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorInjectionWithCustomMapAsBean() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
RootBeanDefinition bd = new RootBeanDefinition(CustomMapConstructorInjectionBean.class);
|
||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
RootBeanDefinition tbm = new RootBeanDefinition(CustomCollectionFactoryMethods.class);
|
||||
tbm.setUniqueFactoryMethodName("testBeanMap");
|
||||
bf.registerBeanDefinition("myTestBeanMap", tbm);
|
||||
bf.registerSingleton("testBean1", new TestBean());
|
||||
bf.registerSingleton("testBean2", new TestBean());
|
||||
|
||||
CustomMapConstructorInjectionBean bean = (CustomMapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bf.getBean("myTestBeanMap"), bean.getTestBeanMap());
|
||||
bean = (CustomMapConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bf.getBean("myTestBeanMap"), bean.getTestBeanMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorInjectionWithTypedSetAsBean() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
@@ -942,7 +965,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
tbs.add(new TestBean("tb1"));
|
||||
tbs.add(new TestBean("tb2"));
|
||||
bf.registerSingleton("testBeans", tbs);
|
||||
bf.registerSingleton("otherSet", new HashSet<Object>());
|
||||
bf.registerSingleton("otherSet", new HashSet<>());
|
||||
|
||||
SetConstructorInjectionBean bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(tbs, bean.getTestBeanSet());
|
||||
@@ -963,7 +986,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
RootBeanDefinition tbs = new RootBeanDefinition(CollectionFactoryMethods.class);
|
||||
tbs.setUniqueFactoryMethodName("testBeanSet");
|
||||
bf.registerBeanDefinition("myTestBeanSet", tbs);
|
||||
bf.registerSingleton("otherSet", new HashSet<Object>());
|
||||
bf.registerSingleton("otherSet", new HashSet<>());
|
||||
|
||||
SetConstructorInjectionBean bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bf.getBean("myTestBeanSet"), bean.getTestBeanSet());
|
||||
@@ -971,6 +994,26 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertSame(bf.getBean("myTestBeanSet"), bean.getTestBeanSet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorInjectionWithCustomSetAsBean() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
RootBeanDefinition bd = new RootBeanDefinition(CustomSetConstructorInjectionBean.class);
|
||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
RootBeanDefinition tbs = new RootBeanDefinition(CustomCollectionFactoryMethods.class);
|
||||
tbs.setUniqueFactoryMethodName("testBeanSet");
|
||||
bf.registerBeanDefinition("myTestBeanSet", tbs);
|
||||
|
||||
CustomSetConstructorInjectionBean bean = (CustomSetConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bf.getBean("myTestBeanSet"), bean.getTestBeanSet());
|
||||
bean = (CustomSetConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bf.getBean("myTestBeanSet"), bean.getTestBeanSet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelfReference() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
@@ -978,23 +1021,85 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
RootBeanDefinition bd = new RootBeanDefinition(SelfInjectionBean.class);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class));
|
||||
|
||||
SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bean, bean.selfReference);
|
||||
assertSame(bean, bean.reference);
|
||||
assertNull(bean.referenceCollection);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObjectFactoryInjection() {
|
||||
public void testSelfReferenceWithOther() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class));
|
||||
bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(SelfInjectionBean.class));
|
||||
|
||||
SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean");
|
||||
SelfInjectionBean bean2 = (SelfInjectionBean) bf.getBean("annotatedBean2");
|
||||
assertSame(bean2, bean.reference);
|
||||
assertEquals(1, bean.referenceCollection.size());
|
||||
assertSame(bean2, bean.referenceCollection.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelfReferenceCollection() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionCollectionBean.class));
|
||||
|
||||
SelfInjectionCollectionBean bean = (SelfInjectionCollectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bean, bean.reference);
|
||||
assertNull(bean.referenceCollection);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelfReferenceCollectionWithOther() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionCollectionBean.class));
|
||||
bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(SelfInjectionCollectionBean.class));
|
||||
|
||||
SelfInjectionCollectionBean bean = (SelfInjectionCollectionBean) bf.getBean("annotatedBean");
|
||||
SelfInjectionCollectionBean bean2 = (SelfInjectionCollectionBean) bf.getBean("annotatedBean2");
|
||||
assertSame(bean2, bean.reference);
|
||||
assertSame(1, bean2.referenceCollection.size());
|
||||
assertSame(bean2, bean.referenceCollection.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObjectFactoryFieldInjection() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryInjectionBean.class));
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryFieldInjectionBean.class));
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
ObjectFactoryInjectionBean bean = (ObjectFactoryInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectFactoryFieldInjectionBean bean = (ObjectFactoryFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bf.getBean("testBean"), bean.getTestBean());
|
||||
bf.destroySingletons();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObjectFactoryConstructorInjection() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryConstructorInjectionBean.class));
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
ObjectFactoryConstructorInjectionBean bean = (ObjectFactoryConstructorInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bf.getBean("testBean"), bean.getTestBean());
|
||||
bf.destroySingletons();
|
||||
}
|
||||
@@ -1005,14 +1110,14 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
RootBeanDefinition annotatedBeanDefinition = new RootBeanDefinition(ObjectFactoryInjectionBean.class);
|
||||
RootBeanDefinition annotatedBeanDefinition = new RootBeanDefinition(ObjectFactoryFieldInjectionBean.class);
|
||||
annotatedBeanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", annotatedBeanDefinition);
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
ObjectFactoryInjectionBean bean = (ObjectFactoryInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectFactoryFieldInjectionBean bean = (ObjectFactoryFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bf.getBean("testBean"), bean.getTestBean());
|
||||
ObjectFactoryInjectionBean anotherBean = (ObjectFactoryInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectFactoryFieldInjectionBean anotherBean = (ObjectFactoryFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
assertNotSame(anotherBean, bean);
|
||||
assertSame(bf.getBean("testBean"), anotherBean.getTestBean());
|
||||
}
|
||||
@@ -1062,13 +1167,13 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryInjectionBean.class));
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryFieldInjectionBean.class));
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
bf.setSerializationId("test");
|
||||
|
||||
ObjectFactoryInjectionBean bean = (ObjectFactoryInjectionBean) bf.getBean("annotatedBean");
|
||||
ObjectFactoryFieldInjectionBean bean = (ObjectFactoryFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bf.getBean("testBean"), bean.getTestBean());
|
||||
bean = (ObjectFactoryInjectionBean) SerializationTestUtils.serializeAndDeserialize(bean);
|
||||
bean = (ObjectFactoryFieldInjectionBean) SerializationTestUtils.serializeAndDeserialize(bean);
|
||||
assertSame(bf.getBean("testBean"), bean.getTestBean());
|
||||
bf.destroySingletons();
|
||||
}
|
||||
@@ -1246,7 +1351,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
}
|
||||
catch (UnsatisfiedDependencyException ex) {
|
||||
// expected
|
||||
ex.printStackTrace();
|
||||
assertSame(CustomAnnotationRequiredFieldResourceInjectionBean.class,
|
||||
ex.getInjectionPoint().getField().getDeclaringClass());
|
||||
}
|
||||
@@ -1502,12 +1606,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBean.class);
|
||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
String sv = "X";
|
||||
bf.registerSingleton("stringValue", sv);
|
||||
Integer iv = 1;
|
||||
bf.registerSingleton("integerValue", iv);
|
||||
StringRepository sr = new StringRepository();
|
||||
bf.registerSingleton("stringRepo", sr);
|
||||
IntegerRepository ir = new IntegerRepository();
|
||||
bf.registerSingleton("integerRepo", ir);
|
||||
|
||||
RepositoryFieldInjectionBean bean = (RepositoryFieldInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(sv, bean.string);
|
||||
assertSame(iv, bean.integer);
|
||||
assertSame(1, bean.stringArray.length);
|
||||
assertSame(1, bean.integerArray.length);
|
||||
assertSame(sv, bean.stringArray[0]);
|
||||
assertSame(iv, bean.integerArray[0]);
|
||||
assertSame(1, bean.stringList.size());
|
||||
assertSame(1, bean.integerList.size());
|
||||
assertSame(sv, bean.stringList.get(0));
|
||||
assertSame(iv, bean.integerList.get(0));
|
||||
assertSame(1, bean.stringMap.size());
|
||||
assertSame(1, bean.integerMap.size());
|
||||
assertSame(sv, bean.stringMap.get("stringValue"));
|
||||
assertSame(iv, bean.integerMap.get("integerValue"));
|
||||
assertSame(sr, bean.stringRepository);
|
||||
assertSame(ir, bean.integerRepository);
|
||||
assertSame(1, bean.stringRepositoryArray.length);
|
||||
@@ -1534,12 +1656,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBeanWithSubstitutedVariables.class);
|
||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
String sv = "X";
|
||||
bf.registerSingleton("stringValue", sv);
|
||||
Integer iv = 1;
|
||||
bf.registerSingleton("integerValue", iv);
|
||||
StringRepository sr = new StringRepository();
|
||||
bf.registerSingleton("stringRepo", sr);
|
||||
IntegerRepository ir = new IntegerRepository();
|
||||
bf.registerSingleton("integerRepo", ir);
|
||||
|
||||
RepositoryFieldInjectionBeanWithSubstitutedVariables bean = (RepositoryFieldInjectionBeanWithSubstitutedVariables) bf.getBean("annotatedBean");
|
||||
assertSame(sv, bean.string);
|
||||
assertSame(iv, bean.integer);
|
||||
assertSame(1, bean.stringArray.length);
|
||||
assertSame(1, bean.integerArray.length);
|
||||
assertSame(sv, bean.stringArray[0]);
|
||||
assertSame(iv, bean.integerArray[0]);
|
||||
assertSame(1, bean.stringList.size());
|
||||
assertSame(1, bean.integerList.size());
|
||||
assertSame(sv, bean.stringList.get(0));
|
||||
assertSame(iv, bean.integerList.get(0));
|
||||
assertSame(1, bean.stringMap.size());
|
||||
assertSame(1, bean.integerMap.size());
|
||||
assertSame(sv, bean.stringMap.get("stringValue"));
|
||||
assertSame(iv, bean.integerMap.get("integerValue"));
|
||||
assertSame(sr, bean.stringRepository);
|
||||
assertSame(ir, bean.integerRepository);
|
||||
assertSame(1, bean.stringRepositoryArray.length);
|
||||
@@ -1632,9 +1772,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertSame(ir, bean.integerRepositoryMap.get("integerRepository"));
|
||||
}
|
||||
|
||||
@Qualifier("integerRepo")
|
||||
private Repository<?> integerRepositoryQualifierProvider;
|
||||
|
||||
@Test
|
||||
public void testGenericsBasedFieldInjectionWithSimpleMatch() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
@@ -1785,12 +1922,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(RepositoryMethodInjectionBean.class);
|
||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
String sv = "X";
|
||||
bf.registerSingleton("stringValue", sv);
|
||||
Integer iv = 1;
|
||||
bf.registerSingleton("integerValue", iv);
|
||||
StringRepository sr = new StringRepository();
|
||||
bf.registerSingleton("stringRepo", sr);
|
||||
IntegerRepository ir = new IntegerRepository();
|
||||
bf.registerSingleton("integerRepo", ir);
|
||||
|
||||
RepositoryMethodInjectionBean bean = (RepositoryMethodInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(sv, bean.string);
|
||||
assertSame(iv, bean.integer);
|
||||
assertSame(1, bean.stringArray.length);
|
||||
assertSame(1, bean.integerArray.length);
|
||||
assertSame(sv, bean.stringArray[0]);
|
||||
assertSame(iv, bean.integerArray[0]);
|
||||
assertSame(1, bean.stringList.size());
|
||||
assertSame(1, bean.integerList.size());
|
||||
assertSame(sv, bean.stringList.get(0));
|
||||
assertSame(iv, bean.integerList.get(0));
|
||||
assertSame(1, bean.stringMap.size());
|
||||
assertSame(1, bean.integerMap.size());
|
||||
assertSame(sv, bean.stringMap.get("stringValue"));
|
||||
assertSame(iv, bean.integerMap.get("integerValue"));
|
||||
assertSame(sr, bean.stringRepository);
|
||||
assertSame(ir, bean.integerRepository);
|
||||
assertSame(1, bean.stringRepositoryArray.length);
|
||||
@@ -1817,12 +1972,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(RepositoryMethodInjectionBeanWithSubstitutedVariables.class);
|
||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
String sv = "X";
|
||||
bf.registerSingleton("stringValue", sv);
|
||||
Integer iv = 1;
|
||||
bf.registerSingleton("integerValue", iv);
|
||||
StringRepository sr = new StringRepository();
|
||||
bf.registerSingleton("stringRepo", sr);
|
||||
IntegerRepository ir = new IntegerRepository();
|
||||
bf.registerSingleton("integerRepo", ir);
|
||||
|
||||
RepositoryMethodInjectionBeanWithSubstitutedVariables bean = (RepositoryMethodInjectionBeanWithSubstitutedVariables) bf.getBean("annotatedBean");
|
||||
assertSame(sv, bean.string);
|
||||
assertSame(iv, bean.integer);
|
||||
assertSame(1, bean.stringArray.length);
|
||||
assertSame(1, bean.integerArray.length);
|
||||
assertSame(sv, bean.stringArray[0]);
|
||||
assertSame(iv, bean.integerArray[0]);
|
||||
assertSame(1, bean.stringList.size());
|
||||
assertSame(1, bean.integerList.size());
|
||||
assertSame(sv, bean.stringList.get(0));
|
||||
assertSame(iv, bean.integerList.get(0));
|
||||
assertSame(1, bean.stringMap.size());
|
||||
assertSame(1, bean.integerMap.size());
|
||||
assertSame(sv, bean.stringMap.get("stringValue"));
|
||||
assertSame(iv, bean.integerMap.get("integerValue"));
|
||||
assertSame(sr, bean.stringRepository);
|
||||
assertSame(ir, bean.integerRepository);
|
||||
assertSame(1, bean.stringRepositoryArray.length);
|
||||
@@ -2135,6 +2308,45 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertNotNull(bf.getBean(ProvidedArgumentBean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotatedDefaultConstructor() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(AnnotatedDefaultConstructorBean.class));
|
||||
|
||||
assertNotNull(bf.getBean("annotatedBean"));
|
||||
}
|
||||
|
||||
@Test // SPR-15125
|
||||
public void testFactoryBeanSelfInjection() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectingFactoryBean.class));
|
||||
|
||||
SelfInjectingFactoryBean bean = bf.getBean(SelfInjectingFactoryBean.class);
|
||||
assertSame(bf.getBean("annotatedBean"), bean.testBean);
|
||||
}
|
||||
|
||||
@Test // SPR-15125
|
||||
public void testFactoryBeanSelfInjectionViaFactoryMethod() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
RootBeanDefinition bd = new RootBeanDefinition(SelfInjectingFactoryBean.class);
|
||||
bd.setFactoryMethodName("create");
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
|
||||
SelfInjectingFactoryBean bean = bf.getBean(SelfInjectingFactoryBean.class);
|
||||
assertSame(bf.getBean("annotatedBean"), bean.testBean);
|
||||
}
|
||||
|
||||
|
||||
@Qualifier("integerRepo")
|
||||
private Repository<?> integerRepositoryQualifierProvider;
|
||||
|
||||
|
||||
public static class ResourceInjectionBean {
|
||||
|
||||
@@ -2582,7 +2794,21 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
public static class SelfInjectionBean {
|
||||
|
||||
@Autowired
|
||||
public SelfInjectionBean selfReference;
|
||||
public SelfInjectionBean reference;
|
||||
|
||||
@Autowired(required = false)
|
||||
public List<SelfInjectionBean> referenceCollection;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class SelfInjectionCollectionBean extends LinkedList<SelfInjectionCollectionBean> {
|
||||
|
||||
@Autowired
|
||||
public SelfInjectionCollectionBean reference;
|
||||
|
||||
@Autowired(required = false)
|
||||
public List<SelfInjectionCollectionBean> referenceCollection;
|
||||
}
|
||||
|
||||
|
||||
@@ -2620,7 +2846,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class ObjectFactoryInjectionBean implements Serializable {
|
||||
public static class ObjectFactoryFieldInjectionBean implements Serializable {
|
||||
|
||||
@Autowired
|
||||
private ObjectFactory<TestBean> testBeanFactory;
|
||||
@@ -2631,6 +2857,21 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class ObjectFactoryConstructorInjectionBean implements Serializable {
|
||||
|
||||
private final ObjectFactory<TestBean> testBeanFactory;
|
||||
|
||||
public ObjectFactoryConstructorInjectionBean(ObjectFactory<TestBean> testBeanFactory) {
|
||||
this.testBeanFactory = testBeanFactory;
|
||||
}
|
||||
|
||||
public TestBean getTestBean() {
|
||||
return this.testBeanFactory.getObject();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ObjectFactoryQualifierInjectionBean {
|
||||
|
||||
@Autowired
|
||||
@@ -2828,6 +3069,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
public static class RepositoryFieldInjectionBean {
|
||||
|
||||
@Autowired
|
||||
public String string;
|
||||
|
||||
@Autowired
|
||||
public Integer integer;
|
||||
|
||||
@Autowired
|
||||
public String[] stringArray;
|
||||
|
||||
@Autowired
|
||||
public Integer[] integerArray;
|
||||
|
||||
@Autowired
|
||||
public List<String> stringList;
|
||||
|
||||
@Autowired
|
||||
public List<Integer> integerList;
|
||||
|
||||
@Autowired
|
||||
public Map<String, String> stringMap;
|
||||
|
||||
@Autowired
|
||||
public Map<String, Integer> integerMap;
|
||||
|
||||
@Autowired
|
||||
public Repository<String> stringRepository;
|
||||
|
||||
@@ -2856,6 +3121,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
public static class RepositoryFieldInjectionBeanWithVariables<S, I> {
|
||||
|
||||
@Autowired
|
||||
public S string;
|
||||
|
||||
@Autowired
|
||||
public I integer;
|
||||
|
||||
@Autowired
|
||||
public S[] stringArray;
|
||||
|
||||
@Autowired
|
||||
public I[] integerArray;
|
||||
|
||||
@Autowired
|
||||
public List<S> stringList;
|
||||
|
||||
@Autowired
|
||||
public List<I> integerList;
|
||||
|
||||
@Autowired
|
||||
public Map<String, S> stringMap;
|
||||
|
||||
@Autowired
|
||||
public Map<String, I> integerMap;
|
||||
|
||||
@Autowired
|
||||
public Repository<S> stringRepository;
|
||||
|
||||
@@ -2952,6 +3241,22 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
public static class RepositoryMethodInjectionBean {
|
||||
|
||||
public String string;
|
||||
|
||||
public Integer integer;
|
||||
|
||||
public String[] stringArray;
|
||||
|
||||
public Integer[] integerArray;
|
||||
|
||||
public List<String> stringList;
|
||||
|
||||
public List<Integer> integerList;
|
||||
|
||||
public Map<String, String> stringMap;
|
||||
|
||||
public Map<String, Integer> integerMap;
|
||||
|
||||
public Repository<String> stringRepository;
|
||||
|
||||
public Repository<Integer> integerRepository;
|
||||
@@ -2968,6 +3273,46 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
public Map<String, Repository<Integer>> integerRepositoryMap;
|
||||
|
||||
@Autowired
|
||||
public void setString(String string) {
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setInteger(Integer integer) {
|
||||
this.integer = integer;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setStringArray(String[] stringArray) {
|
||||
this.stringArray = stringArray;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setIntegerArray(Integer[] integerArray) {
|
||||
this.integerArray = integerArray;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setStringList(List<String> stringList) {
|
||||
this.stringList = stringList;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setIntegerList(List<Integer> integerList) {
|
||||
this.integerList = integerList;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setStringMap(Map<String, String> stringMap) {
|
||||
this.stringMap = stringMap;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setIntegerMap(Map<String, Integer> integerMap) {
|
||||
this.integerMap = integerMap;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setStringRepository(Repository<String> stringRepository) {
|
||||
this.stringRepository = stringRepository;
|
||||
@@ -3012,6 +3357,22 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
public static class RepositoryMethodInjectionBeanWithVariables<S, I> {
|
||||
|
||||
public S string;
|
||||
|
||||
public I integer;
|
||||
|
||||
public S[] stringArray;
|
||||
|
||||
public I[] integerArray;
|
||||
|
||||
public List<S> stringList;
|
||||
|
||||
public List<I> integerList;
|
||||
|
||||
public Map<String, S> stringMap;
|
||||
|
||||
public Map<String, I> integerMap;
|
||||
|
||||
public Repository<S> stringRepository;
|
||||
|
||||
public Repository<I> integerRepository;
|
||||
@@ -3028,6 +3389,46 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
public Map<String, Repository<I>> integerRepositoryMap;
|
||||
|
||||
@Autowired
|
||||
public void setString(S string) {
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setInteger(I integer) {
|
||||
this.integer = integer;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setStringArray(S[] stringArray) {
|
||||
this.stringArray = stringArray;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setIntegerArray(I[] integerArray) {
|
||||
this.integerArray = integerArray;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setStringList(List<S> stringList) {
|
||||
this.stringList = stringList;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setIntegerList(List<I> integerList) {
|
||||
this.integerList = integerList;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setStringMap(Map<String, S> stringMap) {
|
||||
this.stringMap = stringMap;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setIntegerMap(Map<String, I> integerMap) {
|
||||
this.integerMap = integerMap;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setStringRepository(Repository<S> stringRepository) {
|
||||
this.stringRepository = stringRepository;
|
||||
@@ -3149,7 +3550,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
}
|
||||
|
||||
public static GenericInterface1<String> createErased() {
|
||||
return new GenericInterface1Impl<String>();
|
||||
return new GenericInterface1Impl<>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@@ -3165,7 +3566,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
|
||||
public interface GenericInterface2<K> {
|
||||
|
||||
public String doSomethingMoreGeneric(K o);
|
||||
String doSomethingMoreGeneric(K o);
|
||||
}
|
||||
|
||||
|
||||
@@ -3336,19 +3737,120 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
public static class CollectionFactoryMethods {
|
||||
|
||||
public static Map<String, TestBean> testBeanMap() {
|
||||
Map<String, TestBean> tbm = new LinkedHashMap<String, TestBean>();
|
||||
Map<String, TestBean> tbm = new LinkedHashMap<>();
|
||||
tbm.put("testBean1", new TestBean("tb1"));
|
||||
tbm.put("testBean2", new TestBean("tb2"));
|
||||
return tbm;
|
||||
}
|
||||
|
||||
public static Set<TestBean> testBeanSet() {
|
||||
Set<TestBean> tbs = new LinkedHashSet<TestBean>();
|
||||
Set<TestBean> tbs = new LinkedHashSet<>();
|
||||
tbs.add(new TestBean("tb1"));
|
||||
tbs.add(new TestBean("tb2"));
|
||||
return tbs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class CustomCollectionFactoryMethods {
|
||||
|
||||
public static CustomMap<String, TestBean> testBeanMap() {
|
||||
CustomMap<String, TestBean> tbm = new CustomHashMap<>();
|
||||
tbm.put("testBean1", new TestBean("tb1"));
|
||||
tbm.put("testBean2", new TestBean("tb2"));
|
||||
return tbm;
|
||||
}
|
||||
|
||||
public static CustomSet<TestBean> testBeanSet() {
|
||||
CustomSet<TestBean> tbs = new CustomHashSet<>();
|
||||
tbs.add(new TestBean("tb1"));
|
||||
tbs.add(new TestBean("tb2"));
|
||||
return tbs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class CustomMapConstructorInjectionBean {
|
||||
|
||||
private CustomMap<String, TestBean> testBeanMap;
|
||||
|
||||
@Autowired
|
||||
public CustomMapConstructorInjectionBean(CustomMap<String, TestBean> testBeanMap) {
|
||||
this.testBeanMap = testBeanMap;
|
||||
}
|
||||
|
||||
public CustomMap<String, TestBean> getTestBeanMap() {
|
||||
return this.testBeanMap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class CustomSetConstructorInjectionBean {
|
||||
|
||||
private CustomSet<TestBean> testBeanSet;
|
||||
|
||||
@Autowired
|
||||
public CustomSetConstructorInjectionBean(CustomSet<TestBean> testBeanSet) {
|
||||
this.testBeanSet = testBeanSet;
|
||||
}
|
||||
|
||||
public CustomSet<TestBean> getTestBeanSet() {
|
||||
return this.testBeanSet;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface CustomMap<K, V> extends Map<K, V> {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class CustomHashMap<K, V> extends LinkedHashMap<K, V> implements CustomMap<K, V> {
|
||||
}
|
||||
|
||||
|
||||
public interface CustomSet<E> extends Set<E> {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class CustomHashSet<E> extends LinkedHashSet<E> implements CustomSet<E> {
|
||||
}
|
||||
|
||||
|
||||
public static class AnnotatedDefaultConstructorBean {
|
||||
|
||||
@Autowired
|
||||
public AnnotatedDefaultConstructorBean() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class SelfInjectingFactoryBean implements FactoryBean<TestBean> {
|
||||
|
||||
private final TestBean exposedTestBean = new TestBean();
|
||||
|
||||
@Autowired
|
||||
TestBean testBean;
|
||||
|
||||
@Override
|
||||
public TestBean getObject() {
|
||||
return exposedTestBean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return TestBean.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static SelfInjectingFactoryBean create() {
|
||||
return new SelfInjectingFactoryBean();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+18
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -742,6 +742,15 @@ public class InjectAnnotationBeanPostProcessorTests {
|
||||
bf.destroySingletons();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotatedDefaultConstructor() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(AnnotatedDefaultConstructorBean.class));
|
||||
|
||||
assertNotNull(bf.getBean("annotatedBean"));
|
||||
}
|
||||
|
||||
|
||||
public static class ResourceInjectionBean {
|
||||
|
||||
@@ -750,7 +759,6 @@ public class InjectAnnotationBeanPostProcessorTests {
|
||||
|
||||
private TestBean testBean2;
|
||||
|
||||
|
||||
@Inject
|
||||
public void setTestBean2(TestBean testBean2) {
|
||||
if (this.testBean2 != null) {
|
||||
@@ -819,7 +827,6 @@ public class InjectAnnotationBeanPostProcessorTests {
|
||||
|
||||
|
||||
public static class TypedExtendedResourceInjectionBean extends ExtendedResourceInjectionBean<NestedTestBean> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1087,7 +1094,6 @@ public class InjectAnnotationBeanPostProcessorTests {
|
||||
@Inject
|
||||
private Map<String, TestBean> testBeanMap;
|
||||
|
||||
|
||||
public Map<String, TestBean> getTestBeanMap() {
|
||||
return this.testBeanMap;
|
||||
}
|
||||
@@ -1346,4 +1352,12 @@ public class InjectAnnotationBeanPostProcessorTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class AnnotatedDefaultConstructorBean {
|
||||
|
||||
@Inject
|
||||
public AnnotatedDefaultConstructorBean() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+31
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,43 +34,40 @@ import static org.junit.Assert.*;
|
||||
* Tests for {@link YamlMapFactoryBean}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class YamlMapFactoryBeanTests {
|
||||
|
||||
private final YamlMapFactoryBean factory = new YamlMapFactoryBean();
|
||||
|
||||
|
||||
@Test
|
||||
public void testSetIgnoreResourceNotFound() throws Exception {
|
||||
this.factory
|
||||
.setResolutionMethod(YamlMapFactoryBean.ResolutionMethod.OVERRIDE_AND_IGNORE);
|
||||
this.factory.setResources(new FileSystemResource[] {new FileSystemResource(
|
||||
"non-exsitent-file.yml")});
|
||||
this.factory.setResolutionMethod(YamlMapFactoryBean.ResolutionMethod.OVERRIDE_AND_IGNORE);
|
||||
this.factory.setResources(new FileSystemResource("non-exsitent-file.yml"));
|
||||
assertEquals(0, this.factory.getObject().size());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testSetBarfOnResourceNotFound() throws Exception {
|
||||
this.factory.setResources(new FileSystemResource[] {new FileSystemResource(
|
||||
"non-exsitent-file.yml")});
|
||||
this.factory.setResources(new FileSystemResource("non-exsitent-file.yml"));
|
||||
assertEquals(0, this.factory.getObject().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetObject() throws Exception {
|
||||
this.factory.setResources(new ByteArrayResource[] {new ByteArrayResource(
|
||||
"foo: bar".getBytes())});
|
||||
this.factory.setResources(new ByteArrayResource("foo: bar".getBytes()));
|
||||
assertEquals(1, this.factory.getObject().size());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testOverrideAndremoveDefaults() throws Exception {
|
||||
this.factory.setResources(new ByteArrayResource[] {
|
||||
new ByteArrayResource("foo:\n bar: spam".getBytes()),
|
||||
new ByteArrayResource("foo:\n spam: bar".getBytes())});
|
||||
public void testOverrideAndRemoveDefaults() throws Exception {
|
||||
this.factory.setResources(new ByteArrayResource("foo:\n bar: spam".getBytes()),
|
||||
new ByteArrayResource("foo:\n spam: bar".getBytes()));
|
||||
|
||||
assertEquals(1, this.factory.getObject().size());
|
||||
assertEquals(2,
|
||||
((Map<String, Object>) this.factory.getObject().get("foo")).size());
|
||||
assertEquals(2, ((Map<String, Object>) this.factory.getObject().get("foo")).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -81,20 +78,20 @@ public class YamlMapFactoryBeanTests {
|
||||
public String getDescription() {
|
||||
return "non-existent";
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
throw new IOException("planned");
|
||||
}
|
||||
}, new ByteArrayResource("foo:\n spam: bar".getBytes()));
|
||||
|
||||
assertEquals(1, this.factory.getObject().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapWithPeriodsInKey() throws Exception {
|
||||
this.factory.setResources(new ByteArrayResource[] {new ByteArrayResource(
|
||||
"foo:\n ? key1.key2\n : value".getBytes())});
|
||||
this.factory.setResources(new ByteArrayResource("foo:\n ? key1.key2\n : value".getBytes()));
|
||||
Map<String, Object> map = this.factory.getObject();
|
||||
|
||||
assertEquals(1, map.size());
|
||||
assertTrue(map.containsKey("foo"));
|
||||
Object object = map.get("foo");
|
||||
@@ -105,10 +102,24 @@ public class YamlMapFactoryBeanTests {
|
||||
assertEquals("value", sub.get("key1.key2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapWithIntegerValue() throws Exception {
|
||||
this.factory.setResources(new ByteArrayResource("foo:\n ? key1.key2\n : 3".getBytes()));
|
||||
Map<String, Object> map = this.factory.getObject();
|
||||
|
||||
assertEquals(1, map.size());
|
||||
assertTrue(map.containsKey("foo"));
|
||||
Object object = map.get("foo");
|
||||
assertTrue(object instanceof LinkedHashMap);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> sub = (Map<String, Object>) object;
|
||||
assertTrue(sub.containsKey("key1.key2"));
|
||||
assertEquals(Integer.valueOf(3), sub.get("key1.key2"));
|
||||
}
|
||||
|
||||
@Test(expected = ParserException.class)
|
||||
public void testDuplicateKey() throws Exception {
|
||||
this.factory.setResources(new ByteArrayResource[] {new ByteArrayResource(
|
||||
"mymap:\n foo: bar\nmymap:\n bar: foo".getBytes())});
|
||||
this.factory.setResources(new ByteArrayResource("mymap:\n foo: bar\nmymap:\n bar: foo".getBytes()));
|
||||
this.factory.getObject().get("mymap");
|
||||
}
|
||||
|
||||
|
||||
+23
-23
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.config;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -24,6 +25,7 @@ import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.yaml.snakeyaml.parser.ParserException;
|
||||
import org.yaml.snakeyaml.scanner.ScannerException;
|
||||
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
@@ -33,34 +35,38 @@ import static org.springframework.beans.factory.config.YamlProcessor.*;
|
||||
* Tests for {@link YamlProcessor}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class YamlProcessorTests {
|
||||
|
||||
private final YamlProcessor processor = new YamlProcessor() {
|
||||
};
|
||||
private final YamlProcessor processor = new YamlProcessor() {};
|
||||
|
||||
@Rule
|
||||
public ExpectedException exception = ExpectedException.none();
|
||||
|
||||
|
||||
@Test
|
||||
public void arrayConvertedToIndexedBeanReference() {
|
||||
this.processor.setResources(new ByteArrayResource(
|
||||
"foo: bar\nbar: [1,2,3]".getBytes()));
|
||||
this.processor.setResources(new ByteArrayResource("foo: bar\nbar: [1,2,3]".getBytes()));
|
||||
this.processor.process(new MatchCallback() {
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
assertEquals(1, properties.get("bar[0]"));
|
||||
assertEquals(2, properties.get("bar[1]"));
|
||||
assertEquals(3, properties.get("bar[2]"));
|
||||
assertEquals(4, properties.size());
|
||||
assertEquals("bar", properties.get("foo"));
|
||||
assertEquals("bar", properties.getProperty("foo"));
|
||||
assertEquals(1, properties.get("bar[0]"));
|
||||
assertEquals("1", properties.getProperty("bar[0]"));
|
||||
assertEquals(2, properties.get("bar[1]"));
|
||||
assertEquals("2", properties.getProperty("bar[1]"));
|
||||
assertEquals(3, properties.get("bar[2]"));
|
||||
assertEquals("3", properties.getProperty("bar[2]"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringResource() throws Exception {
|
||||
this.processor.setResources(new ByteArrayResource(
|
||||
"foo # a document that is a literal".getBytes()));
|
||||
this.processor.setResources(new ByteArrayResource("foo # a document that is a literal".getBytes()));
|
||||
this.processor.process(new MatchCallback() {
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
@@ -71,8 +77,7 @@ public class YamlProcessorTests {
|
||||
|
||||
@Test
|
||||
public void testBadDocumentStart() throws Exception {
|
||||
this.processor.setResources(new ByteArrayResource(
|
||||
"foo # a document\nbar: baz".getBytes()));
|
||||
this.processor.setResources(new ByteArrayResource("foo # a document\nbar: baz".getBytes()));
|
||||
this.exception.expect(ParserException.class);
|
||||
this.exception.expectMessage("line 2, column 1");
|
||||
this.processor.process(new MatchCallback() {
|
||||
@@ -84,8 +89,7 @@ public class YamlProcessorTests {
|
||||
|
||||
@Test
|
||||
public void testBadResource() throws Exception {
|
||||
this.processor.setResources(new ByteArrayResource(
|
||||
"foo: bar\ncd\nspam:\n foo: baz".getBytes()));
|
||||
this.processor.setResources(new ByteArrayResource("foo: bar\ncd\nspam:\n foo: baz".getBytes()));
|
||||
this.exception.expect(ScannerException.class);
|
||||
this.exception.expectMessage("line 3, column 1");
|
||||
this.processor.process(new MatchCallback() {
|
||||
@@ -97,8 +101,7 @@ public class YamlProcessorTests {
|
||||
|
||||
@Test
|
||||
public void mapConvertedToIndexedBeanReference() {
|
||||
this.processor.setResources(new ByteArrayResource(
|
||||
"foo: bar\nbar:\n spam: bucket".getBytes()));
|
||||
this.processor.setResources(new ByteArrayResource("foo: bar\nbar:\n spam: bucket".getBytes()));
|
||||
this.processor.process(new MatchCallback() {
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
@@ -111,8 +114,7 @@ public class YamlProcessorTests {
|
||||
|
||||
@Test
|
||||
public void integerKeyBehaves() {
|
||||
this.processor.setResources(new ByteArrayResource(
|
||||
"foo: bar\n1: bar".getBytes()));
|
||||
this.processor.setResources(new ByteArrayResource("foo: bar\n1: bar".getBytes()));
|
||||
this.processor.process(new MatchCallback() {
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
@@ -124,10 +126,8 @@ public class YamlProcessorTests {
|
||||
|
||||
@Test
|
||||
public void integerDeepKeyBehaves() {
|
||||
this.processor.setResources(new ByteArrayResource(
|
||||
"foo:\n 1: bar".getBytes()));
|
||||
this.processor.setResources(new ByteArrayResource("foo:\n 1: bar".getBytes()));
|
||||
this.processor.process(new MatchCallback() {
|
||||
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
assertEquals("bar", properties.get("foo[1]"));
|
||||
@@ -139,8 +139,7 @@ public class YamlProcessorTests {
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void flattenedMapIsSameAsPropertiesButOrdered() {
|
||||
this.processor.setResources(new ByteArrayResource(
|
||||
"foo: bar\nbar:\n spam: bucket".getBytes()));
|
||||
this.processor.setResources(new ByteArrayResource("foo: bar\nbar:\n spam: bucket".getBytes()));
|
||||
this.processor.process(new MatchCallback() {
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
@@ -155,4 +154,5 @@ public class YamlProcessorTests {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+25
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,12 +38,14 @@ import static org.springframework.beans.factory.config.YamlProcessor.*;
|
||||
* Tests for {@link YamlPropertiesFactoryBean}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class YamlPropertiesFactoryBeanTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException exception = ExpectedException.none();
|
||||
|
||||
|
||||
@Test
|
||||
public void testLoadResource() throws Exception {
|
||||
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||
@@ -113,8 +115,8 @@ public class YamlPropertiesFactoryBeanTests {
|
||||
factory.setDocumentMatchers(new DocumentMatcher() {
|
||||
@Override
|
||||
public MatchStatus matches(Properties properties) {
|
||||
return "bag".equals(properties.getProperty("foo")) ? MatchStatus.FOUND
|
||||
: MatchStatus.NOT_FOUND;
|
||||
return ("bag".equals(properties.getProperty("foo")) ?
|
||||
MatchStatus.FOUND : MatchStatus.NOT_FOUND);
|
||||
}
|
||||
});
|
||||
Properties properties = factory.getObject();
|
||||
@@ -134,8 +136,8 @@ public class YamlPropertiesFactoryBeanTests {
|
||||
if (!properties.containsKey("foo")) {
|
||||
return MatchStatus.ABSTAIN;
|
||||
}
|
||||
return "bag".equals(properties.getProperty("foo")) ? MatchStatus.FOUND
|
||||
: MatchStatus.NOT_FOUND;
|
||||
return ("bag".equals(properties.getProperty("foo")) ?
|
||||
MatchStatus.FOUND : MatchStatus.NOT_FOUND);
|
||||
}
|
||||
});
|
||||
Properties properties = factory.getObject();
|
||||
@@ -156,8 +158,8 @@ public class YamlPropertiesFactoryBeanTests {
|
||||
if (!properties.containsKey("foo")) {
|
||||
return MatchStatus.ABSTAIN;
|
||||
}
|
||||
return "bag".equals(properties.getProperty("foo")) ? MatchStatus.FOUND
|
||||
: MatchStatus.NOT_FOUND;
|
||||
return ("bag".equals(properties.getProperty("foo")) ?
|
||||
MatchStatus.FOUND : MatchStatus.NOT_FOUND);
|
||||
}
|
||||
});
|
||||
Properties properties = factory.getObject();
|
||||
@@ -178,8 +180,8 @@ public class YamlPropertiesFactoryBeanTests {
|
||||
if (!properties.containsKey("foo")) {
|
||||
return MatchStatus.ABSTAIN;
|
||||
}
|
||||
return "bag".equals(properties.getProperty("foo")) ? MatchStatus.FOUND
|
||||
: MatchStatus.NOT_FOUND;
|
||||
return ("bag".equals(properties.getProperty("foo")) ?
|
||||
MatchStatus.FOUND : MatchStatus.NOT_FOUND);
|
||||
}
|
||||
});
|
||||
Properties properties = factory.getObject();
|
||||
@@ -200,8 +202,7 @@ public class YamlPropertiesFactoryBeanTests {
|
||||
@Test
|
||||
public void testLoadNull() throws Exception {
|
||||
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||
factory.setResources(new ByteArrayResource("foo: bar\nspam:"
|
||||
.getBytes()));
|
||||
factory.setResources(new ByteArrayResource("foo: bar\nspam:".getBytes()));
|
||||
Properties properties = factory.getObject();
|
||||
assertThat(properties.getProperty("foo"), equalTo("bar"));
|
||||
assertThat(properties.getProperty("spam"), equalTo(""));
|
||||
@@ -210,20 +211,28 @@ public class YamlPropertiesFactoryBeanTests {
|
||||
@Test
|
||||
public void testLoadArrayOfString() throws Exception {
|
||||
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||
factory.setResources(new ByteArrayResource("foo:\n- bar\n- baz"
|
||||
.getBytes()));
|
||||
factory.setResources(new ByteArrayResource("foo:\n- bar\n- baz".getBytes()));
|
||||
Properties properties = factory.getObject();
|
||||
assertThat(properties.getProperty("foo[0]"), equalTo("bar"));
|
||||
assertThat(properties.getProperty("foo[1]"), equalTo("baz"));
|
||||
assertThat(properties.get("foo"), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadArrayOfInteger() throws Exception {
|
||||
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||
factory.setResources(new ByteArrayResource("foo:\n- 1\n- 2".getBytes()));
|
||||
Properties properties = factory.getObject();
|
||||
assertThat(properties.getProperty("foo[0]"), equalTo("1"));
|
||||
assertThat(properties.getProperty("foo[1]"), equalTo("2"));
|
||||
assertThat(properties.get("foo"), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadArrayOfObject() throws Exception {
|
||||
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||
factory.setResources(new ByteArrayResource(
|
||||
"foo:\n- bar:\n spam: crap\n- baz\n- one: two\n three: four"
|
||||
.getBytes()
|
||||
"foo:\n- bar:\n spam: crap\n- baz\n- one: two\n three: four".getBytes()
|
||||
));
|
||||
Properties properties = factory.getObject();
|
||||
assertThat(properties.getProperty("foo[0].bar.spam"), equalTo("crap"));
|
||||
@@ -239,8 +248,7 @@ public class YamlPropertiesFactoryBeanTests {
|
||||
Yaml yaml = new Yaml();
|
||||
Map<String, ?> map = yaml.loadAs("foo: bar\nspam:\n foo: baz", Map.class);
|
||||
assertThat(map.get("foo"), equalTo((Object) "bar"));
|
||||
assertThat(((Map<String, Object>) map.get("spam")).get("foo"),
|
||||
equalTo((Object) "baz"));
|
||||
assertThat(((Map<String, Object>) map.get("spam")).get("foo"), equalTo((Object) "baz"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,9 +23,7 @@ import org.springframework.util.comparator.CompoundComparator;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PropertyComparator}
|
||||
*
|
||||
* @see org.springframework.util.comparator.ComparatorTests
|
||||
* Unit tests for {@link PropertyComparator}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Chris Beams
|
||||
@@ -40,7 +38,7 @@ public class PropertyComparatorTests {
|
||||
Dog dog2 = new Dog();
|
||||
dog2.setNickName("biscy");
|
||||
|
||||
PropertyComparator c = new PropertyComparator("nickName", false, true);
|
||||
PropertyComparator<Dog> c = new PropertyComparator<>("nickName", false, true);
|
||||
assertTrue(c.compare(dog, dog2) > 0);
|
||||
assertTrue(c.compare(dog, dog) == 0);
|
||||
assertTrue(c.compare(dog2, dog) < 0);
|
||||
@@ -50,15 +48,14 @@ public class PropertyComparatorTests {
|
||||
public void testPropertyComparatorNulls() {
|
||||
Dog dog = new Dog();
|
||||
Dog dog2 = new Dog();
|
||||
PropertyComparator c = new PropertyComparator("nickName", false, true);
|
||||
PropertyComparator<Dog> c = new PropertyComparator<>("nickName", false, true);
|
||||
assertTrue(c.compare(dog, dog2) == 0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testCompoundComparator() {
|
||||
CompoundComparator<Dog> c = new CompoundComparator<Dog>();
|
||||
c.addComparator(new PropertyComparator("lastName", false, true));
|
||||
CompoundComparator<Dog> c = new CompoundComparator<>();
|
||||
c.addComparator(new PropertyComparator<>("lastName", false, true));
|
||||
|
||||
Dog dog1 = new Dog();
|
||||
dog1.setFirstName("macy");
|
||||
@@ -70,19 +67,19 @@ public class PropertyComparatorTests {
|
||||
|
||||
assertTrue(c.compare(dog1, dog2) == 0);
|
||||
|
||||
c.addComparator(new PropertyComparator("firstName", false, true));
|
||||
c.addComparator(new PropertyComparator<>("firstName", false, true));
|
||||
assertTrue(c.compare(dog1, dog2) > 0);
|
||||
|
||||
dog2.setLastName("konikk dog");
|
||||
assertTrue(c.compare(dog2, dog1) > 0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testCompoundComparatorInvert() {
|
||||
CompoundComparator<Dog> c = new CompoundComparator<Dog>();
|
||||
c.addComparator(new PropertyComparator("lastName", false, true));
|
||||
c.addComparator(new PropertyComparator("firstName", false, true));
|
||||
CompoundComparator<Dog> c = new CompoundComparator<>();
|
||||
c.addComparator(new PropertyComparator<>("lastName", false, true));
|
||||
c.addComparator(new PropertyComparator<>("firstName", false, true));
|
||||
|
||||
Dog dog1 = new Dog();
|
||||
dog1.setFirstName("macy");
|
||||
dog1.setLastName("grayspots");
|
||||
@@ -97,7 +94,6 @@ public class PropertyComparatorTests {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class Dog implements Comparable<Object> {
|
||||
|
||||
private String nickName;
|
||||
@@ -106,11 +102,6 @@ public class PropertyComparatorTests {
|
||||
|
||||
private String lastName;
|
||||
|
||||
@Override
|
||||
public int compareTo(Object o) {
|
||||
return nickName.compareTo(((Dog)o).nickName);
|
||||
}
|
||||
|
||||
public String getNickName() {
|
||||
return nickName;
|
||||
}
|
||||
@@ -134,6 +125,11 @@ public class PropertyComparatorTests {
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Object o) {
|
||||
return this.nickName.compareTo(((Dog) o).nickName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -98,7 +98,7 @@ public class EhCacheCache implements Cache {
|
||||
try {
|
||||
value = valueLoader.call();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
catch (Throwable ex) {
|
||||
throw new ValueRetrievalException(key, valueLoader, ex);
|
||||
}
|
||||
put(key, value);
|
||||
|
||||
+8
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,6 +39,7 @@ class CacheResultInterceptor extends AbstractKeyCacheInterceptor<CacheResultOper
|
||||
super(errorHandler);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Object invoke(CacheOperationInvocationContext<CacheResultOperation> context,
|
||||
CacheOperationInvoker invoker) {
|
||||
@@ -59,7 +60,7 @@ class CacheResultInterceptor extends AbstractKeyCacheInterceptor<CacheResultOper
|
||||
|
||||
try {
|
||||
Object invocationResult = invoker.invoke();
|
||||
cache.put(cacheKey, invocationResult);
|
||||
doPut(cache, cacheKey, invocationResult);
|
||||
return invocationResult;
|
||||
}
|
||||
catch (CacheOperationInvoker.ThrowableWrapper ex) {
|
||||
@@ -82,17 +83,15 @@ class CacheResultInterceptor extends AbstractKeyCacheInterceptor<CacheResultOper
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void cacheException(Cache exceptionCache, ExceptionTypeFilter filter, Object cacheKey, Throwable ex) {
|
||||
if (exceptionCache == null) {
|
||||
return;
|
||||
}
|
||||
if (filter.match(ex.getClass())) {
|
||||
exceptionCache.put(cacheKey, ex);
|
||||
doPut(exceptionCache, cacheKey, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Cache resolveExceptionCache(CacheOperationInvocationContext<CacheResultOperation> context) {
|
||||
CacheResolver exceptionCacheResolver = context.getOperation().getExceptionCacheResolver();
|
||||
if (exceptionCacheResolver != null) {
|
||||
@@ -101,9 +100,10 @@ class CacheResultInterceptor extends AbstractKeyCacheInterceptor<CacheResultOper
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rewrite the call stack of the specified {@code exception} so that it matches
|
||||
* the current call stack up-to (included) the specified method invocation.
|
||||
* the current call stack up to (included) the specified method invocation.
|
||||
* <p>Clone the specified exception. If the exception is not {@code serializable},
|
||||
* the original exception is returned. If no common ancestor can be found, returns
|
||||
* the original exception.
|
||||
@@ -111,8 +111,8 @@ class CacheResultInterceptor extends AbstractKeyCacheInterceptor<CacheResultOper
|
||||
* @param exception the exception to merge with the current call stack
|
||||
* @param className the class name of the common ancestor
|
||||
* @param methodName the method name of the common ancestor
|
||||
* @return a clone exception with a rewritten call stack composed of the current
|
||||
* call stack up to (included) the common ancestor specified by the {@code className} and
|
||||
* @return a clone exception with a rewritten call stack composed of the current call
|
||||
* stack up to (included) the common ancestor specified by the {@code className} and
|
||||
* {@code methodName} arguments, followed by stack trace elements of the specified
|
||||
* {@code exception} after the common ancestor.
|
||||
*/
|
||||
|
||||
+12
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,14 +44,15 @@ class DefaultCacheInvocationContext<A extends Annotation>
|
||||
|
||||
private final CacheInvocationParameter[] allParameters;
|
||||
|
||||
public DefaultCacheInvocationContext(JCacheOperation<A> operation,
|
||||
Object target, Object[] args) {
|
||||
|
||||
public DefaultCacheInvocationContext(JCacheOperation<A> operation, Object target, Object[] args) {
|
||||
this.operation = operation;
|
||||
this.target = target;
|
||||
this.args = args;
|
||||
this.allParameters = operation.getAllParameters(args);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JCacheOperation<A> getOperation() {
|
||||
return this.operation;
|
||||
@@ -94,17 +95,19 @@ class DefaultCacheInvocationContext<A extends Annotation>
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> cls) {
|
||||
throw new IllegalArgumentException("Could not unwrap to '" + cls.getName() + "'");
|
||||
throw new IllegalArgumentException("Cannot unwrap to " + cls);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("CacheInvocationContext{");
|
||||
sb.append("operation=").append(operation);
|
||||
sb.append(", target=").append(target);
|
||||
sb.append(", args=").append(Arrays.toString(args));
|
||||
sb.append(", allParameters=").append(Arrays.toString(allParameters));
|
||||
StringBuilder sb = new StringBuilder("CacheInvocationContext{");
|
||||
sb.append("operation=").append(this.operation);
|
||||
sb.append(", target=").append(this.target);
|
||||
sb.append(", args=").append(Arrays.toString(this.args));
|
||||
sb.append(", allParameters=").append(Arrays.toString(this.allParameters));
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -66,7 +66,7 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
|
||||
|
||||
|
||||
public void setCacheOperationSource(JCacheOperationSource cacheOperationSource) {
|
||||
Assert.notNull(cacheOperationSource);
|
||||
Assert.notNull(cacheOperationSource, "JCacheOperationSource must not be null");
|
||||
this.cacheOperationSource = cacheOperationSource;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
|
||||
public void afterPropertiesSet() {
|
||||
Assert.state(getCacheOperationSource() != null, "The 'cacheOperationSource' property is required: " +
|
||||
"If there are no cacheable methods, then don't use a cache aspect.");
|
||||
Assert.state(getErrorHandler() != null, "The 'errorHandler' is required");
|
||||
Assert.state(getErrorHandler() != null, "The 'errorHandler' property is required");
|
||||
|
||||
this.cacheResultInterceptor = new CacheResultInterceptor(getErrorHandler());
|
||||
this.cachePutInterceptor = new CachePutInterceptor(getErrorHandler());
|
||||
@@ -128,23 +128,23 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial
|
||||
BasicOperation operation = context.getOperation();
|
||||
|
||||
if (operation instanceof CacheResultOperation) {
|
||||
return cacheResultInterceptor.invoke(
|
||||
return this.cacheResultInterceptor.invoke(
|
||||
(CacheOperationInvocationContext<CacheResultOperation>) context, adapter);
|
||||
}
|
||||
else if (operation instanceof CachePutOperation) {
|
||||
return cachePutInterceptor.invoke(
|
||||
return this.cachePutInterceptor.invoke(
|
||||
(CacheOperationInvocationContext<CachePutOperation>) context, adapter);
|
||||
}
|
||||
else if (operation instanceof CacheRemoveOperation) {
|
||||
return cacheRemoveEntryInterceptor.invoke(
|
||||
return this.cacheRemoveEntryInterceptor.invoke(
|
||||
(CacheOperationInvocationContext<CacheRemoveOperation>) context, adapter);
|
||||
}
|
||||
else if (operation instanceof CacheRemoveAllOperation) {
|
||||
return cacheRemoveAllInterceptor.invoke(
|
||||
return this.cacheRemoveAllInterceptor.invoke(
|
||||
(CacheOperationInvocationContext<CacheRemoveAllOperation>) context, adapter);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Could not handle " + operation);
|
||||
throw new IllegalArgumentException("Cannot handle " + operation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,7 +43,6 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
import org.springframework.scheduling.SchedulingException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
@@ -210,7 +209,6 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
* @see #setQuartzProperties
|
||||
*/
|
||||
public void setSchedulerFactoryClass(Class<? extends SchedulerFactory> schedulerFactoryClass) {
|
||||
Assert.isAssignable(SchedulerFactory.class, schedulerFactoryClass);
|
||||
this.schedulerFactoryClass = schedulerFactoryClass;
|
||||
}
|
||||
|
||||
@@ -652,6 +650,8 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
logger.info("Will start Quartz Scheduler [" + scheduler.getSchedulerName() +
|
||||
"] in " + startupDelay + " seconds");
|
||||
}
|
||||
// Not using the Quartz startDelayed method since we explicitly want a daemon
|
||||
// thread here, not keeping the JVM alive in case of all other threads ending.
|
||||
Thread schedulerThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -342,7 +342,7 @@ public class FreeMarkerConfigurationFactory {
|
||||
}
|
||||
return new FileTemplateLoader(file);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
catch (Exception ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cannot resolve template loader path [" + templateLoaderPath +
|
||||
"] to [java.io.File]: using SpringTemplateLoader as fallback", ex);
|
||||
|
||||
+8
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,8 +30,6 @@ import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.jcache.AbstractJCacheTests;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.BDDMockito.*;
|
||||
@@ -46,7 +44,7 @@ public class CacheResolverAdapterTests extends AbstractJCacheTests {
|
||||
|
||||
|
||||
@Test
|
||||
public void resolveSimpleCache() {
|
||||
public void resolveSimpleCache() throws Exception {
|
||||
DefaultCacheInvocationContext<?> dummyContext = createDummyContext();
|
||||
CacheResolverAdapter adapter = new CacheResolverAdapter(getCacheResolver(dummyContext, "testCache"));
|
||||
Collection<? extends Cache> caches = adapter.resolveCaches(dummyContext);
|
||||
@@ -56,7 +54,7 @@ public class CacheResolverAdapterTests extends AbstractJCacheTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveUnknownCache() {
|
||||
public void resolveUnknownCache() throws Exception {
|
||||
DefaultCacheInvocationContext<?> dummyContext = createDummyContext();
|
||||
CacheResolverAdapter adapter = new CacheResolverAdapter(getCacheResolver(dummyContext, null));
|
||||
|
||||
@@ -66,7 +64,7 @@ public class CacheResolverAdapterTests extends AbstractJCacheTests {
|
||||
|
||||
protected CacheResolver getCacheResolver(CacheInvocationContext<? extends Annotation> context, String cacheName) {
|
||||
CacheResolver cacheResolver = mock(CacheResolver.class);
|
||||
final javax.cache.Cache cache;
|
||||
javax.cache.Cache cache;
|
||||
if (cacheName == null) {
|
||||
cache = null;
|
||||
}
|
||||
@@ -78,22 +76,21 @@ public class CacheResolverAdapterTests extends AbstractJCacheTests {
|
||||
return cacheResolver;
|
||||
}
|
||||
|
||||
protected DefaultCacheInvocationContext<?> createDummyContext() {
|
||||
Method method = ReflectionUtils.findMethod(Sample.class, "get", String.class);
|
||||
Assert.notNull(method);
|
||||
protected DefaultCacheInvocationContext<?> createDummyContext() throws Exception {
|
||||
Method method = Sample.class.getMethod("get", String.class);
|
||||
CacheResult cacheAnnotation = method.getAnnotation(CacheResult.class);
|
||||
CacheMethodDetails<CacheResult> methodDetails =
|
||||
new DefaultCacheMethodDetails<>(method, cacheAnnotation, "test");
|
||||
CacheResultOperation operation = new CacheResultOperation(methodDetails,
|
||||
defaultCacheResolver, defaultKeyGenerator, defaultExceptionCacheResolver);
|
||||
return new DefaultCacheInvocationContext<CacheResult>(operation, new Sample(), new Object[] {"id"});
|
||||
return new DefaultCacheInvocationContext<>(operation, new Sample(), new Object[] {"id"});
|
||||
}
|
||||
|
||||
|
||||
static class Sample {
|
||||
|
||||
@CacheResult
|
||||
private Object get(String id) {
|
||||
public Object get(String id) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+64
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,6 +41,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.BDDMockito.*;
|
||||
|
||||
/**
|
||||
@@ -48,60 +49,93 @@ import static org.mockito.BDDMockito.*;
|
||||
*/
|
||||
public class JCacheErrorHandlerTests {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private Cache cache;
|
||||
|
||||
private Cache errorCache;
|
||||
|
||||
private CacheErrorHandler errorHandler;
|
||||
|
||||
private SimpleService simpleService;
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
|
||||
this.cache = context.getBean("mockCache", Cache.class);
|
||||
this.errorCache = context.getBean("mockErrorCache", Cache.class);
|
||||
this.errorHandler = context.getBean(CacheErrorHandler.class);
|
||||
this.simpleService = context.getBean(SimpleService.class);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getFail() {
|
||||
UnsupportedOperationException exception = new UnsupportedOperationException("Test exception on get");
|
||||
Object key = SimpleKeyGenerator.generateKey(0L);
|
||||
willThrow(exception).given(cache).get(key);
|
||||
willThrow(exception).given(this.cache).get(key);
|
||||
|
||||
this.simpleService.get(0L);
|
||||
verify(errorHandler).handleCacheGetError(exception, cache, key);
|
||||
verify(this.errorHandler).handleCacheGetError(exception, this.cache, key);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPutNewElementFail() {
|
||||
UnsupportedOperationException exception = new UnsupportedOperationException("Test exception on put");
|
||||
Object key = SimpleKeyGenerator.generateKey(0L);
|
||||
given(this.cache.get(key)).willReturn(null);
|
||||
willThrow(exception).given(this.cache).put(key, 0L);
|
||||
|
||||
this.simpleService.get(0L);
|
||||
verify(this.errorHandler).handleCachePutError(exception, this.cache, key, 0L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFailPutExceptionFail() {
|
||||
UnsupportedOperationException exceptionOnPut = new UnsupportedOperationException("Test exception on put");
|
||||
Object key = SimpleKeyGenerator.generateKey(0L);
|
||||
given(this.cache.get(key)).willReturn(null);
|
||||
willThrow(exceptionOnPut).given(this.errorCache).put(key, SimpleService.TEST_EXCEPTION);
|
||||
|
||||
try {
|
||||
this.simpleService.getFail(0L);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertEquals("Test exception", ex.getMessage());
|
||||
}
|
||||
verify(this.errorHandler).handleCachePutError(
|
||||
exceptionOnPut, this.errorCache, key, SimpleService.TEST_EXCEPTION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putFail() {
|
||||
UnsupportedOperationException exception = new UnsupportedOperationException("Test exception on put");
|
||||
Object key = SimpleKeyGenerator.generateKey(0L);
|
||||
willThrow(exception).given(cache).put(key, 234L);
|
||||
willThrow(exception).given(this.cache).put(key, 234L);
|
||||
|
||||
this.simpleService.put(0L, 234L);
|
||||
verify(errorHandler).handleCachePutError(exception, cache, key, 234L);
|
||||
verify(this.errorHandler).handleCachePutError(exception, this.cache, key, 234L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void evictFail() {
|
||||
UnsupportedOperationException exception = new UnsupportedOperationException("Test exception on evict");
|
||||
Object key = SimpleKeyGenerator.generateKey(0L);
|
||||
willThrow(exception).given(cache).evict(key);
|
||||
willThrow(exception).given(this.cache).evict(key);
|
||||
|
||||
this.simpleService.evict(0L);
|
||||
verify(errorHandler).handleCacheEvictError(exception, cache, key);
|
||||
verify(this.errorHandler).handleCacheEvictError(exception, this.cache, key);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearFail() {
|
||||
UnsupportedOperationException exception = new UnsupportedOperationException("Test exception on evict");
|
||||
willThrow(exception).given(cache).clear();
|
||||
willThrow(exception).given(this.cache).clear();
|
||||
|
||||
this.simpleService.clear();
|
||||
verify(errorHandler).handleCacheClearError(exception, cache);
|
||||
verify(this.errorHandler).handleCacheClearError(exception, this.cache);
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +147,7 @@ public class JCacheErrorHandlerTests {
|
||||
@Override
|
||||
public CacheManager cacheManager() {
|
||||
SimpleCacheManager cacheManager = new SimpleCacheManager();
|
||||
cacheManager.setCaches(Arrays.asList(mockCache()));
|
||||
cacheManager.setCaches(Arrays.asList(mockCache(), mockErrorCache()));
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
@@ -135,15 +169,30 @@ public class JCacheErrorHandlerTests {
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Cache mockErrorCache() {
|
||||
Cache cache = mock(Cache.class);
|
||||
given(cache.getName()).willReturn("error");
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@CacheDefaults(cacheName = "test")
|
||||
public static class SimpleService {
|
||||
|
||||
private static final IllegalStateException TEST_EXCEPTION = new IllegalStateException("Test exception");
|
||||
|
||||
private AtomicLong counter = new AtomicLong();
|
||||
|
||||
@CacheResult
|
||||
public Object get(long id) {
|
||||
return counter.getAndIncrement();
|
||||
return this.counter.getAndIncrement();
|
||||
}
|
||||
|
||||
@CacheResult(exceptionCacheName = "error")
|
||||
public Object getFail(long id) {
|
||||
throw TEST_EXCEPTION;
|
||||
}
|
||||
|
||||
@CachePut
|
||||
@@ -158,4 +207,5 @@ public class JCacheErrorHandlerTests {
|
||||
public void clear() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,8 +43,7 @@ import org.springframework.util.Assert;
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource
|
||||
implements Serializable {
|
||||
public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource implements Serializable {
|
||||
|
||||
private final boolean publicMethodsOnly;
|
||||
|
||||
@@ -177,6 +176,7 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati
|
||||
return this.annotationParsers.hashCode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback interface providing {@link CacheOperation} instance(s) based on
|
||||
* a given {@link CacheAnnotationParser}.
|
||||
@@ -184,10 +184,9 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati
|
||||
protected interface CacheOperationProvider {
|
||||
|
||||
/**
|
||||
* Returns the {@link CacheOperation} instance(s) provided by the specified parser.
|
||||
*
|
||||
* Return the {@link CacheOperation} instance(s) provided by the specified parser.
|
||||
* @param parser the parser to use
|
||||
* @return the cache operations or {@code null} if none is found
|
||||
* @return the cache operations, or {@code null} if none found
|
||||
*/
|
||||
Collection<CacheOperation> getCacheOperations(CacheAnnotationParser parser);
|
||||
}
|
||||
|
||||
Vendored
+6
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,7 +28,6 @@ import org.springframework.cache.interceptor.CacheOperation;
|
||||
import org.springframework.cache.interceptor.CachePutOperation;
|
||||
import org.springframework.cache.interceptor.CacheableOperation;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -62,28 +61,28 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
|
||||
protected Collection<CacheOperation> parseCacheAnnotations(DefaultCacheConfig cachingConfig, AnnotatedElement ae) {
|
||||
Collection<CacheOperation> ops = null;
|
||||
|
||||
Collection<Cacheable> cacheables = AnnotatedElementUtils.findAllMergedAnnotations(ae, Cacheable.class);
|
||||
Collection<Cacheable> cacheables = AnnotatedElementUtils.getAllMergedAnnotations(ae, Cacheable.class);
|
||||
if (!cacheables.isEmpty()) {
|
||||
ops = lazyInit(ops);
|
||||
for (Cacheable cacheable : cacheables) {
|
||||
ops.add(parseCacheableAnnotation(ae, cachingConfig, cacheable));
|
||||
}
|
||||
}
|
||||
Collection<CacheEvict> evicts = AnnotatedElementUtils.findAllMergedAnnotations(ae, CacheEvict.class);
|
||||
Collection<CacheEvict> evicts = AnnotatedElementUtils.getAllMergedAnnotations(ae, CacheEvict.class);
|
||||
if (!evicts.isEmpty()) {
|
||||
ops = lazyInit(ops);
|
||||
for (CacheEvict evict : evicts) {
|
||||
ops.add(parseEvictAnnotation(ae, cachingConfig, evict));
|
||||
}
|
||||
}
|
||||
Collection<CachePut> puts = AnnotatedElementUtils.findAllMergedAnnotations(ae, CachePut.class);
|
||||
Collection<CachePut> puts = AnnotatedElementUtils.getAllMergedAnnotations(ae, CachePut.class);
|
||||
if (!puts.isEmpty()) {
|
||||
ops = lazyInit(ops);
|
||||
for (CachePut put : puts) {
|
||||
ops.add(parsePutAnnotation(ae, cachingConfig, put));
|
||||
}
|
||||
}
|
||||
Collection<Caching> cachings = AnnotatedElementUtils.findAllMergedAnnotations(ae, Caching.class);
|
||||
Collection<Caching> cachings = AnnotatedElementUtils.getAllMergedAnnotations(ae, Caching.class);
|
||||
if (!cachings.isEmpty()) {
|
||||
ops = lazyInit(ops);
|
||||
for (Caching caching : cachings) {
|
||||
@@ -194,7 +193,7 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
|
||||
* @return the default config (never {@code null})
|
||||
*/
|
||||
DefaultCacheConfig getDefaultCacheConfig(Class<?> target) {
|
||||
CacheConfig annotation = AnnotationUtils.getAnnotation(target, CacheConfig.class);
|
||||
CacheConfig annotation = AnnotatedElementUtils.getMergedAnnotation(target, CacheConfig.class);
|
||||
if (annotation != null) {
|
||||
return new DefaultCacheConfig(annotation.cacheNames(), annotation.keyGenerator(),
|
||||
annotation.cacheManager(), annotation.cacheResolver());
|
||||
|
||||
+7
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -149,7 +149,7 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache {
|
||||
try {
|
||||
value = valueLoader.call();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
catch (Throwable ex) {
|
||||
throw new ValueRetrievalException(key, valueLoader, ex);
|
||||
}
|
||||
put(key, value);
|
||||
@@ -186,9 +186,9 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache {
|
||||
try {
|
||||
return serializeValue(storeValue);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException("Failed to serialize cache value '"
|
||||
+ userValue + "'. Does it implement Serializable?", ex);
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalArgumentException("Failed to serialize cache value '" + userValue +
|
||||
"'. Does it implement Serializable?", ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -213,9 +213,8 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache {
|
||||
try {
|
||||
return super.fromStoreValue(deserializeValue(storeValue));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException("Failed to deserialize cache value '" +
|
||||
storeValue + "'", ex);
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalArgumentException("Failed to deserialize cache value '" + storeValue + "'", ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
+7
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,10 +39,11 @@ public class CacheNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
static final String DEFAULT_CACHE_MANAGER_BEAN_NAME = "cacheManager";
|
||||
|
||||
|
||||
static String extractCacheManager(Element element) {
|
||||
return (element.hasAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE) ? element
|
||||
.getAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE)
|
||||
: CacheNamespaceHandler.DEFAULT_CACHE_MANAGER_BEAN_NAME);
|
||||
return (element.hasAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE) ?
|
||||
element.getAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE) :
|
||||
CacheNamespaceHandler.DEFAULT_CACHE_MANAGER_BEAN_NAME);
|
||||
}
|
||||
|
||||
static BeanDefinition parseKeyGenerator(Element element, BeanDefinition def) {
|
||||
@@ -53,9 +54,11 @@ public class CacheNamespaceHandler extends NamespaceHandlerSupport {
|
||||
return def;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("advice", new CacheAdviceParser());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,7 +37,7 @@ public abstract class AbstractCacheInvoker {
|
||||
}
|
||||
|
||||
protected AbstractCacheInvoker(CacheErrorHandler errorHandler) {
|
||||
Assert.notNull("ErrorHandler must not be null");
|
||||
Assert.notNull(errorHandler, "ErrorHandler must not be null");
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -84,6 +84,10 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
|
||||
*/
|
||||
@Override
|
||||
public Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) {
|
||||
if (method.getDeclaringClass() == Object.class) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object cacheKey = getCacheKey(method, targetClass);
|
||||
Collection<CacheOperation> cached = this.attributeCache.get(cacheKey);
|
||||
|
||||
|
||||
+20
-16
@@ -361,12 +361,12 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
|
||||
Cache cache = context.getCaches().iterator().next();
|
||||
try {
|
||||
return cache.get(key, new Callable<Object>() {
|
||||
return wrapCacheValue(method, cache.get(key, new Callable<Object>() {
|
||||
@Override
|
||||
public Object call() throws Exception {
|
||||
return invokeOperation(invoker);
|
||||
return unwrapReturnValue(invokeOperation(invoker));
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
catch (Cache.ValueRetrievalException ex) {
|
||||
// The invoker wraps any Throwable in a ThrowableWrapper instance so we
|
||||
@@ -401,23 +401,12 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
if (cacheHit != null && cachePutRequests.isEmpty() && !hasCachePut(contexts)) {
|
||||
// If there are no put requests, just use the cache hit
|
||||
cacheValue = cacheHit.get();
|
||||
if (method.getReturnType() == javaUtilOptionalClass &&
|
||||
(cacheValue == null || cacheValue.getClass() != javaUtilOptionalClass)) {
|
||||
returnValue = OptionalUnwrapper.wrap(cacheValue);
|
||||
}
|
||||
else {
|
||||
returnValue = cacheValue;
|
||||
}
|
||||
returnValue = wrapCacheValue(method, cacheValue);
|
||||
}
|
||||
else {
|
||||
// Invoke the method if we don't have a cache hit
|
||||
returnValue = invokeOperation(invoker);
|
||||
if (returnValue != null && returnValue.getClass() == javaUtilOptionalClass) {
|
||||
cacheValue = OptionalUnwrapper.unwrap(returnValue);
|
||||
}
|
||||
else {
|
||||
cacheValue = returnValue;
|
||||
}
|
||||
cacheValue = unwrapReturnValue(returnValue);
|
||||
}
|
||||
|
||||
// Collect any explicit @CachePuts
|
||||
@@ -434,6 +423,21 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private Object wrapCacheValue(Method method, Object cacheValue) {
|
||||
if (method.getReturnType() == javaUtilOptionalClass &&
|
||||
(cacheValue == null || cacheValue.getClass() != javaUtilOptionalClass)) {
|
||||
return OptionalUnwrapper.wrap(cacheValue);
|
||||
}
|
||||
return cacheValue;
|
||||
}
|
||||
|
||||
private Object unwrapReturnValue(Object returnValue) {
|
||||
if (returnValue != null && returnValue.getClass() == javaUtilOptionalClass) {
|
||||
return OptionalUnwrapper.unwrap(returnValue);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private boolean hasCachePut(CacheOperationContexts contexts) {
|
||||
// Evaluate the conditions *without* the result object because we don't have it yet...
|
||||
Collection<CacheOperationContext> cachePutContexts = contexts.get(CachePutOperation.class);
|
||||
|
||||
+9
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -145,19 +145,19 @@ public abstract class CacheOperation implements BasicOperation {
|
||||
private String condition = "";
|
||||
|
||||
public void setName(String name) {
|
||||
Assert.hasText(name);
|
||||
Assert.hasText(name, "Name must not be empty");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setCacheName(String cacheName) {
|
||||
Assert.hasText(cacheName);
|
||||
Assert.hasText(cacheName, "Cache name must not be empty");
|
||||
this.cacheNames = Collections.singleton(cacheName);
|
||||
}
|
||||
|
||||
public void setCacheNames(String... cacheNames) {
|
||||
this.cacheNames = new LinkedHashSet<String>(cacheNames.length);
|
||||
for (String cacheName : cacheNames) {
|
||||
Assert.hasText(cacheName, "Cache name must be non-null if specified");
|
||||
Assert.hasText(cacheName, "Cache name must be non-empty if specified");
|
||||
this.cacheNames.add(cacheName);
|
||||
}
|
||||
}
|
||||
@@ -167,7 +167,7 @@ public abstract class CacheOperation implements BasicOperation {
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
Assert.notNull(key);
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@@ -188,22 +188,22 @@ public abstract class CacheOperation implements BasicOperation {
|
||||
}
|
||||
|
||||
public void setKeyGenerator(String keyGenerator) {
|
||||
Assert.notNull(keyGenerator);
|
||||
Assert.notNull(keyGenerator, "KeyGenerator name must not be null");
|
||||
this.keyGenerator = keyGenerator;
|
||||
}
|
||||
|
||||
public void setCacheManager(String cacheManager) {
|
||||
Assert.notNull(cacheManager);
|
||||
Assert.notNull(cacheManager, "CacheManager name must not be null");
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
public void setCacheResolver(String cacheResolver) {
|
||||
Assert.notNull(this.cacheManager);
|
||||
Assert.notNull(cacheResolver, "CacheResolver name must not be null");
|
||||
this.cacheResolver = cacheResolver;
|
||||
}
|
||||
|
||||
public void setCondition(String condition) {
|
||||
Assert.notNull(condition);
|
||||
Assert.notNull(condition, "Condition must not be null");
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.support;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
/**
|
||||
* A no operation {@link Cache} implementation suitable
|
||||
* for disabling caching.
|
||||
*
|
||||
* <p>Will simply accept any items into the cache not actually storing them.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.3.4
|
||||
*/
|
||||
public class NoOpCache implements Cache {
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Create a {@link NoOpCache} instance with the specified name
|
||||
* @param name the name of the cache
|
||||
*/
|
||||
public NoOpCache(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Object key) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueWrapper get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(Object key, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(Object key, Callable<T> valueLoader) {
|
||||
try {
|
||||
return valueLoader.call();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new ValueRetrievalException(key, valueLoader, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getNativeCache() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Object key, Object value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueWrapper putIfAbsent(Object key, Object value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
-58
@@ -20,7 +20,6 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
@@ -73,61 +72,4 @@ public class NoOpCacheManager implements CacheManager {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class NoOpCache implements Cache {
|
||||
|
||||
private final String name;
|
||||
|
||||
public NoOpCache(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Object key) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueWrapper get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(Object key, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(Object key, Callable<T> valueLoader) {
|
||||
try {
|
||||
return valueLoader.call();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new ValueRetrievalException(key, valueLoader, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getNativeCache() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Object key, Object value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueWrapper putIfAbsent(Object key, Object value) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user