mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
383 Commits
v7.0.0
...
v3.2.8.RELEASE
| Author | SHA1 | Date | |
|---|---|---|---|
| 28d43f886c | |||
| 082a564b9b | |||
| fb0683c066 | |||
| 09c57203bb | |||
| 4886bf0708 | |||
| 75e08695a0 | |||
| 5da79ebca6 | |||
| bb7a1372c0 | |||
| 7e3c722146 | |||
| d7591c6bd7 | |||
| 42dec02203 | |||
| 27ad1990e3 | |||
| 337b5ff5d6 | |||
| b40403cdc9 | |||
| 0972582880 | |||
| bc879100c4 | |||
| 9f77ef4102 | |||
| 7f95a27e6d | |||
| 4ac4630b0b | |||
| 29b40b9d0e | |||
| 85e336e6da | |||
| b223e6efec | |||
| d55a173e2e | |||
| 4d2d223b0c | |||
| c3d74b4521 | |||
| 61ab40cd7a | |||
| 3da9a3193c | |||
| 7e9cb5195a | |||
| 4233d0a99e | |||
| ad91610796 | |||
| f558396e91 | |||
| a2ec8f864e | |||
| 03e243a4ab | |||
| 60b24cffdb | |||
| 036bd791f0 | |||
| a53df0b2c1 | |||
| 1a011616d9 | |||
| 3af9d1f29b | |||
| b3fb81bf72 | |||
| dd5af764b5 | |||
| 3ffbb24211 | |||
| 4c385f0073 | |||
| 7d527f9771 | |||
| 3ba7ab15ab | |||
| 36ab65ace7 | |||
| 35753eb54d | |||
| 1cb9b9cf52 | |||
| fe4b57c199 | |||
| 2a3b29f98e | |||
| d26a570192 | |||
| ac3c670f70 | |||
| 398f91cb74 | |||
| b4115f3202 | |||
| 7e2167fd17 | |||
| 09ad8347be | |||
| 2ef39a5666 | |||
| 1a2033eb41 | |||
| 6162917b4e | |||
| e07ad5a19b | |||
| 5307a87d1a | |||
| 87179b075b | |||
| 23249cda98 | |||
| 341d645d09 | |||
| 9845d9eb21 | |||
| edb660863b | |||
| 866c7847e3 | |||
| fc361844ec | |||
| 52d050d21a | |||
| c1569d7ecd | |||
| fdd31c0e66 | |||
| cfa78a9b25 | |||
| d434ef9713 | |||
| c406c56d57 | |||
| d9ab6aaf6c | |||
| aa1babdfde | |||
| 09c9137b75 | |||
| 603d79ac9b | |||
| fdac4a7d18 | |||
| 11ef4308b8 | |||
| e0f9a85955 | |||
| b229d54172 | |||
| c77832ba6d | |||
| 59893d1f13 | |||
| 9aefa0334f | |||
| f532607d4b | |||
| 16bf501b30 | |||
| fd13c994c9 | |||
| 1f60738431 | |||
| 68b1eb1aba | |||
| 5fb2665d1c | |||
| 52c11eab41 | |||
| b6362c5016 | |||
| 6deb597cdf | |||
| bfecbaf88e | |||
| 3429a4186c | |||
| f18debb5a3 | |||
| 62fd12c527 | |||
| f8f6c5fd89 | |||
| 354917c53d | |||
| 1e0bf493cc | |||
| 0ea4f8ecb7 | |||
| 139adba96a | |||
| 7502ecd35e | |||
| 477e60f28a | |||
| 3db6a7f715 | |||
| 0606c98277 | |||
| dbfe68a6dc | |||
| ab6c6b104d | |||
| c2459b4a61 | |||
| 4f24643fd3 | |||
| 1a0a381559 | |||
| 8c8eead667 | |||
| b35050caf2 | |||
| 72a5737ab9 | |||
| be2d915cc2 | |||
| 6045914057 | |||
| 78646f1f32 | |||
| f88cbda6ef | |||
| c48da0d9a4 | |||
| e3344898cd | |||
| 2e123b01e5 | |||
| 57eedf33d6 | |||
| f477a024ad | |||
| 5dddb492b8 | |||
| ecee20f1fe | |||
| e08f743301 | |||
| a05c957d0e | |||
| a2de329db9 | |||
| 551364f668 | |||
| 08aa22ff1f | |||
| a115a7dad5 | |||
| f457319965 | |||
| 7ad6df8c75 | |||
| f5d5882f46 | |||
| 0a4d28d5d5 | |||
| 9002742873 | |||
| c2d98de6a6 | |||
| bf31f7178d | |||
| 249d8379ae | |||
| bfcfbe41a1 | |||
| f17ae5a7a8 | |||
| 779d5716e5 | |||
| 2a6c642408 | |||
| 126116e759 | |||
| 1ea218cee2 | |||
| ec78165072 | |||
| e4fb72f6e3 | |||
| 6fb10981b0 | |||
| d48b9b1ef7 | |||
| c3907cdae5 | |||
| 7f895222e1 | |||
| 22ece06b39 | |||
| b20b7415d8 | |||
| 38ad39f467 | |||
| 6ded287144 | |||
| 6e275b7663 | |||
| 882726377f | |||
| 2e15f94cf2 | |||
| d0fc38ec76 | |||
| 8e52e650f4 | |||
| 71650c0a44 | |||
| c89985c1db | |||
| d4b0751626 | |||
| 6bed18004e | |||
| dfed8afb26 | |||
| 236981aaa9 | |||
| 6ce2eb9622 | |||
| 6224ddd0cb | |||
| 25c7e3645b | |||
| 9c9cc7fcb4 | |||
| 5639eb66b6 | |||
| 1dc79f7f9c | |||
| c1b772cd9c | |||
| 73a8a1b966 | |||
| 0f26a7795d | |||
| 47ae15b7ee | |||
| df7b661702 | |||
| fe46a01a57 | |||
| 2f13e05b4f | |||
| 4b38dc8972 | |||
| 7387cb990e | |||
| 863570abb7 | |||
| 70907fd326 | |||
| 494cc22bcd | |||
| 044d68b336 | |||
| a95eb1d044 | |||
| b00c31a620 | |||
| 23cc44f16e | |||
| e1a065906e | |||
| 3bfddc501d | |||
| f9081bedb4 | |||
| 1ac8e48ebf | |||
| d4f4225e53 | |||
| c53184cb6d | |||
| f9f106936c | |||
| bcf7aecf0f | |||
| 5854d519a1 | |||
| 1ea7f741fe | |||
| 8c6fe2cb42 | |||
| 7a5a6893e3 | |||
| c8e8d6cd49 | |||
| 094ff8883d | |||
| 44f79f95a7 | |||
| 3eaec64ee8 | |||
| ff9c695599 | |||
| 6021822ce4 | |||
| 045f78e6c5 | |||
| 42568afb37 | |||
| ce001c23f7 | |||
| 93405fb289 | |||
| db056ae0e0 | |||
| 35d53af2ca | |||
| 63de2fab4c | |||
| 5d8aa635c6 | |||
| ad9049e68a | |||
| b9135788b9 | |||
| b62652aca1 | |||
| fce02d94b8 | |||
| 2dca5b6815 | |||
| a302c4ac45 | |||
| 507cf8ad14 | |||
| 7500caea52 | |||
| 7994b63c13 | |||
| 26e697b60c | |||
| ef66708aa6 | |||
| 30b3e24a32 | |||
| 0a31892475 | |||
| 6fb2c72a55 | |||
| c82d701a4e | |||
| d66cf0c32f | |||
| 562c323989 | |||
| 13a68c6060 | |||
| 6110919842 | |||
| c5aa0d12b0 | |||
| 6de67cc2df | |||
| b9d726fb84 | |||
| 2b57020c18 | |||
| 77298a19c9 | |||
| 55961544a7 | |||
| 5639aa7064 | |||
| 0c30618ae8 | |||
| 9317d8f43e | |||
| 692908b722 | |||
| c890d1e69d | |||
| 4c7cb858d2 | |||
| 5a49d657d8 | |||
| 8a1ae53166 | |||
| 0765a05434 | |||
| 072e5e8471 | |||
| a17912d19e | |||
| 610e7796d9 | |||
| 8efac21c2b | |||
| 40c7303702 | |||
| c00782a3e8 | |||
| 96f5314df6 | |||
| 2b628a1a0d | |||
| 349143864c | |||
| fc73f6bb2c | |||
| 119364f326 | |||
| 434735fbf6 | |||
| 8f4221deb3 | |||
| 2d646ca79e | |||
| 1245919331 | |||
| bcbd338fe2 | |||
| 945463b826 | |||
| 3ba3dd61d1 | |||
| cd523c7051 | |||
| 20ddd3254b | |||
| e30b842316 | |||
| b0675c031e | |||
| 0f71da5be6 | |||
| 9035a97e18 | |||
| d32a77a5f0 | |||
| d8e3ef7640 | |||
| ccb02a2355 | |||
| d0948f1f03 | |||
| ae0f23e942 | |||
| b40263e06b | |||
| 2f8dfb3e52 | |||
| d5c78c953d | |||
| dfac1d0510 | |||
| 14b83c3fcc | |||
| ae6e84bc7d | |||
| 4213a31a7d | |||
| 22454c8edf | |||
| 98da5a7b2b | |||
| 0a37552beb | |||
| 1b702fa6a2 | |||
| a2e438b2be | |||
| 9ff9d45283 | |||
| 1fee4c0c0b | |||
| dc87a2211c | |||
| 77b7344530 | |||
| 7cde4f1503 | |||
| 6c11fd3b5e | |||
| eec4a37d1c | |||
| 1e3dc4aeae | |||
| d4b54d834e | |||
| 3562cd759b | |||
| c1dc4e2c75 | |||
| 8feeec4a60 | |||
| 440a63a3d0 | |||
| 274ed1fe67 | |||
| 1b47f6c0b0 | |||
| 66e4c9b2bb | |||
| e608055021 | |||
| 199be0ad3c | |||
| af7753eac6 | |||
| cce74b8ba2 | |||
| dd7508d606 | |||
| 3bf56dda56 | |||
| a72209aad3 | |||
| 67f41b15eb | |||
| 3515acfa3d | |||
| 7fdd0c22b2 | |||
| a0f8a894f2 | |||
| 55f02db18e | |||
| 71e88cbf30 | |||
| 514a2e9568 | |||
| abfb439bfe | |||
| 4ba43b4737 | |||
| 2655657a51 | |||
| 404671416a | |||
| 260eafc819 | |||
| ef8b5763e6 | |||
| 6b89af824d | |||
| 86b4b2ef23 | |||
| faa8430fd7 | |||
| 76f870caca | |||
| 615315728b | |||
| 115442242f | |||
| 10c0e8af01 | |||
| b6e20a4cc9 | |||
| a8adec7673 | |||
| 2ae61c503e | |||
| c2b2f30669 | |||
| 239a7cd85f | |||
| 6e4317ebfb | |||
| 325d8834e3 | |||
| 0c76cb7e80 | |||
| 940011e233 | |||
| 92bbd8103b | |||
| 9c194699c7 | |||
| 25701ef984 | |||
| 87ef99df5e | |||
| 13ca2752ae | |||
| ef363b0f7a | |||
| f9db59e730 | |||
| 0dcca2304f | |||
| ad272a0c87 | |||
| be224e1f30 | |||
| 4bb0916202 | |||
| d3eda09c01 | |||
| 399f887128 | |||
| 4d005b6987 | |||
| 532a7a3a02 | |||
| b2d416fd5f | |||
| 7298c3d669 | |||
| 7bbd38b9e0 | |||
| 64d83a550e | |||
| 0df1630ab9 | |||
| 7cbc115da6 | |||
| b962239e11 | |||
| 872cf6b076 | |||
| b2bd319d47 | |||
| e3fa49063e | |||
| c302efdbbf | |||
| 12699696f4 | |||
| c4f2566070 | |||
| 6458643f15 | |||
| 2145545e69 | |||
| f6545cde38 | |||
| 601c64a65c | |||
| 964f1a6213 | |||
| 886cc2cce8 | |||
| 5bdd2d245c | |||
| d0513f7521 | |||
| 265c0c1505 | |||
| 886cf825cb | |||
| 03033f6c06 | |||
| 5ff2dfbe13 | |||
| fa44ab6336 | |||
| eed1a58b81 |
+258
-181
@@ -3,8 +3,8 @@ buildscript {
|
||||
maven { url "http://repo.springsource.org/plugins-release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.3")
|
||||
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.6")
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.5")
|
||||
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.8")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,15 @@ configure(allprojects) { project ->
|
||||
group = "org.springframework"
|
||||
version = qualifyVersionIfNecessary(version)
|
||||
|
||||
ext.aspectjVersion = "1.7.2"
|
||||
// The following is a work-around for allowing to build on JDK 8 until the
|
||||
// Gradle build uses Ant 1.9.x by default. This is necessary to avoid the
|
||||
// "Class not found: javac1.8" issue with Ant versions prior to 1.9.x
|
||||
ant.properties["build.compiler"] = "javac1.7"
|
||||
|
||||
ext.aspectjVersion = "1.7.4"
|
||||
ext.hsqldbVersion = "1.8.0.10"
|
||||
ext.junitVersion = "4.11"
|
||||
ext.slf4jVersion = "1.6.1"
|
||||
ext.slf4jVersion = "1.6.6"
|
||||
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"
|
||||
|
||||
apply plugin: "propdeps"
|
||||
@@ -58,10 +63,13 @@ configure(allprojects) { project ->
|
||||
test {
|
||||
systemProperty("java.awt.headless", "true")
|
||||
systemProperty("testGroups", project.properties.get("testGroups"))
|
||||
scanForTestClasses = false
|
||||
include '**/*Tests.*'
|
||||
exclude '**/*Abstract*.*'
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url "http://repo.springsource.org/libs-release" }
|
||||
maven { url "http://repo.spring.io/libs-release" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -71,25 +79,27 @@ configure(allprojects) { project ->
|
||||
}
|
||||
|
||||
ext.javadocLinks = [
|
||||
"http://docs.oracle.com/javase/6/docs/api",
|
||||
"http://docs.oracle.com/javaee/6/api",
|
||||
"http://portals.apache.org/pluto/portlet-2.0-apidocs/",
|
||||
"http://commons.apache.org/proper/commons-lang/javadocs/api-release/",
|
||||
"http://commons.apache.org/proper/commons-codec/apidocs/",
|
||||
"http://docs.oracle.com/javase/7/docs/api/",
|
||||
"http://docs.oracle.com/javaee/6/api/",
|
||||
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
|
||||
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
|
||||
"http://glassfish.java.net/nonav/docs/v3/api/",
|
||||
"http://docs.jboss.org/jbossas/javadoc/4.0.5/connector/",
|
||||
"http://docs.jboss.org/jbossas/javadoc/7.1.2.Final/",
|
||||
"http://aopalliance.sourceforge.net/doc/",
|
||||
"http://glassfish.java.net/nonav/docs/v3/api/",
|
||||
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // commonj
|
||||
"http://quartz-scheduler.org/api/2.1.5/",
|
||||
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
|
||||
"http://hc.apache.org/httpclient-3.x/apidocs/",
|
||||
"http://fasterxml.github.com/jackson-core/javadoc/2.0.0/",
|
||||
"http://jackson.codehaus.org/1.4.2/javadoc/",
|
||||
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
|
||||
"http://ibatis.apache.org/docs/java/dev/",
|
||||
"http://tiles.apache.org/framework/apidocs/",
|
||||
"http://commons.apache.org/proper/commons-lang/javadocs/api-2.5/",
|
||||
"http://commons.apache.org/proper/commons-codec/apidocs/",
|
||||
"http://commons.apache.org/proper/commons-dbcp/apidocs/",
|
||||
"http://portals.apache.org/pluto/portlet-2.0-apidocs/",
|
||||
"http://tiles.apache.org/framework/apidocs/",
|
||||
"http://aopalliance.sourceforge.net/doc/",
|
||||
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
|
||||
"http://ehcache.org/apidocs/",
|
||||
"http://quartz-scheduler.org/api/2.1.7/",
|
||||
"http://jackson.codehaus.org/1.9.4/javadoc/",
|
||||
"http://fasterxml.github.com/jackson-core/javadoc/2.3.0/",
|
||||
"http://fasterxml.github.com/jackson-databind/javadoc/2.3.0/",
|
||||
"http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs",
|
||||
"http://ibatis.apache.org/docs/java/dev/"
|
||||
] as String[]
|
||||
}
|
||||
|
||||
@@ -118,6 +128,9 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
|
||||
options.author = true
|
||||
options.header = project.name
|
||||
options.links(project.ext.javadocLinks)
|
||||
if (JavaVersion.current().isJava8Compatible()) {
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
}
|
||||
|
||||
// suppress warnings due to cross-module @see and @link references;
|
||||
// note that global 'api' task does display all warnings.
|
||||
@@ -148,7 +161,7 @@ project("spring-build-src") {
|
||||
|
||||
dependencies {
|
||||
compile gradleApi()
|
||||
groovy localGroovy()
|
||||
compile localGroovy()
|
||||
}
|
||||
|
||||
configurations.archives.artifacts.clear()
|
||||
@@ -219,10 +232,11 @@ project("spring-core") {
|
||||
cglib("cglib:cglib:${cglibVersion}@jar")
|
||||
jarjar("com.googlecode.jarjar:jarjar:1.3")
|
||||
|
||||
compile(files(cglibRepackJar))
|
||||
compile(files(asmRepackJar))
|
||||
compile("commons-logging:commons-logging:1.1.1")
|
||||
compile("commons-logging:commons-logging:1.1.3")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("net.sf.jopt-simple:jopt-simple:3.0")
|
||||
optional("net.sf.jopt-simple:jopt-simple:3.3")
|
||||
optional("log4j:log4j:1.2.17")
|
||||
testCompile("xmlunit:xmlunit:1.3")
|
||||
testCompile("org.codehaus.woodstox:wstx-asl:3.2.7") {
|
||||
@@ -245,30 +259,33 @@ project("spring-core") {
|
||||
|
||||
project("spring-beans") {
|
||||
description = "Spring Beans"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
provided("javax.el:el-api:1.0")
|
||||
provided("javax.inject:javax.inject:1")
|
||||
optional("javax.el:el-api:1.0")
|
||||
optional("javax.inject:javax.inject:1")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-aop") {
|
||||
description = "Spring AOP"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
compile(project(":spring-beans"))
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
optional("com.jamonapi:jamon:2.4")
|
||||
optional("commons-pool:commons-pool:1.5.3")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("commons-pool:commons-pool:1.5.7")
|
||||
optional("com.jamonapi:jamon:2.4")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-expression") {
|
||||
description = "Spring Expression Language (SpEL)"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
}
|
||||
@@ -276,17 +293,19 @@ project("spring-expression") {
|
||||
|
||||
project("spring-instrument") {
|
||||
description = "Spring Instrument"
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest.attributes["Premain-Class"] =
|
||||
"org.springframework.instrument.InstrumentationSavingAgent"
|
||||
manifest.attributes["Can-Redefine-Classes"] = "true"
|
||||
manifest.attributes["Can-Retransform-Classes"] = "true"
|
||||
manifest.attributes["Can-Set-Native-Method-Prefix"] = "false"
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-instrument-tomcat") {
|
||||
description = "Spring Instrument Tomcat"
|
||||
|
||||
dependencies {
|
||||
provided("org.apache.tomcat:catalina:6.0.16")
|
||||
}
|
||||
@@ -294,31 +313,34 @@ project("spring-instrument-tomcat") {
|
||||
|
||||
project("spring-context") {
|
||||
description = "Spring Context"
|
||||
|
||||
dependencies {
|
||||
optional(project(":spring-instrument"))
|
||||
compile(project(":spring-aop"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-expression"))
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
optional("backport-util-concurrent:backport-util-concurrent:3.0")
|
||||
optional("javax.ejb:ejb-api:3.0")
|
||||
optional(project(":spring-instrument"))
|
||||
optional("javax.inject:javax.inject:1")
|
||||
optional("javax.ejb:ejb-api:3.0")
|
||||
optional("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
|
||||
optional("backport-util-concurrent:backport-util-concurrent:3.0")
|
||||
optional("javax.persistence:persistence-api:1.0")
|
||||
optional("javax.validation:validation-api:1.0.0.GA")
|
||||
optional("org.beanshell:bsh:2.0b4")
|
||||
optional("org.codehaus.groovy:groovy-all:1.8.8")
|
||||
optional("org.jruby:jruby:1.6.5.1")
|
||||
optional("joda-time:joda-time:2.1")
|
||||
optional("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
optional("org.hibernate:hibernate-validator:4.3.0.Final")
|
||||
optional("org.hibernate:hibernate-validator:4.3.1.Final")
|
||||
optional("joda-time:joda-time:2.2")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.2.2")
|
||||
optional("org.codehaus.groovy:groovy-all:1.8.9")
|
||||
optional("org.beanshell:bsh:2.0b4")
|
||||
optional("org.jruby:jruby:1.7.10")
|
||||
testCompile("javax.inject:javax.inject-tck:1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.3")
|
||||
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
}
|
||||
|
||||
// pick up RmiInvocationWrapperRTD.xml in src/main
|
||||
sourceSets.main.resources.srcDirs += "src/main/java"
|
||||
|
||||
test {
|
||||
jvmArgs = ["-disableassertions:org.aspectj.weaver.UnresolvedType"] // SPR-7989
|
||||
}
|
||||
@@ -326,18 +348,19 @@ project("spring-context") {
|
||||
|
||||
project("spring-tx") {
|
||||
description = "Spring Transaction"
|
||||
|
||||
dependencies {
|
||||
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
|
||||
optional(project(":spring-aop"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
provided("com.ibm.websphere:uow:6.0.2.17")
|
||||
optional("javax.resource:connector-api:1.5")
|
||||
optional(project(":spring-aop"))
|
||||
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
optional("javax.resource:connector-api:1.5")
|
||||
optional("javax.ejb:ejb-api:3.0")
|
||||
testCompile("javax.persistence:persistence-api:1.0")
|
||||
optional("com.ibm.websphere:uow:6.0.2.17")
|
||||
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile("javax.persistence:persistence-api:1.0")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,13 +378,11 @@ project("spring-oxm") {
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
optional(project(":spring-context")) // for Jaxb2Marshaller
|
||||
compile("commons-lang:commons-lang:2.5")
|
||||
optional("com.thoughtworks.xstream:xstream:1.3.1")
|
||||
optional("com.sun.xml.bind:jaxb-impl:2.1.7")
|
||||
optional("org.jibx:jibx-run:1.2.3")
|
||||
optional("org.apache.xmlbeans:xmlbeans:2.4.0")
|
||||
optional("com.thoughtworks.xstream:xstream:1.4.4")
|
||||
optional("org.jibx:jibx-run:1.2.5")
|
||||
optional("org.apache.xmlbeans:xmlbeans:2.6.0")
|
||||
optional("org.codehaus.castor:castor-xml:1.3.2")
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile("org.codehaus.jettison:jettison:1.0.1")
|
||||
testCompile("xmlunit:xmlunit:1.3")
|
||||
testCompile("xmlpull:xmlpull:1.1.3.4a")
|
||||
@@ -373,61 +394,64 @@ project("spring-oxm") {
|
||||
|
||||
project("spring-jms") {
|
||||
description = "Spring JMS"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-aop"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-oxm"))
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
provided("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
|
||||
optional(project(":spring-oxm"))
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
optional("javax.resource:connector-api:1.5")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.1")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.7.9")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.6")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-jdbc") {
|
||||
description = "Spring JDBC"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
optional(project(":spring-context")) // for JndiDataSourceLookup
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-context")) // for JndiDataSourceLookup
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
optional("c3p0:c3p0:0.9.1.2")
|
||||
optional("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
optional("com.h2database:h2:1.0.71")
|
||||
optional("org.apache.derby:derby:10.5.3.0_1")
|
||||
optional("org.apache.derby:derbyclient:10.5.3.0_1")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-context-support") {
|
||||
description = "Spring Context Support"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional(project(":spring-jdbc")) // for Quartz support
|
||||
optional(project(":spring-tx")) // for Quartz support
|
||||
optional("javax.mail:mail:1.4")
|
||||
optional("javax.mail:mail:1.4.7")
|
||||
optional("javax.cache:cache-api:0.5")
|
||||
optional("net.sf.ehcache:ehcache-core:2.0.0")
|
||||
optional("opensymphony:quartz:1.6.2")
|
||||
optional("net.sf.ehcache:ehcache-core:2.0.1")
|
||||
optional("org.quartz-scheduler:quartz:1.7.3")
|
||||
optional("org.codehaus.fabric3.api:commonj:1.1.0")
|
||||
optional("velocity:velocity:1.5")
|
||||
optional("org.freemarker:freemarker:2.3.15")
|
||||
optional("org.freemarker:freemarker:2.3.20")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("jasperreports:jasperreports:2.0.5")
|
||||
optional("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
provided("javax.activation:activation:1.1")
|
||||
testCompile("org.apache.poi:poi:3.0.2-FINAL")
|
||||
testCompile("commons-beanutils:commons-beanutils:1.8.0") // for Velocity/JasperReports
|
||||
testCompile("commons-digester:commons-digester:1.8.1") // for Velocity/JasperReports
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
}
|
||||
|
||||
// pick up **/*.types files in src/main
|
||||
@@ -436,29 +460,30 @@ project("spring-context-support") {
|
||||
|
||||
project("spring-web") {
|
||||
description = "Spring Web"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans")) // for MultiPartFilter
|
||||
compile(project(":spring-aop")) // for JaxWsPortProxyFactoryBean
|
||||
compile(project(":spring-beans")) // for MultiPartFilter
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional(project(":spring-oxm")) // for MarshallingHttpMessageConverter
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
optional("com.caucho:hessian:3.2.1")
|
||||
optional("rome:rome:1.0")
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.portlet:portlet-api:2.0")
|
||||
optional("javax.el:el-api:1.0")
|
||||
optional("javax.faces:jsf-api:1.2_08")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.xml:jaxrpc-api:1.1")
|
||||
provided("javax.xml.soap:saaj-api:1.3")
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional("commons-fileupload:commons-fileupload:1.2")
|
||||
optional("javax.xml.soap:saaj-api:1.3")
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("com.caucho:hessian:3.2.1")
|
||||
optional("commons-fileupload:commons-fileupload:1.3.1")
|
||||
optional("commons-io:commons-io:1.3")
|
||||
optional("commons-httpclient:commons-httpclient:3.1")
|
||||
optional("org.apache.httpcomponents:httpclient:4.2")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.1")
|
||||
optional("org.apache.httpcomponents:httpclient:4.2.6")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.7.9")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.6")
|
||||
optional("rome:rome:1.0")
|
||||
optional("taglibs:standard:1.1.2")
|
||||
optional("org.eclipse.jetty:jetty-servlet:8.1.5.v20120716") {
|
||||
exclude group: "org.eclipse.jetty.orbit", module: "javax.servlet"
|
||||
@@ -486,78 +511,79 @@ project("spring-orm") {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-jdbc"))
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-aop"))
|
||||
optional(project(":spring-context"))
|
||||
optional(project(":spring-web"))
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("javax.persistence:persistence-api:1.0")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.core:1.0.1")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:1.0.1")
|
||||
optional("org.hibernate:hibernate-core:3.3.2.GA")
|
||||
optional("org.hibernate:hibernate-annotations:3.4.0.GA")
|
||||
optional("org.hibernate:hibernate-entitymanager:3.4.0.GA")
|
||||
optional("org.apache.openjpa:openjpa:1.1.0")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.core:1.0.1")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:1.0.1")
|
||||
optional("toplink.essentials:toplink-essentials:2.0-41b")
|
||||
optional("javax.jdo:jdo-api:3.0")
|
||||
optional("org.apache.ibatis:ibatis-sqlmap:2.3.4.726")
|
||||
optional("javax.persistence:persistence-api:1.0")
|
||||
provided("javax.servlet:servlet-api:2.5")
|
||||
optional("javax.servlet:servlet-api:2.5")
|
||||
testCompile("javax.servlet:javax.servlet-api:3.0.1")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.2.2")
|
||||
testCompile("org.eclipse.persistence:org.eclipse.persistence.asm:1.0.1")
|
||||
testCompile("org.eclipse.persistence:org.eclipse.persistence.antlr:1.0.1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.3")
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
optional(project(":spring-aop"))
|
||||
optional(project(":spring-context"))
|
||||
compile(project(":spring-tx"))
|
||||
compile(project(":spring-jdbc"))
|
||||
optional(project(":spring-web"))
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-orm-hibernate4") {
|
||||
description = "Spring Object/Relational Mapping - Hibernate 4 support"
|
||||
merge.into = project(":spring-orm")
|
||||
|
||||
dependencies {
|
||||
provided(project(":spring-tx"))
|
||||
provided(project(":spring-jdbc"))
|
||||
optional("org.hibernate:hibernate-core:4.1.0.Final")
|
||||
optional("org.hibernate:hibernate-entitymanager:4.1.0.Final")
|
||||
provided(project(":spring-tx"))
|
||||
optional(project(":spring-web"))
|
||||
optional("org.hibernate:hibernate-core:4.2.8.Final")
|
||||
optional("org.hibernate:hibernate-entitymanager:4.2.8.Final")
|
||||
optional("javax.servlet:servlet-api:2.5")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-webmvc") {
|
||||
description = "Spring Web MVC"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-expression"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-web"))
|
||||
compile(project(":spring-context"))
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional(project(":spring-context-support")) // for Velocity support
|
||||
optional(project(":spring-oxm")) // for MarshallingView
|
||||
optional("org.apache.tiles:tiles-api:2.1.2")
|
||||
optional("org.apache.tiles:tiles-core:2.1.2")
|
||||
optional("org.apache.tiles:tiles-jsp:2.1.2")
|
||||
optional("org.apache.tiles:tiles-servlet:2.1.2")
|
||||
optional("velocity-tools:velocity-tools-view:1.4")
|
||||
optional("net.sourceforge.jexcelapi:jxl:2.6.3")
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("net.sourceforge.jexcelapi:jxl:2.6.12")
|
||||
optional("org.apache.poi:poi:3.0.2-FINAL")
|
||||
optional("velocity:velocity:1.5")
|
||||
optional("velocity-tools:velocity-tools-view:1.4")
|
||||
optional("org.freemarker:freemarker:2.3.20")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("jasperreports:jasperreports:2.0.5") {
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
}
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.7.9")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.6")
|
||||
optional("rome:rome:1.0")
|
||||
optional("velocity:velocity:1.5")
|
||||
optional("org.freemarker:freemarker:2.3.15")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.1")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("org.apache.tiles:tiles-api:2.1.2")
|
||||
optional("org.apache.tiles:tiles-core:2.1.2")
|
||||
optional("org.apache.tiles:tiles-jsp:2.1.2")
|
||||
optional("org.apache.tiles:tiles-servlet:2.1.2")
|
||||
testCompile(project(":spring-aop"))
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("rhino:js:1.7R1")
|
||||
testCompile("xmlunit:xmlunit:1.3")
|
||||
testCompile("dom4j:dom4j:1.6.1") {
|
||||
@@ -575,10 +601,11 @@ project("spring-webmvc") {
|
||||
exclude group: "org.eclipse.jetty.orbit", module: "javax.servlet"
|
||||
}
|
||||
testCompile("javax.validation:validation-api:1.0.0.GA")
|
||||
testCompile("commons-fileupload:commons-fileupload:1.2")
|
||||
testCompile("org.hibernate:hibernate-validator:4.3.1.Final")
|
||||
testCompile("org.apache.httpcomponents:httpclient:4.2.6")
|
||||
testCompile("commons-fileupload:commons-fileupload:1.3.1")
|
||||
testCompile("commons-io:commons-io:1.3")
|
||||
testCompile("org.hibernate:hibernate-validator:4.3.0.Final")
|
||||
testCompile("org.apache.httpcomponents:httpclient:4.2")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
|
||||
// pick up DispatcherServlet.properties in src/main
|
||||
@@ -588,12 +615,14 @@ project("spring-webmvc") {
|
||||
project("spring-webmvc-tiles3") {
|
||||
description = "Spring Framework Tiles3 Integration"
|
||||
merge.into = project(":spring-webmvc")
|
||||
|
||||
dependencies {
|
||||
provided(project(":spring-context"))
|
||||
provided(project(":spring-web"))
|
||||
provided("javax.el:el-api:1.0")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
provided("javax.servlet.jsp:jsp-api:2.1")
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("javax.el:el-api:1.0")
|
||||
optional("org.apache.tiles:tiles-request-api:1.0.1")
|
||||
optional("org.apache.tiles:tiles-api:3.0.1")
|
||||
optional("org.apache.tiles:tiles-core:3.0.1") {
|
||||
@@ -605,28 +634,29 @@ project("spring-webmvc-tiles3") {
|
||||
optional("org.apache.tiles:tiles-jsp:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-extras:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-el:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional("org.apache.tiles:tiles-extras:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
exclude group: "org.springframework", module: "spring-web"
|
||||
}
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-webmvc-portlet") {
|
||||
description = "Spring Web Portlet"
|
||||
|
||||
dependencies {
|
||||
provided("javax.servlet:servlet-api:2.5")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-web"))
|
||||
compile(project(":spring-webmvc"))
|
||||
optional("commons-fileupload:commons-fileupload:1.2")
|
||||
provided("javax.servlet:servlet-api:2.5")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
optional("commons-fileupload:commons-fileupload:1.3.1")
|
||||
}
|
||||
|
||||
// pick up DispatcherPortlet.properties in src/main
|
||||
@@ -636,23 +666,9 @@ project("spring-webmvc-portlet") {
|
||||
project("spring-test") {
|
||||
description = "Spring TestContext Framework"
|
||||
|
||||
task testNG(type: Test) {
|
||||
useTestNG()
|
||||
// "TestCase" classes are run by other test classes, not the build.
|
||||
exclude "**/*TestCase.class"
|
||||
// Generate TestNG reports alongside JUnit reports.
|
||||
testReport true
|
||||
}
|
||||
|
||||
test {
|
||||
dependsOn testNG
|
||||
useJUnit()
|
||||
// "TestCase" classes are run by other test classes, not the build.
|
||||
exclude(["**/*TestCase.class", "**/*TestSuite.class"])
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional(project(":spring-beans"))
|
||||
optional(project(":spring-context"))
|
||||
optional(project(":spring-jdbc"))
|
||||
@@ -660,20 +676,42 @@ project("spring-test") {
|
||||
optional(project(":spring-orm"))
|
||||
optional(project(":spring-web"))
|
||||
optional(project(":spring-webmvc"))
|
||||
optional(project(":spring-webmvc-portlet"), )
|
||||
optional(project(":spring-webmvc-portlet"))
|
||||
optional("junit:junit:${junitVersion}")
|
||||
optional("org.testng:testng:6.5.2")
|
||||
optional("org.testng:testng:6.8.7")
|
||||
optional("javax.inject:javax.inject:1")
|
||||
optional("javax.servlet:servlet-api:2.5")
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("javax.portlet:portlet-api:2.0")
|
||||
optional("javax.persistence:persistence-api:1.0")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile("org.hibernate:hibernate-core:3.3.2.GA")
|
||||
provided("javax.inject:javax.inject:1")
|
||||
provided("javax.activation:activation:1.1")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
testCompile "org.slf4j:slf4j-jcl:${slf4jVersion}"
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
testCompile "org.slf4j:slf4j-jcl:${slf4jVersion}"
|
||||
}
|
||||
|
||||
task testNG(type: Test) {
|
||||
useTestNG()
|
||||
// forkEvery 1
|
||||
scanForTestClasses = false
|
||||
include "**/testng/**/*.*"
|
||||
exclude "**/FailingBeforeAndAfterMethodsTests.class"
|
||||
// "TestCase" classes are run by other test classes, not the build.
|
||||
exclude "**/*TestCase.class"
|
||||
// Generate TestNG reports alongside JUnit reports.
|
||||
getReports().getHtml().setEnabled(true)
|
||||
// show standard out and standard error of the test JVM(s) on the console
|
||||
// testLogging.showStandardStreams = true
|
||||
}
|
||||
|
||||
test {
|
||||
dependsOn testNG
|
||||
useJUnit()
|
||||
exclude "**/testng/**/*.*"
|
||||
include "**/testng/FailingBeforeAndAfterMethodsTests"
|
||||
// "TestCase" classes are run by other test classes, not the build.
|
||||
exclude(["**/*TestCase.class", "**/*TestSuite.class"])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,25 +719,22 @@ project("spring-test-mvc") {
|
||||
description = "Spring Test MVC Framework"
|
||||
merge.into = project(":spring-test")
|
||||
dependencies {
|
||||
optional(project(":spring-context"))
|
||||
provided(project(":spring-webmvc"))
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional(project(":spring-context"))
|
||||
optional("org.hamcrest:hamcrest-core:1.3")
|
||||
optional("com.jayway.jsonpath:json-path:0.8.1")
|
||||
optional("xmlunit:xmlunit:1.3")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("javax.servlet:jstl:1.2")
|
||||
testCompile("org.hibernate:hibernate-validator:4.3.0.Final")
|
||||
testCompile("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
|
||||
testCompile("com.fasterxml.jackson.core:jackson-databind:2.0.1")
|
||||
testCompile(project(":spring-context-support"))
|
||||
testCompile(project(":spring-oxm"))
|
||||
testCompile("javax.servlet:jstl:1.2")
|
||||
testCompile("javax.mail:mail:1.4.7")
|
||||
testCompile("org.hibernate:hibernate-validator:4.3.1.Final")
|
||||
testCompile("com.thoughtworks.xstream:xstream:1.3.1")
|
||||
testCompile("cglib:cglib-nodep:2.2")
|
||||
testCompile("org.codehaus.jackson:jackson-mapper-asl:1.7.9")
|
||||
testCompile("com.fasterxml.jackson.core:jackson-databind:2.0.6")
|
||||
testCompile("rome:rome:1.0")
|
||||
testCompile("javax.activation:activation:1.1")
|
||||
testCompile("javax.mail:mail:1.4")
|
||||
testCompile("javax.xml.bind:jaxb-api:2.2.6")
|
||||
testCompile("org.apache.tiles:tiles-request-api:1.0.1")
|
||||
testCompile("org.apache.tiles:tiles-api:3.0.1")
|
||||
testCompile("org.apache.tiles:tiles-core:3.0.1") {
|
||||
@@ -708,6 +743,7 @@ project("spring-test-mvc") {
|
||||
testCompile("org.apache.tiles:tiles-servlet:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,23 +766,24 @@ project("spring-struts") {
|
||||
project("spring-aspects") {
|
||||
description = "Spring Aspects"
|
||||
apply from: "aspects.gradle"
|
||||
|
||||
dependencies {
|
||||
optional(project(":spring-beans")) // for @Configurable support
|
||||
optional(project(":spring-aop")) // for @Async support
|
||||
optional(project(":spring-context")) // for @Enable* support
|
||||
compile(project(":spring-context-support")) // for JavaMail support
|
||||
optional(project(":spring-tx")) // for JPA, @Transactional support
|
||||
optional(project(":spring-orm")) // for JPA exception translation support
|
||||
aspects(project(":spring-orm"))
|
||||
provided("javax.persistence:persistence-api:1.0")
|
||||
testCompile("javax.mail:mail:1.4")
|
||||
ajc("org.aspectj:aspectjtools:${aspectjVersion}")
|
||||
rt("org.aspectj:aspectjrt:${aspectjVersion}")
|
||||
compile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
provided("javax.persistence:persistence-api:1.0")
|
||||
optional(project(":spring-aop")) // for @Async support
|
||||
optional(project(":spring-beans")) // for @Configurable support
|
||||
optional(project(":spring-context")) // for @Enable* support
|
||||
optional(project(":spring-context-support")) // for JavaMail support
|
||||
optional(project(":spring-orm")) // for JPA exception translation support
|
||||
optional(project(":spring-tx")) // for JPA, @Transactional support
|
||||
testCompile(project(":spring-core")) // for CodeStyleAspect
|
||||
compile(project(":spring-beans")) // for "p" namespace visibility
|
||||
testCompile(project(":spring-test"))
|
||||
testCompile("javax.mail:mail:1.4.7")
|
||||
}
|
||||
|
||||
eclipse.project {
|
||||
natures += "org.eclipse.ajdt.ui.ajnature"
|
||||
buildCommands = [new org.gradle.plugins.ide.eclipse.model.
|
||||
@@ -754,12 +791,47 @@ project("spring-aspects") {
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-framework-bom") {
|
||||
description = "Spring Framework (Bill of Materials)"
|
||||
|
||||
configurations.archives.artifacts.clear()
|
||||
artifacts {
|
||||
// work around GRADLE-2406 by attaching text artifact
|
||||
archives(file("spring-framework-bom.txt"))
|
||||
}
|
||||
|
||||
install {
|
||||
repositories.mavenInstaller {
|
||||
pom.whenConfigured {
|
||||
packaging = "pom"
|
||||
withXml {
|
||||
asNode().children().last() + {
|
||||
delegate.dependencyManagement {
|
||||
delegate.dependencies {
|
||||
parent.subprojects.sort { "$it.name" }.each { p ->
|
||||
if (p.hasProperty("merge") && p.merge.into == null && p != project) {
|
||||
delegate.dependency {
|
||||
delegate.groupId(p.group)
|
||||
delegate.artifactId(p.name)
|
||||
delegate.version(p.version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configure(rootProject) {
|
||||
description = "Spring Framework"
|
||||
|
||||
apply plugin: "docbook-reference"
|
||||
apply plugin: "groovy"
|
||||
apply plugin: "detect-split-packages"
|
||||
// apply plugin: "detect-split-packages"
|
||||
apply from: "${gradleScriptDir}/jdiff.gradle"
|
||||
|
||||
reference {
|
||||
@@ -767,31 +839,33 @@ configure(rootProject) {
|
||||
pdfFilename = "spring-framework-reference.pdf"
|
||||
}
|
||||
|
||||
detectSplitPackages {
|
||||
projectsToScan -= project(":spring-instrument-tomcat")
|
||||
}
|
||||
// TODO: DetectSplitPackagesPlugin fails in line 154 due to method not found on java.io.File.
|
||||
// TODO: Possibly related to user rights or OS differences on OpenJDK 8; works fine on JDK 7.
|
||||
// detectSplitPackages {
|
||||
// projectsToScan -= project(":spring-instrument-tomcat")
|
||||
// }
|
||||
|
||||
// don't publish the default jar for the root project
|
||||
configurations.archives.artifacts.clear()
|
||||
|
||||
dependencies { // for integration tests
|
||||
testCompile(project(":spring-core"))
|
||||
testCompile(project(":spring-beans"))
|
||||
testCompile(project(":spring-aop"))
|
||||
testCompile(project(":spring-expression"))
|
||||
testCompile(project(":spring-beans"))
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile(project(":spring-tx"))
|
||||
testCompile(project(":spring-core"))
|
||||
testCompile(project(":spring-expression"))
|
||||
testCompile(project(":spring-jdbc"))
|
||||
testCompile(project(":spring-orm"))
|
||||
testCompile(project(":spring-test"))
|
||||
testCompile(project(":spring-tx"))
|
||||
testCompile(project(":spring-web"))
|
||||
testCompile(project(":spring-webmvc-portlet"))
|
||||
testCompile(project(":spring-orm"))
|
||||
testCompile("org.hibernate:hibernate-core:4.1.0.Final")
|
||||
testCompile("javax.servlet:servlet-api:2.5")
|
||||
testCompile("javax.portlet:portlet-api:2.0")
|
||||
testCompile("javax.inject:javax.inject:1")
|
||||
testCompile("javax.resource:connector-api:1.5")
|
||||
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile("org.hibernate:hibernate-core:4.2.8.Final")
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
}
|
||||
|
||||
@@ -812,6 +886,9 @@ configure(rootProject) {
|
||||
options.stylesheetFile = file("src/api/stylesheet.css")
|
||||
options.splitIndex = true
|
||||
options.links(project.ext.javadocLinks)
|
||||
if (JavaVersion.current().isJava8Compatible()) {
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
}
|
||||
|
||||
source subprojects.collect { project ->
|
||||
project.sourceSets.main.allJava
|
||||
@@ -822,7 +899,7 @@ 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" },
|
||||
@@ -959,7 +1036,7 @@ configure(rootProject) {
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
description = "Generates gradlew[.bat] scripts"
|
||||
gradleVersion = "1.3"
|
||||
gradleVersion = "1.11"
|
||||
|
||||
doLast() {
|
||||
def gradleOpts = "-XX:MaxPermSize=1024m -Xmx1024m"
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ import org.gradle.api.tasks.TaskAction
|
||||
public class DetectSplitPackagesPlugin implements Plugin<Project> {
|
||||
public void apply(Project project) {
|
||||
def tasks = project.tasks
|
||||
Task detectSplitPackages = tasks.add("detectSplitPackages", DetectSplitPackagesTask.class)
|
||||
Task detectSplitPackages = tasks.create("detectSplitPackages", DetectSplitPackagesTask.class)
|
||||
if (tasks.asMap.containsKey("check")) {
|
||||
tasks.getByName("check").dependsOn detectSplitPackages
|
||||
}
|
||||
|
||||
@@ -67,8 +67,8 @@ class MergePlugin implements Plugin<Project> {
|
||||
project.plugins.apply(IdeaPlugin)
|
||||
|
||||
MergeModel model = project.extensions.create("merge", MergeModel)
|
||||
project.configurations.add("merging")
|
||||
Configuration runtimeMerge = project.configurations.add("runtimeMerge")
|
||||
project.configurations.create("merging")
|
||||
Configuration runtimeMerge = project.configurations.create("runtimeMerge")
|
||||
|
||||
// Ensure the IDE can reference merged projects
|
||||
project.eclipse.classpath.plusConfigurations += [runtimeMerge]
|
||||
@@ -121,7 +121,7 @@ class MergePlugin implements Plugin<Project> {
|
||||
project.configurations.each { configuration ->
|
||||
Conf2ScopeMapping mapping = project.conf2ScopeMappings.getMapping([configuration])
|
||||
if(mapping.scope) {
|
||||
Configuration intoConfiguration = project.merge.into.configurations.add(
|
||||
Configuration intoConfiguration = project.merge.into.configurations.create(
|
||||
project.name + "-" + configuration.name)
|
||||
configuration.excludeRules.each {
|
||||
configuration.exclude([
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
version=3.2.3.BUILD-SNAPSHOT
|
||||
version=3.2.8.RELEASE
|
||||
|
||||
@@ -43,7 +43,7 @@ def customizePom(pom, gradleProject) {
|
||||
developer {
|
||||
id = "jhoeller"
|
||||
name = "Juergen Hoeller"
|
||||
email = "jhoeller@vmware.com"
|
||||
email = "jhoeller@gopivotal.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-2
@@ -1,6 +1,6 @@
|
||||
#Wed Nov 28 09:14:59 PST 2012
|
||||
#Thu Feb 13 00:23:41 CET 2014
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.3-bin.zip
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-bin.zip
|
||||
|
||||
@@ -22,6 +22,7 @@ include "spring-web"
|
||||
include "spring-webmvc"
|
||||
include "spring-webmvc-portlet"
|
||||
include "spring-webmvc-tiles3"
|
||||
include "spring-framework-bom"
|
||||
|
||||
// Exposes gradle buildSrc for IDE support
|
||||
include "buildSrc"
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,9 +19,9 @@ package org.springframework.aop;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* A specialized type of MethodMatcher that takes into account introductions when
|
||||
* matching methods. If there are no introductions on the target class, a method
|
||||
* matcher may be able to optimize matching more effectively for example.
|
||||
* A specialized type of {@link MethodMatcher} that takes into account introductions
|
||||
* when matching methods. If there are no introductions on the target class,
|
||||
* a method matcher may be able to optimize matching more effectively for example.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
@@ -39,6 +39,6 @@ public interface IntroductionAwareMethodMatcher extends MethodMatcher {
|
||||
* asking is the subject on one or more introductions; {@code false} otherwise
|
||||
* @return whether or not this method matches statically
|
||||
*/
|
||||
boolean matches(Method method, Class targetClass, boolean hasIntroductions);
|
||||
boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions);
|
||||
|
||||
}
|
||||
|
||||
+57
-62
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,6 +42,7 @@ import org.aspectj.weaver.tools.PointcutParameter;
|
||||
import org.aspectj.weaver.tools.PointcutParser;
|
||||
import org.aspectj.weaver.tools.PointcutPrimitive;
|
||||
import org.aspectj.weaver.tools.ShadowMatch;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.IntroductionAwareMethodMatcher;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
@@ -55,6 +56,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -98,11 +100,11 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class);
|
||||
|
||||
private Class pointcutDeclarationScope;
|
||||
private Class<?> pointcutDeclarationScope;
|
||||
|
||||
private String[] pointcutParameterNames = new String[0];
|
||||
|
||||
private Class[] pointcutParameterTypes = new Class[0];
|
||||
private Class<?>[] pointcutParameterTypes = new Class<?>[0];
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
@@ -123,7 +125,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
* @param paramNames the parameter names for the pointcut
|
||||
* @param paramTypes the parameter types for the pointcut
|
||||
*/
|
||||
public AspectJExpressionPointcut(Class declarationScope, String[] paramNames, Class[] paramTypes) {
|
||||
public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
|
||||
this.pointcutDeclarationScope = declarationScope;
|
||||
if (paramNames.length != paramTypes.length) {
|
||||
throw new IllegalStateException(
|
||||
@@ -137,21 +139,21 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
/**
|
||||
* Set the declaration scope for the pointcut.
|
||||
*/
|
||||
public void setPointcutDeclarationScope(Class pointcutDeclarationScope) {
|
||||
public void setPointcutDeclarationScope(Class<?> pointcutDeclarationScope) {
|
||||
this.pointcutDeclarationScope = pointcutDeclarationScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameter names for the pointcut.
|
||||
*/
|
||||
public void setParameterNames(String[] names) {
|
||||
public void setParameterNames(String... names) {
|
||||
this.pointcutParameterNames = names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameter types for the pointcut.
|
||||
*/
|
||||
public void setParameterTypes(Class[] types) {
|
||||
public void setParameterTypes(Class<?>... types) {
|
||||
this.pointcutParameterTypes = types;
|
||||
}
|
||||
|
||||
@@ -188,9 +190,9 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
private PointcutExpression buildPointcutExpression() {
|
||||
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ? ((ConfigurableBeanFactory) this.beanFactory)
|
||||
.getBeanClassLoader() : Thread.currentThread()
|
||||
.getContextClassLoader());
|
||||
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
return buildPointcutExpression(cl);
|
||||
}
|
||||
|
||||
@@ -202,8 +204,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
|
||||
for (int i = 0; i < pointcutParameters.length; i++) {
|
||||
pointcutParameters[i] = parser.createPointcutParameter(
|
||||
this.pointcutParameterNames[i],
|
||||
this.pointcutParameterTypes[i]);
|
||||
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
|
||||
}
|
||||
return parser.parsePointcutExpression(
|
||||
replaceBooleanOperators(getExpression()),
|
||||
@@ -244,20 +245,19 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
return this.pointcutExpression;
|
||||
}
|
||||
|
||||
public boolean matches(Class targetClass) {
|
||||
public boolean matches(Class<?> targetClass) {
|
||||
checkReadyToMatch();
|
||||
try {
|
||||
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
|
||||
} catch (ReflectionWorldException e) {
|
||||
logger.debug("PointcutExpression matching rejected target class", e);
|
||||
}
|
||||
catch (ReflectionWorldException rwe) {
|
||||
logger.debug("PointcutExpression matching rejected target class", rwe);
|
||||
try {
|
||||
// Actually this is still a "maybe" - treat the pointcut as dynamic if we
|
||||
// don't know enough yet
|
||||
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
|
||||
return getFallbackPointcutExpression(targetClass).couldMatchJoinPointsInType(targetClass);
|
||||
} catch (BCException ex) {
|
||||
logger.debug(
|
||||
"Fallback PointcutExpression matching rejected target class",
|
||||
ex);
|
||||
}
|
||||
catch (BCException bce) {
|
||||
logger.debug("Fallback PointcutExpression matching rejected target class", bce);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -267,7 +267,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, boolean beanHasIntroductions) {
|
||||
public boolean matches(Method method, Class<?> targetClass, boolean beanHasIntroductions) {
|
||||
checkReadyToMatch();
|
||||
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);
|
||||
@@ -283,11 +283,19 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
else {
|
||||
// the maybe case
|
||||
return (beanHasIntroductions || matchesIgnoringSubtypes(shadowMatch) || matchesTarget(shadowMatch, targetClass));
|
||||
if (beanHasIntroductions) {
|
||||
return true;
|
||||
}
|
||||
// A match test returned maybe - if there are any subtype sensitive variables
|
||||
// involved in the test (this, target, at_this, at_target, at_annotation) then
|
||||
// we say this is not a match as in Spring there will never be a different
|
||||
// runtime subtype.
|
||||
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
|
||||
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return matches(method, targetClass, false);
|
||||
}
|
||||
|
||||
@@ -296,7 +304,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
return this.pointcutExpression.mayNeedDynamicTest();
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, Object[] args) {
|
||||
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
|
||||
checkReadyToMatch();
|
||||
ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
|
||||
ShadowMatch originalShadowMatch = getShadowMatch(method, method);
|
||||
@@ -336,14 +344,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (joinPointMatch.matches() && pmi != null) {
|
||||
bindParameters(pmi, joinPointMatch);
|
||||
if (joinPointMatch.matches()) {
|
||||
bindParameters(pmi, joinPointMatch);
|
||||
}
|
||||
}
|
||||
return joinPointMatch.matches();
|
||||
}
|
||||
|
||||
|
||||
protected String getCurrentProxiedBeanName() {
|
||||
return ProxyCreationContext.getCurrentProxiedBeanName();
|
||||
}
|
||||
@@ -353,29 +360,14 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
* Get a new pointcut expression based on a target class's loader, rather
|
||||
* than the default.
|
||||
*/
|
||||
private PointcutExpression getFallbackPointcutExpression(
|
||||
Class<?> targetClass) {
|
||||
private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
|
||||
ClassLoader classLoader = targetClass.getClassLoader();
|
||||
return classLoader == null ? this.pointcutExpression : buildPointcutExpression(classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* A match test returned maybe - if there are any subtype sensitive variables
|
||||
* involved in the test (this, target, at_this, at_target, at_annotation) then
|
||||
* we say this is not a match as in Spring there will never be a different
|
||||
* runtime subtype.
|
||||
*/
|
||||
private boolean matchesIgnoringSubtypes(ShadowMatch shadowMatch) {
|
||||
return !(getRuntimeTestWalker(shadowMatch).testsSubtypeSensitiveVars());
|
||||
}
|
||||
|
||||
private boolean matchesTarget(ShadowMatch shadowMatch, Class targetClass) {
|
||||
return getRuntimeTestWalker(shadowMatch).testTargetInstanceOfResidue(targetClass);
|
||||
return (classLoader != null ? buildPointcutExpression(classLoader) : this.pointcutExpression);
|
||||
}
|
||||
|
||||
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
|
||||
if (shadowMatch instanceof DefensiveShadowMatch) {
|
||||
return new RuntimeTestWalker(((DefensiveShadowMatch)shadowMatch).primary);
|
||||
return new RuntimeTestWalker(((DefensiveShadowMatch) shadowMatch).primary);
|
||||
}
|
||||
return new RuntimeTestWalker(shadowMatch);
|
||||
}
|
||||
@@ -409,7 +401,8 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
try {
|
||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
} catch (ReflectionWorld.ReflectionWorldException e) {
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex2) {
|
||||
if (targetMethod == originalMethod) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
}
|
||||
@@ -417,21 +410,22 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(originalMethod);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex2) {
|
||||
catch (ReflectionWorld.ReflectionWorldException ex3) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's simply consider this method as non-matching.
|
||||
methodToMatch = originalMethod;
|
||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
try {
|
||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
} catch (ReflectionWorld.ReflectionWorldException e2) {
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex4) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shadowMatch.maybeMatches() && fallbackPointcutExpression!=null) {
|
||||
if (shadowMatch.maybeMatches() && fallbackPointcutExpression != null) {
|
||||
shadowMatch = new DefensiveShadowMatch(shadowMatch,
|
||||
fallbackPointcutExpression.matchesMethodExecution(methodToMatch));
|
||||
}
|
||||
@@ -601,9 +595,11 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
this.shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
}
|
||||
|
||||
|
||||
private static class DefensiveShadowMatch implements ShadowMatch {
|
||||
|
||||
private final ShadowMatch primary;
|
||||
|
||||
private final ShadowMatch other;
|
||||
|
||||
public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) {
|
||||
@@ -612,31 +608,30 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
|
||||
public boolean alwaysMatches() {
|
||||
return primary.alwaysMatches();
|
||||
return this.primary.alwaysMatches();
|
||||
}
|
||||
|
||||
public boolean maybeMatches() {
|
||||
return primary.maybeMatches();
|
||||
return this.primary.maybeMatches();
|
||||
}
|
||||
|
||||
public boolean neverMatches() {
|
||||
return primary.neverMatches();
|
||||
return this.primary.neverMatches();
|
||||
}
|
||||
|
||||
public JoinPointMatch matchesJoinPoint(Object thisObject,
|
||||
Object targetObject, Object[] args) {
|
||||
public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
|
||||
try {
|
||||
return primary.matchesJoinPoint(thisObject, targetObject, args);
|
||||
} catch (ReflectionWorldException e) {
|
||||
return other.matchesJoinPoint(thisObject, targetObject, args);
|
||||
return this.primary.matchesJoinPoint(thisObject, targetObject, args);
|
||||
}
|
||||
catch (ReflectionWorldException ex) {
|
||||
return this.other.matchesJoinPoint(thisObject, targetObject, args);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMatchingContext(MatchingContext aMatchContext) {
|
||||
primary.setMatchingContext(aMatchContext);
|
||||
other.setMatchingContext(aMatchContext);
|
||||
this.primary.setMatchingContext(aMatchContext);
|
||||
this.other.setMatchingContext(aMatchContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-14
@@ -45,43 +45,41 @@ public class AspectJWeaverMessageHandler implements IMessageHandler {
|
||||
|
||||
private static final String AJ_ID = "[AspectJ] ";
|
||||
|
||||
private static final Log LOGGER = LogFactory.getLog("AspectJ Weaver");
|
||||
private static final Log logger = LogFactory.getLog("AspectJ Weaver");
|
||||
|
||||
|
||||
public boolean handleMessage(IMessage message) throws AbortException {
|
||||
Kind messageKind = message.getKind();
|
||||
|
||||
if (messageKind == IMessage.DEBUG) {
|
||||
if (LOGGER.isDebugEnabled() || LOGGER.isTraceEnabled()) {
|
||||
LOGGER.debug(makeMessageFor(message));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(makeMessageFor(message));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if ((messageKind == IMessage.INFO) || (messageKind == IMessage.WEAVEINFO)) {
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info(makeMessageFor(message));
|
||||
else if (messageKind == IMessage.INFO || messageKind == IMessage.WEAVEINFO) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(makeMessageFor(message));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (messageKind == IMessage.WARNING) {
|
||||
if (LOGGER.isWarnEnabled()) {
|
||||
LOGGER.warn(makeMessageFor(message));
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(makeMessageFor(message));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (messageKind == IMessage.ERROR) {
|
||||
if (LOGGER.isErrorEnabled()) {
|
||||
LOGGER.error(makeMessageFor(message));
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error(makeMessageFor(message));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (messageKind == IMessage.ABORT) {
|
||||
if (LOGGER.isFatalEnabled()) {
|
||||
LOGGER.fatal(makeMessageFor(message));
|
||||
if (logger.isFatalEnabled()) {
|
||||
logger.fatal(makeMessageFor(message));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,8 @@ package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.aspectj.weaver.ReferenceType;
|
||||
import org.aspectj.weaver.ReferenceTypeDelegate;
|
||||
import org.aspectj.weaver.ResolvedType;
|
||||
import org.aspectj.weaver.ast.And;
|
||||
import org.aspectj.weaver.ast.Call;
|
||||
@@ -30,6 +32,7 @@ import org.aspectj.weaver.ast.Not;
|
||||
import org.aspectj.weaver.ast.Or;
|
||||
import org.aspectj.weaver.ast.Test;
|
||||
import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
|
||||
import org.aspectj.weaver.reflect.ReflectionBasedReferenceTypeDelegate;
|
||||
import org.aspectj.weaver.reflect.ReflectionVar;
|
||||
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
||||
import org.aspectj.weaver.tools.ShadowMatch;
|
||||
@@ -55,25 +58,36 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
class RuntimeTestWalker {
|
||||
|
||||
private static final Field residualTestField;
|
||||
|
||||
private static final Field varTypeField;
|
||||
|
||||
private static final Field myClassField;
|
||||
|
||||
|
||||
static {
|
||||
try {
|
||||
residualTestField = ShadowMatchImpl.class.getDeclaredField("residualTest");
|
||||
varTypeField = ReflectionVar.class.getDeclaredField("varType");
|
||||
myClassField = ReflectionBasedReferenceTypeDelegate.class.getDeclaredField("myClass");
|
||||
}
|
||||
catch (NoSuchFieldException ex) {
|
||||
throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " +
|
||||
"on the classpath is incompatible with this version of Spring: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final Test runtimeTest;
|
||||
|
||||
|
||||
public RuntimeTestWalker(ShadowMatch shadowMatch) {
|
||||
ShadowMatchImpl shadowMatchImplementation = (ShadowMatchImpl) shadowMatch;
|
||||
try {
|
||||
Field testField = shadowMatchImplementation.getClass().getDeclaredField("residualTest");
|
||||
ReflectionUtils.makeAccessible(testField);
|
||||
this.runtimeTest = (Test) testField.get(shadowMatch);
|
||||
ReflectionUtils.makeAccessible(residualTestField);
|
||||
this.runtimeTest = (Test) residualTestField.get(shadowMatch);
|
||||
}
|
||||
catch (NoSuchFieldException noSuchFieldEx) {
|
||||
throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " +
|
||||
"on the classpath is incompatible with this version of Spring: Expected field " +
|
||||
"'runtimeTest' is not present on ShadowMatchImpl class.");
|
||||
}
|
||||
catch (IllegalAccessException illegalAccessEx) {
|
||||
// Famous last words... but I don't see how this can happen given the
|
||||
// makeAccessible call above
|
||||
throw new IllegalStateException("Unable to access ShadowMatchImpl.residualTest field");
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,12 +101,12 @@ class RuntimeTestWalker {
|
||||
new SubtypeSensitiveVarTypeTestVisitor().testsSubtypeSensitiveVars(this.runtimeTest));
|
||||
}
|
||||
|
||||
public boolean testThisInstanceOfResidue(Class thisClass) {
|
||||
public boolean testThisInstanceOfResidue(Class<?> thisClass) {
|
||||
return (this.runtimeTest != null &&
|
||||
new ThisInstanceOfResidueTestVisitor(thisClass).thisInstanceOfMatches(this.runtimeTest));
|
||||
}
|
||||
|
||||
public boolean testTargetInstanceOfResidue(Class targetClass) {
|
||||
public boolean testTargetInstanceOfResidue(Class<?> targetClass) {
|
||||
return (this.runtimeTest != null &&
|
||||
new TargetInstanceOfResidueTestVisitor(targetClass).targetInstanceOfMatches(this.runtimeTest));
|
||||
}
|
||||
@@ -140,19 +154,11 @@ class RuntimeTestWalker {
|
||||
|
||||
protected int getVarType(ReflectionVar v) {
|
||||
try {
|
||||
Field varTypeField = ReflectionVar.class.getDeclaredField("varType");
|
||||
ReflectionUtils.makeAccessible(varTypeField);
|
||||
return (Integer) varTypeField.get(v);
|
||||
}
|
||||
catch (NoSuchFieldException noSuchFieldEx) {
|
||||
throw new IllegalStateException("the version of aspectjtools.jar / aspectjweaver.jar " +
|
||||
"on the classpath is incompatible with this version of Spring:- expected field " +
|
||||
"'varType' is not present on ReflectionVar class");
|
||||
}
|
||||
catch (IllegalAccessException illegalAccessEx) {
|
||||
// Famous last words... but I don't see how this can happen given the
|
||||
// makeAccessible call above
|
||||
throw new IllegalStateException("Unable to access ReflectionVar.varType field");
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,11 +166,13 @@ class RuntimeTestWalker {
|
||||
|
||||
private static abstract class InstanceOfResidueTestVisitor extends TestVisitorAdapter {
|
||||
|
||||
private Class matchClass;
|
||||
private boolean matches;
|
||||
private int matchVarType;
|
||||
private final Class<?> matchClass;
|
||||
|
||||
public InstanceOfResidueTestVisitor(Class matchClass, boolean defaultMatches, int matchVarType) {
|
||||
private boolean matches;
|
||||
|
||||
private final int matchVarType;
|
||||
|
||||
public InstanceOfResidueTestVisitor(Class<?> matchClass, boolean defaultMatches, int matchVarType) {
|
||||
this.matchClass = matchClass;
|
||||
this.matches = defaultMatches;
|
||||
this.matchVarType = matchVarType;
|
||||
@@ -172,19 +180,34 @@ class RuntimeTestWalker {
|
||||
|
||||
public boolean instanceOfMatches(Test test) {
|
||||
test.accept(this);
|
||||
return matches;
|
||||
return this.matches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Instanceof i) {
|
||||
ResolvedType type = (ResolvedType) i.getType();
|
||||
int varType = getVarType((ReflectionVar) i.getVar());
|
||||
if (varType != this.matchVarType) {
|
||||
return;
|
||||
}
|
||||
Class<?> typeClass = null;
|
||||
ResolvedType type = (ResolvedType) i.getType();
|
||||
if (type instanceof ReferenceType) {
|
||||
ReferenceTypeDelegate delegate = ((ReferenceType) type).getDelegate();
|
||||
if (delegate instanceof ReflectionBasedReferenceTypeDelegate) {
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(myClassField);
|
||||
typeClass = (Class<?>) myClassField.get(delegate);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
Class typeClass = ClassUtils.forName(type.getName(), this.matchClass.getClassLoader());
|
||||
// Don't use ReflectionType.isAssignableFrom() as it won't be aware of (Spring) mixins
|
||||
// Don't use ResolvedType.isAssignableFrom() as it won't be aware of (Spring) mixins
|
||||
if (typeClass == null) {
|
||||
typeClass = ClassUtils.forName(type.getName(), this.matchClass.getClassLoader());
|
||||
}
|
||||
this.matches = typeClass.isAssignableFrom(this.matchClass);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -199,7 +222,7 @@ class RuntimeTestWalker {
|
||||
*/
|
||||
private static class TargetInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
|
||||
|
||||
public TargetInstanceOfResidueTestVisitor(Class targetClass) {
|
||||
public TargetInstanceOfResidueTestVisitor(Class<?> targetClass) {
|
||||
super(targetClass, false, TARGET_VAR);
|
||||
}
|
||||
|
||||
@@ -214,7 +237,7 @@ class RuntimeTestWalker {
|
||||
*/
|
||||
private static class ThisInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
|
||||
|
||||
public ThisInstanceOfResidueTestVisitor(Class thisClass) {
|
||||
public ThisInstanceOfResidueTestVisitor(Class<?> thisClass) {
|
||||
super(thisClass, true, THIS_VAR);
|
||||
}
|
||||
|
||||
@@ -228,8 +251,11 @@ class RuntimeTestWalker {
|
||||
private static class SubtypeSensitiveVarTypeTestVisitor extends TestVisitorAdapter {
|
||||
|
||||
private final Object thisObj = new Object();
|
||||
|
||||
private final Object targetObj = new Object();
|
||||
|
||||
private final Object[] argsObjs = new Object[0];
|
||||
|
||||
private boolean testsSubtypeSensitiveVars = false;
|
||||
|
||||
public boolean testsSubtypeSensitiveVars(Test aTest) {
|
||||
@@ -240,8 +266,8 @@ class RuntimeTestWalker {
|
||||
@Override
|
||||
public void visit(Instanceof i) {
|
||||
ReflectionVar v = (ReflectionVar) i.getVar();
|
||||
Object varUnderTest = v.getBindingAtJoinPoint(thisObj,targetObj,argsObjs);
|
||||
if ((varUnderTest == thisObj) || (varUnderTest == targetObj)) {
|
||||
Object varUnderTest = v.getBindingAtJoinPoint(this.thisObj, this.targetObj, this.argsObjs);
|
||||
if (varUnderTest == this.thisObj || varUnderTest == this.targetObj) {
|
||||
this.testsSubtypeSensitiveVars = true;
|
||||
}
|
||||
}
|
||||
@@ -251,7 +277,7 @@ class RuntimeTestWalker {
|
||||
// If you thought things were bad before, now we sink to new levels of horror...
|
||||
ReflectionVar v = (ReflectionVar) hasAnn.getVar();
|
||||
int varType = getVarType(v);
|
||||
if ((varType == AT_THIS_VAR) || (varType == AT_TARGET_VAR) || (varType == AT_ANNOTATION_VAR)) {
|
||||
if (varType == AT_THIS_VAR || varType == AT_TARGET_VAR || varType == AT_ANNOTATION_VAR) {
|
||||
this.testsSubtypeSensitiveVars = true;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -67,7 +67,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
}
|
||||
|
||||
public void setAspectJAdvisorFactory(AspectJAdvisorFactory aspectJAdvisorFactory) {
|
||||
Assert.notNull(this.aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null");
|
||||
Assert.notNull(aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null");
|
||||
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isInfrastructureClass(Class beanClass) {
|
||||
protected boolean isInfrastructureClass(Class<?> beanClass) {
|
||||
// Previously we setProxyTargetClass(true) in the constructor, but that has too
|
||||
// broad an impact. Instead we now override isInfrastructureClass to avoid proxying
|
||||
// aspects. I'm not entirely happy with that as there is no good reason not
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.aop.aspectj.annotation;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -105,7 +106,7 @@ public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInst
|
||||
if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {
|
||||
return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();
|
||||
}
|
||||
Order order = type.getAnnotation(Order.class);
|
||||
Order order = AnnotationUtils.findAnnotation(type, Order.class);
|
||||
if (order != null) {
|
||||
return order.value();
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import org.springframework.aop.aspectj.SimpleAspectInstanceFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
@@ -58,7 +59,7 @@ public class SimpleMetadataAwareAspectInstanceFactory extends SimpleAspectInstan
|
||||
*/
|
||||
@Override
|
||||
protected int getOrderForAspectClass(Class<?> aspectClass) {
|
||||
Order order = aspectClass.getAnnotation(Order.class);
|
||||
Order order = AnnotationUtils.findAnnotation(aspectClass, Order.class);
|
||||
if (order != null) {
|
||||
return order.value();
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import org.springframework.aop.aspectj.SingletonAspectInstanceFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
@@ -59,7 +60,7 @@ public class SingletonMetadataAwareAspectInstanceFactory extends SingletonAspect
|
||||
*/
|
||||
@Override
|
||||
protected int getOrderForAspectClass(Class<?> aspectClass) {
|
||||
Order order = aspectClass.getAnnotation(Order.class);
|
||||
Order order = AnnotationUtils.findAnnotation(aspectClass, Order.class);
|
||||
if (order != null) {
|
||||
return order.value();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -52,13 +52,13 @@ public interface Advised extends TargetClassAware {
|
||||
* Return the interfaces proxied by the AOP proxy. Will not
|
||||
* include the target class, which may also be proxied.
|
||||
*/
|
||||
Class[] getProxiedInterfaces();
|
||||
Class<?>[] getProxiedInterfaces();
|
||||
|
||||
/**
|
||||
* Determine whether the given interface is proxied.
|
||||
* @param intf the interface to check
|
||||
*/
|
||||
boolean isInterfaceProxied(Class intf);
|
||||
boolean isInterfaceProxied(Class<?> intf);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -158,7 +158,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
* @see #setTargetSource
|
||||
* @see #setTarget
|
||||
*/
|
||||
public void setTargetClass(Class targetClass) {
|
||||
public void setTargetClass(Class<?> targetClass) {
|
||||
this.targetSource = EmptyTargetSource.forClass(targetClass);
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
/**
|
||||
* Set the interfaces to be proxied.
|
||||
*/
|
||||
public void setInterfaces(Class[] interfaces) {
|
||||
public void setInterfaces(Class<?>... interfaces) {
|
||||
Assert.notNull(interfaces, "Interfaces must not be null");
|
||||
this.interfaces.clear();
|
||||
for (Class ifc : interfaces) {
|
||||
@@ -206,7 +206,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
* Add a new proxied interface.
|
||||
* @param intf the additional interface to proxy
|
||||
*/
|
||||
public void addInterface(Class intf) {
|
||||
public void addInterface(Class<?> intf) {
|
||||
Assert.notNull(intf, "Interface must not be null");
|
||||
if (!intf.isInterface()) {
|
||||
throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
|
||||
@@ -224,15 +224,15 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
* @return {@code true} if the interface was removed; {@code false}
|
||||
* if the interface was not found and hence could not be removed
|
||||
*/
|
||||
public boolean removeInterface(Class intf) {
|
||||
public boolean removeInterface(Class<?> intf) {
|
||||
return this.interfaces.remove(intf);
|
||||
}
|
||||
|
||||
public Class[] getProxiedInterfaces() {
|
||||
public Class<?>[] getProxiedInterfaces() {
|
||||
return this.interfaces.toArray(new Class[this.interfaces.size()]);
|
||||
}
|
||||
|
||||
public boolean isInterfaceProxied(Class intf) {
|
||||
public boolean isInterfaceProxied(Class<?> intf) {
|
||||
for (Class proxyIntf : this.interfaces) {
|
||||
if (intf.isAssignableFrom(proxyIntf)) {
|
||||
return true;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,7 +25,19 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.AopInvocationException;
|
||||
import org.springframework.aop.PointcutAdvisor;
|
||||
import org.springframework.aop.RawTargetAccess;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.cglib.core.CodeGenerationException;
|
||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.CallbackFilter;
|
||||
import org.springframework.cglib.proxy.Dispatcher;
|
||||
@@ -34,18 +46,7 @@ import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodInterceptor;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.cglib.proxy.NoOp;
|
||||
import org.springframework.cglib.transform.impl.UndeclaredThrowableStrategy;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.AopInvocationException;
|
||||
import org.springframework.aop.PointcutAdvisor;
|
||||
import org.springframework.aop.RawTargetAccess;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.cglib.transform.impl.MemorySafeUndeclaredThrowableStrategy;
|
||||
import org.springframework.core.SmartClassLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -181,20 +182,20 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
}
|
||||
}
|
||||
enhancer.setSuperclass(proxySuperClass);
|
||||
enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
|
||||
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
|
||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||
enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
|
||||
enhancer.setInterceptDuringConstruction(false);
|
||||
|
||||
Callback[] callbacks = getCallbacks(rootClass);
|
||||
enhancer.setCallbacks(callbacks);
|
||||
enhancer.setCallbackFilter(new ProxyCallbackFilter(
|
||||
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
|
||||
|
||||
Class<?>[] types = new Class[callbacks.length];
|
||||
Class<?>[] types = new Class<?>[callbacks.length];
|
||||
for (int x = 0; x < types.length; x++) {
|
||||
types[x] = callbacks[x].getClass();
|
||||
}
|
||||
enhancer.setCallbackFilter(new ProxyCallbackFilter(
|
||||
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
|
||||
enhancer.setCallbackTypes(types);
|
||||
enhancer.setCallbacks(callbacks);
|
||||
|
||||
// Generate the proxy class and create a proxy instance.
|
||||
Object proxy;
|
||||
@@ -253,11 +254,14 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
* for each one found.
|
||||
*/
|
||||
private void doValidateClass(Class<?> proxySuperClass) {
|
||||
Method[] methods = proxySuperClass.getMethods();
|
||||
for (Method method : methods) {
|
||||
if (!Object.class.equals(method.getDeclaringClass()) && Modifier.isFinal(method.getModifiers())) {
|
||||
logger.warn("Unable to proxy method [" + method + "] because it is final: " +
|
||||
"All calls to this method via a proxy will be routed directly to the proxy.");
|
||||
if (logger.isWarnEnabled()) {
|
||||
Method[] methods = proxySuperClass.getMethods();
|
||||
for (Method method : methods) {
|
||||
if (!Object.class.equals(method.getDeclaringClass()) && !Modifier.isStatic(method.getModifiers()) &&
|
||||
Modifier.isFinal(method.getModifiers())) {
|
||||
logger.warn("Unable to proxy method [" + method + "] because it is final: " +
|
||||
"All calls to this method via a proxy will be routed directly to the proxy.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -309,8 +313,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
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 optimisation 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(
|
||||
@@ -337,16 +340,15 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
*/
|
||||
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.
|
||||
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);
|
||||
throw new AopInvocationException(
|
||||
"Null return value from advice does not match primitive return type for: " + method);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
@@ -848,7 +850,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof ProxyCallbackFilter)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -57,7 +57,7 @@ public class ProxyFactory extends ProxyCreatorSupport {
|
||||
* <p>No target, only interfaces. Must add interceptors.
|
||||
* @param proxyInterfaces the interfaces that the proxy should implement
|
||||
*/
|
||||
public ProxyFactory(Class[] proxyInterfaces) {
|
||||
public ProxyFactory(Class<?>... proxyInterfaces) {
|
||||
setInterfaces(proxyInterfaces);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public class ProxyFactory extends ProxyCreatorSupport {
|
||||
* @param proxyInterface the interface that the proxy should implement
|
||||
* @param interceptor the interceptor that the proxy should invoke
|
||||
*/
|
||||
public ProxyFactory(Class proxyInterface, Interceptor interceptor) {
|
||||
public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) {
|
||||
addInterface(proxyInterface);
|
||||
addAdvice(interceptor);
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public class ProxyFactory extends ProxyCreatorSupport {
|
||||
* @param proxyInterface the interface that the proxy should implement
|
||||
* @param targetSource the TargetSource that the proxy should invoke
|
||||
*/
|
||||
public ProxyFactory(Class proxyInterface, TargetSource targetSource) {
|
||||
public ProxyFactory(Class<?> proxyInterface, TargetSource targetSource) {
|
||||
addInterface(proxyInterface);
|
||||
setTargetSource(targetSource);
|
||||
}
|
||||
|
||||
+26
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -81,24 +81,32 @@ public class BeanFactoryAdvisorRetrievalHelper {
|
||||
|
||||
List<Advisor> advisors = new LinkedList<Advisor>();
|
||||
for (String name : advisorNames) {
|
||||
if (isEligibleBean(name) && !this.beanFactory.isCurrentlyInCreation(name)) {
|
||||
try {
|
||||
advisors.add(this.beanFactory.getBean(name, Advisor.class));
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
Throwable rootCause = ex.getMostSpecificCause();
|
||||
if (rootCause instanceof BeanCurrentlyInCreationException) {
|
||||
BeanCreationException bce = (BeanCreationException) rootCause;
|
||||
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Ignoring currently created advisor '" + name + "': " + ex.getMessage());
|
||||
}
|
||||
// Ignore: indicates a reference back to the bean we're trying to advise.
|
||||
// We want to find advisors other than the currently created bean itself.
|
||||
continue;
|
||||
}
|
||||
if (isEligibleBean(name)) {
|
||||
if (this.beanFactory.isCurrentlyInCreation(name)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Skipping currently created advisor '" + name + "'");
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
advisors.add(this.beanFactory.getBean(name, Advisor.class));
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
Throwable rootCause = ex.getMostSpecificCause();
|
||||
if (rootCause instanceof BeanCurrentlyInCreationException) {
|
||||
BeanCreationException bce = (BeanCreationException) rootCause;
|
||||
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Skipping advisor '" + name +
|
||||
"' with dependency on currently created bean: " + ex.getMessage());
|
||||
}
|
||||
// Ignore: indicates a reference back to the bean we're trying to advise.
|
||||
// We want to find advisors other than the currently created bean itself.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -87,7 +87,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
|
||||
/**
|
||||
* Determine the specific executor to use when executing the given method.
|
||||
* @return the executor to use (never {@code null})
|
||||
* @return the executor to use (or {@code null}, but just if no default executor has been set)
|
||||
*/
|
||||
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
|
||||
AsyncTaskExecutor executor = this.executors.get(method);
|
||||
@@ -101,8 +101,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
this.beanFactory, Executor.class, qualifier);
|
||||
}
|
||||
else if (executorToUse == null) {
|
||||
throw new IllegalStateException("No executor qualifier specified and no default executor set on " +
|
||||
getClass().getSimpleName() + " either");
|
||||
return null;
|
||||
}
|
||||
executor = (executorToUse instanceof AsyncTaskExecutor ?
|
||||
(AsyncTaskExecutor) executorToUse : new TaskExecutorAdapter(executorToUse));
|
||||
|
||||
+7
-1
@@ -82,7 +82,13 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
|
||||
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
||||
|
||||
Future<?> result = determineAsyncExecutor(specificMethod).submit(
|
||||
AsyncTaskExecutor executor = determineAsyncExecutor(specificMethod);
|
||||
if (executor == null) {
|
||||
throw new IllegalStateException(
|
||||
"No executor specified and no default executor set on AsyncExecutionInterceptor either");
|
||||
}
|
||||
|
||||
Future<?> result = executor.submit(
|
||||
new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,7 +38,7 @@ public abstract class ScopedProxyUtils {
|
||||
|
||||
|
||||
/**
|
||||
* Generates a scoped proxy for the supplied target bean, registering the target
|
||||
* Generate a scoped proxy for the supplied target bean, registering the target
|
||||
* bean with an internal name and setting 'targetBeanName' on the scoped proxy.
|
||||
* @param definition the original bean definition
|
||||
* @param registry the bean definition registry
|
||||
@@ -50,20 +50,20 @@ public abstract class ScopedProxyUtils {
|
||||
|
||||
String originalBeanName = definition.getBeanName();
|
||||
BeanDefinition targetDefinition = definition.getBeanDefinition();
|
||||
String targetBeanName = getTargetBeanName(originalBeanName);
|
||||
|
||||
// Create a scoped proxy definition for the original bean name,
|
||||
// "hiding" the target bean in an internal target definition.
|
||||
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
|
||||
proxyDefinition.setOriginatingBeanDefinition(definition.getBeanDefinition());
|
||||
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
|
||||
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
|
||||
proxyDefinition.setSource(definition.getSource());
|
||||
proxyDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
String targetBeanName = getTargetBeanName(originalBeanName);
|
||||
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
|
||||
|
||||
if (proxyTargetClass) {
|
||||
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
|
||||
// ScopedFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
|
||||
// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
|
||||
}
|
||||
else {
|
||||
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
|
||||
|
||||
+28
-25
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,17 +29,16 @@ import org.springframework.util.StringUtils;
|
||||
* <ul>
|
||||
* <li>pattern: regular expression for the fully-qualified method names to match.
|
||||
* The exact regexp syntax will depend on the subclass (e.g. Perl5 regular expressions)
|
||||
* <li>patterns: alternative property taking a String array of patterns. The result will
|
||||
* be the union of these patterns.
|
||||
* <li>patterns: alternative property taking a String array of patterns.
|
||||
* The result will be the union of these patterns.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note: the regular expressions must be a match. For example,
|
||||
* {@code .*get.*} will match com.mycom.Foo.getBar().
|
||||
* {@code get.*} will not.
|
||||
*
|
||||
* <p>This base class is serializable. Subclasses should declare all fields transient
|
||||
* - the initPatternRepresentation method in this class will be invoked again on the
|
||||
* client side on deserialization.
|
||||
* <p>This base class is serializable. Subclasses should declare all fields transient;
|
||||
* the {@link #initPatternRepresentation} method will be invoked again on deserialization.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -51,10 +50,14 @@ import org.springframework.util.StringUtils;
|
||||
public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPointcut
|
||||
implements Serializable {
|
||||
|
||||
/** Regular expressions to match */
|
||||
/**
|
||||
* Regular expressions to match.
|
||||
*/
|
||||
private String[] patterns = new String[0];
|
||||
|
||||
/** Regular expressions <strong>not</strong> to match */
|
||||
/**
|
||||
* Regular expressions <strong>not</strong> to match.
|
||||
*/
|
||||
private String[] excludedPatterns = new String[0];
|
||||
|
||||
|
||||
@@ -64,15 +67,15 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
* @see #setPatterns
|
||||
*/
|
||||
public void setPattern(String pattern) {
|
||||
setPatterns(new String[] {pattern});
|
||||
setPatterns(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the regular expressions defining methods to match.
|
||||
* Matching will be the union of all these; if any match,
|
||||
* the pointcut matches.
|
||||
* Matching will be the union of all these; if any match, the pointcut matches.
|
||||
* @see #setPattern
|
||||
*/
|
||||
public void setPatterns(String[] patterns) {
|
||||
public void setPatterns(String... patterns) {
|
||||
Assert.notEmpty(patterns, "'patterns' must not be empty");
|
||||
this.patterns = new String[patterns.length];
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
@@ -94,15 +97,15 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
* @see #setExcludedPatterns
|
||||
*/
|
||||
public void setExcludedPattern(String excludedPattern) {
|
||||
setExcludedPatterns(new String[] {excludedPattern});
|
||||
setExcludedPatterns(excludedPattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the regular expressions defining methods to match for exclusion.
|
||||
* Matching will be the union of all these; if any match,
|
||||
* the pointcut matches.
|
||||
* Matching will be the union of all these; if any match, the pointcut matches.
|
||||
* @see #setExcludedPattern
|
||||
*/
|
||||
public void setExcludedPatterns(String[] excludedPatterns) {
|
||||
public void setExcludedPatterns(String... excludedPatterns) {
|
||||
Assert.notEmpty(excludedPatterns, "'excludedPatterns' must not be empty");
|
||||
this.excludedPatterns = new String[excludedPatterns.length];
|
||||
for (int i = 0; i < excludedPatterns.length; i++) {
|
||||
@@ -124,7 +127,7 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
* of the target class as well as against the method's declaring class,
|
||||
* plus the name of the method.
|
||||
*/
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return ((targetClass != null && matchesPattern(targetClass.getName() + "." + method.getName())) ||
|
||||
matchesPattern(method.getDeclaringClass().getName() + "." + method.getName()));
|
||||
}
|
||||
@@ -172,18 +175,18 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
protected abstract void initExcludedPatternRepresentation(String[] patterns) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Does the pattern at the given index match this string?
|
||||
* @param pattern {@code String} pattern to match
|
||||
* @param patternIndex index of pattern from 0
|
||||
* @return {@code true} if there is a match, else {@code false}.
|
||||
* Does the pattern at the given index match the given String?
|
||||
* @param pattern the {@code String} pattern to match
|
||||
* @param patternIndex index of pattern (starting from 0)
|
||||
* @return {@code true} if there is a match, {@code false} otherwise
|
||||
*/
|
||||
protected abstract boolean matches(String pattern, int patternIndex);
|
||||
|
||||
/**
|
||||
* Does the exclusion pattern at the given index match this string?
|
||||
* @param pattern {@code String} pattern to match.
|
||||
* @param patternIndex index of pattern starting from 0.
|
||||
* @return {@code true} if there is a match, else {@code false}.
|
||||
* Does the exclusion pattern at the given index match the given String?
|
||||
* @param pattern the {@code String} pattern to match
|
||||
* @param patternIndex index of pattern (starting from 0)
|
||||
* @return {@code true} if there is a match, {@code false} otherwise
|
||||
*/
|
||||
protected abstract boolean matchesExclusion(String pattern, int patternIndex);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,8 +23,7 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Static utility methods for composing
|
||||
* {@link org.springframework.aop.ClassFilter ClassFilters}.
|
||||
* Static utility methods for composing {@link ClassFilter ClassFilters}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
@@ -96,9 +95,9 @@ public abstract class ClassFilters {
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
public boolean matches(Class clazz) {
|
||||
for (int i = 0; i < this.filters.length; i++) {
|
||||
if (this.filters[i].matches(clazz)) {
|
||||
public boolean matches(Class<?> clazz) {
|
||||
for (ClassFilter filter : this.filters) {
|
||||
if (filter.matches(clazz)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -130,9 +129,9 @@ public abstract class ClassFilters {
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
public boolean matches(Class clazz) {
|
||||
for (int i = 0; i < this.filters.length; i++) {
|
||||
if (!this.filters[i].matches(clazz)) {
|
||||
public boolean matches(Class<?> clazz) {
|
||||
for (ClassFilter filter : this.filters) {
|
||||
if (!filter.matches(clazz)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -178,7 +178,6 @@ public class ComposablePointcut implements Pointcut, Serializable {
|
||||
return this.methodMatcher;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
@@ -187,7 +186,6 @@ public class ComposablePointcut implements Pointcut, Serializable {
|
||||
if (!(other instanceof ComposablePointcut)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ComposablePointcut that = (ComposablePointcut) other;
|
||||
return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) &&
|
||||
ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher);
|
||||
@@ -207,8 +205,7 @@ public class ComposablePointcut implements Pointcut, Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ComposablePointcut: ClassFilter [" + this.classFilter +
|
||||
"], MethodMatcher [" + this.methodMatcher + "]";
|
||||
return "ComposablePointcut: " + this.classFilter + ", " +this.methodMatcher;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,12 +25,11 @@ import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Static utility methods for composing
|
||||
* {@link org.springframework.aop.MethodMatcher MethodMatchers}.
|
||||
* Static utility methods for composing {@link MethodMatcher MethodMatchers}.
|
||||
*
|
||||
* <p>A MethodMatcher may be evaluated statically (based on method
|
||||
* and target class) or need further evaluation dynamically
|
||||
* (based on arguments at the time of method invocation).
|
||||
* <p>A MethodMatcher may be evaluated statically (based on method and target
|
||||
* class) or need further evaluation dynamically (based on arguments at the
|
||||
* time of method invocation).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
@@ -88,7 +87,7 @@ public abstract class MethodMatchers {
|
||||
* asking is the subject on one or more introductions; {@code false} otherwise
|
||||
* @return whether or not this method matches statically
|
||||
*/
|
||||
public static boolean matches(MethodMatcher mm, Method method, Class targetClass, boolean hasIntroductions) {
|
||||
public static boolean matches(MethodMatcher mm, Method method, Class<?> targetClass, boolean hasIntroductions) {
|
||||
Assert.notNull(mm, "MethodMatcher must not be null");
|
||||
return ((mm instanceof IntroductionAwareMethodMatcher &&
|
||||
((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions)) ||
|
||||
@@ -102,8 +101,9 @@ public abstract class MethodMatchers {
|
||||
@SuppressWarnings("serial")
|
||||
private static class UnionMethodMatcher implements IntroductionAwareMethodMatcher, Serializable {
|
||||
|
||||
private MethodMatcher mm1;
|
||||
private MethodMatcher mm2;
|
||||
private final MethodMatcher mm1;
|
||||
|
||||
private final MethodMatcher mm2;
|
||||
|
||||
public UnionMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
|
||||
Assert.notNull(mm1, "First MethodMatcher must not be null");
|
||||
@@ -112,21 +112,21 @@ public abstract class MethodMatchers {
|
||||
this.mm2 = mm2;
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, boolean hasIntroductions) {
|
||||
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
|
||||
return (matchesClass1(targetClass) && MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions)) ||
|
||||
(matchesClass2(targetClass) && MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions));
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return (matchesClass1(targetClass) && this.mm1.matches(method, targetClass)) ||
|
||||
(matchesClass2(targetClass) && this.mm2.matches(method, targetClass));
|
||||
}
|
||||
|
||||
protected boolean matchesClass1(Class targetClass) {
|
||||
protected boolean matchesClass1(Class<?> targetClass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean matchesClass2(Class targetClass) {
|
||||
protected boolean matchesClass2(Class<?> targetClass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ public abstract class MethodMatchers {
|
||||
return this.mm1.isRuntime() || this.mm2.isRuntime();
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, Object[] args) {
|
||||
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
|
||||
return this.mm1.matches(method, targetClass, args) || this.mm2.matches(method, targetClass, args);
|
||||
}
|
||||
|
||||
@@ -168,6 +168,7 @@ public abstract class MethodMatchers {
|
||||
private static class ClassFilterAwareUnionMethodMatcher extends UnionMethodMatcher {
|
||||
|
||||
private final ClassFilter cf1;
|
||||
|
||||
private final ClassFilter cf2;
|
||||
|
||||
public ClassFilterAwareUnionMethodMatcher(MethodMatcher mm1, ClassFilter cf1, MethodMatcher mm2, ClassFilter cf2) {
|
||||
@@ -177,12 +178,12 @@ public abstract class MethodMatchers {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matchesClass1(Class targetClass) {
|
||||
protected boolean matchesClass1(Class<?> targetClass) {
|
||||
return this.cf1.matches(targetClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matchesClass2(Class targetClass) {
|
||||
protected boolean matchesClass2(Class<?> targetClass) {
|
||||
return this.cf2.matches(targetClass);
|
||||
}
|
||||
|
||||
@@ -191,11 +192,17 @@ public abstract class MethodMatchers {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof ClassFilterAwareUnionMethodMatcher)) {
|
||||
if (!super.equals(other)) {
|
||||
return false;
|
||||
}
|
||||
ClassFilterAwareUnionMethodMatcher that = (ClassFilterAwareUnionMethodMatcher) other;
|
||||
return (this.cf1.equals(that.cf1) && this.cf2.equals(that.cf2) && super.equals(other));
|
||||
ClassFilter otherCf1 = ClassFilter.TRUE;
|
||||
ClassFilter otherCf2 = ClassFilter.TRUE;
|
||||
if (other instanceof ClassFilterAwareUnionMethodMatcher) {
|
||||
ClassFilterAwareUnionMethodMatcher cfa = (ClassFilterAwareUnionMethodMatcher) other;
|
||||
otherCf1 = cfa.cf1;
|
||||
otherCf2 = cfa.cf2;
|
||||
}
|
||||
return (this.cf1.equals(otherCf1) && this.cf2.equals(otherCf2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,8 +213,9 @@ public abstract class MethodMatchers {
|
||||
@SuppressWarnings("serial")
|
||||
private static class IntersectionMethodMatcher implements IntroductionAwareMethodMatcher, Serializable {
|
||||
|
||||
private MethodMatcher mm1;
|
||||
private MethodMatcher mm2;
|
||||
private final MethodMatcher mm1;
|
||||
|
||||
private final MethodMatcher mm2;
|
||||
|
||||
public IntersectionMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
|
||||
Assert.notNull(mm1, "First MethodMatcher must not be null");
|
||||
@@ -216,12 +224,12 @@ public abstract class MethodMatchers {
|
||||
this.mm2 = mm2;
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, boolean hasIntroductions) {
|
||||
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
|
||||
return MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions) &&
|
||||
MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions);
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return this.mm1.matches(method, targetClass) && this.mm2.matches(method, targetClass);
|
||||
}
|
||||
|
||||
@@ -229,7 +237,7 @@ public abstract class MethodMatchers {
|
||||
return this.mm1.isRuntime() || this.mm2.isRuntime();
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, Object[] args) {
|
||||
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
|
||||
// Because a dynamic intersection may be composed of a static and dynamic part,
|
||||
// we must avoid calling the 3-arg matches method on a dynamic matcher, as
|
||||
// it will probably be an unsupported operation.
|
||||
|
||||
+24
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,10 +59,32 @@ public class AnnotationClassFilter implements ClassFilter {
|
||||
}
|
||||
|
||||
|
||||
public boolean matches(Class clazz) {
|
||||
public boolean matches(Class<?> clazz) {
|
||||
return (this.checkInherited ?
|
||||
(AnnotationUtils.findAnnotation(clazz, this.annotationType) != null) :
|
||||
clazz.isAnnotationPresent(this.annotationType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof AnnotationClassFilter)) {
|
||||
return false;
|
||||
}
|
||||
AnnotationClassFilter otherCf = (AnnotationClassFilter) other;
|
||||
return (this.annotationType.equals(otherCf.annotationType) && this.checkInherited == otherCf.checkInherited);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.annotationType.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + this.annotationType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+32
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,7 @@ import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Simple Pointcut that looks for a specific Java 5 annotation
|
||||
@@ -98,6 +99,36 @@ public class AnnotationMatchingPointcut implements Pointcut {
|
||||
return this.methodMatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof AnnotationMatchingPointcut)) {
|
||||
return false;
|
||||
}
|
||||
AnnotationMatchingPointcut that = (AnnotationMatchingPointcut) other;
|
||||
return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) &&
|
||||
ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = 17;
|
||||
if (this.classFilter != null) {
|
||||
code = 37 * code + this.classFilter.hashCode();
|
||||
}
|
||||
if (this.methodMatcher != null) {
|
||||
code = 37 * code + this.methodMatcher.hashCode();
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AnnotationMatchingPointcut: " + this.classFilter + ", " +this.methodMatcher;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory method for an AnnotationMatchingPointcut that matches
|
||||
|
||||
+6
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -73,4 +73,9 @@ public class AnnotationMethodMatcher extends StaticMethodMatcher {
|
||||
return this.annotationType.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + this.annotationType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,6 +50,7 @@ import org.springframework.beans.factory.DisposableBean;
|
||||
* @see #releaseTarget
|
||||
* @see #destroy
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class AbstractPoolingTargetSource extends AbstractPrototypeBasedTargetSource
|
||||
implements PoolingConfig, DisposableBean {
|
||||
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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 org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
* @see ThreadLocalTargetSource
|
||||
* @see CommonsPoolTargetSource
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFactoryBasedTargetSource {
|
||||
|
||||
@Override
|
||||
|
||||
+10
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,8 +24,8 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.core.Constants;
|
||||
|
||||
/**
|
||||
* TargetSource implementation that holds objects in a configurable
|
||||
* Jakarta Commons Pool.
|
||||
* {@link org.springframework.aop.TargetSource} implementation that holds
|
||||
* objects in a configurable Apache Commons Pool.
|
||||
*
|
||||
* <p>By default, an instance of {@code GenericObjectPool} is created.
|
||||
* Subclasses may change the type of {@code ObjectPool} used by
|
||||
@@ -38,10 +38,12 @@ import org.springframework.core.Constants;
|
||||
* of configuration properties that are relevant to your chosen implementation.
|
||||
*
|
||||
* <p>The {@code testOnBorrow}, {@code testOnReturn} and {@code testWhileIdle}
|
||||
* properties are explictly not mirrored because the implementation of
|
||||
* properties are explicitly not mirrored because the implementation of
|
||||
* {@code PoolableObjectFactory} used by this class does not implement
|
||||
* meaningful validation. All exposed Commons Pool properties use the corresponding
|
||||
* Commons Pool defaults: for example,
|
||||
* meaningful validation. All exposed Commons Pool properties use the
|
||||
* corresponding Commons Pool defaults.
|
||||
*
|
||||
* <p>Compatible with Apache Commons Pool 1.5.x and 1.6.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
@@ -55,10 +57,8 @@ import org.springframework.core.Constants;
|
||||
* @see #setTimeBetweenEvictionRunsMillis
|
||||
* @see #setMinEvictableIdleTimeMillis
|
||||
*/
|
||||
public class CommonsPoolTargetSource extends AbstractPoolingTargetSource
|
||||
implements PoolableObjectFactory {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@SuppressWarnings("serial")
|
||||
public class CommonsPoolTargetSource extends AbstractPoolingTargetSource implements PoolableObjectFactory {
|
||||
|
||||
private static final Constants constants = new Constants(GenericObjectPool.class);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,9 +19,11 @@ package org.springframework.aop.target;
|
||||
import org.springframework.beans.BeansException;
|
||||
|
||||
/**
|
||||
* TargetSource that creates a new instance of the target bean for each
|
||||
* request, destroying each instance on release (after each request).
|
||||
* Obtains bean instances from its containing
|
||||
* {@link org.springframework.aop.TargetSource} implementation that
|
||||
* creates a new instance of the target bean for each request,
|
||||
* destroying each instance on release (after each request).
|
||||
*
|
||||
* <p>Obtains bean instances from its containing
|
||||
* {@link org.springframework.beans.factory.BeanFactory}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
@@ -29,10 +31,9 @@ import org.springframework.beans.BeansException;
|
||||
* @see #setBeanFactory
|
||||
* @see #setTargetBeanName
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class PrototypeTargetSource extends AbstractPrototypeBasedTargetSource {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Obtain a new prototype instance for every call.
|
||||
* @see #newPrototypeInstance()
|
||||
|
||||
+8
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,9 +27,10 @@ import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
|
||||
/**
|
||||
* Alternative to an object pool. This TargetSource uses a threading model in which
|
||||
* every thread has its own copy of the target. There's no contention for targets.
|
||||
* Target object creation is kept to a minimum on the running server.
|
||||
* Alternative to an object pool. This {@link org.springframework.aop.TargetSource}
|
||||
* uses a threading model in which every thread has its own copy of the target.
|
||||
* There's no contention for targets. Target object creation is kept to a minimum
|
||||
* on the running server.
|
||||
*
|
||||
* <p>Application code is written as to a normal pool; callers can't assume they
|
||||
* will be dealing with the same instance in invocations in different threads.
|
||||
@@ -47,11 +48,10 @@ import org.springframework.core.NamedThreadLocal;
|
||||
* @see ThreadLocalTargetSourceStats
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
|
||||
implements ThreadLocalTargetSourceStats, DisposableBean {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ThreadLocal holding the target associated with the current
|
||||
* thread. Unlike most ThreadLocals, which are static, this variable
|
||||
@@ -80,10 +80,8 @@ public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
|
||||
Object target = this.targetInThread.get();
|
||||
if (target == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No target for prototype '" + getTargetBeanName() +
|
||||
"' bound to thread: " +
|
||||
"creating one and binding it to thread '" +
|
||||
Thread.currentThread().getName() + "'");
|
||||
logger.debug("No target for prototype '" + getTargetBeanName() + "' bound to thread: " +
|
||||
"creating one and binding it to thread '" + Thread.currentThread().getName() + "'");
|
||||
}
|
||||
// Associate target with ThreadLocal.
|
||||
target = newPrototypeInstance();
|
||||
|
||||
@@ -43,6 +43,7 @@ public final class MethodMatchersTests {
|
||||
|
||||
private final Method IOTHER_ABSQUATULATE;
|
||||
|
||||
|
||||
public MethodMatchersTests() throws Exception {
|
||||
EXCEPTION_GETMESSAGE = Exception.class.getMethod("getMessage", (Class[]) null);
|
||||
ITESTBEAN_GETAGE = ITestBean.class.getMethod("getAge", (Class[]) null);
|
||||
@@ -50,6 +51,7 @@ public final class MethodMatchersTests {
|
||||
IOTHER_ABSQUATULATE = IOther.class.getMethod("absquatulate", (Class[]) null);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDefaultMatchesAll() throws Exception {
|
||||
MethodMatcher defaultMm = MethodMatcher.TRUE;
|
||||
@@ -99,23 +101,33 @@ public final class MethodMatchersTests {
|
||||
assertTrue("Matched setAge method", union.matches(ITESTBEAN_SETAGE, TestBean.class));
|
||||
assertTrue("Matched getAge method", union.matches(ITESTBEAN_GETAGE, TestBean.class));
|
||||
assertFalse("Didn't matched absquatulate method", union.matches(IOTHER_ABSQUATULATE, TestBean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnionEquals() {
|
||||
MethodMatcher first = MethodMatchers.union(MethodMatcher.TRUE, MethodMatcher.TRUE);
|
||||
MethodMatcher second = new ComposablePointcut(MethodMatcher.TRUE).union(new ComposablePointcut(MethodMatcher.TRUE)).getMethodMatcher();
|
||||
assertTrue(first.equals(second));
|
||||
assertTrue(second.equals(first));
|
||||
}
|
||||
|
||||
|
||||
public static class StartsWithMatcher extends StaticMethodMatcher {
|
||||
private String prefix;
|
||||
|
||||
private final String prefix;
|
||||
|
||||
public StartsWithMatcher(String s) {
|
||||
this.prefix = s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Method m, Class<?> targetClass) {
|
||||
return m.getName().startsWith(prefix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class TestDynamicMethodMatcherWhichMatches extends DynamicMethodMatcher {
|
||||
|
||||
@Override
|
||||
public boolean matches(Method m, Class<?> targetClass, Object[] args) {
|
||||
return true;
|
||||
@@ -123,6 +135,7 @@ public final class MethodMatchersTests {
|
||||
}
|
||||
|
||||
private static class TestDynamicMethodMatcherWhichDoesNotMatch extends DynamicMethodMatcher {
|
||||
|
||||
@Override
|
||||
public boolean matches(Method m, Class<?> targetClass, Object[] args) {
|
||||
return false;
|
||||
|
||||
@@ -12,8 +12,8 @@ configurations {
|
||||
tasks.getByName("idea").onlyIf { false }
|
||||
tasks.getByName("ideaModule").onlyIf { false }
|
||||
|
||||
task compileJava(overwrite: true) {
|
||||
dependsOn JavaPlugin.PROCESS_RESOURCES_TASK_NAME
|
||||
compileJava {
|
||||
actions = []
|
||||
dependsOn configurations.ajc.getTaskDependencyFromProjectDependency(true, "compileJava")
|
||||
|
||||
def outputDir = project.sourceSets.main.output.classesDir
|
||||
@@ -44,8 +44,8 @@ task compileJava(overwrite: true) {
|
||||
}
|
||||
}
|
||||
|
||||
task compileTestJava(overwrite: true) {
|
||||
dependsOn JavaPlugin.PROCESS_TEST_RESOURCES_TASK_NAME
|
||||
compileTestJava {
|
||||
actions = []
|
||||
dependsOn configurations.ajc.getTaskDependencyFromProjectDependency(true, "compileTestJava")
|
||||
dependsOn jar
|
||||
|
||||
|
||||
+78
-47
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,16 +18,22 @@ package org.springframework.mock.staticmock;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Abstract aspect to enable mocking of methods picked out by a pointcut.
|
||||
* Sub-aspects must define the mockStaticsTestMethod() pointcut to
|
||||
* indicate call stacks when mocking should be triggered, and the
|
||||
* methodToMock() pointcut to pick out a method invocations to mock.
|
||||
*
|
||||
* <p>Sub-aspects must define:
|
||||
* <ul>
|
||||
* <li>the {@link #mockStaticsTestMethod()} pointcut to indicate call stacks
|
||||
* when mocking should be triggered
|
||||
* <li>the {@link #methodToMock()} pointcut to pick out method invocations to mock
|
||||
* </ul>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {
|
||||
|
||||
@@ -35,24 +41,34 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
|
||||
protected abstract pointcut methodToMock();
|
||||
|
||||
|
||||
private boolean recording = true;
|
||||
|
||||
static enum CallResponse { nothing, return_, throw_ };
|
||||
|
||||
// Represents a list of expected calls to static entity methods
|
||||
static enum CallResponse {
|
||||
nothing, return_, throw_
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a list of expected calls to methods.
|
||||
*/
|
||||
// Public to allow inserted code to access: is this normal??
|
||||
public class Expectations {
|
||||
|
||||
// Represents an expected call to a static entity method
|
||||
/**
|
||||
* Represents an expected call to a method.
|
||||
*/
|
||||
private class Call {
|
||||
|
||||
private final String signature;
|
||||
private final Object[] args;
|
||||
|
||||
private Object responseObject; // return value or throwable
|
||||
private CallResponse responseType = CallResponse.nothing;
|
||||
|
||||
public Call(String name, Object[] args) {
|
||||
this.signature = name;
|
||||
|
||||
public Call(String signature, Object[] args) {
|
||||
this.signature = signature;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
@@ -77,7 +93,7 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
|
||||
public Object throwException(String lastSig, Object[] args) {
|
||||
checkSignature(lastSig, args);
|
||||
throw (RuntimeException)responseObject;
|
||||
throw (RuntimeException) responseObject;
|
||||
}
|
||||
|
||||
private void checkSignature(String lastSig, Object[] args) {
|
||||
@@ -88,50 +104,62 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
throw new IllegalArgumentException("Arguments don't match");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Call with signature [%s] and arguments %s", this.signature,
|
||||
ObjectUtils.nullSafeToString(args));
|
||||
}
|
||||
}
|
||||
|
||||
private List<Call> calls = new LinkedList<Call>();
|
||||
|
||||
// Calls already verified
|
||||
/**
|
||||
* The list of recorded calls.
|
||||
*/
|
||||
private final LinkedList<Call> calls = new LinkedList<Call>();
|
||||
|
||||
/**
|
||||
* The number of calls already verified.
|
||||
*/
|
||||
private int verified;
|
||||
|
||||
|
||||
public void verify() {
|
||||
if (verified != calls.size()) {
|
||||
throw new IllegalStateException("Expected " + calls.size()
|
||||
+ " calls, received " + verified);
|
||||
throw new IllegalStateException("Expected " + calls.size() + " calls, but received " + verified);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the call and provide the expected return value
|
||||
* @param lastSig
|
||||
* @param args
|
||||
* @return
|
||||
* Validate the call and provide the expected return value.
|
||||
*/
|
||||
public Object respond(String lastSig, Object[] args) {
|
||||
Call call = nextCall();
|
||||
CallResponse responseType = call.responseType;
|
||||
if (responseType == CallResponse.return_) {
|
||||
return call.returnValue(lastSig, args);
|
||||
} else if(responseType == CallResponse.throw_) {
|
||||
return (RuntimeException)call.throwException(lastSig, args);
|
||||
} else if(responseType == CallResponse.nothing) {
|
||||
// do nothing
|
||||
Call c = nextCall();
|
||||
|
||||
switch (c.responseType) {
|
||||
case return_: {
|
||||
return c.returnValue(lastSig, args);
|
||||
}
|
||||
case throw_: {
|
||||
return c.throwException(lastSig, args);
|
||||
}
|
||||
default: {
|
||||
throw new IllegalStateException("Behavior of " + c + " not specified");
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Behavior of " + call + " not specified");
|
||||
}
|
||||
|
||||
private Call nextCall() {
|
||||
if (verified > calls.size() - 1) {
|
||||
throw new IllegalStateException("Expected " + calls.size()
|
||||
+ " calls, received " + verified);
|
||||
verified++;
|
||||
if (verified > calls.size()) {
|
||||
throw new IllegalStateException("Expected " + calls.size() + " calls, but received " + verified);
|
||||
}
|
||||
return calls.get(verified++);
|
||||
// The 'verified' count is 1-based; whereas, 'calls' is 0-based.
|
||||
return calls.get(verified - 1);
|
||||
}
|
||||
|
||||
public void expectCall(String lastSig, Object lastArgs[]) {
|
||||
Call call = new Call(lastSig, lastArgs);
|
||||
calls.add(call);
|
||||
public void expectCall(String lastSig, Object[] lastArgs) {
|
||||
calls.add(new Call(lastSig, lastArgs));
|
||||
}
|
||||
|
||||
public boolean hasCalls() {
|
||||
@@ -139,29 +167,31 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
}
|
||||
|
||||
public void expectReturn(Object retVal) {
|
||||
Call call = calls.get(calls.size() - 1);
|
||||
if (call.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No static method invoked before setting return value");
|
||||
Call c = calls.getLast();
|
||||
if (c.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No method invoked before setting return value");
|
||||
}
|
||||
call.setReturnVal(retVal);
|
||||
c.setReturnVal(retVal);
|
||||
}
|
||||
|
||||
public void expectThrow(Throwable throwable) {
|
||||
Call call = calls.get(calls.size() - 1);
|
||||
if (call.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No static method invoked before setting throwable");
|
||||
Call c = calls.getLast();
|
||||
if (c.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No method invoked before setting throwable");
|
||||
}
|
||||
call.setThrow(throwable);
|
||||
c.setThrow(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private Expectations expectations = new Expectations();
|
||||
|
||||
private final Expectations expectations = new Expectations();
|
||||
|
||||
|
||||
after() returning : mockStaticsTestMethod() {
|
||||
if (recording && (expectations.hasCalls())) {
|
||||
throw new IllegalStateException(
|
||||
"Calls recorded, yet playback state never reached: Create expectations then call "
|
||||
+ this.getClass().getSimpleName() + ".playback()");
|
||||
"Calls recorded, yet playback state never reached: Create expectations then call "
|
||||
+ this.getClass().getSimpleName() + ".playback()");
|
||||
}
|
||||
expectations.verify();
|
||||
}
|
||||
@@ -171,7 +201,8 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
expectations.expectCall(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
|
||||
// Return value doesn't matter
|
||||
return null;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return expectations.respond(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
|
||||
}
|
||||
}
|
||||
|
||||
+41
-22
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,50 +17,69 @@
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
/**
|
||||
* Annotation-based aspect to use in test build to enable mocking static methods
|
||||
* on JPA-annotated {@code @Entity} classes, as used by Roo for finders.
|
||||
* Annotation-based aspect to use in test builds to enable mocking of static methods
|
||||
* on JPA-annotated {@code @Entity} classes, as used by Spring Roo for so-called
|
||||
* <em>finder methods</em>.
|
||||
*
|
||||
* <p>Mocking will occur in the call stack of any method in a class (typically a test class)
|
||||
* that is annotated with the @MockStaticEntityMethods annotation.
|
||||
* <p>Mocking will occur within the call stack of any method in a class (typically a
|
||||
* test class) that is annotated with {@code @MockStaticEntityMethods}.
|
||||
*
|
||||
* <p>Also provides static methods to simplify the programming model for
|
||||
* entering playback mode and setting expected return values.
|
||||
* <p>This aspect also provides static methods to simplify the programming model for
|
||||
* setting expectations and entering playback mode.
|
||||
*
|
||||
* <p>Usage:
|
||||
* <ol>
|
||||
* <li>Annotate a test class with @MockStaticEntityMethods.
|
||||
* <li>In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode.
|
||||
* Invoke static methods on Entity classes, with each recording-mode invocation
|
||||
* being followed by an invocation to the static expectReturn() or expectThrow()
|
||||
* method on AnnotationDrivenStaticEntityMockingControl.
|
||||
* <li>Invoke the static AnnotationDrivenStaticEntityMockingControl() method.
|
||||
* <li>Call the code you wish to test that uses the static methods. Verification will
|
||||
* occur automatically.
|
||||
* <li>Annotate a test class with {@code @MockStaticEntityMethods}.
|
||||
* <li>In each test method, {@code AnnotationDrivenStaticEntityMockingControl}
|
||||
* will begin in <em>recording</em> mode.
|
||||
* <li>Invoke static methods on JPA-annotated {@code @Entity} classes, with each
|
||||
* recording-mode invocation being followed by an invocation of either the static
|
||||
* {@link #expectReturn(Object)} method or the static {@link #expectThrow(Throwable)}
|
||||
* method on {@code AnnotationDrivenStaticEntityMockingControl}.
|
||||
* <li>Invoke the static {@link #playback()} method.
|
||||
* <li>Call the code you wish to test that uses the static methods.
|
||||
* <li>Verification will occur automatically.
|
||||
* </ol>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
* @see MockStaticEntityMethods
|
||||
*/
|
||||
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
|
||||
|
||||
/**
|
||||
* Stop recording mock calls and enter playback state
|
||||
* Expect the supplied {@link Object} to be returned by the previous static
|
||||
* method invocation.
|
||||
* @see #playback()
|
||||
*/
|
||||
public static void playback() {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal();
|
||||
}
|
||||
|
||||
public static void expectReturn(Object retVal) {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectReturnInternal(retVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect the supplied {@link Throwable} to be thrown by the previous static
|
||||
* method invocation.
|
||||
* @see #playback()
|
||||
*/
|
||||
public static void expectThrow(Throwable throwable) {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectThrowInternal(throwable);
|
||||
}
|
||||
|
||||
// Only matches directly annotated @Test methods, to allow methods in
|
||||
// @MockStatics classes to invoke each other without resetting the mocking environment
|
||||
/**
|
||||
* Stop recording mock expectations and enter <em>playback</em> mode.
|
||||
* @see #expectReturn(Object)
|
||||
* @see #expectThrow(Throwable)
|
||||
*/
|
||||
public static void playback() {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal();
|
||||
}
|
||||
|
||||
// Apparently, the following pointcut was originally defined to only match
|
||||
// methods directly annotated with @Test (in order to allow methods in
|
||||
// @MockStaticEntityMethods classes to invoke each other without resetting
|
||||
// the mocking environment); however, this is no longer the case. The current
|
||||
// pointcut applies to all public methods in @MockStaticEntityMethods classes.
|
||||
protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..));
|
||||
|
||||
protected pointcut methodToMock() : execution(public static * (@javax.persistence.Entity *).*(..));
|
||||
|
||||
+6
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,11 +22,13 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to indicate a test class for whose @Test methods
|
||||
* static methods on Entity classes should be mocked. See
|
||||
* {@code AbstractMethodMockingControl}.
|
||||
* Annotation to indicate a test class for whose {@code @Test} methods
|
||||
* static methods on JPA-annotated {@code @Entity} classes should be mocked.
|
||||
*
|
||||
* <p>See {@link AnnotationDrivenStaticEntityMockingControl} for details.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,11 +32,11 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
||||
* @since 3.1
|
||||
* @see EnableAsync
|
||||
* @see org.springframework.scheduling.annotation.AsyncConfigurationSelector
|
||||
* @see org.springframework.scheduling.annotation.ProxyAsyncConfiguration
|
||||
*/
|
||||
@Configuration
|
||||
public class AspectJAsyncConfiguration extends AbstractAsyncConfiguration {
|
||||
|
||||
@Override
|
||||
@Bean(name=AnnotationConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public AnnotationAsyncExecutionAspect asyncAdvisor() {
|
||||
|
||||
-148
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.expectReturn;
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.expectThrow;
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.playback;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
|
||||
/**
|
||||
* Test for static entity mocking framework.
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
@MockStaticEntityMethods
|
||||
@RunWith(JUnit4.class)
|
||||
public class AnnotationDrivenStaticEntityMockingControlTest {
|
||||
|
||||
@Test
|
||||
public void testNoArgIntReturn() {
|
||||
int expectedCount = 13;
|
||||
Person.countPeople();
|
||||
expectReturn(expectedCount);
|
||||
playback();
|
||||
assertEquals(expectedCount, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected=PersistenceException.class)
|
||||
public void testNoArgThrows() {
|
||||
Person.countPeople();
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodMatches() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLongSeriesOfCalls() {
|
||||
long id1 = 13;
|
||||
long id2 = 24;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(id2);
|
||||
expectReturn(found2);
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person.countPeople();
|
||||
expectReturn(0);
|
||||
playback();
|
||||
|
||||
assertEquals(found1, Person.findPerson(id1));
|
||||
assertEquals(found2, Person.findPerson(id2));
|
||||
assertEquals(found1, Person.findPerson(id1));
|
||||
assertEquals(0, Person.countPeople());
|
||||
}
|
||||
|
||||
// Note delegation is used when tests are invalid and should fail, as otherwise
|
||||
// the failure will occur on the verify() method in the aspect after
|
||||
// this method returns, failing the test case
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
try {
|
||||
new Delegate().testArgMethodNoMatchExpectReturn();
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
new Delegate().testArgMethodNoMatchExpectThrow();
|
||||
}
|
||||
|
||||
private void called(Person found, long id) {
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReentrant() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
called(found, id);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testRejectUnexpectedCall() {
|
||||
new Delegate().rejectUnexpectedCall();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testFailTooFewCalls() {
|
||||
new Delegate().failTooFewCalls();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
// Test that verification check doesn't blow up if no replay() call happened
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverReplay() {
|
||||
new Delegate().doesntEverReplay();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverSetReturn() {
|
||||
new Delegate().doesntEverSetReturn();
|
||||
}
|
||||
}
|
||||
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*;
|
||||
|
||||
/**
|
||||
* Tests for Spring's static entity mocking framework (i.e., @{@link MockStaticEntityMethods}
|
||||
* and {@link AnnotationDrivenStaticEntityMockingControl}).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@MockStaticEntityMethods
|
||||
public class AnnotationDrivenStaticEntityMockingControlTests {
|
||||
|
||||
@Test
|
||||
public void noArgumentMethodInvocationReturnsInt() {
|
||||
int expectedCount = 13;
|
||||
Person.countPeople();
|
||||
expectReturn(expectedCount);
|
||||
playback();
|
||||
assertEquals(expectedCount, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected = PersistenceException.class)
|
||||
public void noArgumentMethodInvocationThrowsException() {
|
||||
Person.countPeople();
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodArgumentsMatch() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longSeriesOfCalls() {
|
||||
long id1 = 13;
|
||||
long id2 = 24;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(id2);
|
||||
expectReturn(found2);
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person.countPeople();
|
||||
expectReturn(0);
|
||||
playback();
|
||||
|
||||
assertEquals(found1, Person.findPerson(id1));
|
||||
assertEquals(found2, Person.findPerson(id2));
|
||||
assertEquals(found1, Person.findPerson(id1));
|
||||
assertEquals(0, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void methodArgumentsDoNotMatchAndReturnsObject() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void methodArgumentsDoNotMatchAndThrowsException() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reentrant() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
called(found, id);
|
||||
}
|
||||
|
||||
private void called(Person found, long id) {
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void rejectUnexpectedCall() {
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void tooFewCalls() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void empty() {
|
||||
// Test that verification check doesn't blow up if no replay() call happened.
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void doesNotEnterPlaybackMode() {
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void doesNotSetExpectedReturnValue() {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: this test method currently does NOT actually verify that the mock
|
||||
* verification fails.
|
||||
*/
|
||||
// TODO Determine if it's possible for a mock verification failure to fail a test in
|
||||
// JUnit 4+ if the test method itself throws an expected exception.
|
||||
@Test(expected = RemoteException.class)
|
||||
public void verificationFailsEvenWhenTestFailsInExpectedManner() throws Exception {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
// No calls in order to allow verification failure
|
||||
throw new RemoteException();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl;
|
||||
import org.springframework.mock.staticmock.MockStaticEntityMethods;
|
||||
|
||||
//Used because verification failures occur after method returns,
|
||||
//so we can't test for them in the test case itself
|
||||
@MockStaticEntityMethods
|
||||
@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl
|
||||
public class Delegate {
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failTooFewCalls() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverReplay() {
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverSetReturn() {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectUnexpectedCall() {
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected=RemoteException.class)
|
||||
public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
// No calls to allow verification failure
|
||||
throw new RemoteException();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,33 +20,36 @@ import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
|
||||
/**
|
||||
* Strategy for creating {@link BeanInfo} instances.
|
||||
* Strategy interface for creating {@link BeanInfo} instances for Spring beans.
|
||||
* Can be used to plug in custom bean property resolution strategies (e.g. for other
|
||||
* languages on the JVM) or more efficient {@link BeanInfo} retrieval algorithms.
|
||||
*
|
||||
* <p>BeanInfoFactories are are instantiated by the {@link CachedIntrospectionResults},
|
||||
* by using the {@link org.springframework.core.io.support.SpringFactoriesLoader} utility
|
||||
* class.
|
||||
* by using the {@link org.springframework.core.io.support.SpringFactoriesLoader}
|
||||
* utility class.
|
||||
*
|
||||
* When a {@link BeanInfo} is to be created, the {@code CachedIntrospectionResults}
|
||||
* will iterate through the discovered factories, calling {@link
|
||||
* #getBeanInfo(Class)} on each one. If {@code null} is returned, the next factory will
|
||||
* be queried. If none of the factories support the class, an standard {@link BeanInfo}
|
||||
* is created as a default.
|
||||
* will iterate through the discovered factories, calling {@link #getBeanInfo(Class)}
|
||||
* on each one. If {@code null} is returned, the next factory will be queried.
|
||||
* If none of the factories support the class, a standard {@link BeanInfo} will be
|
||||
* created as a default.
|
||||
*
|
||||
* <p>Note that the {@link org.springframework.core.io.support.SpringFactoriesLoader}
|
||||
* sorts the {@code BeanInfoFactory} instances by
|
||||
* {@link org.springframework.core.annotation.Order @Order}, so that ones with
|
||||
* a higher precedence come first.
|
||||
* {@link org.springframework.core.annotation.Order @Order}, so that ones with a
|
||||
* higher precedence come first.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.2
|
||||
* @see CachedIntrospectionResults
|
||||
* @see org.springframework.core.io.support.SpringFactoriesLoader
|
||||
*/
|
||||
public interface BeanInfoFactory {
|
||||
|
||||
/**
|
||||
* Returns the bean info for the given class, if supported.
|
||||
*
|
||||
* Return the bean info for the given class, if supported.
|
||||
* @param beanClass the bean class
|
||||
* @return the bean info, or {@code null} if not the given class is not supported
|
||||
* @return the BeanInfo, or {@code null} if the given class is not supported
|
||||
* @throws IntrospectionException in case of exceptions
|
||||
*/
|
||||
BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -57,7 +57,7 @@ public abstract class BeanUtils {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(BeanUtils.class);
|
||||
|
||||
// using WeakHashMap as a Set
|
||||
// Effectively using a WeakHashMap as a Set
|
||||
private static final Map<Class<?>, Boolean> unknownEditorTypes =
|
||||
Collections.synchronizedMap(new WeakHashMap<Class<?>, Boolean>());
|
||||
|
||||
@@ -127,7 +127,7 @@ public abstract class BeanUtils {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo) throws BeanInstantiationException {
|
||||
Assert.isAssignable(assignableTo, clazz);
|
||||
return (T)instantiateClass(clazz);
|
||||
return (T) instantiateClass(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,7 +199,7 @@ public abstract class BeanUtils {
|
||||
* @return the Method object, or {@code null} if not found
|
||||
* @see Class#getDeclaredMethod
|
||||
*/
|
||||
public static Method findDeclaredMethod(Class<?> clazz, String methodName, Class<?>[] paramTypes) {
|
||||
public static Method findDeclaredMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
|
||||
try {
|
||||
return clazz.getDeclaredMethod(methodName, paramTypes);
|
||||
}
|
||||
@@ -281,7 +281,7 @@ public abstract class BeanUtils {
|
||||
}
|
||||
else {
|
||||
if (targetMethod.getParameterTypes().length == numParams) {
|
||||
// Additional candidate with same length.
|
||||
// Additional candidate with same length
|
||||
numMethodsFoundWithCurrentMinimumArgs++;
|
||||
}
|
||||
}
|
||||
@@ -317,10 +317,8 @@ public abstract class BeanUtils {
|
||||
public static Method resolveSignature(String signature, Class<?> clazz) {
|
||||
Assert.hasText(signature, "'signature' must not be empty");
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
|
||||
int firstParen = signature.indexOf("(");
|
||||
int lastParen = signature.indexOf(")");
|
||||
|
||||
if (firstParen > -1 && lastParen == -1) {
|
||||
throw new IllegalArgumentException("Invalid method signature '" + signature +
|
||||
"': expected closing ')' for args list");
|
||||
@@ -336,7 +334,7 @@ public abstract class BeanUtils {
|
||||
String methodName = signature.substring(0, firstParen);
|
||||
String[] parameterTypeNames =
|
||||
StringUtils.commaDelimitedListToStringArray(signature.substring(firstParen + 1, lastParen));
|
||||
Class<?>[] parameterTypes = new Class[parameterTypeNames.length];
|
||||
Class<?>[] parameterTypes = new Class<?>[parameterTypeNames.length];
|
||||
for (int i = 0; i < parameterTypeNames.length; i++) {
|
||||
String parameterTypeName = parameterTypeNames[i].trim();
|
||||
try {
|
||||
@@ -455,7 +453,7 @@ public abstract class BeanUtils {
|
||||
* @param beanClasses the classes to check against
|
||||
* @return the property type, or {@code Object.class} as fallback
|
||||
*/
|
||||
public static Class<?> findPropertyType(String propertyName, Class<?>[] beanClasses) {
|
||||
public static Class<?> findPropertyType(String propertyName, Class<?>... beanClasses) {
|
||||
if (beanClasses != null) {
|
||||
for (Class<?> beanClass : beanClasses) {
|
||||
PropertyDescriptor pd = getPropertyDescriptor(beanClass, propertyName);
|
||||
@@ -475,8 +473,7 @@ public abstract class BeanUtils {
|
||||
*/
|
||||
public static MethodParameter getWriteMethodParameter(PropertyDescriptor pd) {
|
||||
if (pd instanceof GenericTypeAwarePropertyDescriptor) {
|
||||
return new MethodParameter(
|
||||
((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodParameter());
|
||||
return new MethodParameter(((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodParameter());
|
||||
}
|
||||
else {
|
||||
return new MethodParameter(pd.getWriteMethod(), 0);
|
||||
@@ -528,7 +525,7 @@ public abstract class BeanUtils {
|
||||
* @see BeanWrapper
|
||||
*/
|
||||
public static void copyProperties(Object source, Object target) throws BeansException {
|
||||
copyProperties(source, target, null, null);
|
||||
copyProperties(source, target, null, (String[]) null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -545,10 +542,8 @@ public abstract class BeanUtils {
|
||||
* @throws BeansException if the copying failed
|
||||
* @see BeanWrapper
|
||||
*/
|
||||
public static void copyProperties(Object source, Object target, Class<?> editable)
|
||||
throws BeansException {
|
||||
|
||||
copyProperties(source, target, editable, null);
|
||||
public static void copyProperties(Object source, Object target, Class<?> editable) throws BeansException {
|
||||
copyProperties(source, target, editable, (String[]) null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -565,9 +560,7 @@ public abstract class BeanUtils {
|
||||
* @throws BeansException if the copying failed
|
||||
* @see BeanWrapper
|
||||
*/
|
||||
public static void copyProperties(Object source, Object target, String[] ignoreProperties)
|
||||
throws BeansException {
|
||||
|
||||
public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException {
|
||||
copyProperties(source, target, null, ignoreProperties);
|
||||
}
|
||||
|
||||
@@ -583,7 +576,7 @@ public abstract class BeanUtils {
|
||||
* @throws BeansException if the copying failed
|
||||
* @see BeanWrapper
|
||||
*/
|
||||
private static void copyProperties(Object source, Object target, Class<?> editable, String[] ignoreProperties)
|
||||
private static void copyProperties(Object source, Object target, Class<?> editable, String... ignoreProperties)
|
||||
throws BeansException {
|
||||
|
||||
Assert.notNull(source, "Source must not be null");
|
||||
@@ -601,24 +594,27 @@ public abstract class BeanUtils {
|
||||
List<String> ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null;
|
||||
|
||||
for (PropertyDescriptor targetPd : targetPds) {
|
||||
if (targetPd.getWriteMethod() != null &&
|
||||
(ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) {
|
||||
Method writeMethod = targetPd.getWriteMethod();
|
||||
if (writeMethod != null && (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) {
|
||||
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
|
||||
if (sourcePd != null && sourcePd.getReadMethod() != null) {
|
||||
try {
|
||||
Method readMethod = sourcePd.getReadMethod();
|
||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
|
||||
readMethod.setAccessible(true);
|
||||
if (sourcePd != null) {
|
||||
Method readMethod = sourcePd.getReadMethod();
|
||||
if (readMethod != null &&
|
||||
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
|
||||
try {
|
||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
|
||||
readMethod.setAccessible(true);
|
||||
}
|
||||
Object value = readMethod.invoke(source);
|
||||
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
|
||||
writeMethod.setAccessible(true);
|
||||
}
|
||||
writeMethod.invoke(target, value);
|
||||
}
|
||||
Object value = readMethod.invoke(source);
|
||||
Method writeMethod = targetPd.getWriteMethod();
|
||||
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
|
||||
writeMethod.setAccessible(true);
|
||||
catch (Throwable ex) {
|
||||
throw new FatalBeanException(
|
||||
"Could not copy property '" + targetPd.getName() + "' from source to target", ex);
|
||||
}
|
||||
writeMethod.invoke(target, value);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new FatalBeanException("Could not copy properties from source to target", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,7 +59,7 @@ public interface BeanWrapper extends ConfigurablePropertyAccessor {
|
||||
* @return the type of the wrapped bean instance,
|
||||
* or {@code null} if no wrapped object has been set
|
||||
*/
|
||||
Class getWrappedClass();
|
||||
Class<?> getWrappedClass();
|
||||
|
||||
/**
|
||||
* Obtain the PropertyDescriptors for the wrapped object
|
||||
@@ -79,11 +79,13 @@ public interface BeanWrapper extends ConfigurablePropertyAccessor {
|
||||
PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;
|
||||
|
||||
/**
|
||||
* Set whether this BeanWrapper should attempt to "auto-grow" a nested path that contains a null value.
|
||||
* <p>If "true", a null path location will be populated with a default object value and traversed
|
||||
* instead of resulting in a {@link NullValueInNestedPathException}. Turning this flag on also
|
||||
* enables auto-growth of collection elements when accessing an out-of-bounds index.
|
||||
* <p>Default is "false" on a plain BeanWrapper.
|
||||
* Set whether this BeanWrapper should attempt to "auto-grow" a
|
||||
* nested path that contains a {@code null} value.
|
||||
* <p>If {@code true}, a {@code null} path location will be populated
|
||||
* with a default object value and traversed instead of resulting in a
|
||||
* {@link NullValueInNestedPathException}. Turning this flag on also enables
|
||||
* auto-growth of collection elements when accessing an out-of-bounds index.
|
||||
* <p>Default is {@code false} on a plain BeanWrapper.
|
||||
*/
|
||||
void setAutoGrowNestedPaths(boolean autoGrowNestedPaths);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -223,7 +223,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
return this.object;
|
||||
}
|
||||
|
||||
public final Class getWrappedClass() {
|
||||
public final Class<?> getWrappedClass() {
|
||||
return (this.object != null ? this.object.getClass() : null);
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
* Return the class of the root object at the top of the path of this BeanWrapper.
|
||||
* @see #getNestedPath
|
||||
*/
|
||||
public final Class getRootClass() {
|
||||
public final Class<?> getRootClass() {
|
||||
return (this.rootObject != null ? this.rootObject.getClass() : null);
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
* Needs to be called when the target object changes.
|
||||
* @param clazz the class to introspect
|
||||
*/
|
||||
protected void setIntrospectionClass(Class clazz) {
|
||||
protected void setIntrospectionClass(Class<?> clazz) {
|
||||
if (this.cachedIntrospectionResults != null &&
|
||||
!clazz.equals(this.cachedIntrospectionResults.getBeanClass())) {
|
||||
this.cachedIntrospectionResults = null;
|
||||
@@ -352,7 +352,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getPropertyType(String propertyName) throws BeansException {
|
||||
public Class<?> getPropertyType(String propertyName) throws BeansException {
|
||||
try {
|
||||
PropertyDescriptor pd = getPropertyDescriptorInternal(propertyName);
|
||||
if (pd != null) {
|
||||
@@ -366,7 +366,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
// Check to see if there is a custom editor,
|
||||
// which might give an indication on the desired target type.
|
||||
Class editorType = guessPropertyTypeFromEditors(propertyName);
|
||||
Class<?> editorType = guessPropertyTypeFromEditors(propertyName);
|
||||
if (editorType != null) {
|
||||
return editorType;
|
||||
}
|
||||
@@ -485,13 +485,13 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"No property '" + propertyName + "' found");
|
||||
}
|
||||
return convertForProperty(propertyName, null, value, pd);
|
||||
return convertForProperty(propertyName, null, value, new TypeDescriptor(property(pd)));
|
||||
}
|
||||
|
||||
private Object convertForProperty(String propertyName, Object oldValue, Object newValue, PropertyDescriptor pd)
|
||||
private Object convertForProperty(String propertyName, Object oldValue, Object newValue, TypeDescriptor td)
|
||||
throws TypeMismatchException {
|
||||
|
||||
return convertIfNecessary(propertyName, oldValue, newValue, pd.getPropertyType(), new TypeDescriptor(property(pd)));
|
||||
return convertIfNecessary(propertyName, oldValue, newValue, td.getType(), td);
|
||||
}
|
||||
|
||||
private Property property(PropertyDescriptor pd) {
|
||||
@@ -699,7 +699,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
return nestedBw.getPropertyValue(tokens);
|
||||
}
|
||||
|
||||
private Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {
|
||||
String propertyName = tokens.canonicalName;
|
||||
String actualName = tokens.actualName;
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
|
||||
@@ -766,20 +767,20 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
else if (value instanceof List) {
|
||||
int index = Integer.parseInt(key);
|
||||
List list = (List) value;
|
||||
List<Object> list = (List<Object>) value;
|
||||
growCollectionIfNecessary(list, index, indexedPropertyName, pd, i + 1);
|
||||
value = list.get(index);
|
||||
}
|
||||
else if (value instanceof Set) {
|
||||
// Apply index to Iterator in case of a Set.
|
||||
Set set = (Set) value;
|
||||
Set<Object> set = (Set<Object>) value;
|
||||
int index = Integer.parseInt(key);
|
||||
if (index < 0 || index >= set.size()) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot get element with index " + index + " from Set of size " +
|
||||
set.size() + ", accessed using property path '" + propertyName + "'");
|
||||
}
|
||||
Iterator it = set.iterator();
|
||||
Iterator<Object> it = set.iterator();
|
||||
for (int j = 0; it.hasNext(); j++) {
|
||||
Object elem = it.next();
|
||||
if (j == index) {
|
||||
@@ -789,11 +790,12 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
else if (value instanceof Map) {
|
||||
Map map = (Map) value;
|
||||
Map<Object, Object> map = (Map<Object, Object>) value;
|
||||
Class<?> mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(pd.getReadMethod(), i + 1);
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
TypeDescriptor typeDescriptor = mapKeyType != null ? TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class);
|
||||
TypeDescriptor typeDescriptor = (mapKeyType != null ?
|
||||
TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class));
|
||||
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
|
||||
value = map.get(convertedMapKey);
|
||||
}
|
||||
@@ -850,16 +852,15 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void growCollectionIfNecessary(
|
||||
Collection collection, int index, String name, PropertyDescriptor pd, int nestingLevel) {
|
||||
private void growCollectionIfNecessary(Collection<Object> collection, int index, String name,
|
||||
PropertyDescriptor pd, int nestingLevel) {
|
||||
|
||||
if (!this.autoGrowNestedPaths) {
|
||||
return;
|
||||
}
|
||||
int size = collection.size();
|
||||
if (index >= size && index < this.autoGrowCollectionLimit) {
|
||||
Class elementType = GenericCollectionTypeResolver.getCollectionReturnType(pd.getReadMethod(), nestingLevel);
|
||||
Class<?> elementType = GenericCollectionTypeResolver.getCollectionReturnType(pd.getReadMethod(), nestingLevel);
|
||||
if (elementType != null) {
|
||||
for (int i = collection.size(); i < index + 1; i++) {
|
||||
collection.add(newValue(elementType, name));
|
||||
@@ -945,7 +946,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
if (propValue.getClass().isArray()) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
|
||||
Class requiredType = propValue.getClass().getComponentType();
|
||||
Class<?> requiredType = propValue.getClass().getComponentType();
|
||||
int arrayIndex = Integer.parseInt(key);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
@@ -963,9 +964,9 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
else if (propValue instanceof List) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
|
||||
Class requiredType = GenericCollectionTypeResolver.getCollectionReturnType(
|
||||
Class<?> requiredType = GenericCollectionTypeResolver.getCollectionReturnType(
|
||||
pd.getReadMethod(), tokens.keys.length);
|
||||
List list = (List) propValue;
|
||||
List<Object> list = (List<Object>) propValue;
|
||||
int index = Integer.parseInt(key);
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor() && index < list.size()) {
|
||||
@@ -1000,11 +1001,11 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
else if (propValue instanceof Map) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
|
||||
Class mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(
|
||||
Class<?> mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(
|
||||
pd.getReadMethod(), tokens.keys.length);
|
||||
Class mapValueType = GenericCollectionTypeResolver.getMapValueReturnType(
|
||||
Class<?> mapValueType = GenericCollectionTypeResolver.getMapValueReturnType(
|
||||
pd.getReadMethod(), tokens.keys.length);
|
||||
Map map = (Map) propValue;
|
||||
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 = (mapKeyType != null ?
|
||||
@@ -1094,7 +1095,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
}
|
||||
valueToApply = convertForProperty(propertyName, oldValue, originalValue, pd);
|
||||
valueToApply = convertForProperty(
|
||||
propertyName, oldValue, originalValue, new TypeDescriptor(property(pd)));
|
||||
}
|
||||
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
|
||||
}
|
||||
|
||||
+72
-32
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,6 +33,7 @@ import java.util.WeakHashMap;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.SpringProperties;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -50,6 +51,18 @@ import org.springframework.util.StringUtils;
|
||||
* implements the factory design pattern, using a private constructor and
|
||||
* a static {@link #forClass(Class)} factory method to obtain instances.
|
||||
*
|
||||
* <p>Note that for caching to work effectively, some preconditions need to be met:
|
||||
* Prefer an arrangement where the Spring jars live in the same ClassLoader as the
|
||||
* application classes, which allows for clean caching along with the application's
|
||||
* lifecycle in any case. For a web application, consider declaring a local
|
||||
* {@link org.springframework.web.util.IntrospectorCleanupListener} in {@code web.xml}
|
||||
* in case of a multi-ClassLoader layout, which will allow for effective caching as well.
|
||||
*
|
||||
* <p>In case of a non-clean ClassLoader arrangement without a cleanup listener having
|
||||
* been set up, this class will fall back to a weak-reference-based caching model that
|
||||
* recreates much-requested entries every time the garbage collector removed them. In
|
||||
* such a scenario, consider the {@link #IGNORE_BEANINFO_PROPERTY_NAME} system property.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 05 May 2001
|
||||
@@ -59,11 +72,34 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class CachedIntrospectionResults {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class);
|
||||
/**
|
||||
* System property that instructs Spring to use the {@link Introspector#IGNORE_ALL_BEANINFO}
|
||||
* mode when calling the JavaBeans {@link Introspector}: "spring.beaninfo.ignore", with a
|
||||
* value of "true" skipping the search for {@code BeanInfo} classes (typically for scenarios
|
||||
* where no such classes are being defined for beans in the application in the first place).
|
||||
* <p>The default is "false", considering all {@code BeanInfo} metadata classes, like for
|
||||
* standard {@link Introspector#getBeanInfo(Class)} calls. Consider switching this flag to
|
||||
* "true" if you experience repeated ClassLoader access for non-existing {@code BeanInfo}
|
||||
* classes, in case such access is expensive on startup or on lazy loading.
|
||||
* <p>Note that such an effect may also indicate a scenario where caching doesn't work
|
||||
* effectively: Prefer an arrangement where the Spring jars live in the same ClassLoader
|
||||
* as the application classes, which allows for clean caching along with the application's
|
||||
* lifecycle in any case. For a web application, consider declaring a local
|
||||
* {@link org.springframework.web.util.IntrospectorCleanupListener} in {@code web.xml}
|
||||
* in case of a multi-ClassLoader layout, which will allow for effective caching as well.
|
||||
* @see Introspector#getBeanInfo(Class, int)
|
||||
*/
|
||||
public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";
|
||||
|
||||
|
||||
private static final boolean shouldIntrospectorIgnoreBeaninfoClasses =
|
||||
SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME);
|
||||
|
||||
/** Stores the BeanInfoFactory instances */
|
||||
private static List<BeanInfoFactory> beanInfoFactories =
|
||||
SpringFactoriesLoader.loadFactories(BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());
|
||||
private static List<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories(
|
||||
BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class);
|
||||
|
||||
/**
|
||||
* Set of ClassLoaders that this CachedIntrospectionResults class will always
|
||||
@@ -76,7 +112,7 @@ public class CachedIntrospectionResults {
|
||||
* Needs to be a WeakHashMap with WeakReferences as values to allow
|
||||
* for proper garbage collection in case of multiple class loaders.
|
||||
*/
|
||||
static final Map<Class, Object> classCache = new WeakHashMap<Class, Object>();
|
||||
static final Map<Class<?>, Object> classCache = new WeakHashMap<Class<?>, Object>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -101,15 +137,14 @@ public class CachedIntrospectionResults {
|
||||
|
||||
/**
|
||||
* Clear the introspection cache for the given ClassLoader, removing the
|
||||
* introspection results for all classes underneath that ClassLoader,
|
||||
* and deregistering the ClassLoader (and any of its children) from the
|
||||
* acceptance list.
|
||||
* introspection results for all classes underneath that ClassLoader, and
|
||||
* removing the ClassLoader (and its children) from the acceptance list.
|
||||
* @param classLoader the ClassLoader to clear the cache for
|
||||
*/
|
||||
public static void clearClassLoader(ClassLoader classLoader) {
|
||||
synchronized (classCache) {
|
||||
for (Iterator<Class> it = classCache.keySet().iterator(); it.hasNext();) {
|
||||
Class beanClass = it.next();
|
||||
for (Iterator<Class<?>> it = classCache.keySet().iterator(); it.hasNext();) {
|
||||
Class<?> beanClass = it.next();
|
||||
if (isUnderneathClassLoader(beanClass.getClassLoader(), classLoader)) {
|
||||
it.remove();
|
||||
}
|
||||
@@ -127,21 +162,20 @@ public class CachedIntrospectionResults {
|
||||
|
||||
/**
|
||||
* Create CachedIntrospectionResults for the given bean class.
|
||||
* <P>We don't want to use synchronization here. Object references are atomic,
|
||||
* so we can live with doing the occasional unnecessary lookup at startup only.
|
||||
* @param beanClass the bean class to analyze
|
||||
* @return the corresponding CachedIntrospectionResults
|
||||
* @throws BeansException in case of introspection failure
|
||||
*/
|
||||
static CachedIntrospectionResults forClass(Class beanClass) throws BeansException {
|
||||
@SuppressWarnings("unchecked")
|
||||
static CachedIntrospectionResults forClass(Class<?> beanClass) throws BeansException {
|
||||
CachedIntrospectionResults results;
|
||||
Object value;
|
||||
synchronized (classCache) {
|
||||
value = classCache.get(beanClass);
|
||||
}
|
||||
if (value instanceof Reference) {
|
||||
Reference ref = (Reference) value;
|
||||
results = (CachedIntrospectionResults) ref.get();
|
||||
Reference<CachedIntrospectionResults> ref = (Reference<CachedIntrospectionResults>) value;
|
||||
results = ref.get();
|
||||
}
|
||||
else {
|
||||
results = (CachedIntrospectionResults) value;
|
||||
@@ -181,8 +215,8 @@ public class CachedIntrospectionResults {
|
||||
synchronized (acceptedClassLoaders) {
|
||||
acceptedLoaderArray = acceptedClassLoaders.toArray(new ClassLoader[acceptedClassLoaders.size()]);
|
||||
}
|
||||
for (ClassLoader registeredLoader : acceptedLoaderArray) {
|
||||
if (isUnderneathClassLoader(classLoader, registeredLoader)) {
|
||||
for (ClassLoader acceptedLoader : acceptedLoaderArray) {
|
||||
if (isUnderneathClassLoader(classLoader, acceptedLoader)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -225,7 +259,7 @@ public class CachedIntrospectionResults {
|
||||
* @param beanClass the bean class to analyze
|
||||
* @throws BeansException in case of introspection failure
|
||||
*/
|
||||
private CachedIntrospectionResults(Class beanClass) throws BeansException {
|
||||
private CachedIntrospectionResults(Class<?> beanClass) throws BeansException {
|
||||
try {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Getting BeanInfo for class [" + beanClass.getName() + "]");
|
||||
@@ -240,20 +274,25 @@ public class CachedIntrospectionResults {
|
||||
}
|
||||
if (beanInfo == null) {
|
||||
// If none of the factories supported the class, fall back to the default
|
||||
beanInfo = Introspector.getBeanInfo(beanClass);
|
||||
beanInfo = (shouldIntrospectorIgnoreBeaninfoClasses ?
|
||||
Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) :
|
||||
Introspector.getBeanInfo(beanClass));
|
||||
}
|
||||
this.beanInfo = beanInfo;
|
||||
|
||||
// Immediately remove class from Introspector cache, to allow for proper
|
||||
// garbage collection on class loader shutdown - we cache it here anyway,
|
||||
// in a GC-friendly manner. In contrast to CachedIntrospectionResults,
|
||||
// Introspector does not use WeakReferences as values of its WeakHashMap!
|
||||
Class classToFlush = beanClass;
|
||||
do {
|
||||
Introspector.flushFromCaches(classToFlush);
|
||||
classToFlush = classToFlush.getSuperclass();
|
||||
// Only bother with flushFromCaches if the Introspector actually cached...
|
||||
if (!shouldIntrospectorIgnoreBeaninfoClasses) {
|
||||
// Immediately remove class from Introspector cache, to allow for proper
|
||||
// garbage collection on class loader shutdown - we cache it here anyway,
|
||||
// in a GC-friendly manner. In contrast to CachedIntrospectionResults,
|
||||
// Introspector does not use WeakReferences as values of its WeakHashMap!
|
||||
Class<?> classToFlush = beanClass;
|
||||
do {
|
||||
Introspector.flushFromCaches(classToFlush);
|
||||
classToFlush = classToFlush.getSuperclass();
|
||||
}
|
||||
while (classToFlush != null && classToFlush != Object.class);
|
||||
}
|
||||
while (classToFlush != null);
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]");
|
||||
@@ -263,8 +302,9 @@ public class CachedIntrospectionResults {
|
||||
// This call is slow so we do it once.
|
||||
PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
|
||||
for (PropertyDescriptor pd : pds) {
|
||||
if (Class.class.equals(beanClass) && "classLoader".equals(pd.getName())) {
|
||||
// Ignore Class.getClassLoader() method - nobody needs to bind to that
|
||||
if (Class.class.equals(beanClass) &&
|
||||
("classLoader".equals(pd.getName()) || "protectionDomain".equals(pd.getName()))) {
|
||||
// Ignore Class.getClassLoader() and getProtectionDomain() methods - nobody needs to bind to those
|
||||
continue;
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
@@ -286,7 +326,7 @@ public class CachedIntrospectionResults {
|
||||
return this.beanInfo;
|
||||
}
|
||||
|
||||
Class getBeanClass() {
|
||||
Class<?> getBeanClass() {
|
||||
return this.beanInfo.getBeanDescriptor().getBeanClass();
|
||||
}
|
||||
|
||||
@@ -314,7 +354,7 @@ public class CachedIntrospectionResults {
|
||||
return pds;
|
||||
}
|
||||
|
||||
private PropertyDescriptor buildGenericTypeAwarePropertyDescriptor(Class beanClass, PropertyDescriptor pd) {
|
||||
private PropertyDescriptor buildGenericTypeAwarePropertyDescriptor(Class<?> beanClass, PropertyDescriptor pd) {
|
||||
try {
|
||||
return new GenericTypeAwarePropertyDescriptor(beanClass, pd.getName(), pd.getReadMethod(),
|
||||
pd.getWriteMethod(), pd.getPropertyEditorClass());
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.beans;
|
||||
|
||||
import java.awt.Image;
|
||||
|
||||
import java.beans.BeanDescriptor;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.EventSetDescriptor;
|
||||
@@ -26,10 +25,8 @@ import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.MethodDescriptor;
|
||||
import java.beans.PropertyDescriptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -44,7 +41,7 @@ import static org.springframework.beans.PropertyDescriptorUtils.*;
|
||||
* Decorator for a standard {@link BeanInfo} object, e.g. as created by
|
||||
* {@link Introspector#getBeanInfo(Class)}, designed to discover and register static
|
||||
* and/or non-void returning setter methods. For example:
|
||||
* <pre>{@code
|
||||
* <pre class="code">
|
||||
* public class Bean {
|
||||
* private Foo foo;
|
||||
*
|
||||
@@ -56,7 +53,7 @@ import static org.springframework.beans.PropertyDescriptorUtils.*;
|
||||
* this.foo = foo;
|
||||
* return this;
|
||||
* }
|
||||
* }}</pre>
|
||||
* }</pre>
|
||||
* The standard JavaBeans {@code Introspector} will discover the {@code getFoo} read
|
||||
* method, but will bypass the {@code #setFoo(Foo)} write method, because its non-void
|
||||
* returning signature does not comply with the JavaBeans specification.
|
||||
@@ -84,8 +81,8 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
|
||||
/**
|
||||
* Wrap the given {@link BeanInfo} instance; copy all its existing property descriptors
|
||||
* locally, wrapping each in a custom {@link SimpleIndexedPropertyDescriptor indexed} or
|
||||
* {@link SimpleNonIndexedPropertyDescriptor non-indexed} {@code PropertyDescriptor}
|
||||
* locally, wrapping each in a custom {@link SimpleIndexedPropertyDescriptor indexed}
|
||||
* or {@link SimplePropertyDescriptor non-indexed} {@code PropertyDescriptor}
|
||||
* variant that bypasses default JDK weak/soft reference management; then search
|
||||
* through its method descriptors to find any non-void returning write methods and
|
||||
* update or create the corresponding {@link PropertyDescriptor} for each one found.
|
||||
@@ -96,15 +93,16 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
*/
|
||||
public ExtendedBeanInfo(BeanInfo delegate) throws IntrospectionException {
|
||||
this.delegate = delegate;
|
||||
|
||||
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
|
||||
this.propertyDescriptors.add(pd instanceof IndexedPropertyDescriptor ?
|
||||
new SimpleIndexedPropertyDescriptor((IndexedPropertyDescriptor) pd) :
|
||||
new SimpleNonIndexedPropertyDescriptor(pd));
|
||||
new SimplePropertyDescriptor(pd));
|
||||
}
|
||||
|
||||
for (Method method : findCandidateWriteMethods(delegate.getMethodDescriptors())) {
|
||||
handleCandidateWriteMethod(method);
|
||||
MethodDescriptor[] methodDescriptors = delegate.getMethodDescriptors();
|
||||
if (methodDescriptors != null) {
|
||||
for (Method method : findCandidateWriteMethods(methodDescriptors)) {
|
||||
handleCandidateWriteMethod(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,58 +130,44 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
String methodName = method.getName();
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
int nParams = parameterTypes.length;
|
||||
if (methodName.length() > 3 && methodName.startsWith("set") &&
|
||||
Modifier.isPublic(method.getModifiers()) &&
|
||||
(
|
||||
!void.class.isAssignableFrom(method.getReturnType()) ||
|
||||
Modifier.isStatic(method.getModifiers())
|
||||
) &&
|
||||
(nParams == 1 || (nParams == 2 && parameterTypes[0].equals(int.class)))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return methodName.length() > 3 && methodName.startsWith("set") && Modifier.isPublic(method.getModifiers()) &&
|
||||
(!void.class.isAssignableFrom(method.getReturnType()) || Modifier.isStatic(method.getModifiers())) &&
|
||||
(nParams == 1 || (nParams == 2 && parameterTypes[0].equals(int.class)));
|
||||
}
|
||||
|
||||
private void handleCandidateWriteMethod(Method method) throws IntrospectionException {
|
||||
int nParams = method.getParameterTypes().length;
|
||||
String propertyName = propertyNameFor(method);
|
||||
Class<?> propertyType = method.getParameterTypes()[nParams-1];
|
||||
PropertyDescriptor existingPD = findExistingPropertyDescriptor(propertyName, propertyType);
|
||||
PropertyDescriptor existingPd = findExistingPropertyDescriptor(propertyName, propertyType);
|
||||
if (nParams == 1) {
|
||||
if (existingPD == null) {
|
||||
this.propertyDescriptors.add(
|
||||
new SimpleNonIndexedPropertyDescriptor(propertyName, null, method));
|
||||
if (existingPd == null) {
|
||||
this.propertyDescriptors.add(new SimplePropertyDescriptor(propertyName, null, method));
|
||||
}
|
||||
else {
|
||||
existingPD.setWriteMethod(method);
|
||||
existingPd.setWriteMethod(method);
|
||||
}
|
||||
}
|
||||
else if (nParams == 2) {
|
||||
if (existingPD == null) {
|
||||
if (existingPd == null) {
|
||||
this.propertyDescriptors.add(
|
||||
new SimpleIndexedPropertyDescriptor(
|
||||
propertyName, null, null, null, method));
|
||||
new SimpleIndexedPropertyDescriptor(propertyName, null, null, null, method));
|
||||
}
|
||||
else if (existingPD instanceof IndexedPropertyDescriptor) {
|
||||
((IndexedPropertyDescriptor)existingPD).setIndexedWriteMethod(method);
|
||||
else if (existingPd instanceof IndexedPropertyDescriptor) {
|
||||
((IndexedPropertyDescriptor) existingPd).setIndexedWriteMethod(method);
|
||||
}
|
||||
else {
|
||||
this.propertyDescriptors.remove(existingPD);
|
||||
this.propertyDescriptors.add(
|
||||
new SimpleIndexedPropertyDescriptor(
|
||||
propertyName, existingPD.getReadMethod(),
|
||||
existingPD.getWriteMethod(), null, method));
|
||||
this.propertyDescriptors.remove(existingPd);
|
||||
this.propertyDescriptors.add(new SimpleIndexedPropertyDescriptor(
|
||||
propertyName, existingPd.getReadMethod(), existingPd.getWriteMethod(), null, method));
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
"write method must have exactly 1 or 2 parameters: " + method);
|
||||
throw new IllegalArgumentException("Write method must have exactly 1 or 2 parameters: " + method);
|
||||
}
|
||||
}
|
||||
|
||||
private PropertyDescriptor findExistingPropertyDescriptor(
|
||||
String propertyName, Class<?> propertyType) {
|
||||
|
||||
private PropertyDescriptor findExistingPropertyDescriptor(String propertyName, Class<?> propertyType) {
|
||||
for (PropertyDescriptor pd : this.propertyDescriptors) {
|
||||
final Class<?> candidateType;
|
||||
final String candidateName = pd.getName();
|
||||
@@ -191,16 +175,14 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
|
||||
candidateType = ipd.getIndexedPropertyType();
|
||||
if (candidateName.equals(propertyName) &&
|
||||
(candidateType.equals(propertyType) ||
|
||||
candidateType.equals(propertyType.getComponentType()))) {
|
||||
(candidateType.equals(propertyType) || candidateType.equals(propertyType.getComponentType()))) {
|
||||
return pd;
|
||||
}
|
||||
}
|
||||
else {
|
||||
candidateType = pd.getPropertyType();
|
||||
if (candidateName.equals(propertyName) &&
|
||||
(candidateType.equals(propertyType) ||
|
||||
propertyType.equals(candidateType.getComponentType()))) {
|
||||
(candidateType.equals(propertyType) || propertyType.equals(candidateType.getComponentType()))) {
|
||||
return pd;
|
||||
}
|
||||
}
|
||||
@@ -209,8 +191,7 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
}
|
||||
|
||||
private String propertyNameFor(Method method) {
|
||||
return Introspector.decapitalize(
|
||||
method.getName().substring(3, method.getName().length()));
|
||||
return Introspector.decapitalize(method.getName().substring(3, method.getName().length()));
|
||||
}
|
||||
|
||||
|
||||
@@ -221,65 +202,61 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
* @see #ExtendedBeanInfo(BeanInfo)
|
||||
*/
|
||||
public PropertyDescriptor[] getPropertyDescriptors() {
|
||||
return this.propertyDescriptors.toArray(
|
||||
new PropertyDescriptor[this.propertyDescriptors.size()]);
|
||||
return this.propertyDescriptors.toArray(new PropertyDescriptor[this.propertyDescriptors.size()]);
|
||||
}
|
||||
|
||||
public BeanInfo[] getAdditionalBeanInfo() {
|
||||
return delegate.getAdditionalBeanInfo();
|
||||
return this.delegate.getAdditionalBeanInfo();
|
||||
}
|
||||
|
||||
public BeanDescriptor getBeanDescriptor() {
|
||||
return delegate.getBeanDescriptor();
|
||||
return this.delegate.getBeanDescriptor();
|
||||
}
|
||||
|
||||
public int getDefaultEventIndex() {
|
||||
return delegate.getDefaultEventIndex();
|
||||
return this.delegate.getDefaultEventIndex();
|
||||
}
|
||||
|
||||
public int getDefaultPropertyIndex() {
|
||||
return delegate.getDefaultPropertyIndex();
|
||||
return this.delegate.getDefaultPropertyIndex();
|
||||
}
|
||||
|
||||
public EventSetDescriptor[] getEventSetDescriptors() {
|
||||
return delegate.getEventSetDescriptors();
|
||||
return this.delegate.getEventSetDescriptors();
|
||||
}
|
||||
|
||||
public Image getIcon(int iconKind) {
|
||||
return delegate.getIcon(iconKind);
|
||||
return this.delegate.getIcon(iconKind);
|
||||
}
|
||||
|
||||
public MethodDescriptor[] getMethodDescriptors() {
|
||||
return delegate.getMethodDescriptors();
|
||||
return this.delegate.getMethodDescriptors();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
|
||||
class SimplePropertyDescriptor extends PropertyDescriptor {
|
||||
|
||||
private Method readMethod;
|
||||
|
||||
private Method writeMethod;
|
||||
|
||||
private Class<?> propertyType;
|
||||
|
||||
private Class<?> propertyEditorClass;
|
||||
|
||||
|
||||
public SimpleNonIndexedPropertyDescriptor(PropertyDescriptor original)
|
||||
throws IntrospectionException {
|
||||
|
||||
public SimplePropertyDescriptor(PropertyDescriptor original) throws IntrospectionException {
|
||||
this(original.getName(), original.getReadMethod(), original.getWriteMethod());
|
||||
copyNonMethodProperties(original, this);
|
||||
}
|
||||
|
||||
public SimpleNonIndexedPropertyDescriptor(String propertyName,
|
||||
Method readMethod, Method writeMethod) throws IntrospectionException {
|
||||
|
||||
public SimplePropertyDescriptor(String propertyName, Method readMethod, Method writeMethod) throws IntrospectionException {
|
||||
super(propertyName, null, null);
|
||||
this.setReadMethod(readMethod);
|
||||
this.setWriteMethod(writeMethod);
|
||||
this.readMethod = readMethod;
|
||||
this.writeMethod = writeMethod;
|
||||
this.propertyType = findPropertyType(readMethod, writeMethod);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Method getReadMethod() {
|
||||
return this.readMethod;
|
||||
@@ -305,8 +282,9 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
|
||||
if (this.propertyType == null) {
|
||||
try {
|
||||
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
|
||||
} catch (IntrospectionException ex) {
|
||||
// ignore, as does PropertyDescriptor#getPropertyType
|
||||
}
|
||||
catch (IntrospectionException ex) {
|
||||
// Ignore, as does PropertyDescriptor#getPropertyType
|
||||
}
|
||||
}
|
||||
return this.propertyType;
|
||||
@@ -322,7 +300,6 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
|
||||
this.propertyEditorClass = propertyEditorClass;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return PropertyDescriptorUtils.equals(this, obj);
|
||||
@@ -331,8 +308,7 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s[name=%s, propertyType=%s, readMethod=%s, writeMethod=%s]",
|
||||
this.getClass().getSimpleName(), this.getName(), this.getPropertyType(),
|
||||
this.readMethod, this.writeMethod);
|
||||
getClass().getSimpleName(), getName(), getPropertyType(), this.readMethod, this.writeMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,40 +316,37 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
|
||||
class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
|
||||
|
||||
private Method readMethod;
|
||||
|
||||
private Method writeMethod;
|
||||
|
||||
private Class<?> propertyType;
|
||||
private Class<?> propertyEditorClass;
|
||||
|
||||
private Method indexedReadMethod;
|
||||
|
||||
private Method indexedWriteMethod;
|
||||
|
||||
private Class<?> indexedPropertyType;
|
||||
|
||||
private Class<?> propertyEditorClass;
|
||||
|
||||
public SimpleIndexedPropertyDescriptor(IndexedPropertyDescriptor original)
|
||||
throws IntrospectionException {
|
||||
|
||||
public SimpleIndexedPropertyDescriptor(IndexedPropertyDescriptor original) throws IntrospectionException {
|
||||
this(original.getName(), original.getReadMethod(), original.getWriteMethod(),
|
||||
original.getIndexedReadMethod(), original.getIndexedWriteMethod());
|
||||
copyNonMethodProperties(original, this);
|
||||
}
|
||||
|
||||
public SimpleIndexedPropertyDescriptor(String propertyName,
|
||||
Method readMethod, Method writeMethod,
|
||||
Method indexedReadMethod, Method indexedWriteMethod)
|
||||
throws IntrospectionException {
|
||||
public SimpleIndexedPropertyDescriptor(String propertyName, Method readMethod, Method writeMethod,
|
||||
Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException {
|
||||
|
||||
super(propertyName, null, null, null, null);
|
||||
this.setReadMethod(readMethod);
|
||||
this.setWriteMethod(writeMethod);
|
||||
this.readMethod = readMethod;
|
||||
this.writeMethod = writeMethod;
|
||||
this.propertyType = findPropertyType(readMethod, writeMethod);
|
||||
|
||||
this.setIndexedReadMethod(indexedReadMethod);
|
||||
this.setIndexedWriteMethod(indexedWriteMethod);
|
||||
this.indexedPropertyType = findIndexedPropertyType(
|
||||
this.getName(), this.propertyType, indexedReadMethod, indexedWriteMethod);
|
||||
this.indexedReadMethod = indexedReadMethod;
|
||||
this.indexedWriteMethod = indexedWriteMethod;
|
||||
this.indexedPropertyType = findIndexedPropertyType(propertyName, this.propertyType, indexedReadMethod, indexedWriteMethod);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Method getReadMethod() {
|
||||
return this.readMethod;
|
||||
@@ -399,8 +372,9 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
|
||||
if (this.propertyType == null) {
|
||||
try {
|
||||
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
|
||||
} catch (IntrospectionException ex) {
|
||||
// ignore, as does IndexedPropertyDescriptor#getPropertyType
|
||||
}
|
||||
catch (IntrospectionException ex) {
|
||||
// Ignore, as does IndexedPropertyDescriptor#getPropertyType
|
||||
}
|
||||
}
|
||||
return this.propertyType;
|
||||
@@ -431,10 +405,10 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
|
||||
if (this.indexedPropertyType == null) {
|
||||
try {
|
||||
this.indexedPropertyType = findIndexedPropertyType(
|
||||
this.getName(), this.getPropertyType(),
|
||||
this.indexedReadMethod, this.indexedWriteMethod);
|
||||
} catch (IntrospectionException ex) {
|
||||
// ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
|
||||
getName(), getPropertyType(), this.indexedReadMethod, this.indexedWriteMethod);
|
||||
}
|
||||
catch (IntrospectionException ex) {
|
||||
// Ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
|
||||
}
|
||||
}
|
||||
return this.indexedPropertyType;
|
||||
@@ -450,26 +424,22 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
|
||||
this.propertyEditorClass = propertyEditorClass;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @see java.beans.IndexedPropertyDescriptor#equals(java.lang.Object)
|
||||
* See java.beans.IndexedPropertyDescriptor#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj != null && obj instanceof IndexedPropertyDescriptor) {
|
||||
IndexedPropertyDescriptor other = (IndexedPropertyDescriptor) obj;
|
||||
if (!compareMethods(getIndexedReadMethod(), other.getIndexedReadMethod())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!compareMethods(getIndexedWriteMethod(), other.getIndexedWriteMethod())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getIndexedPropertyType() != other.getIndexedPropertyType()) {
|
||||
return false;
|
||||
}
|
||||
@@ -482,9 +452,8 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
|
||||
public String toString() {
|
||||
return String.format("%s[name=%s, propertyType=%s, indexedPropertyType=%s, " +
|
||||
"readMethod=%s, writeMethod=%s, indexedReadMethod=%s, indexedWriteMethod=%s]",
|
||||
this.getClass().getSimpleName(), this.getName(), this.getPropertyType(),
|
||||
this.getIndexedPropertyType(), this.readMethod, this.writeMethod,
|
||||
this.indexedReadMethod, this.indexedWriteMethod);
|
||||
getClass().getSimpleName(), getName(), getPropertyType(), getIndexedPropertyType(),
|
||||
this.readMethod, this.writeMethod, this.indexedReadMethod, this.indexedWriteMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +461,7 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
|
||||
class PropertyDescriptorUtils {
|
||||
|
||||
/*
|
||||
* see java.beans.FeatureDescriptor#FeatureDescriptor(FeatureDescriptor)
|
||||
* See java.beans.FeatureDescriptor#FeatureDescriptor(FeatureDescriptor)
|
||||
*/
|
||||
public static void copyNonMethodProperties(PropertyDescriptor source, PropertyDescriptor target)
|
||||
throws IntrospectionException {
|
||||
@@ -504,14 +473,14 @@ class PropertyDescriptorUtils {
|
||||
target.setShortDescription(source.getShortDescription());
|
||||
target.setDisplayName(source.getDisplayName());
|
||||
|
||||
// copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
|
||||
// Copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
|
||||
Enumeration<String> keys = source.attributeNames();
|
||||
while (keys.hasMoreElements()) {
|
||||
String key = keys.nextElement();
|
||||
target.setValue(key, source.getValue(key));
|
||||
}
|
||||
|
||||
// see java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
|
||||
// See java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
|
||||
target.setPropertyEditorClass(source.getPropertyEditorClass());
|
||||
target.setBound(source.isBound());
|
||||
target.setConstrained(source.isConstrained());
|
||||
@@ -520,32 +489,39 @@ class PropertyDescriptorUtils {
|
||||
/*
|
||||
* See PropertyDescriptor#findPropertyType
|
||||
*/
|
||||
public static Class<?> findPropertyType(Method readMethod, Method writeMethod)
|
||||
throws IntrospectionException {
|
||||
|
||||
public static Class<?> findPropertyType(Method readMethod, Method writeMethod) throws IntrospectionException {
|
||||
Class<?> propertyType = null;
|
||||
|
||||
if (readMethod != null) {
|
||||
Class<?>[] params = readMethod.getParameterTypes();
|
||||
if (params.length != 0) {
|
||||
throw new IntrospectionException("bad read method arg count: " + readMethod);
|
||||
throw new IntrospectionException("Bad read method arg count: " + readMethod);
|
||||
}
|
||||
propertyType = readMethod.getReturnType();
|
||||
if (propertyType == Void.TYPE) {
|
||||
throw new IntrospectionException("read method "
|
||||
+ readMethod.getName() + " returns void");
|
||||
throw new IntrospectionException("Read method returns void: " + readMethod);
|
||||
}
|
||||
}
|
||||
if (writeMethod != null) {
|
||||
Class<?> params[] = writeMethod.getParameterTypes();
|
||||
if (params.length != 1) {
|
||||
throw new IntrospectionException("bad write method arg count: " + writeMethod);
|
||||
throw new IntrospectionException("Bad write method arg count: " + writeMethod);
|
||||
}
|
||||
if (propertyType != null
|
||||
&& !params[0].isAssignableFrom(propertyType)) {
|
||||
throw new IntrospectionException("type mismatch between read and write methods");
|
||||
if (propertyType != null) {
|
||||
if (propertyType.isAssignableFrom(params[0])) {
|
||||
// Write method's property type potentially more specific
|
||||
propertyType = params[0];
|
||||
}
|
||||
else if (params[0].isAssignableFrom(propertyType)) {
|
||||
// Proceed with read method's property type
|
||||
}
|
||||
else {
|
||||
throw new IntrospectionException(
|
||||
"Type mismatch between read and write methods: " + readMethod + " - " + writeMethod);
|
||||
}
|
||||
}
|
||||
else {
|
||||
propertyType = params[0];
|
||||
}
|
||||
propertyType = params[0];
|
||||
}
|
||||
return propertyType;
|
||||
}
|
||||
@@ -554,48 +530,51 @@ class PropertyDescriptorUtils {
|
||||
* See IndexedPropertyDescriptor#findIndexedPropertyType
|
||||
*/
|
||||
public static Class<?> findIndexedPropertyType(String name, Class<?> propertyType,
|
||||
Method indexedReadMethod, Method indexedWriteMethod)
|
||||
throws IntrospectionException {
|
||||
Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException {
|
||||
|
||||
Class<?> indexedPropertyType = null;
|
||||
|
||||
if (indexedReadMethod != null) {
|
||||
Class<?> params[] = indexedReadMethod.getParameterTypes();
|
||||
if (params.length != 1) {
|
||||
throw new IntrospectionException(
|
||||
"bad indexed read method arg count");
|
||||
throw new IntrospectionException("Bad indexed read method arg count: " + indexedReadMethod);
|
||||
}
|
||||
if (params[0] != Integer.TYPE) {
|
||||
throw new IntrospectionException(
|
||||
"non int index to indexed read method");
|
||||
throw new IntrospectionException("Non int index to indexed read method: " + indexedReadMethod);
|
||||
}
|
||||
indexedPropertyType = indexedReadMethod.getReturnType();
|
||||
if (indexedPropertyType == Void.TYPE) {
|
||||
throw new IntrospectionException(
|
||||
"indexed read method returns void");
|
||||
throw new IntrospectionException("Indexed read method returns void: " + indexedReadMethod);
|
||||
}
|
||||
}
|
||||
if (indexedWriteMethod != null) {
|
||||
Class<?> params[] = indexedWriteMethod.getParameterTypes();
|
||||
if (params.length != 2) {
|
||||
throw new IntrospectionException(
|
||||
"bad indexed write method arg count");
|
||||
throw new IntrospectionException("Bad indexed write method arg count: " + indexedWriteMethod);
|
||||
}
|
||||
if (params[0] != Integer.TYPE) {
|
||||
throw new IntrospectionException(
|
||||
"non int index to indexed write method");
|
||||
throw new IntrospectionException("Non int index to indexed write method: " + indexedWriteMethod);
|
||||
}
|
||||
if (indexedPropertyType != null && indexedPropertyType != params[1]) {
|
||||
throw new IntrospectionException(
|
||||
"type mismatch between indexed read and indexed write methods: " + name);
|
||||
if (indexedPropertyType != null) {
|
||||
if (indexedPropertyType.isAssignableFrom(params[1])) {
|
||||
// Write method's property type potentially more specific
|
||||
indexedPropertyType = params[1];
|
||||
}
|
||||
else if (params[1].isAssignableFrom(indexedPropertyType)) {
|
||||
// Proceed with read method's property type
|
||||
}
|
||||
else {
|
||||
throw new IntrospectionException("Type mismatch between indexed read and write methods: " +
|
||||
indexedReadMethod + " - " + indexedWriteMethod);
|
||||
}
|
||||
}
|
||||
else {
|
||||
indexedPropertyType = params[1];
|
||||
}
|
||||
indexedPropertyType = params[1];
|
||||
}
|
||||
if (propertyType != null
|
||||
&& (!propertyType.isArray() ||
|
||||
propertyType.getComponentType() != indexedPropertyType)) {
|
||||
throw new IntrospectionException(
|
||||
"type mismatch between indexed and non-indexed methods: " + name);
|
||||
if (propertyType != null && (!propertyType.isArray() ||
|
||||
propertyType.getComponentType() != indexedPropertyType)) {
|
||||
throw new IntrospectionException("Type mismatch between indexed and non-indexed methods: " +
|
||||
indexedReadMethod + " - " + indexedWriteMethod);
|
||||
}
|
||||
return indexedPropertyType;
|
||||
}
|
||||
@@ -605,7 +584,6 @@ class PropertyDescriptorUtils {
|
||||
* return {@code true} if they are objects are equivalent, i.e. both are {@code
|
||||
* PropertyDescriptor}s whose read method, write method, property types, property
|
||||
* editor and flags are equivalent.
|
||||
*
|
||||
* @see PropertyDescriptor#equals(Object)
|
||||
*/
|
||||
public static boolean equals(PropertyDescriptor pd1, Object obj) {
|
||||
@@ -617,15 +595,12 @@ class PropertyDescriptorUtils {
|
||||
if (!compareMethods(pd1.getReadMethod(), pd2.getReadMethod())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!compareMethods(pd1.getWriteMethod(), pd2.getWriteMethod())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pd1.getPropertyType() == pd2.getPropertyType()
|
||||
&& pd1.getPropertyEditorClass() == pd2.getPropertyEditorClass()
|
||||
&& pd1.isBound() == pd2.isBound()
|
||||
&& pd1.isConstrained() == pd2.isConstrained()) {
|
||||
if (pd1.getPropertyType() == pd2.getPropertyType() &&
|
||||
pd1.getPropertyEditorClass() == pd2.getPropertyEditorClass() &&
|
||||
pd1.isBound() == pd2.isBound() && pd1.isConstrained() == pd2.isConstrained()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -633,14 +608,13 @@ class PropertyDescriptorUtils {
|
||||
}
|
||||
|
||||
/*
|
||||
* see PropertyDescriptor#compareMethods
|
||||
* See PropertyDescriptor#compareMethods
|
||||
*/
|
||||
public static boolean compareMethods(Method a, Method b) {
|
||||
if ((a == null) != (b == null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a != null && b != null) {
|
||||
if (a != null) {
|
||||
if (!a.equals(b)) {
|
||||
return false;
|
||||
}
|
||||
@@ -653,7 +627,6 @@ class PropertyDescriptorUtils {
|
||||
/**
|
||||
* Sorts PropertyDescriptor instances alpha-numerically to emulate the behavior of
|
||||
* {@link java.beans.BeanInfo#getPropertyDescriptors()}.
|
||||
*
|
||||
* @see ExtendedBeanInfo#propertyDescriptors
|
||||
*/
|
||||
class PropertyDescriptorComparator implements Comparator<PropertyDescriptor> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,8 +25,8 @@ import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* {@link BeanInfoFactory} implementation that evaluates whether bean classes have
|
||||
* "non-standard" JavaBeans setter methods and are thus candidates for introspection by
|
||||
* Spring's {@link ExtendedBeanInfo}.
|
||||
* "non-standard" JavaBeans setter methods and are thus candidates for introspection
|
||||
* by Spring's (package-visible) {@code ExtendedBeanInfo} implementation.
|
||||
*
|
||||
* <p>Ordered at {@link Ordered#LOWEST_PRECEDENCE} to allow other user-defined
|
||||
* {@link BeanInfoFactory} types to take precedence.
|
||||
@@ -34,20 +34,20 @@ import org.springframework.core.Ordered;
|
||||
* @author Chris Beams
|
||||
* @since 3.2
|
||||
* @see BeanInfoFactory
|
||||
* @see CachedIntrospectionResults
|
||||
*/
|
||||
public class ExtendedBeanInfoFactory implements Ordered, BeanInfoFactory {
|
||||
public class ExtendedBeanInfoFactory implements BeanInfoFactory, Ordered {
|
||||
|
||||
/**
|
||||
* Return a new {@link ExtendedBeanInfo} for the given bean class.
|
||||
* Return an {@link ExtendedBeanInfo} for the given bean class, if applicable.
|
||||
*/
|
||||
public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
|
||||
return supports(beanClass) ?
|
||||
new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass)) : null;
|
||||
return (supports(beanClass) ? new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass)) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given bean class declares or inherits any non-void returning
|
||||
* JavaBeans or <em>indexed property</em> setter methods.
|
||||
* Return whether the given bean class declares or inherits any non-void
|
||||
* returning bean property or indexed property setter methods.
|
||||
*/
|
||||
private boolean supports(Class<?> beanClass) {
|
||||
for (Method method : beanClass.getMethods()) {
|
||||
|
||||
+16
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,32 +31,32 @@ import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Extension of the standard JavaBeans PropertyDescriptor class,
|
||||
* overriding {@code getPropertyType()} such that a generically
|
||||
* declared type will be resolved against the containing bean class.
|
||||
* Extension of the standard JavaBeans {@link PropertyDescriptor} class,
|
||||
* overriding {@code getPropertyType()} such that a generically declared
|
||||
* type variable will be resolved against the containing bean class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.2
|
||||
*/
|
||||
class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
|
||||
|
||||
private final Class beanClass;
|
||||
private final Class<?> beanClass;
|
||||
|
||||
private final Method readMethod;
|
||||
|
||||
private final Method writeMethod;
|
||||
|
||||
private final Class propertyEditorClass;
|
||||
private final Class<?> propertyEditorClass;
|
||||
|
||||
private volatile Set<Method> ambiguousWriteMethods;
|
||||
|
||||
private Class propertyType;
|
||||
private Class<?> propertyType;
|
||||
|
||||
private MethodParameter writeMethodParameter;
|
||||
|
||||
|
||||
public GenericTypeAwarePropertyDescriptor(Class beanClass, String propertyName,
|
||||
Method readMethod, Method writeMethod, Class propertyEditorClass)
|
||||
public GenericTypeAwarePropertyDescriptor(Class<?> beanClass, String propertyName,
|
||||
Method readMethod, Method writeMethod, Class<?> propertyEditorClass)
|
||||
throws IntrospectionException {
|
||||
|
||||
super(propertyName, null, null);
|
||||
@@ -69,8 +69,11 @@ class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
|
||||
// Fallback: Original JavaBeans introspection might not have found matching setter
|
||||
// method due to lack of bridge method resolution, in case of the getter using a
|
||||
// covariant return type whereas the setter is defined for the concrete property type.
|
||||
writeMethodToUse = ClassUtils.getMethodIfAvailable(this.beanClass,
|
||||
"set" + StringUtils.capitalize(getName()), readMethodToUse.getReturnType());
|
||||
Method candidate = ClassUtils.getMethodIfAvailable(
|
||||
this.beanClass, "set" + StringUtils.capitalize(getName()), (Class<?>[]) null);
|
||||
if (candidate != null && candidate.getParameterTypes().length == 1) {
|
||||
writeMethodToUse = candidate;
|
||||
}
|
||||
}
|
||||
this.readMethod = readMethodToUse;
|
||||
this.writeMethod = writeMethodToUse;
|
||||
@@ -118,12 +121,12 @@ class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getPropertyEditorClass() {
|
||||
public Class<?> getPropertyEditorClass() {
|
||||
return this.propertyEditorClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Class getPropertyType() {
|
||||
public synchronized Class<?> getPropertyType() {
|
||||
if (this.propertyType == null) {
|
||||
if (this.readMethod != null) {
|
||||
this.propertyType = GenericTypeResolver.resolveReturnType(this.readMethod, this.beanClass);
|
||||
|
||||
@@ -187,6 +187,9 @@ class TypeConverterDelegate {
|
||||
// Try to apply some standard type conversion rules if appropriate.
|
||||
|
||||
if (convertedValue != null) {
|
||||
if (Object.class.equals(requiredType)) {
|
||||
return (T) convertedValue;
|
||||
}
|
||||
if (requiredType.isArray()) {
|
||||
// Array required -> apply appropriate conversion of elements.
|
||||
if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
|
||||
|
||||
@@ -139,7 +139,7 @@ public abstract class BeanFactoryUtils {
|
||||
* @param type the type that beans must match
|
||||
* @return the array of matching bean names, or an empty array if none
|
||||
*/
|
||||
public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, Class type) {
|
||||
public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, Class<?> type) {
|
||||
Assert.notNull(lbf, "ListableBeanFactory must not be null");
|
||||
String[] result = lbf.getBeanNamesForType(type);
|
||||
if (lbf instanceof HierarchicalBeanFactory) {
|
||||
@@ -181,7 +181,7 @@ public abstract class BeanFactoryUtils {
|
||||
* @return the array of matching bean names, or an empty array if none
|
||||
*/
|
||||
public static String[] beanNamesForTypeIncludingAncestors(
|
||||
ListableBeanFactory lbf, Class type, boolean includeNonSingletons, boolean allowEagerInit) {
|
||||
ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
|
||||
|
||||
Assert.notNull(lbf, "ListableBeanFactory must not be null");
|
||||
String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
|
||||
|
||||
+9
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -58,15 +58,19 @@ public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implem
|
||||
* allowing for ASM-based processing and avoidance of early loading of the bean class.
|
||||
* Note that this constructor is functionally equivalent to
|
||||
* {@link org.springframework.context.annotation.ScannedGenericBeanDefinition
|
||||
* ScannedGenericBeanDefinition}, however the semantics of the latter indicate that
|
||||
* a bean was discovered specifically via component-scanning as opposed to other
|
||||
* means.
|
||||
* ScannedGenericBeanDefinition}, however the semantics of the latter indicate that a
|
||||
* bean was discovered specifically via component-scanning as opposed to other means.
|
||||
* @param metadata the annotation metadata for the bean class in question
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
|
||||
Assert.notNull(metadata, "AnnotationMetadata must not be null");
|
||||
setBeanClassName(metadata.getClassName());
|
||||
if (metadata instanceof StandardAnnotationMetadata) {
|
||||
setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
|
||||
}
|
||||
else {
|
||||
setBeanClassName(metadata.getClassName());
|
||||
}
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
|
||||
+17
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,6 +59,7 @@ import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
|
||||
@@ -121,8 +122,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache =
|
||||
new ConcurrentHashMap<Class<?>, Constructor<?>[]>(64);
|
||||
|
||||
private final Map<Class<?>, InjectionMetadata> injectionMetadataCache =
|
||||
new ConcurrentHashMap<Class<?>, InjectionMetadata>(64);
|
||||
private final Map<String, InjectionMetadata> injectionMetadataCache =
|
||||
new ConcurrentHashMap<String, InjectionMetadata>(64);
|
||||
|
||||
|
||||
/**
|
||||
@@ -214,7 +215,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
|
||||
if (beanType != null) {
|
||||
InjectionMetadata metadata = findAutowiringMetadata(beanType);
|
||||
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType);
|
||||
metadata.checkConfigMembers(beanDefinition);
|
||||
}
|
||||
}
|
||||
@@ -264,10 +265,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
if (requiredConstructor == null && defaultConstructor != null) {
|
||||
candidates.add(defaultConstructor);
|
||||
}
|
||||
candidateConstructors = candidates.toArray(new Constructor[candidates.size()]);
|
||||
candidateConstructors = candidates.toArray(new Constructor<?>[candidates.size()]);
|
||||
}
|
||||
else {
|
||||
candidateConstructors = new Constructor[0];
|
||||
candidateConstructors = new Constructor<?>[0];
|
||||
}
|
||||
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
|
||||
}
|
||||
@@ -280,7 +281,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
public PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
|
||||
|
||||
InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());
|
||||
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass());
|
||||
try {
|
||||
metadata.inject(bean, beanName, pvs);
|
||||
}
|
||||
@@ -298,7 +299,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
*/
|
||||
public void processInjection(Object bean) throws BeansException {
|
||||
Class<?> clazz = bean.getClass();
|
||||
InjectionMetadata metadata = findAutowiringMetadata(clazz);
|
||||
InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz);
|
||||
try {
|
||||
metadata.inject(bean, null, null);
|
||||
}
|
||||
@@ -308,15 +309,17 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
|
||||
|
||||
private InjectionMetadata findAutowiringMetadata(Class<?> clazz) {
|
||||
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz) {
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
|
||||
if (metadata == null) {
|
||||
// Fall back to class name as cache key, for backwards compatibility with custom callers.
|
||||
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
|
||||
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
synchronized (this.injectionMetadataCache) {
|
||||
metadata = this.injectionMetadataCache.get(clazz);
|
||||
if (metadata == null) {
|
||||
metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
metadata = buildAutowiringMetadata(clazz);
|
||||
this.injectionMetadataCache.put(clazz, metadata);
|
||||
this.injectionMetadataCache.put(cacheKey, metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -48,14 +48,14 @@ public class InjectionMetadata {
|
||||
|
||||
private final Log logger = LogFactory.getLog(InjectionMetadata.class);
|
||||
|
||||
private final Class targetClass;
|
||||
private final Class<?> targetClass;
|
||||
|
||||
private final Collection<InjectedElement> injectedElements;
|
||||
|
||||
private volatile Set<InjectedElement> checkedElements;
|
||||
|
||||
|
||||
public InjectionMetadata(Class targetClass, Collection<InjectedElement> elements) {
|
||||
public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) {
|
||||
this.targetClass = targetClass;
|
||||
this.injectedElements = elements;
|
||||
}
|
||||
@@ -90,6 +90,11 @@ public class InjectionMetadata {
|
||||
}
|
||||
|
||||
|
||||
public static boolean needsRefresh(InjectionMetadata metadata, Class<?> clazz) {
|
||||
return (metadata == null || !metadata.targetClass.equals(clazz));
|
||||
}
|
||||
|
||||
|
||||
public static abstract class InjectedElement {
|
||||
|
||||
protected final Member member;
|
||||
@@ -110,7 +115,7 @@ public class InjectionMetadata {
|
||||
return this.member;
|
||||
}
|
||||
|
||||
protected final Class getResourceType() {
|
||||
protected final Class<?> getResourceType() {
|
||||
if (this.isField) {
|
||||
return ((Field) this.member).getType();
|
||||
}
|
||||
@@ -122,16 +127,16 @@ public class InjectionMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
protected final void checkResourceType(Class resourceType) {
|
||||
protected final void checkResourceType(Class<?> resourceType) {
|
||||
if (this.isField) {
|
||||
Class fieldType = ((Field) this.member).getType();
|
||||
Class<?> fieldType = ((Field) this.member).getType();
|
||||
if (!(resourceType.isAssignableFrom(fieldType) || fieldType.isAssignableFrom(resourceType))) {
|
||||
throw new IllegalStateException("Specified field type [" + fieldType +
|
||||
"] is incompatible with resource type [" + resourceType.getName() + "]");
|
||||
}
|
||||
}
|
||||
else {
|
||||
Class paramType =
|
||||
Class<?> paramType =
|
||||
(this.pd != null ? this.pd.getPropertyType() : ((Method) this.member).getParameterTypes()[0]);
|
||||
if (!(resourceType.isAssignableFrom(paramType) || paramType.isAssignableFrom(resourceType))) {
|
||||
throw new IllegalStateException("Specified parameter type [" + paramType +
|
||||
|
||||
+37
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,7 +26,9 @@ import org.springframework.beans.SimpleTypeConverter;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
|
||||
import org.springframework.beans.factory.support.AutowireCandidateResolver;
|
||||
@@ -227,17 +229,22 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
||||
|
||||
Class<? extends Annotation> type = annotation.annotationType();
|
||||
RootBeanDefinition bd = (RootBeanDefinition) bdHolder.getBeanDefinition();
|
||||
|
||||
AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName());
|
||||
if (qualifier == null) {
|
||||
qualifier = bd.getQualifier(ClassUtils.getShortName(type));
|
||||
}
|
||||
if (qualifier == null) {
|
||||
Annotation targetAnnotation = null;
|
||||
if (bd.getResolvedFactoryMethod() != null) {
|
||||
targetAnnotation = AnnotationUtils.getAnnotation(bd.getResolvedFactoryMethod(), type);
|
||||
// First, check annotation on factory method, if applicable
|
||||
Annotation targetAnnotation = getFactoryMethodAnnotation(bd, type);
|
||||
if (targetAnnotation == null) {
|
||||
RootBeanDefinition dbd = getResolvedDecoratedDefinition(bd);
|
||||
if (dbd != null) {
|
||||
targetAnnotation = getFactoryMethodAnnotation(dbd, type);
|
||||
}
|
||||
}
|
||||
if (targetAnnotation == null) {
|
||||
// look for matching annotation on the target class
|
||||
// Look for matching annotation on the target class
|
||||
if (this.beanFactory != null) {
|
||||
Class<?> beanType = this.beanFactory.getType(bdHolder.getBeanName());
|
||||
if (beanType != null) {
|
||||
@@ -252,30 +259,31 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
|
||||
if (attributes.isEmpty() && qualifier == null) {
|
||||
// if no attributes, the qualifier must be present
|
||||
// If no attributes, the qualifier must be present
|
||||
return false;
|
||||
}
|
||||
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
|
||||
String attributeName = entry.getKey();
|
||||
Object expectedValue = entry.getValue();
|
||||
Object actualValue = null;
|
||||
// check qualifier first
|
||||
// Check qualifier first
|
||||
if (qualifier != null) {
|
||||
actualValue = qualifier.getAttribute(attributeName);
|
||||
}
|
||||
if (actualValue == null) {
|
||||
// fall back on bean definition attribute
|
||||
// Fall back on bean definition attribute
|
||||
actualValue = bd.getAttribute(attributeName);
|
||||
}
|
||||
if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) &&
|
||||
expectedValue instanceof String && bdHolder.matchesName((String) expectedValue)) {
|
||||
// fall back on bean name (or alias) match
|
||||
// Fall back on bean name (or alias) match
|
||||
continue;
|
||||
}
|
||||
if (actualValue == null && qualifier != null) {
|
||||
// fall back on default, but only if the qualifier is present
|
||||
// Fall back on default, but only if the qualifier is present
|
||||
actualValue = AnnotationUtils.getDefaultValue(annotation, attributeName);
|
||||
}
|
||||
if (actualValue != null) {
|
||||
@@ -288,6 +296,25 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
||||
return true;
|
||||
}
|
||||
|
||||
protected RootBeanDefinition getResolvedDecoratedDefinition(RootBeanDefinition rbd) {
|
||||
BeanDefinitionHolder decDef = rbd.getDecoratedDefinition();
|
||||
if (decDef != null && this.beanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) this.beanFactory;
|
||||
if (clbf.containsBeanDefinition(decDef.getBeanName())) {
|
||||
BeanDefinition dbd = clbf.getMergedBeanDefinition(decDef.getBeanName());
|
||||
if (dbd instanceof RootBeanDefinition) {
|
||||
return (RootBeanDefinition) dbd;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Annotation getFactoryMethodAnnotation(RootBeanDefinition bd, Class<? extends Annotation> type) {
|
||||
Method resolvedFactoryMethod = bd.getResolvedFactoryMethod();
|
||||
return (resolvedFactoryMethod != null ? AnnotationUtils.getAnnotation(resolvedFactoryMethod, type) : null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the given dependency carries a value annotation.
|
||||
|
||||
+2
-2
@@ -185,7 +185,7 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
|
||||
* @see #AUTOWIRE_BY_TYPE
|
||||
* @see #AUTOWIRE_CONSTRUCTOR
|
||||
*/
|
||||
Object createBean(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
|
||||
Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
|
||||
|
||||
/**
|
||||
* Instantiate a new bean instance of the given class with the specified autowire
|
||||
@@ -213,7 +213,7 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
|
||||
* @see #applyBeanPostProcessorsBeforeInitialization
|
||||
* @see #applyBeanPostProcessorsAfterInitialization
|
||||
*/
|
||||
Object autowire(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
|
||||
Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
|
||||
|
||||
/**
|
||||
* Autowire the bean properties of the given bean instance by name or type.
|
||||
|
||||
+16
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -146,7 +146,7 @@ public class ConstructorArgumentValues {
|
||||
* untyped values only)
|
||||
* @return the ValueHolder for the argument, or {@code null} if none set
|
||||
*/
|
||||
public ValueHolder getIndexedArgumentValue(int index, Class requiredType) {
|
||||
public ValueHolder getIndexedArgumentValue(int index, Class<?> requiredType) {
|
||||
return getIndexedArgumentValue(index, requiredType, null);
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ public class ConstructorArgumentValues {
|
||||
* unnamed values only)
|
||||
* @return the ValueHolder for the argument, or {@code null} if none set
|
||||
*/
|
||||
public ValueHolder getIndexedArgumentValue(int index, Class requiredType, String requiredName) {
|
||||
public ValueHolder getIndexedArgumentValue(int index, Class<?> requiredType, String requiredName) {
|
||||
Assert.isTrue(index >= 0, "Index must not be negative");
|
||||
ValueHolder valueHolder = this.indexedArgumentValues.get(index);
|
||||
if (valueHolder != null &&
|
||||
@@ -247,7 +247,7 @@ public class ConstructorArgumentValues {
|
||||
* @param requiredType the type to match
|
||||
* @return the ValueHolder for the argument, or {@code null} if none set
|
||||
*/
|
||||
public ValueHolder getGenericArgumentValue(Class requiredType) {
|
||||
public ValueHolder getGenericArgumentValue(Class<?> requiredType) {
|
||||
return getGenericArgumentValue(requiredType, null, null);
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ public class ConstructorArgumentValues {
|
||||
* @param requiredName the name to match
|
||||
* @return the ValueHolder for the argument, or {@code null} if none set
|
||||
*/
|
||||
public ValueHolder getGenericArgumentValue(Class requiredType, String requiredName) {
|
||||
public ValueHolder getGenericArgumentValue(Class<?> requiredType, String requiredName) {
|
||||
return getGenericArgumentValue(requiredType, requiredName, null);
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ public class ConstructorArgumentValues {
|
||||
* in the current resolution process and should therefore not be returned again
|
||||
* @return the ValueHolder for the argument, or {@code null} if none found
|
||||
*/
|
||||
public ValueHolder getGenericArgumentValue(Class requiredType, String requiredName, Set<ValueHolder> usedValueHolders) {
|
||||
public ValueHolder getGenericArgumentValue(Class<?> requiredType, String requiredName, Set<ValueHolder> usedValueHolders) {
|
||||
for (ValueHolder valueHolder : this.genericArgumentValues) {
|
||||
if (usedValueHolders != null && usedValueHolders.contains(valueHolder)) {
|
||||
continue;
|
||||
@@ -309,10 +309,10 @@ public class ConstructorArgumentValues {
|
||||
* Look for an argument value that either corresponds to the given index
|
||||
* in the constructor argument list or generically matches by type.
|
||||
* @param index the index in the constructor argument list
|
||||
* @param requiredType the type to match
|
||||
* @param requiredType the parameter type to match
|
||||
* @return the ValueHolder for the argument, or {@code null} if none set
|
||||
*/
|
||||
public ValueHolder getArgumentValue(int index, Class requiredType) {
|
||||
public ValueHolder getArgumentValue(int index, Class<?> requiredType) {
|
||||
return getArgumentValue(index, requiredType, null, null);
|
||||
}
|
||||
|
||||
@@ -320,11 +320,11 @@ public class ConstructorArgumentValues {
|
||||
* Look for an argument value that either corresponds to the given index
|
||||
* in the constructor argument list or generically matches by type.
|
||||
* @param index the index in the constructor argument list
|
||||
* @param requiredType the type to match
|
||||
* @param requiredName the name to match
|
||||
* @param requiredType the parameter type to match
|
||||
* @param requiredName the parameter name to match
|
||||
* @return the ValueHolder for the argument, or {@code null} if none set
|
||||
*/
|
||||
public ValueHolder getArgumentValue(int index, Class requiredType, String requiredName) {
|
||||
public ValueHolder getArgumentValue(int index, Class<?> requiredType, String requiredName) {
|
||||
return getArgumentValue(index, requiredType, requiredName, null);
|
||||
}
|
||||
|
||||
@@ -332,15 +332,17 @@ public class ConstructorArgumentValues {
|
||||
* Look for an argument value that either corresponds to the given index
|
||||
* in the constructor argument list or generically matches by type.
|
||||
* @param index the index in the constructor argument list
|
||||
* @param requiredType the type to match (can be {@code null} to find
|
||||
* an untyped argument value)
|
||||
* @param requiredType the parameter type to match (can be {@code null}
|
||||
* to find an untyped argument value)
|
||||
* @param requiredName the parameter name to match (can be {@code null}
|
||||
* to find an unnamed argument value)
|
||||
* @param usedValueHolders a Set of ValueHolder objects that have already
|
||||
* been used in the current resolution process and should therefore not
|
||||
* be returned again (allowing to return the next generic argument match
|
||||
* in case of multiple generic argument values of the same type)
|
||||
* @return the ValueHolder for the argument, or {@code null} if none set
|
||||
*/
|
||||
public ValueHolder getArgumentValue(int index, Class requiredType, String requiredName, Set<ValueHolder> usedValueHolders) {
|
||||
public ValueHolder getArgumentValue(int index, Class<?> requiredType, String requiredName, Set<ValueHolder> usedValueHolders) {
|
||||
Assert.isTrue(index >= 0, "Index must not be negative");
|
||||
ValueHolder valueHolder = getIndexedArgumentValue(index, requiredType, requiredName);
|
||||
if (valueHolder == null) {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,7 +44,7 @@ public class DependencyDescriptor implements Serializable {
|
||||
|
||||
private transient Field field;
|
||||
|
||||
private Class declaringClass;
|
||||
private Class<?> declaringClass;
|
||||
|
||||
private String methodName;
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -206,7 +206,7 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
|
||||
visitor.visitBeanDefinition(bd);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage());
|
||||
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,8 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.core.Constants;
|
||||
import org.springframework.core.SpringProperties;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.util.PropertyPlaceholderHelper;
|
||||
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
@@ -82,7 +84,8 @@ public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport
|
||||
|
||||
private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK;
|
||||
|
||||
private boolean searchSystemEnvironment = true;
|
||||
private boolean searchSystemEnvironment =
|
||||
!SpringProperties.getFlag(AbstractEnvironment.IGNORE_GETENV_PROPERTY_NAME);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -61,7 +61,7 @@ public class TypedStringValue implements BeanMetadataElement {
|
||||
* @param value the String value
|
||||
* @param targetType the type to convert to
|
||||
*/
|
||||
public TypedStringValue(String value, Class targetType) {
|
||||
public TypedStringValue(String value, Class<?> targetType) {
|
||||
setValue(value);
|
||||
setTargetType(targetType);
|
||||
}
|
||||
@@ -101,7 +101,7 @@ public class TypedStringValue implements BeanMetadataElement {
|
||||
* for example in BeanFactoryPostProcessors.
|
||||
* @see PropertyPlaceholderConfigurer
|
||||
*/
|
||||
public void setTargetType(Class targetType) {
|
||||
public void setTargetType(Class<?> targetType) {
|
||||
Assert.notNull(targetType, "'targetType' must not be null");
|
||||
this.targetType = targetType;
|
||||
}
|
||||
@@ -109,7 +109,7 @@ public class TypedStringValue implements BeanMetadataElement {
|
||||
/**
|
||||
* Return the type to convert to.
|
||||
*/
|
||||
public Class getTargetType() {
|
||||
public Class<?> getTargetType() {
|
||||
Object targetTypeValue = this.targetType;
|
||||
if (!(targetTypeValue instanceof Class)) {
|
||||
throw new IllegalStateException("Typed String value does not carry a resolved target type");
|
||||
@@ -153,11 +153,11 @@ public class TypedStringValue implements BeanMetadataElement {
|
||||
* @return the resolved type to convert to
|
||||
* @throws ClassNotFoundException if the type cannot be resolved
|
||||
*/
|
||||
public Class resolveTargetType(ClassLoader classLoader) throws ClassNotFoundException {
|
||||
public Class<?> resolveTargetType(ClassLoader classLoader) throws ClassNotFoundException {
|
||||
if (this.targetType == null) {
|
||||
return null;
|
||||
}
|
||||
Class resolvedClass = ClassUtils.forName(getTargetTypeName(), classLoader);
|
||||
Class<?> resolvedClass = ClassUtils.forName(getTargetTypeName(), classLoader);
|
||||
this.targetType = resolvedClass;
|
||||
return resolvedClass;
|
||||
}
|
||||
|
||||
+84
-60
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -63,7 +63,7 @@ import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
|
||||
@@ -135,21 +135,21 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* Dependency types to ignore on dependency check and autowire, as Set of
|
||||
* Class objects: for example, String. Default is none.
|
||||
*/
|
||||
private final Set<Class> ignoredDependencyTypes = new HashSet<Class>();
|
||||
private final Set<Class<?>> ignoredDependencyTypes = new HashSet<Class<?>>();
|
||||
|
||||
/**
|
||||
* Dependency interfaces to ignore on dependency check and autowire, as Set of
|
||||
* Class objects. By default, only the BeanFactory interface is ignored.
|
||||
*/
|
||||
private final Set<Class> ignoredDependencyInterfaces = new HashSet<Class>();
|
||||
private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<Class<?>>();
|
||||
|
||||
/** Cache of unfinished FactoryBean instances: FactoryBean name --> BeanWrapper */
|
||||
private final Map<String, BeanWrapper> factoryBeanInstanceCache =
|
||||
new ConcurrentHashMap<String, BeanWrapper>(16);
|
||||
|
||||
/** Cache of filtered PropertyDescriptors: bean Class -> PropertyDescriptor array */
|
||||
private final Map<Class, PropertyDescriptor[]> filteredPropertyDescriptorsCache =
|
||||
new ConcurrentHashMap<Class, PropertyDescriptor[]>(64);
|
||||
private final Map<Class<?>, PropertyDescriptor[]> filteredPropertyDescriptorsCache =
|
||||
new ConcurrentHashMap<Class<?>, PropertyDescriptor[]>(64);
|
||||
|
||||
|
||||
/**
|
||||
@@ -171,6 +171,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
setParentBeanFactory(parentBeanFactory);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the instantiation strategy to use for creating bean instances.
|
||||
* Default is CglibSubclassingInstantiationStrategy.
|
||||
@@ -243,7 +244,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* Ignore the given dependency type for autowiring:
|
||||
* for example, String. Default is none.
|
||||
*/
|
||||
public void ignoreDependencyType(Class type) {
|
||||
public void ignoreDependencyType(Class<?> type) {
|
||||
this.ignoredDependencyTypes.add(type);
|
||||
}
|
||||
|
||||
@@ -257,11 +258,10 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @see org.springframework.beans.factory.BeanFactoryAware
|
||||
* @see org.springframework.context.ApplicationContextAware
|
||||
*/
|
||||
public void ignoreDependencyInterface(Class ifc) {
|
||||
public void ignoreDependencyInterface(Class<?> ifc) {
|
||||
this.ignoredDependencyInterfaces.add(ifc);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
|
||||
super.copyConfigurationFrom(otherFactory);
|
||||
@@ -305,12 +305,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
RootBeanDefinition bd = null;
|
||||
if (mbd instanceof RootBeanDefinition) {
|
||||
RootBeanDefinition rbd = (RootBeanDefinition) mbd;
|
||||
if (rbd.isPrototype()) {
|
||||
bd = rbd;
|
||||
}
|
||||
bd = (rbd.isPrototype() ? rbd : rbd.cloneBeanDefinition());
|
||||
}
|
||||
if (bd == null) {
|
||||
bd = new RootBeanDefinition(mbd);
|
||||
if (!mbd.isPrototype()) {
|
||||
if (bd == null) {
|
||||
bd = new RootBeanDefinition(mbd);
|
||||
}
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bd.allowCaching = false;
|
||||
}
|
||||
@@ -329,14 +329,14 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
// Specialized methods for fine-grained control over the bean lifecycle
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
public Object createBean(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
|
||||
public Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
|
||||
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
|
||||
RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
return createBean(beanClass.getName(), bd, null);
|
||||
}
|
||||
|
||||
public Object autowire(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
|
||||
public Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
|
||||
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
|
||||
final RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
@@ -346,10 +346,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
else {
|
||||
Object bean;
|
||||
final BeanFactory parent = this;
|
||||
|
||||
if (System.getSecurityManager() != null) {
|
||||
bean = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
|
||||
public Object run() {
|
||||
return getInstantiationStrategy().instantiate(bd, null, parent);
|
||||
}
|
||||
@@ -358,7 +356,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
else {
|
||||
bean = getInstantiationStrategy().instantiate(bd, null, parent);
|
||||
}
|
||||
|
||||
populateBean(beanClass.getName(), bd, new BeanWrapperImpl(bean));
|
||||
return bean;
|
||||
}
|
||||
@@ -490,7 +487,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
instanceWrapper = createBeanInstance(beanName, mbd, args);
|
||||
}
|
||||
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
|
||||
Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
|
||||
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
|
||||
|
||||
// Allow post-processors to modify the merged bean definition.
|
||||
synchronized (mbd.postProcessingLock) {
|
||||
@@ -509,7 +506,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
logger.debug("Eagerly caching bean '" + beanName +
|
||||
"' to allow for resolving potential circular references");
|
||||
}
|
||||
addSingletonFactory(beanName, new ObjectFactory() {
|
||||
addSingletonFactory(beanName, new ObjectFactory<Object>() {
|
||||
public Object getObject() throws BeansException {
|
||||
return getEarlyBeanReference(beanName, mbd, bean);
|
||||
}
|
||||
@@ -572,7 +569,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class... typesToMatch) {
|
||||
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
|
||||
Class<?> targetType = mbd.getTargetType();
|
||||
if (targetType == null) {
|
||||
targetType = (mbd.getFactoryMethodName() != null ? getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
|
||||
@@ -587,7 +584,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
for (BeanPostProcessor bp : getBeanPostProcessors()) {
|
||||
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
|
||||
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
|
||||
Class predicted = ibp.predictBeanType(targetType, beanName);
|
||||
Class<?> predicted = ibp.predictBeanType(targetType, beanName);
|
||||
if (predicted != null && (typesToMatch.length != 1 || !FactoryBean.class.equals(typesToMatch[0]) ||
|
||||
FactoryBean.class.isAssignableFrom(predicted))) {
|
||||
return predicted;
|
||||
@@ -635,31 +632,61 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ValueHolder> argumentValues = mbd.getConstructorArgumentValues().getGenericArgumentValues();
|
||||
Object[] args = new Object[argumentValues.size()];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
args[i] = argumentValues.get(i).getValue();
|
||||
}
|
||||
|
||||
// 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;
|
||||
int minNrOfArgs = mbd.getConstructorArgumentValues().getArgumentCount();
|
||||
Method[] candidates = ReflectionUtils.getUniqueDeclaredMethods(factoryClass);
|
||||
Set<Class<?>> returnTypes = new HashSet<Class<?>>(1);
|
||||
for (Method factoryMethod : candidates) {
|
||||
if (Modifier.isStatic(factoryMethod.getModifiers()) == isStatic &&
|
||||
factoryMethod.getName().equals(mbd.getFactoryMethodName()) &&
|
||||
factoryMethod.getParameterTypes().length >= minNrOfArgs) {
|
||||
Class<?> returnType = GenericTypeResolver.resolveReturnTypeForGenericMethod(factoryMethod, args);
|
||||
if (returnType != null) {
|
||||
returnTypes.add(returnType);
|
||||
// No declared type variables to inspect, so just process the standard return type.
|
||||
if (factoryMethod.getTypeParameters().length > 0) {
|
||||
try {
|
||||
// Fully resolve parameter names and argument values.
|
||||
Class<?>[] paramTypes = factoryMethod.getParameterTypes();
|
||||
String[] paramNames = null;
|
||||
ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
|
||||
if (pnd != null) {
|
||||
paramNames = pnd.getParameterNames(factoryMethod);
|
||||
}
|
||||
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
|
||||
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders =
|
||||
new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length);
|
||||
Object[] args = new Object[paramTypes.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(
|
||||
i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders);
|
||||
if (valueHolder == null) {
|
||||
valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders);
|
||||
}
|
||||
if (valueHolder != null) {
|
||||
args[i] = valueHolder.getValue();
|
||||
usedValueHolders.add(valueHolder);
|
||||
}
|
||||
}
|
||||
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
|
||||
factoryMethod, args, getBeanClassLoader());
|
||||
if (returnType != null) {
|
||||
commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to resolve generic return type for factory method: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
commonType = ClassUtils.determineCommonAncestor(factoryMethod.getReturnType(), commonType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (returnTypes.size() == 1) {
|
||||
if (commonType != null) {
|
||||
// Clear return type found: all factory methods return same type.
|
||||
return returnTypes.iterator().next();
|
||||
return commonType;
|
||||
}
|
||||
else {
|
||||
// Ambiguous return types found: return null to indicate "not determinable".
|
||||
@@ -688,22 +715,19 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
// Try to obtain the FactoryBean's object type without instantiating it at all.
|
||||
BeanDefinition fbDef = getBeanDefinition(factoryBeanName);
|
||||
if (fbDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) fbDef).hasBeanClass()) {
|
||||
Class<?> fbClass = ((AbstractBeanDefinition) fbDef).getBeanClass();
|
||||
if (ClassUtils.isCglibProxyClass(fbClass)) {
|
||||
// CGLIB subclass methods hide generic parameters. look at the superclass.
|
||||
fbClass = fbClass.getSuperclass();
|
||||
}
|
||||
// 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() {
|
||||
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);
|
||||
new ReflectionUtils.MethodCallback() {
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
if (method.getName().equals(factoryMethodName) &&
|
||||
FactoryBean.class.isAssignableFrom(method.getReturnType())) {
|
||||
objectType.value = GenericTypeResolver.resolveReturnTypeArgument(method, FactoryBean.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
if (objectType.value != null) {
|
||||
return objectType.value;
|
||||
}
|
||||
@@ -764,11 +788,11 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @return the FactoryBean instance, or {@code null} to indicate
|
||||
* that we couldn't obtain a shortcut FactoryBean instance
|
||||
*/
|
||||
private FactoryBean getSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
|
||||
private FactoryBean<?> getSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
|
||||
synchronized (getSingletonMutex()) {
|
||||
BeanWrapper bw = this.factoryBeanInstanceCache.get(beanName);
|
||||
if (bw != null) {
|
||||
return (FactoryBean) bw.getWrappedInstance();
|
||||
return (FactoryBean<?>) bw.getWrappedInstance();
|
||||
}
|
||||
if (isSingletonCurrentlyInCreation(beanName)) {
|
||||
return null;
|
||||
@@ -788,7 +812,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
// Finished partial creation of this bean.
|
||||
afterSingletonCreation(beanName);
|
||||
}
|
||||
FactoryBean fb = getFactoryBean(beanName, instance);
|
||||
FactoryBean<?> fb = getFactoryBean(beanName, instance);
|
||||
if (bw != null) {
|
||||
this.factoryBeanInstanceCache.put(beanName, bw);
|
||||
}
|
||||
@@ -805,7 +829,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @return the FactoryBean instance, or {@code null} to indicate
|
||||
* that we couldn't obtain a shortcut FactoryBean instance
|
||||
*/
|
||||
private FactoryBean getNonSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
|
||||
private FactoryBean<?> getNonSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
|
||||
if (isPrototypeCurrentlyInCreation(beanName)) {
|
||||
return null;
|
||||
}
|
||||
@@ -836,7 +860,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @throws BeansException if any post-processing failed
|
||||
* @see MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
|
||||
*/
|
||||
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class beanType, String beanName)
|
||||
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName)
|
||||
throws BeansException {
|
||||
|
||||
try {
|
||||
@@ -887,7 +911,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @throws BeansException if any post-processing failed
|
||||
* @see InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
|
||||
*/
|
||||
protected Object applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName)
|
||||
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)
|
||||
throws BeansException {
|
||||
|
||||
for (BeanPostProcessor bp : getBeanPostProcessors()) {
|
||||
@@ -916,7 +940,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
*/
|
||||
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
|
||||
// Make sure bean class is actually resolved at this point.
|
||||
Class beanClass = resolveBeanClass(mbd, beanName);
|
||||
Class<?> beanClass = resolveBeanClass(mbd, beanName);
|
||||
|
||||
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
@@ -948,7 +972,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
}
|
||||
|
||||
// Need to determine the constructor...
|
||||
Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
|
||||
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
|
||||
if (ctors != null ||
|
||||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
|
||||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
|
||||
@@ -968,14 +992,14 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @throws org.springframework.beans.BeansException in case of errors
|
||||
* @see org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
|
||||
*/
|
||||
protected Constructor[] determineConstructorsFromBeanPostProcessors(Class beanClass, String beanName)
|
||||
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(Class<?> beanClass, String beanName)
|
||||
throws BeansException {
|
||||
|
||||
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
|
||||
for (BeanPostProcessor bp : getBeanPostProcessors()) {
|
||||
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
|
||||
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
|
||||
Constructor[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
|
||||
Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
|
||||
if (ctors != null) {
|
||||
return ctors;
|
||||
}
|
||||
@@ -1046,7 +1070,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
* @return BeanWrapper for the new instance
|
||||
*/
|
||||
protected BeanWrapper autowireConstructor(
|
||||
String beanName, RootBeanDefinition mbd, Constructor[] ctors, Object[] explicitArgs) {
|
||||
String beanName, RootBeanDefinition mbd, Constructor<?>[] ctors, Object[] explicitArgs) {
|
||||
|
||||
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
|
||||
}
|
||||
@@ -1349,7 +1373,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
MutablePropertyValues mpvs = null;
|
||||
List<PropertyValue> original;
|
||||
|
||||
if (System.getSecurityManager()!= null) {
|
||||
if (System.getSecurityManager() != null) {
|
||||
if (bw instanceof BeanWrapperImpl) {
|
||||
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
|
||||
}
|
||||
@@ -1642,7 +1666,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
|
||||
|
||||
/**
|
||||
* Special DependencyDescriptor variant for autowire="byType".
|
||||
* Special DependencyDescriptor variant for Spring's good old autowire="byType" mode.
|
||||
* Always optional; never considering the parameter name for choosing a primary candidate.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
+9
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -383,7 +383,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
throw new IllegalStateException(
|
||||
"Bean class name [" + beanClassObject + "] has not been resolved into an actual Class");
|
||||
}
|
||||
return (Class) beanClassObject;
|
||||
return (Class<?>) beanClassObject;
|
||||
}
|
||||
|
||||
public void setBeanClassName(String beanClassName) {
|
||||
@@ -393,7 +393,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
public String getBeanClassName() {
|
||||
Object beanClassObject = this.beanClass;
|
||||
if (beanClassObject instanceof Class) {
|
||||
return ((Class) beanClassObject).getName();
|
||||
return ((Class<?>) beanClassObject).getName();
|
||||
}
|
||||
else {
|
||||
return (String) beanClassObject;
|
||||
@@ -408,12 +408,12 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
* @return the resolved bean class
|
||||
* @throws ClassNotFoundException if the class name could be resolved
|
||||
*/
|
||||
public Class resolveBeanClass(ClassLoader classLoader) throws ClassNotFoundException {
|
||||
public Class<?> resolveBeanClass(ClassLoader classLoader) throws ClassNotFoundException {
|
||||
String className = getBeanClassName();
|
||||
if (className == null) {
|
||||
return null;
|
||||
}
|
||||
Class resolvedClass = ClassUtils.forName(className, classLoader);
|
||||
Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
|
||||
this.beanClass = resolvedClass;
|
||||
return resolvedClass;
|
||||
}
|
||||
@@ -551,8 +551,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
// Work out whether to apply setter autowiring or constructor autowiring.
|
||||
// If it has a no-arg constructor it's deemed to be setter autowiring,
|
||||
// otherwise we'll try constructor autowiring.
|
||||
Constructor[] constructors = getBeanClass().getConstructors();
|
||||
for (Constructor constructor : constructors) {
|
||||
Constructor<?>[] constructors = getBeanClass().getConstructors();
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
if (constructor.getParameterTypes().length == 0) {
|
||||
return AUTOWIRE_BY_TYPE;
|
||||
}
|
||||
@@ -678,6 +678,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
/**
|
||||
* Specify whether to allow access to non-public constructors and methods,
|
||||
* for the case of externalized metadata pointing to those.
|
||||
* The default is {@code true}; switch this to {@false} for public access only.
|
||||
* <p>This applies to constructor resolution, factory method resolution,
|
||||
* and also init/destroy methods. Bean property accessors have to be public
|
||||
* in any case and are not affected by this setting.
|
||||
@@ -699,7 +700,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
/**
|
||||
* Specify whether to resolve constructors in lenient mode ({@code true},
|
||||
* which is the default) or to switch to strict resolution (throwing an exception
|
||||
* in case of ambigious constructors that all match when converting the arguments,
|
||||
* in case of ambiguous constructors that all match when converting the arguments,
|
||||
* whereas lenient mode would use the one with the 'closest' type matches).
|
||||
*/
|
||||
public void setLenientConstructorResolution(boolean lenientConstructorResolution) {
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,7 +54,7 @@ public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
private Environment environment = new StandardEnvironment();
|
||||
private Environment environment;
|
||||
|
||||
private BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();
|
||||
|
||||
@@ -90,7 +90,7 @@ public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable
|
||||
|
||||
// Inherit Environment if possible
|
||||
if (this.registry instanceof EnvironmentCapable) {
|
||||
this.environment = ((EnvironmentCapable)this.registry).getEnvironment();
|
||||
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
|
||||
}
|
||||
else {
|
||||
this.environment = new StandardEnvironment();
|
||||
|
||||
+91
-71
@@ -275,76 +275,82 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
markBeanAsCreated(beanName);
|
||||
}
|
||||
|
||||
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||
checkMergedBeanDefinition(mbd, beanName, args);
|
||||
try {
|
||||
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||
checkMergedBeanDefinition(mbd, beanName, args);
|
||||
|
||||
// Guarantee initialization of beans that the current bean depends on.
|
||||
String[] dependsOn = mbd.getDependsOn();
|
||||
if (dependsOn != null) {
|
||||
for (String dependsOnBean : dependsOn) {
|
||||
getBean(dependsOnBean);
|
||||
registerDependentBean(dependsOnBean, beanName);
|
||||
}
|
||||
}
|
||||
|
||||
// Create bean instance.
|
||||
if (mbd.isSingleton()) {
|
||||
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
|
||||
public Object getObject() throws BeansException {
|
||||
try {
|
||||
return createBean(beanName, mbd, args);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
// Explicitly remove instance from singleton cache: It might have been put there
|
||||
// eagerly by the creation process, to allow for circular reference resolution.
|
||||
// Also remove any beans that received a temporary reference to the bean.
|
||||
destroySingleton(beanName);
|
||||
throw ex;
|
||||
}
|
||||
// Guarantee initialization of beans that the current bean depends on.
|
||||
String[] dependsOn = mbd.getDependsOn();
|
||||
if (dependsOn != null) {
|
||||
for (String dependsOnBean : dependsOn) {
|
||||
getBean(dependsOnBean);
|
||||
registerDependentBean(dependsOnBean, beanName);
|
||||
}
|
||||
});
|
||||
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
|
||||
}
|
||||
}
|
||||
|
||||
else if (mbd.isPrototype()) {
|
||||
// It's a prototype -> create a new instance.
|
||||
Object prototypeInstance = null;
|
||||
try {
|
||||
beforePrototypeCreation(beanName);
|
||||
prototypeInstance = createBean(beanName, mbd, args);
|
||||
}
|
||||
finally {
|
||||
afterPrototypeCreation(beanName);
|
||||
}
|
||||
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
|
||||
}
|
||||
|
||||
else {
|
||||
String scopeName = mbd.getScope();
|
||||
final Scope scope = this.scopes.get(scopeName);
|
||||
if (scope == null) {
|
||||
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
|
||||
}
|
||||
try {
|
||||
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
|
||||
// Create bean instance.
|
||||
if (mbd.isSingleton()) {
|
||||
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
|
||||
public Object getObject() throws BeansException {
|
||||
beforePrototypeCreation(beanName);
|
||||
try {
|
||||
return createBean(beanName, mbd, args);
|
||||
}
|
||||
finally {
|
||||
afterPrototypeCreation(beanName);
|
||||
catch (BeansException ex) {
|
||||
// Explicitly remove instance from singleton cache: It might have been put there
|
||||
// eagerly by the creation process, to allow for circular reference resolution.
|
||||
// Also remove any beans that received a temporary reference to the bean.
|
||||
destroySingleton(beanName);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
});
|
||||
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
|
||||
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Scope '" + scopeName + "' is not active for the current thread; " +
|
||||
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
|
||||
ex);
|
||||
|
||||
else if (mbd.isPrototype()) {
|
||||
// It's a prototype -> create a new instance.
|
||||
Object prototypeInstance = null;
|
||||
try {
|
||||
beforePrototypeCreation(beanName);
|
||||
prototypeInstance = createBean(beanName, mbd, args);
|
||||
}
|
||||
finally {
|
||||
afterPrototypeCreation(beanName);
|
||||
}
|
||||
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
|
||||
}
|
||||
|
||||
else {
|
||||
String scopeName = mbd.getScope();
|
||||
final Scope scope = this.scopes.get(scopeName);
|
||||
if (scope == null) {
|
||||
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
|
||||
}
|
||||
try {
|
||||
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
|
||||
public Object getObject() throws BeansException {
|
||||
beforePrototypeCreation(beanName);
|
||||
try {
|
||||
return createBean(beanName, mbd, args);
|
||||
}
|
||||
finally {
|
||||
afterPrototypeCreation(beanName);
|
||||
}
|
||||
}
|
||||
});
|
||||
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Scope '" + scopeName + "' is not active for the current thread; " +
|
||||
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
|
||||
ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
cleanupAfterBeanCreationFailure(beanName);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,26 +517,32 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> beanClass = predictBeanType(beanName, mbd, typesToMatch);
|
||||
if (beanClass == null) {
|
||||
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(beanClass)) {
|
||||
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.
|
||||
Class<?> type = getTypeForFactoryBean(beanName, mbd);
|
||||
return (type != null && typeToMatch.isAssignableFrom(type));
|
||||
}
|
||||
else {
|
||||
return typeToMatch.isAssignableFrom(beanClass);
|
||||
beanType = getTypeForFactoryBean(beanName, mbd);
|
||||
if (beanType == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return !BeanFactoryUtils.isFactoryDereference(name) &&
|
||||
typeToMatch.isAssignableFrom(beanClass);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return typeToMatch.isAssignableFrom(beanType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1335,8 +1347,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
* @param mbd the corresponding bean definition
|
||||
*/
|
||||
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
|
||||
Class<?> beanClass = predictBeanType(beanName, mbd, FactoryBean.class);
|
||||
return (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass));
|
||||
Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
|
||||
return (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1382,6 +1394,14 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
this.alreadyCreated.put(beanName, Boolean.TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform appropriate cleanup of cached metadata after bean creation failed.
|
||||
* @param beanName the name of the bean
|
||||
*/
|
||||
protected void cleanupAfterBeanCreationFailure(String beanName) {
|
||||
this.alreadyCreated.remove(beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the specified bean is eligible for having
|
||||
* its bean definition metadata cached.
|
||||
|
||||
+140
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,20 +23,27 @@ import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Utility class that contains various methods useful for
|
||||
* the implementation of autowire-capable bean factories.
|
||||
* Utility class that contains various methods useful for the implementation of
|
||||
* autowire-capable bean factories.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @author Sam Brannen
|
||||
* @since 1.1.2
|
||||
* @see AbstractAutowireCapableBeanFactory
|
||||
*/
|
||||
@@ -49,9 +56,9 @@ abstract class AutowireUtils {
|
||||
* decreasing number of arguments.
|
||||
* @param constructors the constructor array to sort
|
||||
*/
|
||||
public static void sortConstructors(Constructor[] constructors) {
|
||||
Arrays.sort(constructors, new Comparator<Constructor>() {
|
||||
public int compare(Constructor c1, Constructor c2) {
|
||||
public static void sortConstructors(Constructor<?>[] constructors) {
|
||||
Arrays.sort(constructors, new Comparator<Constructor<?>>() {
|
||||
public int compare(Constructor<?> c1, Constructor<?> c2) {
|
||||
boolean p1 = Modifier.isPublic(c1.getModifiers());
|
||||
boolean p2 = Modifier.isPublic(c2.getModifiers());
|
||||
if (p1 != p2) {
|
||||
@@ -103,7 +110,7 @@ abstract class AutowireUtils {
|
||||
}
|
||||
// It was declared by CGLIB, but we might still want to autowire it
|
||||
// if it was actually declared by the superclass.
|
||||
Class superclass = wm.getDeclaringClass().getSuperclass();
|
||||
Class<?> superclass = wm.getDeclaringClass().getSuperclass();
|
||||
return !ClassUtils.hasMethod(superclass, wm.getName(), wm.getParameterTypes());
|
||||
}
|
||||
|
||||
@@ -114,11 +121,11 @@ abstract class AutowireUtils {
|
||||
* @param interfaces the Set of interfaces (Class objects)
|
||||
* @return whether the setter method is defined by an interface
|
||||
*/
|
||||
public static boolean isSetterDefinedInInterface(PropertyDescriptor pd, Set<Class> interfaces) {
|
||||
public static boolean isSetterDefinedInInterface(PropertyDescriptor pd, Set<Class<?>> interfaces) {
|
||||
Method setter = pd.getWriteMethod();
|
||||
if (setter != null) {
|
||||
Class targetClass = setter.getDeclaringClass();
|
||||
for (Class ifc : interfaces) {
|
||||
Class<?> targetClass = setter.getDeclaringClass();
|
||||
for (Class<?> ifc : interfaces) {
|
||||
if (ifc.isAssignableFrom(targetClass) &&
|
||||
ClassUtils.hasMethod(ifc, setter.getName(), setter.getParameterTypes())) {
|
||||
return true;
|
||||
@@ -135,12 +142,12 @@ abstract class AutowireUtils {
|
||||
* @param requiredType the type to assign the result to
|
||||
* @return the resolved value
|
||||
*/
|
||||
public static Object resolveAutowiringValue(Object autowiringValue, Class requiredType) {
|
||||
public static Object resolveAutowiringValue(Object autowiringValue, Class<?> requiredType) {
|
||||
if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
|
||||
ObjectFactory factory = (ObjectFactory) autowiringValue;
|
||||
ObjectFactory<?> factory = (ObjectFactory<?>) autowiringValue;
|
||||
if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
|
||||
autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(),
|
||||
new Class[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
|
||||
new Class<?>[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
|
||||
}
|
||||
else {
|
||||
return factory.getObject();
|
||||
@@ -149,6 +156,124 @@ abstract class AutowireUtils {
|
||||
return autowiringValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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}.
|
||||
* <pre class="code">{@code public static <T> T createProxy(Class<T> clazz)}</pre>
|
||||
* <h4>Possible Return Values</h4>
|
||||
* <ul>
|
||||
* <li>the target return type, if it can be inferred</li>
|
||||
* <li>the {@linkplain Method#getReturnType() standard return type}, if
|
||||
* the given {@code method} does not declare any {@linkplain
|
||||
* Method#getTypeParameters() formal type variables}</li>
|
||||
* <li>the {@linkplain Method#getReturnType() standard return type}, if the
|
||||
* target return type cannot be inferred (e.g., due to type erasure)</li>
|
||||
* <li>{@code null}, if the length of the given arguments array is shorter
|
||||
* than the length of the {@linkplain
|
||||
* Method#getGenericParameterTypes() formal argument list} for the given
|
||||
* method</li>
|
||||
* </ul>
|
||||
* @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}
|
||||
* @since 3.2.5
|
||||
*/
|
||||
public static Class<?> resolveReturnTypeForFactoryMethod(Method method, Object[] args, ClassLoader classLoader) {
|
||||
Assert.notNull(method, "Method must not be null");
|
||||
Assert.notNull(args, "Argument array must not be null");
|
||||
Assert.notNull(classLoader, "ClassLoader must not be null");
|
||||
|
||||
TypeVariable<Method>[] declaredTypeVariables = method.getTypeParameters();
|
||||
Type genericReturnType = method.getGenericReturnType();
|
||||
Type[] methodParameterTypes = method.getGenericParameterTypes();
|
||||
Assert.isTrue(args.length == methodParameterTypes.length, "Argument array does not match parameter count");
|
||||
|
||||
// Ensure that the type variable (e.g., T) is declared directly on the method
|
||||
// itself (e.g., via <T>), not on the enclosing class or interface.
|
||||
boolean locallyDeclaredTypeVariableMatchesReturnType = false;
|
||||
for (TypeVariable<Method> currentTypeVariable : declaredTypeVariables) {
|
||||
if (currentTypeVariable.equals(genericReturnType)) {
|
||||
locallyDeclaredTypeVariableMatchesReturnType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (locallyDeclaredTypeVariableMatchesReturnType) {
|
||||
for (int i = 0; i < methodParameterTypes.length; i++) {
|
||||
Type methodParameterType = methodParameterTypes[i];
|
||||
Object arg = args[i];
|
||||
if (methodParameterType.equals(genericReturnType)) {
|
||||
if (arg instanceof TypedStringValue) {
|
||||
TypedStringValue typedValue = ((TypedStringValue) arg);
|
||||
if (typedValue.hasTargetType()) {
|
||||
return typedValue.getTargetType();
|
||||
}
|
||||
try {
|
||||
return typedValue.resolveTargetType(classLoader);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new IllegalStateException("Failed to resolve value type [" +
|
||||
typedValue.getTargetTypeName() + "] for factory method argument", ex);
|
||||
}
|
||||
}
|
||||
// Only consider argument type if it is a simple value...
|
||||
if (arg != null && !(arg instanceof BeanMetadataElement)) {
|
||||
return arg.getClass();
|
||||
}
|
||||
return method.getReturnType();
|
||||
}
|
||||
else if (methodParameterType instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) methodParameterType;
|
||||
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
|
||||
for (Type typeArg : actualTypeArguments) {
|
||||
if (typeArg.equals(genericReturnType)) {
|
||||
if (arg instanceof Class) {
|
||||
return (Class<?>) arg;
|
||||
}
|
||||
else {
|
||||
String className = null;
|
||||
if (arg instanceof String) {
|
||||
className = (String) arg;
|
||||
}
|
||||
else if (arg instanceof TypedStringValue) {
|
||||
TypedStringValue typedValue = ((TypedStringValue) arg);
|
||||
String targetTypeName = typedValue.getTargetTypeName();
|
||||
if (targetTypeName == null || Class.class.getName().equals(targetTypeName)) {
|
||||
className = typedValue.getValue();
|
||||
}
|
||||
}
|
||||
if (className != null) {
|
||||
try {
|
||||
return ClassUtils.forName(className, classLoader);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new IllegalStateException("Could not resolve class name [" + arg +
|
||||
"] for factory method argument", ex);
|
||||
}
|
||||
}
|
||||
// Consider adding logic to determine the class of the typeArg, if possible.
|
||||
// For now, just fall back...
|
||||
return method.getReturnType();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back...
|
||||
return method.getReturnType();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reflective InvocationHandler for lazy access to the current target object.
|
||||
@@ -156,9 +281,9 @@ abstract class AutowireUtils {
|
||||
@SuppressWarnings("serial")
|
||||
private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler, Serializable {
|
||||
|
||||
private final ObjectFactory objectFactory;
|
||||
private final ObjectFactory<?> objectFactory;
|
||||
|
||||
public ObjectFactoryDelegatingInvocationHandler(ObjectFactory objectFactory) {
|
||||
public ObjectFactoryDelegatingInvocationHandler(ObjectFactory<?> objectFactory) {
|
||||
this.objectFactory = objectFactory;
|
||||
}
|
||||
|
||||
|
||||
+19
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,7 @@ import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
/**
|
||||
* Simple interface for bean definition readers.
|
||||
* Specifies load methods with Resource parameters.
|
||||
* Specifies load methods with Resource and String location parameters.
|
||||
*
|
||||
* <p>Concrete bean definition readers can of course add additional
|
||||
* load and register methods for bean definitions, specific to
|
||||
@@ -45,23 +45,23 @@ public interface BeanDefinitionReader {
|
||||
*/
|
||||
BeanDefinitionRegistry getRegistry();
|
||||
|
||||
/**
|
||||
* Return the resource loader to use for resource locations.
|
||||
* Can be checked for the <b>ResourcePatternResolver</b> interface and cast
|
||||
* accordingly, for loading multiple resources for a given resource pattern.
|
||||
* <p>Null suggests that absolute resource loading is not available
|
||||
* for this bean definition reader.
|
||||
* <p>This is mainly meant to be used for importing further resources
|
||||
* from within a bean definition resource, for example via the "import"
|
||||
* tag in XML bean definitions. It is recommended, however, to apply
|
||||
* such imports relative to the defining resource; only explicit full
|
||||
* resource locations will trigger absolute resource loading.
|
||||
* <p>There is also a {@code loadBeanDefinitions(String)} method available,
|
||||
* for loading bean definitions from a resource location (or location pattern).
|
||||
* This is a convenience to avoid explicit ResourceLoader handling.
|
||||
* @see #loadBeanDefinitions(String)
|
||||
* @see org.springframework.core.io.support.ResourcePatternResolver
|
||||
*/
|
||||
/**
|
||||
* Return the resource loader to use for resource locations.
|
||||
* Can be checked for the <b>ResourcePatternResolver</b> interface and cast
|
||||
* accordingly, for loading multiple resources for a given resource pattern.
|
||||
* <p>Null suggests that absolute resource loading is not available
|
||||
* for this bean definition reader.
|
||||
* <p>This is mainly meant to be used for importing further resources
|
||||
* from within a bean definition resource, for example via the "import"
|
||||
* tag in XML bean definitions. It is recommended, however, to apply
|
||||
* such imports relative to the defining resource; only explicit full
|
||||
* resource locations will trigger absolute resource loading.
|
||||
* <p>There is also a {@code loadBeanDefinitions(String)} method available,
|
||||
* for loading bean definitions from a resource location (or location pattern).
|
||||
* This is a convenience to avoid explicit ResourceLoader handling.
|
||||
* @see #loadBeanDefinitions(String)
|
||||
* @see org.springframework.core.io.support.ResourcePatternResolver
|
||||
*/
|
||||
ResourceLoader getResourceLoader();
|
||||
|
||||
/**
|
||||
|
||||
+6
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -128,7 +128,7 @@ class BeanDefinitionValueResolver {
|
||||
else if (value instanceof ManagedArray) {
|
||||
// May need to resolve contained runtime references.
|
||||
ManagedArray array = (ManagedArray) value;
|
||||
Class elementType = array.resolvedElementType;
|
||||
Class<?> elementType = array.resolvedElementType;
|
||||
if (elementType == null) {
|
||||
String elementTypeName = array.getElementTypeName();
|
||||
if (StringUtils.hasText(elementTypeName)) {
|
||||
@@ -256,10 +256,8 @@ class BeanDefinitionValueResolver {
|
||||
mbd = this.beanFactory.getMergedBeanDefinition(innerBeanName, innerBd, this.beanDefinition);
|
||||
// Check given bean name whether it is unique. If not already unique,
|
||||
// add counter - increasing the counter until the name is unique.
|
||||
String actualInnerBeanName = innerBeanName;
|
||||
if (mbd.isSingleton()) {
|
||||
actualInnerBeanName = adaptInnerBeanName(innerBeanName);
|
||||
}
|
||||
String actualInnerBeanName = adaptInnerBeanName(innerBeanName);
|
||||
this.beanFactory.registerContainedBean(actualInnerBeanName, this.beanName);
|
||||
// Guarantee initialization of beans that the inner bean depends on.
|
||||
String[] dependsOn = mbd.getDependsOn();
|
||||
if (dependsOn != null) {
|
||||
@@ -269,9 +267,8 @@ class BeanDefinitionValueResolver {
|
||||
}
|
||||
}
|
||||
Object innerBean = this.beanFactory.createBean(actualInnerBeanName, mbd, null);
|
||||
this.beanFactory.registerContainedBean(actualInnerBeanName, this.beanName);
|
||||
if (innerBean instanceof FactoryBean) {
|
||||
boolean synthetic = (mbd != null && mbd.isSynthetic());
|
||||
boolean synthetic = mbd.isSynthetic();
|
||||
return this.beanFactory.getObjectFromFactoryBean((FactoryBean) innerBean, actualInnerBeanName, !synthetic);
|
||||
}
|
||||
else {
|
||||
@@ -335,7 +332,7 @@ class BeanDefinitionValueResolver {
|
||||
/**
|
||||
* For each element in the managed array, resolve reference if necessary.
|
||||
*/
|
||||
private Object resolveManagedArray(Object argName, List<?> ml, Class elementType) {
|
||||
private Object resolveManagedArray(Object argName, List<?> ml, Class<?> elementType) {
|
||||
Object resolved = Array.newInstance(elementType, ml.size());
|
||||
for (int i = 0; i < ml.size(); i++) {
|
||||
Array.set(resolved, i,
|
||||
|
||||
+6
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,7 +23,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
|
||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.CallbackFilter;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
@@ -72,7 +72,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
@Override
|
||||
protected Object instantiateWithMethodInjection(
|
||||
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||
Constructor ctor, Object[] args) {
|
||||
Constructor<?> ctor, Object[] args) {
|
||||
|
||||
return new CglibSubclassCreator(beanDefinition, owner).instantiate(ctor, args);
|
||||
}
|
||||
@@ -104,9 +104,10 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
* Ignored if the ctor parameter is {@code null}.
|
||||
* @return new instance of the dynamically generated class
|
||||
*/
|
||||
public Object instantiate(Constructor ctor, Object[] args) {
|
||||
public Object instantiate(Constructor<?> ctor, Object[] args) {
|
||||
Enhancer enhancer = new Enhancer();
|
||||
enhancer.setSuperclass(this.beanDefinition.getBeanClass());
|
||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||
enhancer.setCallbackFilter(new CallbackFilterImpl());
|
||||
enhancer.setCallbacks(new Callback[] {
|
||||
NoOp.INSTANCE,
|
||||
@@ -114,9 +115,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
new ReplaceOverrideMethodInterceptor()
|
||||
});
|
||||
|
||||
return (ctor == null) ?
|
||||
enhancer.create() :
|
||||
enhancer.create(ctor.getParameterTypes(), args);
|
||||
return (ctor != null ? enhancer.create(ctor.getParameterTypes(), args) : enhancer.create());
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -98,7 +98,7 @@ public class ChildBeanDefinition extends AbstractBeanDefinition {
|
||||
* @param pvs the property values to apply
|
||||
*/
|
||||
public ChildBeanDefinition(
|
||||
String parentName, Class beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
|
||||
String parentName, Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
|
||||
|
||||
super(cargs, pvs);
|
||||
this.parentName = parentName;
|
||||
|
||||
+63
-47
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,12 +54,9 @@ import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Helper class for resolving constructors and factory methods.
|
||||
* Delegate for resolving constructors and factory methods.
|
||||
* Performs constructor resolution through argument matching.
|
||||
*
|
||||
* <p>Operates on an {@link AbstractBeanFactory} and an {@link InstantiationStrategy}.
|
||||
* Used by {@link AbstractAutowireCapableBeanFactory}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Mark Fisher
|
||||
@@ -103,12 +100,12 @@ class ConstructorResolver {
|
||||
* @return a BeanWrapper for the new instance
|
||||
*/
|
||||
public BeanWrapper autowireConstructor(
|
||||
final String beanName, final RootBeanDefinition mbd, Constructor[] chosenCtors, final Object[] explicitArgs) {
|
||||
final String beanName, final RootBeanDefinition mbd, Constructor<?>[] chosenCtors, final Object[] explicitArgs) {
|
||||
|
||||
BeanWrapperImpl bw = new BeanWrapperImpl();
|
||||
this.beanFactory.initBeanWrapper(bw);
|
||||
|
||||
Constructor constructorToUse = null;
|
||||
Constructor<?> constructorToUse = null;
|
||||
ArgumentsHolder argsHolderToUse = null;
|
||||
Object[] argsToUse = null;
|
||||
|
||||
@@ -118,7 +115,7 @@ class ConstructorResolver {
|
||||
else {
|
||||
Object[] argsToResolve = null;
|
||||
synchronized (mbd.constructorArgumentLock) {
|
||||
constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
|
||||
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
|
||||
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
|
||||
// Found a cached constructor...
|
||||
argsToUse = mbd.resolvedConstructorArguments;
|
||||
@@ -149,9 +146,9 @@ class ConstructorResolver {
|
||||
}
|
||||
|
||||
// Take specified constructors, if any.
|
||||
Constructor[] candidates = chosenCtors;
|
||||
Constructor<?>[] candidates = chosenCtors;
|
||||
if (candidates == null) {
|
||||
Class beanClass = mbd.getBeanClass();
|
||||
Class<?> beanClass = mbd.getBeanClass();
|
||||
try {
|
||||
candidates = (mbd.isNonPublicAccessAllowed() ?
|
||||
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
|
||||
@@ -164,12 +161,12 @@ class ConstructorResolver {
|
||||
}
|
||||
AutowireUtils.sortConstructors(candidates);
|
||||
int minTypeDiffWeight = Integer.MAX_VALUE;
|
||||
Set<Constructor> ambiguousConstructors = null;
|
||||
Set<Constructor<?>> ambiguousConstructors = null;
|
||||
List<Exception> causes = null;
|
||||
|
||||
for (int i = 0; i < candidates.length; i++) {
|
||||
Constructor<?> candidate = candidates[i];
|
||||
Class[] paramTypes = candidate.getParameterTypes();
|
||||
Class<?>[] paramTypes = candidate.getParameterTypes();
|
||||
|
||||
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
|
||||
// Already found greedy constructor that can be satisfied ->
|
||||
@@ -185,7 +182,7 @@ class ConstructorResolver {
|
||||
try {
|
||||
String[] paramNames = null;
|
||||
if (constructorPropertiesAnnotationAvailable) {
|
||||
paramNames = ConstructorPropertiesChecker.evaluateAnnotation(candidate, paramTypes.length);
|
||||
paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
|
||||
}
|
||||
if (paramNames == null) {
|
||||
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
|
||||
@@ -239,7 +236,7 @@ class ConstructorResolver {
|
||||
}
|
||||
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
|
||||
if (ambiguousConstructors == null) {
|
||||
ambiguousConstructors = new LinkedHashSet<Constructor>();
|
||||
ambiguousConstructors = new LinkedHashSet<Constructor<?>>();
|
||||
ambiguousConstructors.add(constructorToUse);
|
||||
}
|
||||
ambiguousConstructors.add(candidate);
|
||||
@@ -267,7 +264,7 @@ class ConstructorResolver {
|
||||
Object beanInstance;
|
||||
|
||||
if (System.getSecurityManager() != null) {
|
||||
final Constructor ctorToUse = constructorToUse;
|
||||
final Constructor<?> ctorToUse = constructorToUse;
|
||||
final Object[] argumentsToUse = argsToUse;
|
||||
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
public Object run() {
|
||||
@@ -295,18 +292,22 @@ class ConstructorResolver {
|
||||
* @param mbd the bean definition to check
|
||||
*/
|
||||
public void resolveFactoryMethodIfPossible(RootBeanDefinition mbd) {
|
||||
Class factoryClass;
|
||||
Class<?> factoryClass;
|
||||
boolean isStatic;
|
||||
if (mbd.getFactoryBeanName() != null) {
|
||||
factoryClass = this.beanFactory.getType(mbd.getFactoryBeanName());
|
||||
isStatic = false;
|
||||
}
|
||||
else {
|
||||
factoryClass = mbd.getBeanClass();
|
||||
isStatic = true;
|
||||
}
|
||||
factoryClass = ClassUtils.getUserClass(factoryClass);
|
||||
Method[] candidates = ReflectionUtils.getAllDeclaredMethods(factoryClass);
|
||||
|
||||
Method[] candidates = getCandidateMethods(factoryClass, mbd);
|
||||
Method uniqueCandidate = null;
|
||||
for (Method candidate : candidates) {
|
||||
if (mbd.isFactoryMethod(candidate)) {
|
||||
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
|
||||
if (uniqueCandidate == null) {
|
||||
uniqueCandidate = candidate;
|
||||
}
|
||||
@@ -321,6 +322,27 @@ class ConstructorResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all candidate methods for the given class, considering
|
||||
* the {@link RootBeanDefinition#isNonPublicAccessAllowed()} flag.
|
||||
* Called as the starting point for factory method determination.
|
||||
*/
|
||||
private Method[] getCandidateMethods(final Class<?> factoryClass, final RootBeanDefinition mbd) {
|
||||
if (System.getSecurityManager() != null) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
|
||||
@Override
|
||||
public Method[] run() {
|
||||
return (mbd.isNonPublicAccessAllowed() ?
|
||||
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
return (mbd.isNonPublicAccessAllowed() ?
|
||||
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the bean using a named factory method. The method may be static, if the
|
||||
* bean definition parameter specifies a class, rather than a "factory-bean", or
|
||||
@@ -336,12 +358,14 @@ class ConstructorResolver {
|
||||
* method, or {@code null} if none (-> use constructor argument values from bean definition)
|
||||
* @return a BeanWrapper for the new instance
|
||||
*/
|
||||
public BeanWrapper instantiateUsingFactoryMethod(final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
|
||||
public BeanWrapper instantiateUsingFactoryMethod(
|
||||
final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
|
||||
|
||||
BeanWrapperImpl bw = new BeanWrapperImpl();
|
||||
this.beanFactory.initBeanWrapper(bw);
|
||||
|
||||
Object factoryBean;
|
||||
Class factoryClass;
|
||||
Class<?> factoryClass;
|
||||
boolean isStatic;
|
||||
|
||||
String factoryBeanName = mbd.getFactoryBeanName();
|
||||
@@ -397,27 +421,11 @@ class ConstructorResolver {
|
||||
// Need to determine the factory method...
|
||||
// Try all methods with this name to see if they match the given arguments.
|
||||
factoryClass = ClassUtils.getUserClass(factoryClass);
|
||||
Method[] rawCandidates;
|
||||
|
||||
final Class factoryClazz = factoryClass;
|
||||
if (System.getSecurityManager() != null) {
|
||||
rawCandidates = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
|
||||
public Method[] run() {
|
||||
return (mbd.isNonPublicAccessAllowed() ?
|
||||
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
rawCandidates = (mbd.isNonPublicAccessAllowed() ?
|
||||
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
|
||||
}
|
||||
|
||||
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
|
||||
List<Method> candidateSet = new ArrayList<Method>();
|
||||
for (Method candidate : rawCandidates) {
|
||||
if (Modifier.isStatic(candidate.getModifiers()) == isStatic &&
|
||||
candidate.getName().equals(mbd.getFactoryMethodName()) &&
|
||||
mbd.isFactoryMethod(candidate)) {
|
||||
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
|
||||
candidateSet.add(candidate);
|
||||
}
|
||||
}
|
||||
@@ -445,7 +453,7 @@ class ConstructorResolver {
|
||||
|
||||
for (int i = 0; i < candidates.length; i++) {
|
||||
Method candidate = candidates[i];
|
||||
Class[] paramTypes = candidate.getParameterTypes();
|
||||
Class<?>[] paramTypes = candidate.getParameterTypes();
|
||||
|
||||
if (paramTypes.length >= minNrOfArgs) {
|
||||
ArgumentsHolder argsHolder;
|
||||
@@ -503,7 +511,15 @@ class ConstructorResolver {
|
||||
minTypeDiffWeight = typeDiffWeight;
|
||||
ambiguousFactoryMethods = null;
|
||||
}
|
||||
else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight) {
|
||||
// Find out about ambiguity: In case of the same type difference weight
|
||||
// for methods with the same number of parameters, collect such candidates
|
||||
// and eventually raise an ambiguity exception.
|
||||
// However, only perform that check in non-lenient constructor resolution mode,
|
||||
// and explicitly ignore overridden methods (with the same parameter signature).
|
||||
else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
|
||||
!mbd.isLenientConstructorResolution() &&
|
||||
paramTypes.length == factoryMethodToUse.getParameterTypes().length &&
|
||||
!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
|
||||
if (ambiguousFactoryMethods == null) {
|
||||
ambiguousFactoryMethods = new LinkedHashSet<Method>();
|
||||
ambiguousFactoryMethods.add(factoryMethodToUse);
|
||||
@@ -540,7 +556,7 @@ class ConstructorResolver {
|
||||
"Invalid factory method '" + mbd.getFactoryMethodName() +
|
||||
"': needs to have a non-void return type!");
|
||||
}
|
||||
else if (ambiguousFactoryMethods != null && !mbd.isLenientConstructorResolution()) {
|
||||
else if (ambiguousFactoryMethods != null) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Ambiguous factory method matches found in bean '" + beanName + "' " +
|
||||
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
|
||||
@@ -644,7 +660,7 @@ class ConstructorResolver {
|
||||
*/
|
||||
private ArgumentsHolder createArgumentArray(
|
||||
String beanName, RootBeanDefinition mbd, ConstructorArgumentValues resolvedValues,
|
||||
BeanWrapper bw, Class[] paramTypes, String[] paramNames, Object methodOrCtor,
|
||||
BeanWrapper bw, Class<?>[] paramTypes, String[] paramNames, Object methodOrCtor,
|
||||
boolean autowiring) throws UnsatisfiedDependencyException {
|
||||
|
||||
String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method");
|
||||
@@ -750,8 +766,8 @@ class ConstructorResolver {
|
||||
private Object[] resolvePreparedArguments(
|
||||
String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) {
|
||||
|
||||
Class[] paramTypes = (methodOrCtor instanceof Method ?
|
||||
((Method) methodOrCtor).getParameterTypes() : ((Constructor) methodOrCtor).getParameterTypes());
|
||||
Class<?>[] paramTypes = (methodOrCtor instanceof Method ?
|
||||
((Method) methodOrCtor).getParameterTypes() : ((Constructor<?>) methodOrCtor).getParameterTypes());
|
||||
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
|
||||
this.beanFactory.getCustomTypeConverter() : bw);
|
||||
BeanDefinitionValueResolver valueResolver =
|
||||
@@ -822,7 +838,7 @@ class ConstructorResolver {
|
||||
this.preparedArguments = args;
|
||||
}
|
||||
|
||||
public int getTypeDifferenceWeight(Class[] paramTypes) {
|
||||
public int getTypeDifferenceWeight(Class<?>[] paramTypes) {
|
||||
// If valid arguments found, determine type difference weight.
|
||||
// Try type difference weight on both the converted arguments and
|
||||
// the raw arguments. If the raw weight is better, use it.
|
||||
@@ -832,7 +848,7 @@ class ConstructorResolver {
|
||||
return (rawTypeDiffWeight < typeDiffWeight ? rawTypeDiffWeight : typeDiffWeight);
|
||||
}
|
||||
|
||||
public int getAssignabilityWeight(Class[] paramTypes) {
|
||||
public int getAssignabilityWeight(Class<?>[] paramTypes) {
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
if (!ClassUtils.isAssignableValue(paramTypes[i], this.arguments[i])) {
|
||||
return Integer.MAX_VALUE;
|
||||
@@ -873,7 +889,7 @@ class ConstructorResolver {
|
||||
*/
|
||||
private static class ConstructorPropertiesChecker {
|
||||
|
||||
public static String[] evaluateAnnotation(Constructor<?> candidate, int paramCount) {
|
||||
public static String[] evaluate(Constructor<?> candidate, int paramCount) {
|
||||
ConstructorProperties cp = candidate.getAnnotation(ConstructorProperties.class);
|
||||
if (cp != null) {
|
||||
String[] names = cp.value();
|
||||
|
||||
+8
-6
@@ -31,7 +31,6 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -460,12 +459,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
|
||||
public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) {
|
||||
Set<String> beanNames = new LinkedHashSet<String>(getBeanDefinitionCount());
|
||||
beanNames.addAll(Arrays.asList(getBeanDefinitionNames()));
|
||||
beanNames.addAll(Arrays.asList(getSingletonNames()));
|
||||
Map<String, Object> results = new LinkedHashMap<String, Object>();
|
||||
for (String beanName : beanNames) {
|
||||
if (findAnnotationOnBean(beanName, annotationType) != null) {
|
||||
for (String beanName : getBeanDefinitionNames()) {
|
||||
BeanDefinition beanDefinition = getBeanDefinition(beanName);
|
||||
if (!beanDefinition.isAbstract() && findAnnotationOnBean(beanName, annotationType) != null) {
|
||||
results.put(beanName, getBean(beanName));
|
||||
}
|
||||
}
|
||||
for (String beanName : getSingletonNames()) {
|
||||
if (!results.containsKey(beanName) && findAnnotationOnBean(beanName, annotationType) != null) {
|
||||
results.put(beanName, getBean(beanName));
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -84,7 +84,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
|
||||
|
||||
/** Cache of singleton factories: bean name --> ObjectFactory */
|
||||
private final Map<String, ObjectFactory> singletonFactories = new HashMap<String, ObjectFactory>(16);
|
||||
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
|
||||
|
||||
/** Cache of early singleton objects: bean name --> bean instance */
|
||||
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
|
||||
@@ -181,7 +181,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
synchronized (this.singletonObjects) {
|
||||
singletonObject = this.earlySingletonObjects.get(beanName);
|
||||
if (singletonObject == null && allowEarlyReference) {
|
||||
ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
|
||||
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
|
||||
if (singletonFactory != null) {
|
||||
singletonObject = singletonFactory.getObject();
|
||||
this.earlySingletonObjects.put(beanName, singletonObject);
|
||||
@@ -201,7 +201,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
* with, if necessary
|
||||
* @return the registered singleton object
|
||||
*/
|
||||
public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
|
||||
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
|
||||
Assert.notNull(beanName, "'beanName' must not be null");
|
||||
synchronized (this.singletonObjects) {
|
||||
Object singletonObject = this.singletonObjects.get(beanName);
|
||||
|
||||
+8
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -52,11 +52,11 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
|
||||
* @return the FactoryBean's object type,
|
||||
* or {@code null} if the type cannot be determined yet
|
||||
*/
|
||||
protected Class getTypeForFactoryBean(final FactoryBean factoryBean) {
|
||||
protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
|
||||
try {
|
||||
if (System.getSecurityManager() != null) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Class>() {
|
||||
public Class run() {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
|
||||
public Class<?> run() {
|
||||
return factoryBean.getObjectType();
|
||||
}
|
||||
}, getAccessControlContext());
|
||||
@@ -94,7 +94,7 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
|
||||
* @throws BeanCreationException if FactoryBean object creation failed
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
||||
*/
|
||||
protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {
|
||||
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
|
||||
if (factory.isSingleton() && containsSingleton(beanName)) {
|
||||
synchronized (getSingletonMutex()) {
|
||||
Object object = this.factoryBeanObjectCache.get(beanName);
|
||||
@@ -120,7 +120,7 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
||||
*/
|
||||
private Object doGetObjectFromFactoryBean(
|
||||
final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
|
||||
final FactoryBean<?> factory, final String beanName, final boolean shouldPostProcess)
|
||||
throws BeanCreationException {
|
||||
|
||||
Object object;
|
||||
@@ -190,12 +190,12 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
|
||||
* @return the bean instance as FactoryBean
|
||||
* @throws BeansException if the given bean cannot be exposed as a FactoryBean
|
||||
*/
|
||||
protected FactoryBean getFactoryBean(String beanName, Object beanInstance) throws BeansException {
|
||||
protected FactoryBean<?> getFactoryBean(String beanName, Object beanInstance) throws BeansException {
|
||||
if (!(beanInstance instanceof FactoryBean)) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Bean instance of type [" + beanInstance.getClass() + "] is not a FactoryBean");
|
||||
}
|
||||
return (FactoryBean) beanInstance;
|
||||
return (FactoryBean<?>) beanInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+15
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,14 +23,15 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Object representing the override of a method on a managed
|
||||
* object by the IoC container.
|
||||
* Object representing the override of a method on a managed object by the IoC
|
||||
* container.
|
||||
*
|
||||
* <p>Note that the override mechanism is <i>not</i> intended as a
|
||||
* generic means of inserting crosscutting code: use AOP for that.
|
||||
* <p>Note that the override mechanism is <em>not</em> intended as a generic
|
||||
* means of inserting crosscutting code: use AOP for that.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 1.1
|
||||
*/
|
||||
public abstract class MethodOverride implements BeanMetadataElement {
|
||||
@@ -59,17 +60,18 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the overridden method has to be considered as overloaded
|
||||
* (that is, whether arg type matching has to happen).
|
||||
* <p>Default is "true"; can be switched to "false" to optimize runtime performance.
|
||||
* Set whether the overridden method is <em>overloaded</em> (i.e., whether argument
|
||||
* type matching needs to occur to disambiguate methods of the same name).
|
||||
* <p>Default is {@code true}; can be switched to {@code false} to optimize
|
||||
* runtime performance.
|
||||
*/
|
||||
protected void setOverloaded(boolean overloaded) {
|
||||
this.overloaded = overloaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the overridden method has to be considered as overloaded
|
||||
* (that is, whether arg type matching has to happen).
|
||||
* Return whether the overridden method is <em>overloaded</em> (i.e., whether argument
|
||||
* type matching needs to occur to disambiguate methods of the same name).
|
||||
*/
|
||||
protected boolean isOverloaded() {
|
||||
return this.overloaded;
|
||||
@@ -87,17 +89,15 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses must override this to indicate whether they match
|
||||
* the given method. This allows for argument list checking
|
||||
* as well as method name checking.
|
||||
* Subclasses must override this to indicate whether they <em>match</em> the
|
||||
* given method. This allows for argument list checking as well as method
|
||||
* name checking.
|
||||
* @param method the method to check
|
||||
* @return whether this override matches the given method
|
||||
*/
|
||||
public abstract boolean matches(Method method);
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
@@ -108,7 +108,6 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
}
|
||||
MethodOverride that = (MethodOverride) other;
|
||||
return (ObjectUtils.nullSafeEquals(this.methodName, that.methodName) &&
|
||||
this.overloaded == that.overloaded &&
|
||||
ObjectUtils.nullSafeEquals(this.source, that.source));
|
||||
}
|
||||
|
||||
@@ -116,7 +115,6 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
public int hashCode() {
|
||||
int hashCode = ObjectUtils.nullSafeHashCode(this.methodName);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.source);
|
||||
hashCode = 29 * hashCode + (this.overloaded ? 1 : 0);
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
|
||||
+61
-38
@@ -18,8 +18,8 @@ package org.springframework.beans.factory.support;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -48,19 +48,10 @@ import org.springframework.util.Assert;
|
||||
@SuppressWarnings("serial")
|
||||
public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
|
||||
// using a ConcurrentHashMap as a Set
|
||||
private final Map<Member, Boolean> externallyManagedConfigMembers = new ConcurrentHashMap<Member, Boolean>(0);
|
||||
|
||||
// using a ConcurrentHashMap as a Set
|
||||
private final Map<String, Boolean> externallyManagedInitMethods = new ConcurrentHashMap<String, Boolean>(0);
|
||||
|
||||
// using a ConcurrentHashMap as a Set
|
||||
private final Map<String, Boolean> externallyManagedDestroyMethods = new ConcurrentHashMap<String, Boolean>(0);
|
||||
boolean allowCaching = true;
|
||||
|
||||
private BeanDefinitionHolder decoratedDefinition;
|
||||
|
||||
boolean allowCaching = true;
|
||||
|
||||
private volatile Class<?> targetType;
|
||||
|
||||
boolean isFactoryMethodUnique = false;
|
||||
@@ -87,6 +78,12 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
/** Package-visible field that indicates a before-instantiation post-processor having kicked in */
|
||||
volatile Boolean beforeInstantiationResolved;
|
||||
|
||||
private Set<Member> externallyManagedConfigMembers;
|
||||
|
||||
private Set<String> externallyManagedInitMethods;
|
||||
|
||||
private Set<String> externallyManagedDestroyMethods;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new RootBeanDefinition, to be configured through its bean
|
||||
@@ -107,7 +104,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
* Create a new RootBeanDefinition for a singleton.
|
||||
* @param beanClass the class of the bean to instantiate
|
||||
*/
|
||||
public RootBeanDefinition(Class beanClass) {
|
||||
public RootBeanDefinition(Class<?> beanClass) {
|
||||
super();
|
||||
setBeanClass(beanClass);
|
||||
}
|
||||
@@ -147,7 +144,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
* @param dependencyCheck whether to perform a dependency check for objects
|
||||
* (not applicable to autowiring a constructor, thus ignored there)
|
||||
*/
|
||||
public RootBeanDefinition(Class beanClass, int autowireMode, boolean dependencyCheck) {
|
||||
public RootBeanDefinition(Class<?> beanClass, int autowireMode, boolean dependencyCheck) {
|
||||
super();
|
||||
setBeanClass(beanClass);
|
||||
setAutowireMode(autowireMode);
|
||||
@@ -191,7 +188,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
* @param cargs the constructor argument values to apply
|
||||
* @param pvs the property values to apply
|
||||
*/
|
||||
public RootBeanDefinition(Class beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
|
||||
public RootBeanDefinition(Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
|
||||
super(cargs, pvs);
|
||||
setBeanClass(beanClass);
|
||||
}
|
||||
@@ -225,7 +222,11 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
* @param original the original bean definition to copy from
|
||||
*/
|
||||
public RootBeanDefinition(RootBeanDefinition original) {
|
||||
this((BeanDefinition) original);
|
||||
super((BeanDefinition) original);
|
||||
this.allowCaching = original.allowCaching;
|
||||
this.decoratedDefinition = original.decoratedDefinition;
|
||||
this.targetType = original.targetType;
|
||||
this.isFactoryMethodUnique = original.isFactoryMethodUnique;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -235,13 +236,6 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
*/
|
||||
RootBeanDefinition(BeanDefinition original) {
|
||||
super(original);
|
||||
if (original instanceof RootBeanDefinition) {
|
||||
RootBeanDefinition originalRbd = (RootBeanDefinition) original;
|
||||
this.decoratedDefinition = originalRbd.decoratedDefinition;
|
||||
this.allowCaching = originalRbd.allowCaching;
|
||||
this.targetType = originalRbd.targetType;
|
||||
this.isFactoryMethodUnique = originalRbd.isFactoryMethodUnique;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -255,6 +249,20 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a target definition that is being decorated by this bean definition.
|
||||
*/
|
||||
public void setDecoratedDefinition(BeanDefinitionHolder decoratedDefinition) {
|
||||
this.decoratedDefinition = decoratedDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the target definition that is being decorated by this bean definition, if any.
|
||||
*/
|
||||
public BeanDefinitionHolder getDecoratedDefinition() {
|
||||
return this.decoratedDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the target type of this bean definition, if known in advance.
|
||||
*/
|
||||
@@ -297,37 +305,52 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void registerExternallyManagedConfigMember(Member configMember) {
|
||||
this.externallyManagedConfigMembers.put(configMember, Boolean.TRUE);
|
||||
synchronized (this.postProcessingLock) {
|
||||
if (this.externallyManagedConfigMembers == null) {
|
||||
this.externallyManagedConfigMembers = new HashSet<Member>(1);
|
||||
}
|
||||
this.externallyManagedConfigMembers.add(configMember);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExternallyManagedConfigMember(Member configMember) {
|
||||
return this.externallyManagedConfigMembers.containsKey(configMember);
|
||||
synchronized (this.postProcessingLock) {
|
||||
return (this.externallyManagedConfigMembers != null &&
|
||||
this.externallyManagedConfigMembers.contains(configMember));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerExternallyManagedInitMethod(String initMethod) {
|
||||
this.externallyManagedInitMethods.put(initMethod, Boolean.TRUE);
|
||||
synchronized (this.postProcessingLock) {
|
||||
if (this.externallyManagedInitMethods == null) {
|
||||
this.externallyManagedInitMethods = new HashSet<String>(1);
|
||||
}
|
||||
this.externallyManagedInitMethods.add(initMethod);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExternallyManagedInitMethod(String initMethod) {
|
||||
return this.externallyManagedInitMethods.containsKey(initMethod);
|
||||
synchronized (this.postProcessingLock) {
|
||||
return (this.externallyManagedInitMethods != null &&
|
||||
this.externallyManagedInitMethods.contains(initMethod));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerExternallyManagedDestroyMethod(String destroyMethod) {
|
||||
this.externallyManagedDestroyMethods.put(destroyMethod, Boolean.TRUE);
|
||||
synchronized (this.postProcessingLock) {
|
||||
if (this.externallyManagedDestroyMethods == null) {
|
||||
this.externallyManagedDestroyMethods = new HashSet<String>(1);
|
||||
}
|
||||
this.externallyManagedDestroyMethods.add(destroyMethod);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExternallyManagedDestroyMethod(String destroyMethod) {
|
||||
return this.externallyManagedDestroyMethods.containsKey(destroyMethod);
|
||||
}
|
||||
|
||||
public void setDecoratedDefinition(BeanDefinitionHolder decoratedDefinition) {
|
||||
this.decoratedDefinition = decoratedDefinition;
|
||||
}
|
||||
|
||||
public BeanDefinitionHolder getDecoratedDefinition() {
|
||||
return this.decoratedDefinition;
|
||||
synchronized (this.postProcessingLock) {
|
||||
return (this.externallyManagedDestroyMethods != null &&
|
||||
this.externallyManagedDestroyMethods.contains(destroyMethod));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -62,14 +62,14 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||
synchronized (beanDefinition.constructorArgumentLock) {
|
||||
constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
|
||||
if (constructorToUse == null) {
|
||||
final Class clazz = beanDefinition.getBeanClass();
|
||||
final Class<?> clazz = beanDefinition.getBeanClass();
|
||||
if (clazz.isInterface()) {
|
||||
throw new BeanInstantiationException(clazz, "Specified class is an interface");
|
||||
}
|
||||
try {
|
||||
if (System.getSecurityManager() != null) {
|
||||
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
|
||||
public Constructor run() throws Exception {
|
||||
public Constructor<?> run() throws Exception {
|
||||
return clazz.getDeclaredConstructor((Class[]) null);
|
||||
}
|
||||
});
|
||||
@@ -132,7 +132,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||
* Instantiation should use the given constructor and parameters.
|
||||
*/
|
||||
protected Object instantiateWithMethodInjection(RootBeanDefinition beanDefinition,
|
||||
String beanName, BeanFactory owner, Constructor ctor, Object[] args) {
|
||||
String beanName, BeanFactory owner, Constructor<?> ctor, Object[] args) {
|
||||
|
||||
throw new UnsupportedOperationException(
|
||||
"Method Injection not supported in SimpleInstantiationStrategy");
|
||||
|
||||
+12
-12
@@ -93,7 +93,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||
|
||||
if (bean instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
try {
|
||||
return ((FactoryBean) bean).getObject();
|
||||
return ((FactoryBean<?>) bean).getObject();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
|
||||
@@ -141,18 +141,18 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
|
||||
Object bean = getBean(name);
|
||||
// In case of FactoryBean, return singleton status of created object.
|
||||
return (bean instanceof FactoryBean && ((FactoryBean) bean).isSingleton());
|
||||
return (bean instanceof FactoryBean && ((FactoryBean<?>) bean).isSingleton());
|
||||
}
|
||||
|
||||
public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
|
||||
Object bean = getBean(name);
|
||||
// In case of FactoryBean, return prototype status of created object.
|
||||
return ((bean instanceof SmartFactoryBean && ((SmartFactoryBean) bean).isPrototype()) ||
|
||||
(bean instanceof FactoryBean && !((FactoryBean) bean).isSingleton()));
|
||||
return ((bean instanceof SmartFactoryBean && ((SmartFactoryBean<?>) bean).isPrototype()) ||
|
||||
(bean instanceof FactoryBean && !((FactoryBean<?>) bean).isSingleton()));
|
||||
}
|
||||
|
||||
public boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException {
|
||||
Class type = getType(name);
|
||||
public boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException {
|
||||
Class<?> type = getType(name);
|
||||
return (targetType == null || (type != null && targetType.isAssignableFrom(type)));
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||
|
||||
if (bean instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
|
||||
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
|
||||
return ((FactoryBean) bean).getObjectType();
|
||||
return ((FactoryBean<?>) bean).getObjectType();
|
||||
}
|
||||
return bean.getClass();
|
||||
}
|
||||
@@ -193,18 +193,18 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||
return StringUtils.toStringArray(this.beans.keySet());
|
||||
}
|
||||
|
||||
public String[] getBeanNamesForType(Class type) {
|
||||
public String[] getBeanNamesForType(Class<?> type) {
|
||||
return getBeanNamesForType(type, true, true);
|
||||
}
|
||||
|
||||
public String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean includeFactoryBeans) {
|
||||
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean includeFactoryBeans) {
|
||||
boolean isFactoryType = (type != null && FactoryBean.class.isAssignableFrom(type));
|
||||
List<String> matches = new ArrayList<String>();
|
||||
for (String name : this.beans.keySet()) {
|
||||
Object beanInstance = this.beans.get(name);
|
||||
if (beanInstance instanceof FactoryBean && !isFactoryType) {
|
||||
if (includeFactoryBeans) {
|
||||
Class objectType = ((FactoryBean) beanInstance).getObjectType();
|
||||
Class<?> objectType = ((FactoryBean<?>) beanInstance).getObjectType();
|
||||
if (objectType != null && (type == null || type.isAssignableFrom(objectType))) {
|
||||
matches.add(name);
|
||||
}
|
||||
@@ -237,8 +237,8 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||
if (beanInstance instanceof FactoryBean && !isFactoryType) {
|
||||
if (includeFactoryBeans) {
|
||||
// Match object created by FactoryBean.
|
||||
FactoryBean factory = (FactoryBean) beanInstance;
|
||||
Class objectType = factory.getObjectType();
|
||||
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
|
||||
Class<?> objectType = factory.getObjectType();
|
||||
if ((includeNonSingletons || factory.isSingleton()) &&
|
||||
objectType != null && (type == null || type.isAssignableFrom(objectType))) {
|
||||
matches.put(beanName, getBean(beanName, type));
|
||||
|
||||
+14
-4
@@ -133,7 +133,7 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
|
||||
// then ultimately reset this.delegate back to its original (parent) reference.
|
||||
// this behavior emulates a stack of delegates without actually necessitating one.
|
||||
BeanDefinitionParserDelegate parent = this.delegate;
|
||||
this.delegate = createHelper(this.readerContext, root, parent);
|
||||
this.delegate = createDelegate(this.readerContext, root, parent);
|
||||
|
||||
preProcessXml(root);
|
||||
parseBeanDefinitions(root, this.delegate);
|
||||
@@ -142,12 +142,22 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
|
||||
this.delegate = parent;
|
||||
}
|
||||
|
||||
protected BeanDefinitionParserDelegate createDelegate(
|
||||
XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
|
||||
|
||||
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root, parentDelegate);
|
||||
if (delegate == null) {
|
||||
delegate = new BeanDefinitionParserDelegate(readerContext, this.environment);
|
||||
delegate.initDefaults(root, parentDelegate);
|
||||
}
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
protected BeanDefinitionParserDelegate createHelper(
|
||||
XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
|
||||
|
||||
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, environment);
|
||||
delegate.initDefaults(root, parentDelegate);
|
||||
return delegate;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+5
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -78,9 +78,12 @@ public class ResourceEditorRegistrar implements PropertyEditorRegistrar {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ResourceEditorRegistrar for the given ResourceLoader
|
||||
* Create a new ResourceEditorRegistrar for the given {@link ResourceLoader}
|
||||
* and {@link PropertyResolver}.
|
||||
* @param resourceLoader the ResourceLoader (or ResourcePatternResolver)
|
||||
* to create editors for (usually an ApplicationContext)
|
||||
* @param propertyResolver the PropertyResolver (usually an Environment)
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.core.io.support.ResourcePatternResolver
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
*/
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.beans;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -25,6 +23,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.propertyeditors.CustomDateEditor;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -33,6 +32,7 @@ import org.springframework.tests.sample.beans.DerivedTestBean;
|
||||
import org.springframework.tests.sample.beans.ITestBean;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link BeanUtils}.
|
||||
@@ -79,8 +79,7 @@ public final class BeanUtilsTests {
|
||||
@Test
|
||||
public void testBeanPropertyIsArray() {
|
||||
PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(ContainerBean.class);
|
||||
for (int i = 0; i < descriptors.length; i++) {
|
||||
PropertyDescriptor descriptor = descriptors[i];
|
||||
for (PropertyDescriptor descriptor : descriptors) {
|
||||
if ("containedBeans".equals(descriptor.getName())) {
|
||||
assertTrue("Property should be an array", descriptor.getPropertyType().isArray());
|
||||
assertEquals(descriptor.getPropertyType().getComponentType(), ContainedBean.class);
|
||||
@@ -171,7 +170,7 @@ public final class BeanUtilsTests {
|
||||
assertTrue("Touchy empty", tb2.getTouchy() == null);
|
||||
|
||||
// "spouse", "touchy", "age" should not be copied
|
||||
BeanUtils.copyProperties(tb, tb2, new String[]{"spouse", "touchy", "age"});
|
||||
BeanUtils.copyProperties(tb, tb2, "spouse", "touchy", "age");
|
||||
assertTrue("Name copied", tb2.getName() == null);
|
||||
assertTrue("Age still empty", tb2.getAge() == 0);
|
||||
assertTrue("Touchy still empty", tb2.getTouchy() == null);
|
||||
@@ -182,10 +181,23 @@ public final class BeanUtilsTests {
|
||||
NameAndSpecialProperty source = new NameAndSpecialProperty();
|
||||
source.setName("name");
|
||||
TestBean target = new TestBean();
|
||||
BeanUtils.copyProperties(source, target, new String[]{"specialProperty"});
|
||||
BeanUtils.copyProperties(source, target, "specialProperty");
|
||||
assertEquals(target.getName(), "name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyPropertiesWithInvalidProperty() {
|
||||
InvalidProperty source = new InvalidProperty();
|
||||
source.setName("name");
|
||||
source.setFlag1(true);
|
||||
source.setFlag2(true);
|
||||
InvalidProperty target = new InvalidProperty();
|
||||
BeanUtils.copyProperties(source, target);
|
||||
assertEquals(target.getName(), "name");
|
||||
assertTrue(target.getFlag1());
|
||||
assertTrue(target.getFlag2());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveSimpleSignature() throws Exception {
|
||||
Method desiredMethod = MethodSignatureBean.class.getMethod("doSomething");
|
||||
@@ -257,7 +269,8 @@ public final class BeanUtilsTests {
|
||||
assertEquals(String.class, keyDescr.getPropertyType());
|
||||
for (PropertyDescriptor propertyDescriptor : descrs) {
|
||||
if (propertyDescriptor.getName().equals(keyDescr.getName())) {
|
||||
assertEquals(propertyDescriptor.getName() + " has unexpected type", keyDescr.getPropertyType(), propertyDescriptor.getPropertyType());
|
||||
assertEquals(propertyDescriptor.getName() + " has unexpected type",
|
||||
keyDescr.getPropertyType(), propertyDescriptor.getPropertyType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,6 +305,51 @@ public final class BeanUtilsTests {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class InvalidProperty {
|
||||
|
||||
private String name;
|
||||
|
||||
private String value;
|
||||
|
||||
private boolean flag1;
|
||||
|
||||
private boolean flag2;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
this.value = Integer.toString(value);
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void setFlag1(boolean flag1) {
|
||||
this.flag1 = flag1;
|
||||
}
|
||||
|
||||
public Boolean getFlag1() {
|
||||
return this.flag1;
|
||||
}
|
||||
|
||||
public void setFlag2(Boolean flag2) {
|
||||
this.flag2 = flag2;
|
||||
}
|
||||
|
||||
public boolean getFlag2() {
|
||||
return this.flag2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class ContainerBean {
|
||||
|
||||
@@ -347,6 +405,7 @@ public final class BeanUtilsTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private interface MapEntry<K, V> {
|
||||
|
||||
K getKey();
|
||||
@@ -358,6 +417,7 @@ public final class BeanUtilsTests {
|
||||
void setValue(V value);
|
||||
}
|
||||
|
||||
|
||||
private static class Bean implements MapEntry<String, String> {
|
||||
|
||||
private String key;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,13 +16,6 @@
|
||||
|
||||
package org.springframework.beans;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
@@ -44,11 +37,16 @@ import java.util.TreeSet;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.beans.propertyeditors.CustomNumberEditor;
|
||||
import org.springframework.beans.propertyeditors.StringArrayPropertyEditor;
|
||||
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
|
||||
import org.springframework.beans.support.DerivedFromProtectedBaseBean;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.tests.Assume;
|
||||
import org.springframework.tests.TestGroup;
|
||||
import org.springframework.tests.sample.beans.BooleanTestBean;
|
||||
@@ -56,13 +54,11 @@ import org.springframework.tests.sample.beans.ITestBean;
|
||||
import org.springframework.tests.sample.beans.IndexedTestBean;
|
||||
import org.springframework.tests.sample.beans.NumberTestBean;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
@@ -1553,14 +1549,55 @@ public final class BeanWrapperTests {
|
||||
@Test
|
||||
public void cornerSpr10115() {
|
||||
Spr10115Bean foo = new Spr10115Bean();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl();
|
||||
bwi.setWrappedInstance(foo);
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
|
||||
bwi.setPropertyValue("prop1", "val1");
|
||||
assertEquals("val1", Spr10115Bean.prop1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArrayToObject() {
|
||||
ArrayToObject foo = new ArrayToObject();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
|
||||
|
||||
Object[] array = new Object[] {"1","2"};
|
||||
bwi.setPropertyValue("object", array);
|
||||
assertThat(foo.getObject(), equalTo((Object) array));
|
||||
|
||||
array = new Object[] {"1"};
|
||||
bwi.setPropertyValue("object", array);
|
||||
assertThat(foo.getObject(), equalTo((Object) array));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyTypeMismatch() {
|
||||
PropertyTypeMismatch foo = new PropertyTypeMismatch();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
|
||||
bwi.setPropertyValue("object", "a String");
|
||||
assertEquals("a String", foo.value);
|
||||
assertEquals(8, bwi.getPropertyValue("object"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericArraySetter() {
|
||||
SkipReaderStub foo = new SkipReaderStub();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
|
||||
List<String> values = new LinkedList<String>();
|
||||
values.add("1");
|
||||
values.add("2");
|
||||
values.add("3");
|
||||
values.add("4");
|
||||
bwi.setPropertyValue("items", values);
|
||||
Object[] result = foo.items;
|
||||
assertEquals(4, result.length);
|
||||
assertEquals("1", result[0]);
|
||||
assertEquals("2", result[1]);
|
||||
assertEquals("3", result[2]);
|
||||
assertEquals("4", result[3]);
|
||||
}
|
||||
|
||||
|
||||
static class Spr10115Bean {
|
||||
|
||||
private static String prop1;
|
||||
|
||||
public static void setProp1(String prop1) {
|
||||
@@ -1944,4 +1981,49 @@ public final class BeanWrapperTests {
|
||||
TEST_VALUE
|
||||
}
|
||||
|
||||
|
||||
public static class ArrayToObject {
|
||||
|
||||
private Object object;
|
||||
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class PropertyTypeMismatch {
|
||||
|
||||
public String value;
|
||||
|
||||
public void setObject(String object) {
|
||||
this.value = object;
|
||||
}
|
||||
|
||||
public Integer getObject() {
|
||||
return (this.value != null ? this.value.length() : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class SkipReaderStub<T> {
|
||||
|
||||
public T[] items;
|
||||
|
||||
public SkipReaderStub() {
|
||||
}
|
||||
|
||||
public SkipReaderStub(T... items) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public void setItems(T... items) {
|
||||
this.items = items;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,29 +21,19 @@ import java.beans.IndexedPropertyDescriptor;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.JdkVersion;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.lessThan;
|
||||
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ExtendedBeanInfo}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
@@ -207,10 +197,6 @@ public class ExtendedBeanInfoTests {
|
||||
}
|
||||
}
|
||||
|
||||
interface Spr9453<T> {
|
||||
T getProp();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cornerSpr9453() throws IntrospectionException {
|
||||
final class Bean implements Spr9453<Class<?>> {
|
||||
@@ -335,10 +321,8 @@ public class ExtendedBeanInfoTests {
|
||||
BeanInfo ebi = new ExtendedBeanInfo(bi);
|
||||
|
||||
assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
|
||||
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
|
||||
|
||||
assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
|
||||
assertThat(hasWriteMethodForProperty(ebi, "foo"), is(false));
|
||||
assertEquals(hasWriteMethodForProperty(bi, "foo"), hasWriteMethodForProperty(ebi, "foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -352,10 +336,8 @@ public class ExtendedBeanInfoTests {
|
||||
BeanInfo ebi = new ExtendedBeanInfo(bi);
|
||||
|
||||
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
|
||||
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(false));
|
||||
|
||||
assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
|
||||
assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(false));
|
||||
assertEquals(hasIndexedWriteMethodForProperty(bi, "foos"), hasIndexedWriteMethodForProperty(ebi, "foos"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -595,7 +577,6 @@ public class ExtendedBeanInfoTests {
|
||||
new ExtendedBeanInfo(Introspector.getBeanInfo(BigDecimal.class));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void subclassWriteMethodWithCovariantReturnType() throws IntrospectionException {
|
||||
@SuppressWarnings("unused") class B {
|
||||
@@ -792,6 +773,7 @@ public class ExtendedBeanInfoTests {
|
||||
@Test
|
||||
public void propertyDescriptorComparator() throws IntrospectionException {
|
||||
PropertyDescriptorComparator c = new PropertyDescriptorComparator();
|
||||
|
||||
assertThat(c.compare(new PropertyDescriptor("a", null, null), new PropertyDescriptor("a", null, null)), equalTo(0));
|
||||
assertThat(c.compare(new PropertyDescriptor("abc", null, null), new PropertyDescriptor("abc", null, null)), equalTo(0));
|
||||
assertThat(c.compare(new PropertyDescriptor("a", null, null), new PropertyDescriptor("b", null, null)), lessThan(0));
|
||||
@@ -863,31 +845,6 @@ public class ExtendedBeanInfoTests {
|
||||
new ExtendedBeanInfo(Introspector.getBeanInfo(LawLibrary.class));
|
||||
}
|
||||
|
||||
interface Book { }
|
||||
|
||||
interface TextBook extends Book { }
|
||||
|
||||
interface LawBook extends TextBook { }
|
||||
|
||||
interface BookOperations {
|
||||
Book getBook();
|
||||
void setBook(Book book);
|
||||
}
|
||||
|
||||
interface TextBookOperations extends BookOperations {
|
||||
TextBook getBook();
|
||||
}
|
||||
|
||||
abstract class Library {
|
||||
public Book getBook() { return null; }
|
||||
public void setBook(Book book) { }
|
||||
}
|
||||
|
||||
class LawLibrary extends Library implements TextBookOperations {
|
||||
public LawBook getBook() { return null; }
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void cornerSpr8949() throws IntrospectionException {
|
||||
class A {
|
||||
@@ -905,23 +862,10 @@ public class ExtendedBeanInfoTests {
|
||||
|
||||
BeanInfo bi = Introspector.getBeanInfo(B.class);
|
||||
|
||||
/* first, demonstrate the 'problem':
|
||||
* java.beans.Introspector returns the "wrong" declaring class for overridden read
|
||||
* methods, which in turn violates expectations in {@link ExtendedBeanInfo} regarding
|
||||
* method equality. Spring's {@link ClassUtils#getMostSpecificMethod(Method, Class)}
|
||||
* helps out here, and is now put into use in ExtendedBeanInfo as well
|
||||
*/
|
||||
for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
|
||||
if ("targetMethod".equals(pd.getName())) {
|
||||
Method readMethod = pd.getReadMethod();
|
||||
assertTrue(readMethod.getDeclaringClass().equals(A.class)); // we expected B!
|
||||
|
||||
Method msReadMethod = ClassUtils.getMostSpecificMethod(readMethod, B.class);
|
||||
assertTrue(msReadMethod.getDeclaringClass().equals(B.class)); // and now we get it.
|
||||
}
|
||||
}
|
||||
|
||||
// and now demonstrate that we've indeed fixed the problem
|
||||
// java.beans.Introspector returns the "wrong" declaring class for overridden read
|
||||
// methods, which in turn violates expectations in {@link ExtendedBeanInfo} regarding
|
||||
// method equality. Spring's {@link ClassUtils#getMostSpecificMethod(Method, Class)}
|
||||
// helps out here, and is now put into use in ExtendedBeanInfo as well.
|
||||
BeanInfo ebi = new ExtendedBeanInfo(bi);
|
||||
|
||||
assertThat(hasReadMethodForProperty(bi, "targetMethod"), is(true));
|
||||
@@ -973,8 +917,56 @@ public class ExtendedBeanInfoTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface Spr9453<T> {
|
||||
|
||||
T getProp();
|
||||
}
|
||||
|
||||
interface Book {
|
||||
}
|
||||
|
||||
interface TextBook extends Book {
|
||||
}
|
||||
|
||||
interface LawBook extends TextBook {
|
||||
}
|
||||
|
||||
interface BookOperations {
|
||||
|
||||
Book getBook();
|
||||
|
||||
void setBook(Book book);
|
||||
}
|
||||
|
||||
interface TextBookOperations extends BookOperations {
|
||||
|
||||
@Override
|
||||
TextBook getBook();
|
||||
}
|
||||
|
||||
abstract class Library {
|
||||
|
||||
public Book getBook() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setBook(Book book) {
|
||||
}
|
||||
}
|
||||
|
||||
class LawLibrary extends Library implements TextBookOperations {
|
||||
|
||||
@Override
|
||||
public LawBook getBook() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class WithStaticWriteMethod {
|
||||
|
||||
public static void setProp1(String prop1) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,7 +28,7 @@ import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SimpleNonIndexedPropertyDescriptor} and
|
||||
* Unit tests for {@link SimplePropertyDescriptor} and
|
||||
* {@link SimpleIndexedPropertyDescriptor}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
@@ -39,7 +39,7 @@ public class SimplePropertyDescriptorTests {
|
||||
@Test
|
||||
public void toStringOutput() throws IntrospectionException, SecurityException, NoSuchMethodException {
|
||||
{
|
||||
Object pd = new SimpleNonIndexedPropertyDescriptor("foo", null, null);
|
||||
Object pd = new SimplePropertyDescriptor("foo", null, null);
|
||||
assertThat(pd.toString(), containsString(
|
||||
"PropertyDescriptor[name=foo, propertyType=null, readMethod=null"));
|
||||
}
|
||||
@@ -49,7 +49,7 @@ public class SimplePropertyDescriptorTests {
|
||||
public Object setFoo(String foo) { return null; }
|
||||
}
|
||||
Method m = C.class.getMethod("setFoo", String.class);
|
||||
Object pd = new SimpleNonIndexedPropertyDescriptor("foo", null, m);
|
||||
Object pd = new SimplePropertyDescriptor("foo", null, m);
|
||||
assertThat(pd.toString(), allOf(
|
||||
containsString("PropertyDescriptor[name=foo"),
|
||||
containsString("propertyType=class java.lang.String"),
|
||||
@@ -76,10 +76,10 @@ public class SimplePropertyDescriptorTests {
|
||||
|
||||
@Test
|
||||
public void nonIndexedEquality() throws IntrospectionException, SecurityException, NoSuchMethodException {
|
||||
Object pd1 = new SimpleNonIndexedPropertyDescriptor("foo", null, null);
|
||||
Object pd1 = new SimplePropertyDescriptor("foo", null, null);
|
||||
assertThat(pd1, equalTo(pd1));
|
||||
|
||||
Object pd2 = new SimpleNonIndexedPropertyDescriptor("foo", null, null);
|
||||
Object pd2 = new SimplePropertyDescriptor("foo", null, null);
|
||||
assertThat(pd1, equalTo(pd2));
|
||||
assertThat(pd2, equalTo(pd1));
|
||||
|
||||
@@ -89,12 +89,12 @@ public class SimplePropertyDescriptorTests {
|
||||
public String getFoo() { return null; }
|
||||
}
|
||||
Method wm1 = C.class.getMethod("setFoo", String.class);
|
||||
Object pd3 = new SimpleNonIndexedPropertyDescriptor("foo", null, wm1);
|
||||
Object pd3 = new SimplePropertyDescriptor("foo", null, wm1);
|
||||
assertThat(pd1, not(equalTo(pd3)));
|
||||
assertThat(pd3, not(equalTo(pd1)));
|
||||
|
||||
Method rm1 = C.class.getMethod("getFoo");
|
||||
Object pd4 = new SimpleNonIndexedPropertyDescriptor("foo", rm1, null);
|
||||
Object pd4 = new SimplePropertyDescriptor("foo", rm1, null);
|
||||
assertThat(pd1, not(equalTo(pd4)));
|
||||
assertThat(pd4, not(equalTo(pd1)));
|
||||
|
||||
@@ -147,4 +147,5 @@ public class SimplePropertyDescriptorTests {
|
||||
assertThat(pd1, not(equalTo(pd7)));
|
||||
assertThat(pd7, not(equalTo(pd1)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
@@ -712,6 +712,20 @@ public class DefaultListableBeanFactoryTests {
|
||||
factory.getMergedBeanDefinition("child"), factory.getMergedBeanDefinition("child"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTypeWorksAfterParentChildMerging() {
|
||||
RootBeanDefinition parentDefinition = new RootBeanDefinition(TestBean.class);
|
||||
ChildBeanDefinition childDefinition = new ChildBeanDefinition("parent", DerivedTestBean.class, null, null);
|
||||
|
||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||
factory.registerBeanDefinition("parent", parentDefinition);
|
||||
factory.registerBeanDefinition("child", childDefinition);
|
||||
factory.freezeConfiguration();
|
||||
|
||||
assertEquals(TestBean.class, factory.getType("parent"));
|
||||
assertEquals(DerivedTestBean.class, factory.getType("child"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNameAlreadyBound() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="abstractFactoryBean" class="org.springframework.beans.factory.FactoryBeanTests$AbstractFactoryBean" abstract="true"/>
|
||||
|
||||
</beans>
|
||||
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -38,6 +39,7 @@ public final class FactoryBeanTests {
|
||||
private static final Class<?> CLASS = FactoryBeanTests.class;
|
||||
private static final Resource RETURNS_NULL_CONTEXT = qualifiedResource(CLASS, "returnsNull.xml");
|
||||
private static final Resource WITH_AUTOWIRING_CONTEXT = qualifiedResource(CLASS, "withAutowiring.xml");
|
||||
private static final Resource ABSTRACT_CONTEXT = qualifiedResource(CLASS, "abstract.xml");
|
||||
|
||||
@Test
|
||||
public void testFactoryBeanReturnsNull() throws Exception {
|
||||
@@ -80,6 +82,20 @@ public final class FactoryBeanTests {
|
||||
assertSame(gamma, beta.getGamma());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbstractFactoryBeanViaAnnotation() throws Exception {
|
||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(ABSTRACT_CONTEXT);
|
||||
factory.getBeansWithAnnotation(Component.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbstractFactoryBeanViaType() throws Exception {
|
||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(ABSTRACT_CONTEXT);
|
||||
factory.getBeansOfType(AbstractFactoryBean.class);
|
||||
}
|
||||
|
||||
|
||||
public static class NullReturningFactoryBean implements FactoryBean<Object> {
|
||||
|
||||
@@ -152,6 +168,7 @@ public final class FactoryBeanTests {
|
||||
}
|
||||
|
||||
|
||||
@Component
|
||||
public static class BetaFactoryBean implements FactoryBean<Object> {
|
||||
|
||||
private Beta beta;
|
||||
@@ -176,4 +193,7 @@ public final class FactoryBeanTests {
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class AbstractFactoryBean implements FactoryBean<Object> {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.annotation;
|
||||
package org.springframework.beans.factory.annotation;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
+1
-3
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.annotation;
|
||||
package org.springframework.beans.factory.annotation;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@@ -28,8 +28,6 @@ import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class AutowireUtilsTests {
|
||||
|
||||
@Test
|
||||
public void genericMethodReturnTypes() {
|
||||
Method notParameterized = ReflectionUtils.findMethod(MyTypeWithMethods.class, "notParameterized", new Class[]{});
|
||||
assertEquals(String.class,
|
||||
AutowireUtils.resolveReturnTypeForFactoryMethod(notParameterized, new Object[]{}, getClass().getClassLoader()));
|
||||
|
||||
Method notParameterizedWithArguments = ReflectionUtils.findMethod(MyTypeWithMethods.class, "notParameterizedWithArguments",
|
||||
new Class[] { Integer.class, Boolean.class });
|
||||
assertEquals(String.class,
|
||||
AutowireUtils.resolveReturnTypeForFactoryMethod(notParameterizedWithArguments, new Object[] { 99, true }, getClass().getClassLoader()));
|
||||
|
||||
Method createProxy = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createProxy", new Class[] { Object.class });
|
||||
assertEquals(String.class,
|
||||
AutowireUtils.resolveReturnTypeForFactoryMethod(createProxy, new Object[] { "foo" }, getClass().getClassLoader()));
|
||||
|
||||
Method createNamedProxyWithDifferentTypes = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createNamedProxy",
|
||||
new Class[] { String.class, Object.class });
|
||||
assertEquals(Long.class,
|
||||
AutowireUtils.resolveReturnTypeForFactoryMethod(createNamedProxyWithDifferentTypes, new Object[] { "enigma", 99L }, getClass().getClassLoader()));
|
||||
|
||||
Method createNamedProxyWithDuplicateTypes = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createNamedProxy",
|
||||
new Class[] { String.class, Object.class });
|
||||
assertEquals(String.class,
|
||||
AutowireUtils.resolveReturnTypeForFactoryMethod(createNamedProxyWithDuplicateTypes, new Object[] { "enigma", "foo" }, getClass().getClassLoader()));
|
||||
|
||||
Method createMock = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createMock", new Class[] { Class.class });
|
||||
assertEquals(Runnable.class,
|
||||
AutowireUtils.resolveReturnTypeForFactoryMethod(createMock, new Object[] { Runnable.class }, getClass().getClassLoader()));
|
||||
assertEquals(Runnable.class,
|
||||
AutowireUtils.resolveReturnTypeForFactoryMethod(createMock, new Object[] { Runnable.class.getName() }, getClass().getClassLoader()));
|
||||
|
||||
Method createNamedMock = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createNamedMock", new Class[] { String.class,
|
||||
Class.class });
|
||||
assertEquals(Runnable.class,
|
||||
AutowireUtils.resolveReturnTypeForFactoryMethod(createNamedMock, new Object[] { "foo", Runnable.class }, getClass().getClassLoader()));
|
||||
|
||||
Method createVMock = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createVMock",
|
||||
new Class[] { Object.class, Class.class });
|
||||
assertEquals(Runnable.class,
|
||||
AutowireUtils.resolveReturnTypeForFactoryMethod(createVMock, new Object[] { "foo", Runnable.class }, getClass().getClassLoader()));
|
||||
|
||||
// Ideally we would expect String.class instead of Object.class, but
|
||||
// resolveReturnTypeForFactoryMethod() does not currently support this form of
|
||||
// look-up.
|
||||
Method extractValueFrom = ReflectionUtils.findMethod(MyTypeWithMethods.class, "extractValueFrom",
|
||||
new Class[] { MyInterfaceType.class });
|
||||
assertEquals(Object.class,
|
||||
AutowireUtils.resolveReturnTypeForFactoryMethod(extractValueFrom, new Object[] { new MySimpleInterfaceType() }, getClass().getClassLoader()));
|
||||
|
||||
// Ideally we would expect Boolean.class instead of Object.class, but this
|
||||
// information is not available at run-time due to type erasure.
|
||||
Map<Integer, Boolean> map = new HashMap<Integer, Boolean>();
|
||||
map.put(0, false);
|
||||
map.put(1, true);
|
||||
Method extractMagicValue = ReflectionUtils.findMethod(MyTypeWithMethods.class, "extractMagicValue", new Class[] { Map.class });
|
||||
assertEquals(Object.class, AutowireUtils.resolveReturnTypeForFactoryMethod(extractMagicValue, new Object[] { map }, getClass().getClassLoader()));
|
||||
}
|
||||
|
||||
|
||||
public interface MyInterfaceType<T> {
|
||||
}
|
||||
|
||||
public class MySimpleInterfaceType implements MyInterfaceType<String> {
|
||||
}
|
||||
|
||||
public static class MyTypeWithMethods<T> {
|
||||
|
||||
public MyInterfaceType<Integer> integer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public MySimpleInterfaceType string() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object object() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public MyInterfaceType raw() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String notParameterized() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String notParameterizedWithArguments(Integer x, Boolean b) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates a factory method that wraps the supplied object in a proxy of the
|
||||
* same type.
|
||||
*/
|
||||
public static <T> T createProxy(T object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #createProxy(Object)} but adds an additional argument before
|
||||
* the argument of type {@code T}. Note that they may potentially be of the same
|
||||
* time when invoked!
|
||||
*/
|
||||
public static <T> T createNamedProxy(String name, T object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates factory methods found in libraries such as Mockito and EasyMock.
|
||||
*/
|
||||
public static <MOCK> MOCK createMock(Class<MOCK> toMock) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #createMock(Class)} but adds an additional method argument
|
||||
* before the parameterized argument.
|
||||
*/
|
||||
public static <T> T createNamedMock(String name, Class<T> toMock) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #createNamedMock(String, Class)} but adds an additional
|
||||
* parameterized type.
|
||||
*/
|
||||
public static <V extends Object, T> T createVMock(V name, Class<T> toMock) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract some value of the type supported by the interface (i.e., by a concrete,
|
||||
* non-generic implementation of the interface).
|
||||
*/
|
||||
public static <T> T extractValueFrom(MyInterfaceType<T> myInterfaceType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract some magic value from the supplied map.
|
||||
*/
|
||||
public static <K, V> V extractMagicValue(Map<K, V> map) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void readIntegerInputMessage(MyInterfaceType<Integer> message) {
|
||||
}
|
||||
|
||||
public void readIntegerArrayInputMessage(MyInterfaceType<Integer>[] message) {
|
||||
}
|
||||
|
||||
public void readGenericArrayInputMessage(T[] message) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+127
-18
@@ -16,13 +16,9 @@
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
@@ -37,21 +33,23 @@ import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.PropertyEditorRegistrar;
|
||||
import org.springframework.beans.PropertyEditorRegistry;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.beans.propertyeditors.CustomNumberEditor;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.tests.Assume;
|
||||
import org.springframework.tests.TestGroup;
|
||||
|
||||
import org.springframework.tests.sample.beans.GenericBean;
|
||||
import org.springframework.tests.sample.beans.GenericIntegerBean;
|
||||
import org.springframework.tests.sample.beans.GenericSetOfIntegerBean;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
@@ -115,7 +113,7 @@ public class BeanFactoryGenericsTests {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(GenericIntegerBean.class);
|
||||
|
||||
List input = new ArrayList();
|
||||
List<Integer> input = new ArrayList<Integer>();
|
||||
input.add(1);
|
||||
rbd.getPropertyValues().add("testBeanList", input);
|
||||
|
||||
@@ -655,18 +653,17 @@ public class BeanFactoryGenericsTests {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests support for parameterized {@code factory-method} declarations such
|
||||
* as Mockito {@code mock()} method which has the following signature.
|
||||
*
|
||||
* <pre>{@code
|
||||
* Tests support for parameterized static {@code factory-method} declarations such as
|
||||
* Mockito's {@code mock()} method which has the following signature.
|
||||
* <pre>
|
||||
* {@code
|
||||
* public static <T> T mock(Class<T> classToMock)
|
||||
* }</pre>
|
||||
*
|
||||
* See SPR-9493
|
||||
* @since 3.2
|
||||
* }
|
||||
* </pre>
|
||||
* <p>See SPR-9493
|
||||
*/
|
||||
@Test
|
||||
public void parameterizedFactoryMethod() {
|
||||
public void parameterizedStaticFactoryMethod() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(Mockito.class);
|
||||
rbd.setFactoryMethodName("mock");
|
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
|
||||
@@ -678,6 +675,100 @@ public class BeanFactoryGenericsTests {
|
||||
assertEquals(1, beans.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests support for parameterized instance {@code factory-method} declarations such
|
||||
* as EasyMock's {@code IMocksControl.createMock()} method which has the following
|
||||
* signature.
|
||||
* <pre>
|
||||
* {@code
|
||||
* public <T> T createMock(Class<T> toMock)
|
||||
* }
|
||||
* </pre>
|
||||
* <p>See SPR-10411
|
||||
*/
|
||||
@Test
|
||||
public void parameterizedInstanceFactoryMethod() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
|
||||
bf.registerBeanDefinition("mocksControl", rbd);
|
||||
|
||||
rbd = new RootBeanDefinition();
|
||||
rbd.setFactoryBeanName("mocksControl");
|
||||
rbd.setFactoryMethodName("createMock");
|
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
|
||||
bf.registerBeanDefinition("mock", rbd);
|
||||
|
||||
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
|
||||
assertEquals(1, beans.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parameterizedInstanceFactoryMethodWithNonResolvedClassName() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
|
||||
bf.registerBeanDefinition("mocksControl", rbd);
|
||||
|
||||
rbd = new RootBeanDefinition();
|
||||
rbd.setFactoryBeanName("mocksControl");
|
||||
rbd.setFactoryMethodName("createMock");
|
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class.getName());
|
||||
bf.registerBeanDefinition("mock", rbd);
|
||||
|
||||
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
|
||||
assertEquals(1, beans.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parameterizedInstanceFactoryMethodWithWrappedClassName() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
|
||||
RootBeanDefinition rbd = new RootBeanDefinition();
|
||||
rbd.setBeanClassName(Mockito.class.getName());
|
||||
rbd.setFactoryMethodName("mock");
|
||||
// TypedStringValue used to be equivalent to an XML-defined argument String
|
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue(new TypedStringValue(Runnable.class.getName()));
|
||||
bf.registerBeanDefinition("mock", rbd);
|
||||
|
||||
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
|
||||
assertEquals(1, beans.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parameterizedInstanceFactoryMethodWithInvalidClassName() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
|
||||
bf.registerBeanDefinition("mocksControl", rbd);
|
||||
|
||||
rbd = new RootBeanDefinition();
|
||||
rbd.setFactoryBeanName("mocksControl");
|
||||
rbd.setFactoryMethodName("createMock");
|
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue("x");
|
||||
bf.registerBeanDefinition("mock", rbd);
|
||||
|
||||
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
|
||||
assertEquals(0, beans.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parameterizedInstanceFactoryMethodWithIndexedArgument() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
|
||||
bf.registerBeanDefinition("mocksControl", rbd);
|
||||
|
||||
rbd = new RootBeanDefinition();
|
||||
rbd.setFactoryBeanName("mocksControl");
|
||||
rbd.setFactoryMethodName("createMock");
|
||||
rbd.getConstructorArgumentValues().addIndexedArgumentValue(0, Runnable.class);
|
||||
bf.registerBeanDefinition("mock", rbd);
|
||||
|
||||
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
|
||||
assertEquals(1, beans.size());
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class NamedUrlList extends LinkedList<URL> {
|
||||
@@ -722,4 +813,22 @@ public class BeanFactoryGenericsTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pseudo-implementation of EasyMock's {@code MocksControl} class.
|
||||
*/
|
||||
public static class MocksControl {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T createMock(Class<T> toMock) {
|
||||
return (T) Proxy.newProxyInstance(BeanFactoryGenericsTests.class.getClassLoader(), new Class<?>[] {toMock},
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
throw new UnsupportedOperationException("mocked!");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+57
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author 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,63 +16,95 @@
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@code equals()} and {@code hashCode()} in bean definitions.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class DefinitionMetadataEqualsHashCodeTests extends TestCase {
|
||||
@SuppressWarnings("serial")
|
||||
public class DefinitionMetadataEqualsHashCodeTests {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public void testRootBeanDefinitionEqualsAndHashCode() throws Exception {
|
||||
@Test
|
||||
public void rootBeanDefinition() {
|
||||
RootBeanDefinition master = new RootBeanDefinition(TestBean.class);
|
||||
RootBeanDefinition equal = new RootBeanDefinition(TestBean.class);
|
||||
RootBeanDefinition notEqual = new RootBeanDefinition(String.class);
|
||||
RootBeanDefinition subclass = new RootBeanDefinition(TestBean.class) {};
|
||||
RootBeanDefinition subclass = new RootBeanDefinition(TestBean.class) {
|
||||
};
|
||||
setBaseProperties(master);
|
||||
setBaseProperties(equal);
|
||||
setBaseProperties(notEqual);
|
||||
setBaseProperties(subclass);
|
||||
|
||||
assertEqualsContract(master, equal, notEqual, subclass);
|
||||
assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode());
|
||||
assertEqualsAndHashCodeContracts(master, equal, notEqual, subclass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public void testChildBeanDefinitionEqualsAndHashCode() throws Exception {
|
||||
/**
|
||||
* @since 3.2.8
|
||||
* @see <a href="https://jira.springsource.org/browse/SPR-11420">SPR-11420</a>
|
||||
*/
|
||||
@Test
|
||||
public void rootBeanDefinitionAndMethodOverridesWithDifferentOverloadedValues() {
|
||||
RootBeanDefinition master = new RootBeanDefinition(TestBean.class);
|
||||
RootBeanDefinition equal = new RootBeanDefinition(TestBean.class);
|
||||
|
||||
setBaseProperties(master);
|
||||
setBaseProperties(equal);
|
||||
|
||||
// Simulate AbstractBeanDefinition.validate() which delegates to
|
||||
// AbstractBeanDefinition.prepareMethodOverrides():
|
||||
master.getMethodOverrides().getOverrides().iterator().next().setOverloaded(false);
|
||||
// But do not simulate validation of the 'equal' bean. As a consequence, a method
|
||||
// override in 'equal' will be marked as overloaded, but the corresponding
|
||||
// override in 'master' will not. But... the bean definitions should still be
|
||||
// considered equal.
|
||||
|
||||
assertEquals("Should be equal", master, equal);
|
||||
assertEquals("Hash code for equal instances must match", master.hashCode(), equal.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void childBeanDefinition() {
|
||||
ChildBeanDefinition master = new ChildBeanDefinition("foo");
|
||||
ChildBeanDefinition equal = new ChildBeanDefinition("foo");
|
||||
ChildBeanDefinition notEqual = new ChildBeanDefinition("bar");
|
||||
ChildBeanDefinition subclass = new ChildBeanDefinition("foo"){};
|
||||
ChildBeanDefinition subclass = new ChildBeanDefinition("foo") {
|
||||
};
|
||||
setBaseProperties(master);
|
||||
setBaseProperties(equal);
|
||||
setBaseProperties(notEqual);
|
||||
setBaseProperties(subclass);
|
||||
|
||||
assertEqualsContract(master, equal, notEqual, subclass);
|
||||
assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode());
|
||||
assertEqualsAndHashCodeContracts(master, equal, notEqual, subclass);
|
||||
}
|
||||
|
||||
public void testRuntimeBeanReference() throws Exception {
|
||||
@Test
|
||||
public void runtimeBeanReference() {
|
||||
RuntimeBeanReference master = new RuntimeBeanReference("name");
|
||||
RuntimeBeanReference equal = new RuntimeBeanReference("name");
|
||||
RuntimeBeanReference notEqual = new RuntimeBeanReference("someOtherName");
|
||||
RuntimeBeanReference subclass = new RuntimeBeanReference("name"){};
|
||||
assertEqualsContract(master, equal, notEqual, subclass);
|
||||
RuntimeBeanReference subclass = new RuntimeBeanReference("name") {
|
||||
};
|
||||
assertEqualsAndHashCodeContracts(master, equal, notEqual, subclass);
|
||||
}
|
||||
|
||||
private void setBaseProperties(AbstractBeanDefinition definition) {
|
||||
definition.setAbstract(true);
|
||||
definition.setAttribute("foo", "bar");
|
||||
definition.setAutowireCandidate(false);
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
//definition.getConstructorArgumentValues().addGenericArgumentValue("foo");
|
||||
// definition.getConstructorArgumentValues().addGenericArgumentValue("foo");
|
||||
definition.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
|
||||
definition.setDependsOn(new String[]{"foo", "bar"});
|
||||
definition.setDependsOn(new String[] { "foo", "bar" });
|
||||
definition.setDestroyMethodName("destroy");
|
||||
definition.setEnforceDestroyMethod(false);
|
||||
definition.setEnforceInitMethod(true);
|
||||
@@ -89,10 +121,15 @@ public class DefinitionMetadataEqualsHashCodeTests extends TestCase {
|
||||
definition.setSource("foo");
|
||||
}
|
||||
|
||||
private void assertEqualsContract(Object master, Object equal, Object notEqual, Object subclass) {
|
||||
private void assertEqualsAndHashCodeContracts(Object master, Object equal, Object notEqual, Object subclass) {
|
||||
assertEquals("Should be equal", master, equal);
|
||||
assertFalse("Should not be equal", master.equals(notEqual));
|
||||
assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode());
|
||||
|
||||
assertNotEquals("Should not be equal", master, notEqual);
|
||||
assertNotEquals("Hash code for non-equal instances should not match", master.hashCode(), notEqual.hashCode());
|
||||
|
||||
assertEquals("Subclass should be equal", master, subclass);
|
||||
assertEquals("Hash code for subclass should match", master.hashCode(), subclass.hashCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+37
-25
@@ -16,59 +16,59 @@
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for SPR-8954, in which a custom {@link InstantiationAwareBeanPostProcessor}
|
||||
* forces the predicted type of a FactoryBean, effectively preventing retrieval of the
|
||||
* bean from calls to #getBeansOfType(FactoryBean.class). The implementation of
|
||||
* {@link AbstractBeanFactory#isFactoryBean(String, RootBeanDefinition)} now ensures
|
||||
* that not only the predicted bean type is considered, but also the original bean
|
||||
* definition's beanClass.
|
||||
* {@link AbstractBeanFactory#isFactoryBean(String, RootBeanDefinition)} now ensures that
|
||||
* not only the predicted bean type is considered, but also the original bean definition's
|
||||
* beanClass.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class Spr8954Tests {
|
||||
|
||||
@Test
|
||||
public void repro() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
private DefaultListableBeanFactory bf;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
bf = new DefaultListableBeanFactory();
|
||||
bf.registerBeanDefinition("foo", new RootBeanDefinition(FooFactoryBean.class));
|
||||
bf.addBeanPostProcessor(new PredictingBPP());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void repro() {
|
||||
assertThat(bf.getBean("foo"), instanceOf(Foo.class));
|
||||
assertThat(bf.getBean("&foo"), instanceOf(FooFactoryBean.class));
|
||||
|
||||
assertThat(bf.isTypeMatch("&foo", FactoryBean.class), is(true));
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
Map<String, FactoryBean> fbBeans = bf.getBeansOfType(FactoryBean.class);
|
||||
assertThat(1, equalTo(fbBeans.size()));
|
||||
assertThat("&foo", equalTo(fbBeans.keySet().iterator().next()));
|
||||
assertThat(fbBeans.size(), is(1));
|
||||
assertThat(fbBeans.keySet(), hasItem("&foo"));
|
||||
|
||||
Map<String, AnInterface> aiBeans = bf.getBeansOfType(AnInterface.class);
|
||||
assertThat(1, equalTo(aiBeans.size()));
|
||||
assertThat("&foo", equalTo(aiBeans.keySet().iterator().next()));
|
||||
assertThat(aiBeans.size(), is(1));
|
||||
assertThat(aiBeans.keySet(), hasItem("&foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findsBeansByTypeIfNotInstantiated() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.registerBeanDefinition("foo", new RootBeanDefinition(FooFactoryBean.class));
|
||||
bf.addBeanPostProcessor(new PredictingBPP());
|
||||
|
||||
assertThat(bf.isTypeMatch("&foo", FactoryBean.class), is(true));
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@@ -77,8 +77,21 @@ public class Spr8954Tests {
|
||||
assertThat("&foo", equalTo(fbBeans.keySet().iterator().next()));
|
||||
|
||||
Map<String, AnInterface> aiBeans = bf.getBeansOfType(AnInterface.class);
|
||||
assertThat(1, equalTo(aiBeans.size()));
|
||||
assertThat("&foo", equalTo(aiBeans.keySet().iterator().next()));
|
||||
assertThat(aiBeans.size(), is(1));
|
||||
assertThat(aiBeans.keySet(), hasItem("&foo"));
|
||||
}
|
||||
|
||||
/**
|
||||
* SPR-10517
|
||||
*/
|
||||
@Test
|
||||
public void findsFactoryBeanNameByTypeWithoutInstantiation() {
|
||||
String[] names = bf.getBeanNamesForType(AnInterface.class, false, false);
|
||||
assertThat(Arrays.asList(names), hasItem("&foo"));
|
||||
|
||||
Map<String, AnInterface> beans = bf.getBeansOfType(AnInterface.class, false, false);
|
||||
assertThat(beans.size(), is(1));
|
||||
assertThat(beans.keySet(), hasItem("&foo"));
|
||||
}
|
||||
|
||||
|
||||
@@ -116,8 +129,7 @@ public class Spr8954Tests {
|
||||
|
||||
@Override
|
||||
public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
|
||||
return FactoryBean.class.isAssignableFrom(beanClass) ?
|
||||
PredictedType.class : null;
|
||||
return FactoryBean.class.isAssignableFrom(beanClass) ? PredictedType.class : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -55,11 +55,11 @@ public class FactoryMethods {
|
||||
return new FactoryMethods(tb, name, num);
|
||||
}
|
||||
|
||||
static FactoryMethods newInstance(TestBean tb, int num, Integer something) {
|
||||
static ExtendedFactoryMethods newInstance(TestBean tb, int num, Integer something) {
|
||||
if (something != null) {
|
||||
throw new IllegalStateException("Should never be called with non-null value");
|
||||
}
|
||||
return new FactoryMethods(tb, null, num);
|
||||
return new ExtendedFactoryMethods(tb, null, num);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@@ -120,4 +120,12 @@ public class FactoryMethods {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
public static class ExtendedFactoryMethods extends FactoryMethods {
|
||||
|
||||
ExtendedFactoryMethods(TestBean tb, String name, int num) {
|
||||
super(tb, name, num);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-3
@@ -41,10 +41,12 @@ public class ProfileXmlBeanDefinitionTests {
|
||||
|
||||
private static final String PROD_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-prodProfile.xml";
|
||||
private static final String DEV_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-devProfile.xml";
|
||||
private static final String NOT_DEV_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-notDevProfile.xml";
|
||||
private static final String ALL_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-noProfile.xml";
|
||||
private static final String MULTI_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-multiProfile.xml";
|
||||
private static final String MULTI_NOT_DEV_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-multiProfileNotDev.xml";
|
||||
private static final String MULTI_ELIGIBLE_SPACE_DELIMITED_XML = "ProfileXmlBeanDefinitionTests-spaceDelimitedProfile.xml";
|
||||
private static final String UNKOWN_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-unknownProfile.xml";
|
||||
private static final String UNKNOWN_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-unknownProfile.xml";
|
||||
private static final String DEFAULT_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-defaultProfile.xml";
|
||||
private static final String CUSTOM_DEFAULT_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-customDefaultProfile.xml";
|
||||
private static final String DEFAULT_AND_DEV_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-defaultAndDevProfile.xml";
|
||||
@@ -71,10 +73,15 @@ public class ProfileXmlBeanDefinitionTests {
|
||||
assertThat(beanFactoryFor(PROD_ELIGIBLE_XML, MULTI_ACTIVE), containsTargetBean());
|
||||
|
||||
assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, NONE_ACTIVE), not(containsTargetBean()));
|
||||
assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, PROD_ACTIVE), not(containsTargetBean()));
|
||||
assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, DEV_ACTIVE), containsTargetBean());
|
||||
assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, PROD_ACTIVE), not(containsTargetBean()));
|
||||
assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, MULTI_ACTIVE), containsTargetBean());
|
||||
|
||||
assertThat(beanFactoryFor(NOT_DEV_ELIGIBLE_XML, NONE_ACTIVE), containsTargetBean());
|
||||
assertThat(beanFactoryFor(NOT_DEV_ELIGIBLE_XML, DEV_ACTIVE), not(containsTargetBean()));
|
||||
assertThat(beanFactoryFor(NOT_DEV_ELIGIBLE_XML, PROD_ACTIVE), containsTargetBean());
|
||||
assertThat(beanFactoryFor(NOT_DEV_ELIGIBLE_XML, MULTI_ACTIVE), not(containsTargetBean()));
|
||||
|
||||
assertThat(beanFactoryFor(ALL_ELIGIBLE_XML, NONE_ACTIVE), containsTargetBean());
|
||||
assertThat(beanFactoryFor(ALL_ELIGIBLE_XML, DEV_ACTIVE), containsTargetBean());
|
||||
assertThat(beanFactoryFor(ALL_ELIGIBLE_XML, PROD_ACTIVE), containsTargetBean());
|
||||
@@ -86,13 +93,19 @@ public class ProfileXmlBeanDefinitionTests {
|
||||
assertThat(beanFactoryFor(MULTI_ELIGIBLE_XML, PROD_ACTIVE), containsTargetBean());
|
||||
assertThat(beanFactoryFor(MULTI_ELIGIBLE_XML, MULTI_ACTIVE), containsTargetBean());
|
||||
|
||||
assertThat(beanFactoryFor(MULTI_NOT_DEV_ELIGIBLE_XML, NONE_ACTIVE), containsTargetBean());
|
||||
assertThat(beanFactoryFor(MULTI_NOT_DEV_ELIGIBLE_XML, UNKNOWN_ACTIVE), containsTargetBean());
|
||||
assertThat(beanFactoryFor(MULTI_NOT_DEV_ELIGIBLE_XML, DEV_ACTIVE), not(containsTargetBean()));
|
||||
assertThat(beanFactoryFor(MULTI_NOT_DEV_ELIGIBLE_XML, PROD_ACTIVE), containsTargetBean());
|
||||
assertThat(beanFactoryFor(MULTI_NOT_DEV_ELIGIBLE_XML, MULTI_ACTIVE), containsTargetBean());
|
||||
|
||||
assertThat(beanFactoryFor(MULTI_ELIGIBLE_SPACE_DELIMITED_XML, NONE_ACTIVE), not(containsTargetBean()));
|
||||
assertThat(beanFactoryFor(MULTI_ELIGIBLE_SPACE_DELIMITED_XML, UNKNOWN_ACTIVE), not(containsTargetBean()));
|
||||
assertThat(beanFactoryFor(MULTI_ELIGIBLE_SPACE_DELIMITED_XML, DEV_ACTIVE), containsTargetBean());
|
||||
assertThat(beanFactoryFor(MULTI_ELIGIBLE_SPACE_DELIMITED_XML, PROD_ACTIVE), containsTargetBean());
|
||||
assertThat(beanFactoryFor(MULTI_ELIGIBLE_SPACE_DELIMITED_XML, MULTI_ACTIVE), containsTargetBean());
|
||||
|
||||
assertThat(beanFactoryFor(UNKOWN_ELIGIBLE_XML, MULTI_ACTIVE), not(containsTargetBean()));
|
||||
assertThat(beanFactoryFor(UNKNOWN_ELIGIBLE_XML, MULTI_ACTIVE), not(containsTargetBean()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+16
-15
@@ -29,7 +29,7 @@ import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Rick Evans
|
||||
@@ -38,13 +38,13 @@ import org.springframework.tests.sample.beans.TestBean;
|
||||
public class XmlBeanDefinitionReaderTests extends TestCase {
|
||||
|
||||
public void testSetParserClassSunnyDay() {
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
|
||||
new XmlBeanDefinitionReader(registry).setDocumentReaderClass(DefaultBeanDefinitionDocumentReader.class);
|
||||
}
|
||||
|
||||
public void testSetParserClassToNull() {
|
||||
try {
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
|
||||
new XmlBeanDefinitionReader(registry).setDocumentReaderClass(null);
|
||||
fail("Should have thrown IllegalArgumentException (null parserClass)");
|
||||
}
|
||||
@@ -54,7 +54,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
|
||||
|
||||
public void testSetParserClassToUnsupportedParserType() throws Exception {
|
||||
try {
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
|
||||
new XmlBeanDefinitionReader(registry).setDocumentReaderClass(String.class);
|
||||
fail("Should have thrown IllegalArgumentException (unsupported parserClass)");
|
||||
}
|
||||
@@ -64,7 +64,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
|
||||
|
||||
public void testWithOpenInputStream() {
|
||||
try {
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
|
||||
Resource resource = new InputStreamResource(getClass().getResourceAsStream("test.xml"));
|
||||
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
|
||||
fail("Should have thrown BeanDefinitionStoreException (can't determine validation mode)");
|
||||
@@ -74,7 +74,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testWithOpenInputStreamAndExplicitValidationMode() {
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
|
||||
Resource resource = new InputStreamResource(getClass().getResourceAsStream("test.xml"));
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
|
||||
reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_DTD);
|
||||
@@ -83,14 +83,14 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testWithImport() {
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
|
||||
Resource resource = new ClassPathResource("import.xml", getClass());
|
||||
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
|
||||
testBeanDefinitions(registry);
|
||||
}
|
||||
|
||||
public void testWithWildcardImport() {
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
|
||||
Resource resource = new ClassPathResource("importPattern.xml", getClass());
|
||||
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
|
||||
testBeanDefinitions(registry);
|
||||
@@ -98,7 +98,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
|
||||
|
||||
public void testWithInputSource() {
|
||||
try {
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
|
||||
InputSource resource = new InputSource(getClass().getResourceAsStream("test.xml"));
|
||||
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
|
||||
fail("Should have thrown BeanDefinitionStoreException (can't determine validation mode)");
|
||||
@@ -108,7 +108,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testWithInputSourceAndExplicitValidationMode() {
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
|
||||
InputSource resource = new InputSource(getClass().getResourceAsStream("test.xml"));
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
|
||||
reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_DTD);
|
||||
@@ -117,7 +117,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testWithFreshInputStream() {
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
|
||||
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
|
||||
Resource resource = new ClassPathResource("test.xml", getClass());
|
||||
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
|
||||
testBeanDefinitions(registry);
|
||||
@@ -133,9 +133,10 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
|
||||
assertEquals(TestBean.class.getName(), registry.getBeanDefinition("rod").getBeanClassName());
|
||||
assertEquals(TestBean.class.getName(), registry.getBeanDefinition("aliased").getBeanClassName());
|
||||
assertTrue(registry.isAlias("youralias"));
|
||||
assertEquals(2, registry.getAliases("aliased").length);
|
||||
assertEquals("myalias", registry.getAliases("aliased")[0]);
|
||||
assertEquals("youralias", registry.getAliases("aliased")[1]);
|
||||
String[] aliases = registry.getAliases("aliased");
|
||||
assertEquals(2, aliases.length);
|
||||
assertTrue(ObjectUtils.containsElement(aliases, "myalias"));
|
||||
assertTrue(ObjectUtils.containsElement(aliases, "youralias"));
|
||||
}
|
||||
|
||||
public void testDtdValidationAutodetect() throws Exception {
|
||||
@@ -147,7 +148,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
|
||||
}
|
||||
|
||||
private void doTestValidation(String resourceName) throws Exception {
|
||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();;
|
||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||
Resource resource = new ClassPathResource(resourceName, getClass());
|
||||
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(resource);
|
||||
TestBean bean = (TestBean) factory.getBean("testBean");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user