mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
209 Commits
v5.3.0
...
v3.2.5.RELEASE
| Author | SHA1 | Date | |
|---|---|---|---|
| 015e1bec64 | |||
| 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 |
+96
-58
@@ -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.4")
|
||||
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.7")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,11 @@ configure(allprojects) { project ->
|
||||
group = "org.springframework"
|
||||
version = qualifyVersionIfNecessary(version)
|
||||
|
||||
// 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.2"
|
||||
ext.hsqldbVersion = "1.8.0.10"
|
||||
ext.junitVersion = "4.11"
|
||||
@@ -58,6 +63,9 @@ configure(allprojects) { project ->
|
||||
test {
|
||||
systemProperty("java.awt.headless", "true")
|
||||
systemProperty("testGroups", project.properties.get("testGroups"))
|
||||
scanForTestClasses = false
|
||||
include '**/*Tests.*'
|
||||
exclude '**/*Abstract*.*'
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -71,25 +79,26 @@ 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/6/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://ibatis.apache.org/docs/java/dev/",
|
||||
"http://hc.apache.org/httpclient-3.x/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.5/",
|
||||
"http://jackson.codehaus.org/1.4.2/javadoc/",
|
||||
"http://fasterxml.github.com/jackson-core/javadoc/2.0.1/",
|
||||
] as String[]
|
||||
}
|
||||
|
||||
@@ -118,6 +127,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 +160,7 @@ project("spring-build-src") {
|
||||
|
||||
dependencies {
|
||||
compile gradleApi()
|
||||
groovy localGroovy()
|
||||
compile localGroovy()
|
||||
}
|
||||
|
||||
configurations.archives.artifacts.clear()
|
||||
@@ -219,6 +231,7 @@ 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")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
@@ -245,6 +258,7 @@ project("spring-core") {
|
||||
|
||||
project("spring-beans") {
|
||||
description = "Spring Beans"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
@@ -256,6 +270,7 @@ project("spring-beans") {
|
||||
|
||||
project("spring-aop") {
|
||||
description = "Spring AOP"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
@@ -269,6 +284,7 @@ project("spring-aop") {
|
||||
|
||||
project("spring-expression") {
|
||||
description = "Spring Expression Language (SpEL)"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
}
|
||||
@@ -276,17 +292,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,6 +312,7 @@ project("spring-instrument-tomcat") {
|
||||
|
||||
project("spring-context") {
|
||||
description = "Spring Context"
|
||||
|
||||
dependencies {
|
||||
optional(project(":spring-instrument"))
|
||||
compile(project(":spring-aop"))
|
||||
@@ -306,12 +325,12 @@ project("spring-context") {
|
||||
optional("javax.inject:javax.inject:1")
|
||||
optional("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
|
||||
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("javax.validation:validation-api:1.0.0.GA")
|
||||
optional("org.hibernate:hibernate-validator:4.3.0.Final")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
@@ -319,6 +338,9 @@ project("spring-context") {
|
||||
testCompile("javax.inject:javax.inject-tck:1")
|
||||
}
|
||||
|
||||
// pick up RmiInvocationWrapperRTD.xml in src/main
|
||||
sourceSets.main.resources.srcDirs += "src/main/java"
|
||||
|
||||
test {
|
||||
jvmArgs = ["-disableassertions:org.aspectj.weaver.UnresolvedType"] // SPR-7989
|
||||
}
|
||||
@@ -326,6 +348,7 @@ project("spring-context") {
|
||||
|
||||
project("spring-tx") {
|
||||
description = "Spring Transaction"
|
||||
|
||||
dependencies {
|
||||
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
|
||||
optional(project(":spring-aop"))
|
||||
@@ -355,10 +378,8 @@ 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")
|
||||
testCompile(project(":spring-context"))
|
||||
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("org.codehaus.castor:castor-xml:1.3.2")
|
||||
@@ -373,6 +394,7 @@ project("spring-oxm") {
|
||||
|
||||
project("spring-jms") {
|
||||
description = "Spring JMS"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
@@ -391,6 +413,7 @@ project("spring-jms") {
|
||||
|
||||
project("spring-jdbc") {
|
||||
description = "Spring JDBC"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
@@ -407,6 +430,7 @@ project("spring-jdbc") {
|
||||
|
||||
project("spring-context-support") {
|
||||
description = "Spring Context Support"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
@@ -443,8 +467,6 @@ project("spring-web") {
|
||||
compile(project(":spring-context"))
|
||||
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.el:el-api:1.0")
|
||||
optional("javax.faces:jsf-api:1.2_08")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
@@ -453,6 +475,8 @@ project("spring-web") {
|
||||
optional("javax.xml:jaxrpc-api:1.1")
|
||||
provided("javax.xml.soap:saaj-api:1.3")
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional("com.caucho:hessian:3.2.1")
|
||||
optional("rome:rome:1.0")
|
||||
optional("commons-fileupload:commons-fileupload:1.2")
|
||||
optional("commons-io:commons-io:1.3")
|
||||
optional("commons-httpclient:commons-httpclient:3.1")
|
||||
@@ -487,16 +511,16 @@ project("spring-orm") {
|
||||
|
||||
dependencies {
|
||||
compile("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")
|
||||
testCompile("javax.servlet:javax.servlet-api:3.0.1")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
@@ -517,11 +541,12 @@ project("spring-orm") {
|
||||
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")
|
||||
optional("org.hibernate:hibernate-core:4.1.9.Final")
|
||||
optional("org.hibernate:hibernate-entitymanager:4.1.9.Final")
|
||||
optional(project(":spring-web"))
|
||||
optional("javax.servlet:servlet-api:2.5")
|
||||
}
|
||||
@@ -529,6 +554,7 @@ project("spring-orm-hibernate4") {
|
||||
|
||||
project("spring-webmvc") {
|
||||
description = "Spring Web MVC"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-expression"))
|
||||
@@ -541,7 +567,6 @@ project("spring-webmvc") {
|
||||
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("org.apache.poi:poi:3.0.2-FINAL")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
@@ -550,6 +575,7 @@ project("spring-webmvc") {
|
||||
}
|
||||
optional("rome:rome:1.0")
|
||||
optional("velocity:velocity:1.5")
|
||||
optional("velocity-tools:velocity-tools-view:1.4")
|
||||
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")
|
||||
@@ -588,6 +614,7 @@ 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"))
|
||||
@@ -618,6 +645,7 @@ project("spring-webmvc-tiles3") {
|
||||
|
||||
project("spring-webmvc-portlet") {
|
||||
description = "Spring Web Portlet"
|
||||
|
||||
dependencies {
|
||||
provided("javax.servlet:servlet-api:2.5")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
@@ -636,21 +664,6 @@ 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"))
|
||||
optional(project(":spring-beans"))
|
||||
@@ -675,6 +688,26 @@ project("spring-test") {
|
||||
testCompile "org.slf4j:slf4j-jcl:${slf4jVersion}"
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
}
|
||||
|
||||
task testNG(type: Test) {
|
||||
useTestNG()
|
||||
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.
|
||||
testReport true
|
||||
}
|
||||
|
||||
test {
|
||||
dependsOn testNG
|
||||
useJUnit()
|
||||
exclude "**/testng/*.*"
|
||||
// "TestCase" classes are run by other test classes, not the build.
|
||||
exclude(["**/*TestCase.class", "**/*TestSuite.class"])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
project("spring-test-mvc") {
|
||||
@@ -695,11 +728,9 @@ project("spring-test-mvc") {
|
||||
testCompile(project(":spring-context-support"))
|
||||
testCompile(project(":spring-oxm"))
|
||||
testCompile("com.thoughtworks.xstream:xstream:1.3.1")
|
||||
testCompile("cglib:cglib-nodep:2.2")
|
||||
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") {
|
||||
@@ -730,6 +761,7 @@ 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
|
||||
@@ -747,6 +779,7 @@ project("spring-aspects") {
|
||||
compile(project(":spring-beans")) // for "p" namespace visibility
|
||||
testCompile(project(":spring-test"))
|
||||
}
|
||||
|
||||
eclipse.project {
|
||||
natures += "org.eclipse.ajdt.ui.ajnature"
|
||||
buildCommands = [new org.gradle.plugins.ide.eclipse.model.
|
||||
@@ -759,7 +792,7 @@ configure(rootProject) {
|
||||
|
||||
apply plugin: "docbook-reference"
|
||||
apply plugin: "groovy"
|
||||
apply plugin: "detect-split-packages"
|
||||
// apply plugin: "detect-split-packages"
|
||||
apply from: "${gradleScriptDir}/jdiff.gradle"
|
||||
|
||||
reference {
|
||||
@@ -767,9 +800,11 @@ 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()
|
||||
@@ -786,7 +821,7 @@ configure(rootProject) {
|
||||
testCompile(project(":spring-web"))
|
||||
testCompile(project(":spring-webmvc-portlet"))
|
||||
testCompile(project(":spring-orm"))
|
||||
testCompile("org.hibernate:hibernate-core:4.1.0.Final")
|
||||
testCompile("org.hibernate:hibernate-core:4.1.9.Final")
|
||||
testCompile("javax.servlet:servlet-api:2.5")
|
||||
testCompile("javax.portlet:portlet-api:2.0")
|
||||
testCompile("javax.inject:javax.inject:1")
|
||||
@@ -812,6 +847,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 +860,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 +997,7 @@ configure(rootProject) {
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
description = "Generates gradlew[.bat] scripts"
|
||||
gradleVersion = "1.3"
|
||||
gradleVersion = "1.6"
|
||||
|
||||
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.5.RELEASE
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+4
-4
@@ -1,6 +1,6 @@
|
||||
#Wed Nov 28 09:14:59 PST 2012
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
#Tue Jul 30 09:29:28 PDT 2013
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.3-bin.zip
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
|
||||
+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-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.
|
||||
@@ -34,7 +34,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.springframework.cglib.transform.impl.MemorySafeUndeclaredThrowableStrategy;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
@@ -181,7 +181,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
}
|
||||
}
|
||||
enhancer.setSuperclass(proxySuperClass);
|
||||
enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
|
||||
enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
|
||||
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
|
||||
enhancer.setInterceptDuringConstruction(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.
|
||||
@@ -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.
|
||||
@@ -54,7 +54,7 @@ public abstract class ScopedProxyUtils {
|
||||
// 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.setOriginatingBeanDefinition(targetDefinition);
|
||||
proxyDefinition.setSource(definition.getSource());
|
||||
proxyDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -102,8 +102,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");
|
||||
@@ -168,6 +169,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) {
|
||||
@@ -191,11 +193,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 +214,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");
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+13
-14
@@ -97,36 +97,34 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
|
||||
public void verify() {
|
||||
if (verified != calls.size()) {
|
||||
throw new IllegalStateException("Expected " + calls.size()
|
||||
+ " calls, received " + verified);
|
||||
throw new IllegalStateException("Expected " + calls.size() + " calls, 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) {
|
||||
}
|
||||
else if (responseType == CallResponse.throw_) {
|
||||
return call.throwException(lastSig, args);
|
||||
}
|
||||
else if (responseType == CallResponse.nothing) {
|
||||
// do nothing
|
||||
}
|
||||
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, received " + verified);
|
||||
}
|
||||
return calls.get(verified++);
|
||||
return calls.get(verified);
|
||||
}
|
||||
|
||||
public void expectCall(String lastSig, Object lastArgs[]) {
|
||||
@@ -171,7 +169,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());
|
||||
}
|
||||
}
|
||||
|
||||
+8
-11
@@ -101,15 +101,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();
|
||||
Class<?> beanClass = it.next();
|
||||
if (isUnderneathClassLoader(beanClass.getClassLoader(), classLoader)) {
|
||||
it.remove();
|
||||
}
|
||||
@@ -127,13 +126,11 @@ 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 {
|
||||
static CachedIntrospectionResults forClass(Class<?> beanClass) throws BeansException {
|
||||
CachedIntrospectionResults results;
|
||||
Object value;
|
||||
synchronized (classCache) {
|
||||
@@ -225,7 +222,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() + "]");
|
||||
@@ -248,7 +245,7 @@ public class CachedIntrospectionResults {
|
||||
// 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;
|
||||
Class<?> classToFlush = beanClass;
|
||||
do {
|
||||
Introspector.flushFromCaches(classToFlush);
|
||||
classToFlush = classToFlush.getSuperclass();
|
||||
@@ -286,7 +283,7 @@ public class CachedIntrospectionResults {
|
||||
return this.beanInfo;
|
||||
}
|
||||
|
||||
Class getBeanClass() {
|
||||
Class<?> getBeanClass() {
|
||||
return this.beanInfo.getBeanDescriptor().getBeanClass();
|
||||
}
|
||||
|
||||
@@ -314,7 +311,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;
|
||||
@@ -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,8 +202,7 @@ 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() {
|
||||
@@ -255,31 +235,28 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
}
|
||||
|
||||
|
||||
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,7 +282,8 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
|
||||
if (this.propertyType == null) {
|
||||
try {
|
||||
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
|
||||
} catch (IntrospectionException ex) {
|
||||
}
|
||||
catch (IntrospectionException ex) {
|
||||
// ignore, as does PropertyDescriptor#getPropertyType
|
||||
}
|
||||
}
|
||||
@@ -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,7 +372,8 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
|
||||
if (this.propertyType == null) {
|
||||
try {
|
||||
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
|
||||
} catch (IntrospectionException ex) {
|
||||
}
|
||||
catch (IntrospectionException ex) {
|
||||
// ignore, as does IndexedPropertyDescriptor#getPropertyType
|
||||
}
|
||||
}
|
||||
@@ -431,9 +405,9 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
|
||||
if (this.indexedPropertyType == null) {
|
||||
try {
|
||||
this.indexedPropertyType = findIndexedPropertyType(
|
||||
this.getName(), this.getPropertyType(),
|
||||
this.indexedReadMethod, this.indexedWriteMethod);
|
||||
} catch (IntrospectionException ex) {
|
||||
getName(), getPropertyType(), this.indexedReadMethod, this.indexedWriteMethod);
|
||||
}
|
||||
catch (IntrospectionException ex) {
|
||||
// ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -520,11 +489,8 @@ 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) {
|
||||
@@ -554,8 +520,7 @@ 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;
|
||||
|
||||
@@ -605,7 +570,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) {
|
||||
@@ -633,13 +597,12 @@ 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.equals(b)) {
|
||||
return false;
|
||||
@@ -653,7 +616,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> {
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
|
||||
+13
-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.
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
// 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 (metadata == null) {
|
||||
synchronized (this.injectionMetadataCache) {
|
||||
metadata = this.injectionMetadataCache.get(clazz);
|
||||
metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
if (metadata == null) {
|
||||
metadata = buildAutowiringMetadata(clazz);
|
||||
this.injectionMetadataCache.put(clazz, metadata);
|
||||
this.injectionMetadataCache.put(cacheKey, metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-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;
|
||||
}
|
||||
@@ -110,7 +110,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 +122,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 +
|
||||
|
||||
+4
-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.
|
||||
@@ -233,8 +233,9 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
||||
}
|
||||
if (qualifier == null) {
|
||||
Annotation targetAnnotation = null;
|
||||
if (bd.getResolvedFactoryMethod() != null) {
|
||||
targetAnnotation = AnnotationUtils.getAnnotation(bd.getResolvedFactoryMethod(), type);
|
||||
Method resolvedFactoryMethod = bd.getResolvedFactoryMethod();
|
||||
if (resolvedFactoryMethod != null) {
|
||||
targetAnnotation = AnnotationUtils.getAnnotation(resolvedFactoryMethod, type);
|
||||
}
|
||||
if (targetAnnotation == null) {
|
||||
// look for matching annotation on the target class
|
||||
|
||||
+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;
|
||||
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
+66
-42
@@ -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;
|
||||
@@ -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) {
|
||||
@@ -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,12 +632,6 @@ 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!
|
||||
int minNrOfArgs = mbd.getConstructorArgumentValues().getArgumentCount();
|
||||
@@ -650,9 +641,45 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
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) {
|
||||
returnTypes.add(returnType);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to resolve generic return type for factory method: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
returnTypes.add(factoryMethod.getReturnType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
@@ -968,7 +992,7 @@ 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()) {
|
||||
|
||||
+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.
|
||||
|
||||
+131
-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.
|
||||
@@ -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
|
||||
*/
|
||||
@@ -117,8 +124,8 @@ abstract class AutowireUtils {
|
||||
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,7 +142,7 @@ 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;
|
||||
if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
|
||||
@@ -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.
|
||||
|
||||
+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();
|
||||
|
||||
/**
|
||||
|
||||
+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.
|
||||
@@ -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)) {
|
||||
@@ -271,7 +271,7 @@ 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 +335,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,
|
||||
|
||||
+3
-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.
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -98,7 +97,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;
|
||||
@@ -128,7 +127,7 @@ public class ChildBeanDefinition extends AbstractBeanDefinition {
|
||||
* @param original the original bean definition to copy from
|
||||
*/
|
||||
public ChildBeanDefinition(ChildBeanDefinition original) {
|
||||
super((BeanDefinition) original);
|
||||
super(original);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+20
-12
@@ -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.
|
||||
@@ -151,7 +151,7 @@ class ConstructorResolver {
|
||||
// Take specified constructors, if any.
|
||||
Constructor[] candidates = chosenCtors;
|
||||
if (candidates == null) {
|
||||
Class beanClass = mbd.getBeanClass();
|
||||
Class<?> beanClass = mbd.getBeanClass();
|
||||
try {
|
||||
candidates = (mbd.isNonPublicAccessAllowed() ?
|
||||
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
|
||||
@@ -169,7 +169,7 @@ class ConstructorResolver {
|
||||
|
||||
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 ->
|
||||
@@ -341,7 +341,7 @@ class ConstructorResolver {
|
||||
this.beanFactory.initBeanWrapper(bw);
|
||||
|
||||
Object factoryBean;
|
||||
Class factoryClass;
|
||||
Class<?> factoryClass;
|
||||
boolean isStatic;
|
||||
|
||||
String factoryBeanName = mbd.getFactoryBeanName();
|
||||
@@ -399,7 +399,7 @@ class ConstructorResolver {
|
||||
factoryClass = ClassUtils.getUserClass(factoryClass);
|
||||
Method[] rawCandidates;
|
||||
|
||||
final Class factoryClazz = factoryClass;
|
||||
final Class<?> factoryClazz = factoryClass;
|
||||
if (System.getSecurityManager() != null) {
|
||||
rawCandidates = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
|
||||
public Method[] run() {
|
||||
@@ -445,7 +445,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 +503,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 +548,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 +652,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,7 +758,7 @@ class ConstructorResolver {
|
||||
private Object[] resolvePreparedArguments(
|
||||
String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) {
|
||||
|
||||
Class[] paramTypes = (methodOrCtor instanceof Method ?
|
||||
Class<?>[] paramTypes = (methodOrCtor instanceof Method ?
|
||||
((Method) methodOrCtor).getParameterTypes() : ((Constructor) methodOrCtor).getParameterTypes());
|
||||
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
|
||||
this.beanFactory.getCustomTypeConverter() : bw);
|
||||
@@ -822,7 +830,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 +840,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;
|
||||
|
||||
+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));
|
||||
}
|
||||
}
|
||||
|
||||
+8
-11
@@ -107,7 +107,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 +147,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 +191,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 +225,11 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
* @param original the original bean definition to copy from
|
||||
*/
|
||||
public RootBeanDefinition(RootBeanDefinition original) {
|
||||
this((BeanDefinition) original);
|
||||
super(original);
|
||||
this.decoratedDefinition = original.decoratedDefinition;
|
||||
this.allowCaching = original.allowCaching;
|
||||
this.targetType = original.targetType;
|
||||
this.isFactoryMethodUnique = original.isFactoryMethodUnique;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -235,13 +239,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+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
|
||||
*/
|
||||
|
||||
@@ -63,6 +63,10 @@ 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
|
||||
@@ -1559,6 +1563,20 @@ public final class BeanWrapperTests {
|
||||
assertEquals("val1", Spr10115Bean.prop1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArrayToObject() throws Exception {
|
||||
ArrayToObject foo = new ArrayToObject();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl();
|
||||
bwi.setWrappedInstance(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));
|
||||
}
|
||||
|
||||
static class Spr10115Bean {
|
||||
private static String prop1;
|
||||
@@ -1944,4 +1962,19 @@ public final class BeanWrapperTests {
|
||||
TEST_VALUE
|
||||
}
|
||||
|
||||
|
||||
static class ArrayToObject {
|
||||
|
||||
private Object object;
|
||||
|
||||
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+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> {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+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!");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+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");
|
||||
|
||||
+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.
|
||||
@@ -71,6 +71,11 @@ public class DerivedTestBean extends TestBean implements Serializable, BeanNameA
|
||||
setSpouse(new TestBean(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestBean getSpouse() {
|
||||
return (TestBean) super.getSpouse();
|
||||
}
|
||||
|
||||
|
||||
public void initialize() {
|
||||
this.initialized = true;
|
||||
|
||||
+1
-2
@@ -35,11 +35,10 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="pJenny" class="org.springframework.tests.sample.beans.TestBean" scope="prototype">
|
||||
<bean id="pJenny" class="org.springframework.tests.sample.beans.DerivedTestBean" scope="prototype">
|
||||
<property name="name"><value>Jenny</value></property>
|
||||
<property name="age"><value>30</value></property>
|
||||
<property name="spouse">
|
||||
<!-- Could use id and href -->
|
||||
<ref local="david"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
Vendored
+5
-3
@@ -319,7 +319,8 @@ public class EhCacheFactoryBean implements FactoryBean<Ehcache>, BeanNameAware,
|
||||
// Fetch cache region: If none with the given name exists,
|
||||
// create one on the fly.
|
||||
Ehcache rawCache;
|
||||
if (this.cacheManager.cacheExists(this.cacheName)) {
|
||||
boolean cacheExists = this.cacheManager.cacheExists(cacheName);
|
||||
if (cacheExists) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using existing EhCache cache region '" + this.cacheName + "'");
|
||||
}
|
||||
@@ -330,7 +331,6 @@ public class EhCacheFactoryBean implements FactoryBean<Ehcache>, BeanNameAware,
|
||||
logger.debug("Creating new EhCache cache region '" + this.cacheName + "'");
|
||||
}
|
||||
rawCache = createCache();
|
||||
this.cacheManager.addCache(rawCache);
|
||||
}
|
||||
|
||||
if (this.cacheEventListeners != null) {
|
||||
@@ -348,7 +348,9 @@ public class EhCacheFactoryBean implements FactoryBean<Ehcache>, BeanNameAware,
|
||||
rawCache.setDisabled(true);
|
||||
}
|
||||
|
||||
// Decorate cache if necessary.
|
||||
if (!cacheExists) {
|
||||
this.cacheManager.addCache(rawCache);
|
||||
}
|
||||
Ehcache decoratedCache = decorateCache(rawCache);
|
||||
if (decoratedCache != rawCache) {
|
||||
this.cacheManager.replaceCacheWithDecoratedCache(rawCache, decoratedCache);
|
||||
|
||||
+10
-23
@@ -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.
|
||||
@@ -17,10 +17,9 @@
|
||||
package org.springframework.scheduling.commonj;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import commonj.work.Work;
|
||||
@@ -54,10 +53,8 @@ import org.springframework.util.Assert;
|
||||
* server's JNDI environment, as defined in the server's management console.
|
||||
*
|
||||
* <p><b>Note: At the time of this writing, the CommonJ WorkManager facility
|
||||
* is only supported on IBM WebSphere 6.0+ and BEA WebLogic 9.0+,
|
||||
* is only supported on IBM WebSphere 6.1+ and BEA WebLogic 9.0+,
|
||||
* despite being such a crucial API for an application server.</b>
|
||||
* (There is a similar facility available on WebSphere 5.1 Enterprise,
|
||||
* though, which we will discuss below.)
|
||||
*
|
||||
* <p><b>On JBoss and GlassFish, a similar facility is available through
|
||||
* the JCA WorkManager.</b> See the
|
||||
@@ -80,8 +77,7 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
|
||||
|
||||
/**
|
||||
* Specify the CommonJ WorkManager to delegate to.
|
||||
* <p>Alternatively, you can also specify the JNDI name
|
||||
* of the target WorkManager.
|
||||
* <p>Alternatively, you can also specify the JNDI name of the target WorkManager.
|
||||
* @see #setWorkManagerName
|
||||
*/
|
||||
public void setWorkManager(WorkManager workManager) {
|
||||
@@ -90,9 +86,8 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
|
||||
|
||||
/**
|
||||
* Set the JNDI name of the CommonJ WorkManager.
|
||||
* <p>This can either be a fully qualified JNDI name,
|
||||
* or the JNDI name relative to the current environment
|
||||
* naming context if "resourceRef" is set to "true".
|
||||
* <p>This can either be a fully qualified JNDI name, or the JNDI name relative
|
||||
* to the current environment naming context if "resourceRef" is set to "true".
|
||||
* @see #setWorkManager
|
||||
* @see #setResourceRef
|
||||
*/
|
||||
@@ -170,27 +165,19 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
|
||||
// Implementation of the CommonJ WorkManager interface
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
public WorkItem schedule(Work work)
|
||||
throws WorkException, IllegalArgumentException {
|
||||
|
||||
public WorkItem schedule(Work work) throws WorkException, IllegalArgumentException {
|
||||
return this.workManager.schedule(work);
|
||||
}
|
||||
|
||||
public WorkItem schedule(Work work, WorkListener workListener)
|
||||
throws WorkException, IllegalArgumentException {
|
||||
|
||||
public WorkItem schedule(Work work, WorkListener workListener) throws WorkException {
|
||||
return this.workManager.schedule(work, workListener);
|
||||
}
|
||||
|
||||
public boolean waitForAll(Collection workItems, long timeout)
|
||||
throws InterruptedException, IllegalArgumentException {
|
||||
|
||||
public boolean waitForAll(Collection workItems, long timeout) throws InterruptedException {
|
||||
return this.workManager.waitForAll(workItems, timeout);
|
||||
}
|
||||
|
||||
public Collection waitForAny(Collection workItems, long timeout)
|
||||
throws InterruptedException, IllegalArgumentException {
|
||||
|
||||
public Collection waitForAny(Collection workItems, long timeout) throws InterruptedException {
|
||||
return this.workManager.waitForAny(workItems, timeout);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -30,7 +30,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* JobFactory implementation that supports {@link java.lang.Runnable}
|
||||
* objects as well as standard Quartz {@link org.quartz.Job} instances.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
|
||||
+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.
|
||||
@@ -47,7 +47,7 @@ import org.springframework.util.Assert;
|
||||
* Use Quartz 2.0's native {@code JobDetailImpl} class or the new Quartz 2.0
|
||||
* builder API instead. Alternatively, switch to Spring's {@link CronTriggerFactoryBean}
|
||||
* which largely is a drop-in replacement for this class and its properties and
|
||||
* consistently works against Quartz 1.x as well as Quartz 2.0/2.1.
|
||||
* consistently works against Quartz 1.x as well as Quartz 2.x.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 18.02.2004
|
||||
|
||||
+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.
|
||||
@@ -49,7 +49,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* to automatically register a trigger for the corresponding JobDetail,
|
||||
* instead of registering the JobDetail separately.
|
||||
*
|
||||
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.0/2.1,
|
||||
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.x,
|
||||
* in contrast to the older {@link CronTriggerBean} class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
|
||||
+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.
|
||||
@@ -39,7 +39,7 @@ import org.springframework.context.ApplicationContextAware;
|
||||
* Use Quartz 2.0's native {@code JobDetailImpl} class or the new Quartz 2.0
|
||||
* builder API instead. Alternatively, switch to Spring's {@link JobDetailFactoryBean}
|
||||
* which largely is a drop-in replacement for this class and its properties and
|
||||
* consistently works against Quartz 1.x as well as Quartz 2.0/2.1.
|
||||
* consistently works against Quartz 1.x as well as Quartz 2.x.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 18.02.2004
|
||||
|
||||
+13
-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.
|
||||
@@ -39,7 +39,7 @@ import org.springframework.context.ApplicationContextAware;
|
||||
* sensible defaults. This class uses the Spring bean name as job name,
|
||||
* and the Quartz default group ("DEFAULT") as job group if not specified.
|
||||
*
|
||||
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.0/2.1,
|
||||
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.x,
|
||||
* in contrast to the older {@link JobDetailBean} class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
@@ -62,6 +62,8 @@ public class JobDetailFactoryBean
|
||||
|
||||
private boolean durability = false;
|
||||
|
||||
private boolean requestsRecovery = false;
|
||||
|
||||
private String description;
|
||||
|
||||
private String beanName;
|
||||
@@ -132,6 +134,14 @@ public class JobDetailFactoryBean
|
||||
this.durability = durability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the recovery flag for this job, i.e. whether or not the job should
|
||||
* get re-executed if a 'recovery' or 'fail-over' situation is encountered.
|
||||
*/
|
||||
public void setRequestsRecovery(boolean requestsRecovery) {
|
||||
this.requestsRecovery = requestsRecovery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a textual description for this job.
|
||||
*/
|
||||
@@ -209,6 +219,7 @@ public class JobDetailFactoryBean
|
||||
pvs.add("jobClass", this.jobClass);
|
||||
pvs.add("jobDataMap", this.jobDataMap);
|
||||
pvs.add("durability", this.durability);
|
||||
pvs.add("requestsRecovery", this.requestsRecovery);
|
||||
pvs.add("description", this.description);
|
||||
bw.setPropertyValues(pvs);
|
||||
this.jobDetail = (JobDetail) bw.getWrappedInstance();
|
||||
|
||||
+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.
|
||||
@@ -67,7 +67,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* You need to implement your own Quartz Job as a thin wrapper for each case
|
||||
* where you want a persistent job to delegate to a specific service method.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Alef Arendsen
|
||||
|
||||
+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.
|
||||
@@ -51,7 +51,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* <p>For concrete usage, check out the {@link SchedulerFactoryBean} and
|
||||
* {@link SchedulerAccessorBean} classes.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.6
|
||||
@@ -397,7 +397,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
else {
|
||||
try {
|
||||
Map jobDataMap = (Map) ReflectionUtils.invokeMethod(Trigger.class.getMethod("getJobDataMap"), trigger);
|
||||
return (JobDetail) jobDataMap.get(JobDetailAwareTrigger.JOB_DETAIL_KEY);
|
||||
return (JobDetail) jobDataMap.remove(JobDetailAwareTrigger.JOB_DETAIL_KEY);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Inconsistent Quartz API: " + ex);
|
||||
|
||||
+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.
|
||||
@@ -29,7 +29,7 @@ import org.springframework.beans.factory.ListableBeanFactory;
|
||||
* Spring bean-style class for accessing a Quartz Scheduler, i.e. for registering jobs,
|
||||
* triggers and listeners on a given {@link org.quartz.Scheduler} instance.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.6
|
||||
|
||||
+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.
|
||||
@@ -74,7 +74,7 @@ import org.springframework.util.CollectionUtils;
|
||||
* automatically apply to Scheduler operations performed within those scopes.
|
||||
* Alternatively, you may add transactional advice for the Scheduler itself.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 18.02.2004
|
||||
|
||||
+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.
|
||||
@@ -46,7 +46,7 @@ import org.springframework.core.Constants;
|
||||
* Use Quartz 2.0's native {@code JobDetailImpl} class or the new Quartz 2.0
|
||||
* builder API instead. Alternatively, switch to Spring's {@link SimpleTriggerFactoryBean}
|
||||
* which largely is a drop-in replacement for this class and its properties and
|
||||
* consistently works against Quartz 1.x as well as Quartz 2.0/2.1.
|
||||
* consistently works against Quartz 1.x as well as Quartz 2.x.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 18.02.2004
|
||||
|
||||
+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.
|
||||
@@ -49,7 +49,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* to automatically register a trigger for the corresponding JobDetail,
|
||||
* instead of registering the JobDetail separately.
|
||||
*
|
||||
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.0/2.1,
|
||||
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.x,
|
||||
* in contrast to the older {@link SimpleTriggerBean} class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
|
||||
+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.
|
||||
@@ -37,7 +37,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* as bean property values. If no matching bean property is found, the entry
|
||||
* is by default simply ignored. This is analogous to QuartzJobBean's behavior.
|
||||
*
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
|
||||
@@ -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.
|
||||
@@ -39,11 +39,15 @@ public interface Cache {
|
||||
Object getNativeCache();
|
||||
|
||||
/**
|
||||
* Return the value to which this cache maps the specified key. Returns
|
||||
* {@code null} if the cache contains no mapping for this key.
|
||||
* @param key key whose associated value is to be returned.
|
||||
* Return the value to which this cache maps the specified key.
|
||||
* <p>Returns {@code null} if the cache contains no mapping for this key;
|
||||
* otherwise, the cached value (which may be {@code null} itself) will
|
||||
* be returned in a {@link ValueWrapper}.
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which this cache maps the specified key,
|
||||
* or {@code null} if the cache contains no mapping for this key
|
||||
* contained within a {@link ValueWrapper} which may also hold
|
||||
* a cached {@code null} value. A straight {@code null} being
|
||||
* returned means that the cache contains no mapping for this key.
|
||||
*/
|
||||
ValueWrapper get(Object key);
|
||||
|
||||
|
||||
+72
-93
@@ -25,6 +25,7 @@ import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.framework.AopProxyUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
@@ -61,23 +62,25 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class CacheAspectSupport implements InitializingBean {
|
||||
|
||||
public interface Invoker {
|
||||
Object invoke();
|
||||
}
|
||||
private static final String CACHEABLE = "cacheable";
|
||||
|
||||
private static final String UPDATE = "cacheupdate";
|
||||
|
||||
private static final String EVICT = "cacheevict";
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
|
||||
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private CacheOperationSource cacheOperationSource;
|
||||
|
||||
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
|
||||
|
||||
private KeyGenerator keyGenerator = new DefaultKeyGenerator();
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
private static final String CACHEABLE = "cacheable", UPDATE = "cacheupdate", EVICT = "cacheevict";
|
||||
|
||||
/**
|
||||
* Set the CacheManager that this cache aspect should delegate to.
|
||||
@@ -101,10 +104,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
*/
|
||||
public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {
|
||||
Assert.notEmpty(cacheOperationSources);
|
||||
this.cacheOperationSource =
|
||||
(cacheOperationSources.length > 1 ?
|
||||
new CompositeCacheOperationSource(cacheOperationSources) :
|
||||
cacheOperationSources[0]);
|
||||
this.cacheOperationSource = (cacheOperationSources.length > 1 ?
|
||||
new CompositeCacheOperationSource(cacheOperationSources) : cacheOperationSources[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,13 +135,14 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
throw new IllegalStateException("'cacheManager' is required");
|
||||
}
|
||||
if (this.cacheOperationSource == null) {
|
||||
throw new IllegalStateException("The 'cacheOperationSources' property is required: "
|
||||
+ "If there are no cacheable methods, then don't use a cache aspect.");
|
||||
throw new IllegalStateException("The 'cacheOperationSources' property is required: " +
|
||||
"If there are no cacheable methods, then don't use a cache aspect.");
|
||||
}
|
||||
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenience method to return a String representation of this Method
|
||||
* for use in logging. Can be overridden in subclasses to provide a
|
||||
@@ -161,7 +163,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
for (String cacheName : cacheNames) {
|
||||
Cache cache = this.cacheManager.getCache(cacheName);
|
||||
if (cache == null) {
|
||||
throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + operation);
|
||||
throw new IllegalArgumentException("Cannot find cache named '" + cacheName + "' for " + operation);
|
||||
}
|
||||
caches.add(cache);
|
||||
}
|
||||
@@ -186,39 +188,31 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
if (targetClass == null && target != null) {
|
||||
targetClass = target.getClass();
|
||||
}
|
||||
final Collection<CacheOperation> cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass);
|
||||
Collection<CacheOperation> cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass);
|
||||
|
||||
// analyze caching information
|
||||
if (!CollectionUtils.isEmpty(cacheOp)) {
|
||||
Map<String, Collection<CacheOperationContext>> ops = createOperationContext(cacheOp, method, args, target, targetClass);
|
||||
|
||||
// start with evictions
|
||||
inspectBeforeCacheEvicts(ops.get(EVICT));
|
||||
|
||||
// follow up with cacheable
|
||||
CacheStatus status = inspectCacheables(ops.get(CACHEABLE));
|
||||
|
||||
Object retVal = null;
|
||||
Object retVal;
|
||||
Map<CacheOperationContext, Object> updates = inspectCacheUpdates(ops.get(UPDATE));
|
||||
|
||||
if (status != null) {
|
||||
if (status.updateRequired) {
|
||||
updates.putAll(status.cUpdates);
|
||||
updates.putAll(status.cacheUpdates);
|
||||
}
|
||||
// return cached object
|
||||
else {
|
||||
return status.retVal;
|
||||
}
|
||||
}
|
||||
|
||||
retVal = invoker.invoke();
|
||||
|
||||
inspectAfterCacheEvicts(ops.get(EVICT), retVal);
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
update(updates, retVal);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@@ -229,27 +223,20 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
inspectCacheEvicts(evictions, true, ExpressionEvaluator.NO_RESULT);
|
||||
}
|
||||
|
||||
private void inspectAfterCacheEvicts(Collection<CacheOperationContext> evictions,
|
||||
Object result) {
|
||||
private void inspectAfterCacheEvicts(Collection<CacheOperationContext> evictions, Object result) {
|
||||
inspectCacheEvicts(evictions, false, result);
|
||||
}
|
||||
|
||||
private void inspectCacheEvicts(Collection<CacheOperationContext> evictions,
|
||||
boolean beforeInvocation, Object result) {
|
||||
|
||||
private void inspectCacheEvicts(Collection<CacheOperationContext> evictions, boolean beforeInvocation, Object result) {
|
||||
if (!evictions.isEmpty()) {
|
||||
|
||||
boolean log = logger.isTraceEnabled();
|
||||
|
||||
for (CacheOperationContext context : evictions) {
|
||||
CacheEvictOperation evictOp = (CacheEvictOperation) context.operation;
|
||||
|
||||
if (beforeInvocation == evictOp.isBeforeInvocation()) {
|
||||
if (context.isConditionPassing(result)) {
|
||||
// for each cache
|
||||
// lazy key initialization
|
||||
Object key = null;
|
||||
|
||||
for (Cache cache : context.getCaches()) {
|
||||
// cache-wide flush
|
||||
if (evictOp.isCacheWide()) {
|
||||
@@ -257,7 +244,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
if (log) {
|
||||
logger.trace("Invalidating entire cache for operation " + evictOp + " on method " + context.method);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// check key
|
||||
if (key == null) {
|
||||
key = context.generateKey();
|
||||
@@ -268,7 +256,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
cache.evict(key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (log) {
|
||||
logger.trace("Cache condition failed on method " + context.method + " for operation " + context.operation);
|
||||
}
|
||||
@@ -279,34 +268,27 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
}
|
||||
|
||||
private CacheStatus inspectCacheables(Collection<CacheOperationContext> cacheables) {
|
||||
Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>(cacheables.size());
|
||||
|
||||
Map<CacheOperationContext, Object> cacheUpdates = new LinkedHashMap<CacheOperationContext, Object>(cacheables.size());
|
||||
boolean updateRequired = false;
|
||||
Object retVal = null;
|
||||
|
||||
if (!cacheables.isEmpty()) {
|
||||
boolean log = logger.isTraceEnabled();
|
||||
boolean atLeastOnePassed = false;
|
||||
|
||||
for (CacheOperationContext context : cacheables) {
|
||||
if (context.isConditionPassing()) {
|
||||
atLeastOnePassed = true;
|
||||
Object key = context.generateKey();
|
||||
|
||||
if (log) {
|
||||
logger.trace("Computed cache key " + key + " for operation " + context.operation);
|
||||
}
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Null key returned for cache operation (maybe you are using named params on classes without debug info?) "
|
||||
+ context.operation);
|
||||
throw new IllegalArgumentException("Null key returned for cache operation (maybe you " +
|
||||
"are using named params on classes without debug info?) " + context.operation);
|
||||
}
|
||||
|
||||
// add op/key (in case an update is discovered later on)
|
||||
cUpdates.put(context, key);
|
||||
|
||||
cacheUpdates.put(context, key);
|
||||
boolean localCacheHit = false;
|
||||
|
||||
// check whether the cache needs to be inspected or not (the method will be invoked anyway)
|
||||
if (!updateRequired) {
|
||||
for (Cache cache : context.getCaches()) {
|
||||
@@ -318,7 +300,6 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!localCacheHit) {
|
||||
updateRequired = true;
|
||||
}
|
||||
@@ -330,51 +311,31 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
}
|
||||
}
|
||||
|
||||
// return a status only if at least on cacheable matched
|
||||
// return a status only if at least one cacheable matched
|
||||
if (atLeastOnePassed) {
|
||||
return new CacheStatus(cUpdates, updateRequired, retVal);
|
||||
return new CacheStatus(cacheUpdates, updateRequired, retVal);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class CacheStatus {
|
||||
// caches/key
|
||||
final Map<CacheOperationContext, Object> cUpdates;
|
||||
final boolean updateRequired;
|
||||
final Object retVal;
|
||||
|
||||
CacheStatus(Map<CacheOperationContext, Object> cUpdates, boolean updateRequired, Object retVal) {
|
||||
this.cUpdates = cUpdates;
|
||||
this.updateRequired = updateRequired;
|
||||
this.retVal = retVal;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<CacheOperationContext, Object> inspectCacheUpdates(Collection<CacheOperationContext> updates) {
|
||||
|
||||
Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>(updates.size());
|
||||
|
||||
Map<CacheOperationContext, Object> cacheUpdates = new LinkedHashMap<CacheOperationContext, Object>(updates.size());
|
||||
if (!updates.isEmpty()) {
|
||||
boolean log = logger.isTraceEnabled();
|
||||
|
||||
for (CacheOperationContext context : updates) {
|
||||
if (context.isConditionPassing()) {
|
||||
|
||||
Object key = context.generateKey();
|
||||
|
||||
if (log) {
|
||||
logger.trace("Computed cache key " + key + " for operation " + context.operation);
|
||||
}
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Null key returned for cache operation (maybe you are using named params on classes without debug info?) "
|
||||
+ context.operation);
|
||||
throw new IllegalArgumentException("Null key returned for cache operation (maybe you " +
|
||||
"are using named params on classes without debug info?) " + context.operation);
|
||||
}
|
||||
|
||||
// add op/key (in case an update is discovered later on)
|
||||
cUpdates.put(context, key);
|
||||
cacheUpdates.put(context, key);
|
||||
}
|
||||
else {
|
||||
if (log) {
|
||||
@@ -383,14 +344,13 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cUpdates;
|
||||
return cacheUpdates;
|
||||
}
|
||||
|
||||
private void update(Map<CacheOperationContext, Object> updates, Object retVal) {
|
||||
for (Map.Entry<CacheOperationContext, Object> entry : updates.entrySet()) {
|
||||
CacheOperationContext operationContext = entry.getKey();
|
||||
if(operationContext.canPutToCache(retVal)) {
|
||||
if (operationContext.canPutToCache(retVal)) {
|
||||
for (Cache cache : operationContext.getCaches()) {
|
||||
cache.put(entry.getValue(), retVal);
|
||||
}
|
||||
@@ -398,37 +358,40 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Collection<CacheOperationContext>> createOperationContext(Collection<CacheOperation> cacheOp,
|
||||
Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||
Map<String, Collection<CacheOperationContext>> map = new LinkedHashMap<String, Collection<CacheOperationContext>>(3);
|
||||
private Map<String, Collection<CacheOperationContext>> createOperationContext(
|
||||
Collection<CacheOperation> cacheOperations, Method method, Object[] args, Object target, Class<?> targetClass) {
|
||||
|
||||
Map<String, Collection<CacheOperationContext>> result = new LinkedHashMap<String, Collection<CacheOperationContext>>(3);
|
||||
Collection<CacheOperationContext> cacheables = new ArrayList<CacheOperationContext>();
|
||||
Collection<CacheOperationContext> evicts = new ArrayList<CacheOperationContext>();
|
||||
Collection<CacheOperationContext> updates = new ArrayList<CacheOperationContext>();
|
||||
|
||||
for (CacheOperation cacheOperation : cacheOp) {
|
||||
for (CacheOperation cacheOperation : cacheOperations) {
|
||||
CacheOperationContext opContext = getOperationContext(cacheOperation, method, args, target, targetClass);
|
||||
|
||||
if (cacheOperation instanceof CacheableOperation) {
|
||||
cacheables.add(opContext);
|
||||
}
|
||||
|
||||
if (cacheOperation instanceof CacheEvictOperation) {
|
||||
evicts.add(opContext);
|
||||
}
|
||||
|
||||
if (cacheOperation instanceof CachePutOperation) {
|
||||
updates.add(opContext);
|
||||
}
|
||||
}
|
||||
|
||||
map.put(CACHEABLE, cacheables);
|
||||
map.put(EVICT, evicts);
|
||||
map.put(UPDATE, updates);
|
||||
|
||||
return map;
|
||||
result.put(CACHEABLE, cacheables);
|
||||
result.put(EVICT, evicts);
|
||||
result.put(UPDATE, updates);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public interface Invoker {
|
||||
|
||||
Object invoke();
|
||||
}
|
||||
|
||||
|
||||
protected class CacheOperationContext {
|
||||
|
||||
private final CacheOperation operation;
|
||||
@@ -459,8 +422,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
protected boolean isConditionPassing(Object result) {
|
||||
if (StringUtils.hasText(this.operation.getCondition())) {
|
||||
EvaluationContext evaluationContext = createEvaluationContext(result);
|
||||
return evaluator.condition(this.operation.getCondition(), this.method,
|
||||
evaluationContext);
|
||||
return evaluator.condition(this.operation.getCondition(), this.method, evaluationContext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -473,7 +435,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
else if (this.operation instanceof CachePutOperation) {
|
||||
unless = ((CachePutOperation) this.operation).getUnless();
|
||||
}
|
||||
if(StringUtils.hasText(unless)) {
|
||||
if (StringUtils.hasText(unless)) {
|
||||
EvaluationContext evaluationContext = createEvaluationContext(value);
|
||||
return !evaluator.unless(unless, this.method, evaluationContext);
|
||||
}
|
||||
@@ -493,12 +455,29 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
}
|
||||
|
||||
private EvaluationContext createEvaluationContext(Object result) {
|
||||
return evaluator.createEvaluationContext(this.caches, this.method, this.args,
|
||||
this.target, this.targetClass, result);
|
||||
return evaluator.createEvaluationContext(this.caches, this.method, this.args, this.target, this.targetClass, result);
|
||||
}
|
||||
|
||||
protected Collection<Cache> getCaches() {
|
||||
return this.caches;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class CacheStatus {
|
||||
|
||||
// caches/key
|
||||
final Map<CacheOperationContext, Object> cacheUpdates;
|
||||
|
||||
final boolean updateRequired;
|
||||
|
||||
final Object retVal;
|
||||
|
||||
CacheStatus(Map<CacheOperationContext, Object> cacheUpdates, boolean updateRequired, Object retVal) {
|
||||
this.cacheUpdates = cacheUpdates;
|
||||
this.updateRequired = updateRequired;
|
||||
this.retVal = retVal;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+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.
|
||||
@@ -116,7 +116,10 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
|
||||
(metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME)) ||
|
||||
annotationType.equals("javax.annotation.ManagedBean") ||
|
||||
annotationType.equals("javax.inject.Named");
|
||||
return (isStereotype && attributes != null && attributes.containsKey("value"));
|
||||
|
||||
return (isStereotype && attributes != null &&
|
||||
attributes.containsKey("value") &&
|
||||
attributes.get("value") instanceof String);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-4
@@ -109,7 +109,7 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
|
||||
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
|
||||
this.reader.setBeanNameGenerator(beanNameGenerator);
|
||||
this.scanner.setBeanNameGenerator(beanNameGenerator);
|
||||
this.getBeanFactory().registerSingleton(
|
||||
getBeanFactory().registerSingleton(
|
||||
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
|
||||
}
|
||||
|
||||
@@ -126,9 +126,9 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
|
||||
|
||||
/**
|
||||
* Register one or more annotated classes to be processed.
|
||||
* Note that {@link #refresh()} must be called in order for the context to fully
|
||||
* process the new class.
|
||||
* <p>Calls to {@link #register} are idempotent; adding the same
|
||||
* Note that {@link #refresh()} must be called in order for the context
|
||||
* to fully process the new class.
|
||||
* <p>Calls to {@code register} are idempotent; adding the same
|
||||
* annotated class more than once has no additional effect.
|
||||
* @param annotatedClasses one or more annotated classes,
|
||||
* e.g. {@link Configuration @Configuration} classes
|
||||
|
||||
+2
-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.
|
||||
@@ -230,7 +230,7 @@ public class AnnotationConfigUtils {
|
||||
return new BeanDefinitionHolder(definition, beanName);
|
||||
}
|
||||
|
||||
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
|
||||
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
|
||||
AnnotationMetadata metadata = abd.getMetadata();
|
||||
if (metadata.isAnnotated(Primary.class.getName())) {
|
||||
abd.setPrimary(true);
|
||||
@@ -260,5 +260,4 @@ public class AnnotationConfigUtils {
|
||||
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -317,8 +317,8 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
|
||||
/**
|
||||
* Determine whether the given new bean definition is compatible with
|
||||
* the given existing bean definition.
|
||||
* <p>The default implementation simply considers them as compatible
|
||||
* when the bean class name matches.
|
||||
* <p>The default implementation considers them as compatible when the existing
|
||||
* bean definition comes from the same source or from a non-scanning source.
|
||||
* @param newDefinition the new bean definition, originated from scanning
|
||||
* @param existingDefinition the existing bean definition, potentially an
|
||||
* explicitly defined one or a previously generated one from scanning
|
||||
|
||||
+13
-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.
|
||||
@@ -90,7 +90,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
|
||||
|
||||
/**
|
||||
* Create a ClassPathScanningCandidateComponentProvider.
|
||||
* Create a ClassPathScanningCandidateComponentProvider with a {@link StandardEnvironment}.
|
||||
* @param useDefaultFilters whether to register the default filters for the
|
||||
* {@link Component @Component}, {@link Repository @Repository},
|
||||
* {@link Service @Service}, and {@link Controller @Controller}
|
||||
@@ -101,6 +101,15 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
this(useDefaultFilters, new StandardEnvironment());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ClassPathScanningCandidateComponentProvider with the given {@link Environment}.
|
||||
* @param useDefaultFilters whether to register the default filters for the
|
||||
* {@link Component @Component}, {@link Repository @Repository},
|
||||
* {@link Service @Service}, and {@link Controller @Controller}
|
||||
* stereotype annotations
|
||||
* @param environment the Environment to use
|
||||
* @see #registerDefaultFilters()
|
||||
*/
|
||||
public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
|
||||
if (useDefaultFilters) {
|
||||
registerDefaultFilters();
|
||||
@@ -219,7 +228,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
try {
|
||||
this.includeFilters.add(new AnnotationTypeFilter(
|
||||
((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));
|
||||
logger.info("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
|
||||
logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
|
||||
@@ -227,7 +236,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
try {
|
||||
this.includeFilters.add(new AnnotationTypeFilter(
|
||||
((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));
|
||||
logger.info("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
|
||||
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - simply skip.
|
||||
|
||||
+18
-28
@@ -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.
|
||||
@@ -177,8 +177,8 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
|
||||
private transient BeanFactory beanFactory;
|
||||
|
||||
private transient final Map<Class<?>, InjectionMetadata> injectionMetadataCache =
|
||||
new ConcurrentHashMap<Class<?>, InjectionMetadata>(64);
|
||||
private transient final Map<String, InjectionMetadata> injectionMetadataCache =
|
||||
new ConcurrentHashMap<String, InjectionMetadata>(64);
|
||||
|
||||
|
||||
/**
|
||||
@@ -282,7 +282,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
|
||||
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
|
||||
if (beanType != null) {
|
||||
InjectionMetadata metadata = findResourceMetadata(beanType);
|
||||
InjectionMetadata metadata = findResourceMetadata(beanName, beanType);
|
||||
metadata.checkConfigMembers(beanDefinition);
|
||||
}
|
||||
}
|
||||
@@ -298,7 +298,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
public PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
|
||||
|
||||
InjectionMetadata metadata = findResourceMetadata(bean.getClass());
|
||||
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass());
|
||||
try {
|
||||
metadata.inject(bean, beanName, pvs);
|
||||
}
|
||||
@@ -309,12 +309,14 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
}
|
||||
|
||||
|
||||
private InjectionMetadata findResourceMetadata(final Class<?> clazz) {
|
||||
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz) {
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
|
||||
// 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 (metadata == null) {
|
||||
synchronized (this.injectionMetadataCache) {
|
||||
metadata = this.injectionMetadataCache.get(clazz);
|
||||
metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
if (metadata == null) {
|
||||
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
Class<?> targetClass = clazz;
|
||||
@@ -388,7 +390,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
while (targetClass != null && targetClass != Object.class);
|
||||
|
||||
metadata = new InjectionMetadata(clazz, elements);
|
||||
this.injectionMetadataCache.put(clazz, metadata);
|
||||
this.injectionMetadataCache.put(cacheKey, metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -472,11 +474,8 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
|
||||
public LookupElement(Member member, PropertyDescriptor pd) {
|
||||
super(member, pd);
|
||||
initAnnotation((AnnotatedElement) member);
|
||||
}
|
||||
|
||||
protected abstract void initAnnotation(AnnotatedElement ae);
|
||||
|
||||
/**
|
||||
* Return the resource name for the lookup.
|
||||
*/
|
||||
@@ -511,14 +510,11 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
*/
|
||||
private class ResourceElement extends LookupElement {
|
||||
|
||||
protected boolean shareable = true;
|
||||
protected final boolean shareable;
|
||||
|
||||
public ResourceElement(Member member, PropertyDescriptor pd) {
|
||||
super(member, pd);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initAnnotation(AnnotatedElement ae) {
|
||||
AnnotatedElement ae = (AnnotatedElement) member;
|
||||
Resource resource = ae.getAnnotation(Resource.class);
|
||||
String resourceName = resource.name();
|
||||
Class<?> resourceType = resource.type();
|
||||
@@ -558,16 +554,13 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
*/
|
||||
private class WebServiceRefElement extends LookupElement {
|
||||
|
||||
private Class<?> elementType;
|
||||
private final Class<?> elementType;
|
||||
|
||||
private String wsdlLocation;
|
||||
private final String wsdlLocation;
|
||||
|
||||
public WebServiceRefElement(Member member, PropertyDescriptor pd) {
|
||||
super(member, pd);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initAnnotation(AnnotatedElement ae) {
|
||||
AnnotatedElement ae = (AnnotatedElement) member;
|
||||
WebServiceRef resource = ae.getAnnotation(WebServiceRef.class);
|
||||
String resourceName = resource.name();
|
||||
Class<?> resourceType = resource.type();
|
||||
@@ -647,14 +640,11 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
*/
|
||||
private class EjbRefElement extends LookupElement {
|
||||
|
||||
private String beanName;
|
||||
private final String beanName;
|
||||
|
||||
public EjbRefElement(Member member, PropertyDescriptor pd) {
|
||||
super(member, pd);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initAnnotation(AnnotatedElement ae) {
|
||||
AnnotatedElement ae = (AnnotatedElement) member;
|
||||
EJB resource = ae.getAnnotation(EJB.class);
|
||||
String resourceBeanName = resource.beanName();
|
||||
String resourceName = resource.name();
|
||||
|
||||
+8
-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.
|
||||
@@ -42,7 +42,7 @@ import org.springframework.core.type.filter.TypeFilter;
|
||||
* always registered, meaning that any attempt to disable them at the
|
||||
* {@code @ComponentScan} level would be ignored.
|
||||
*
|
||||
* <p>See @{@link Configuration} Javadoc for usage examples.
|
||||
* <p>See @{@link Configuration}'s javadoc for usage examples.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
@@ -139,24 +139,18 @@ public @interface ComponentScan {
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({})
|
||||
@interface Filter {
|
||||
|
||||
/**
|
||||
* The type of filter to use.
|
||||
* <p>Note that the filter types available are limited to those that may
|
||||
* be expressed as a {@code Class} in the {@link #value()} attribute. This is
|
||||
* in contrast to {@code <context:component-scan/>}, which allows for
|
||||
* expression-based (i.e., string-based) filters such as AspectJ pointcuts.
|
||||
* These filter types are intentionally not supported here, and not available
|
||||
* in the {@link FilterType} enum.
|
||||
* @see FilterType
|
||||
* The type of filter to use. Default is {@link FilterType#ANNOTATION}.
|
||||
*/
|
||||
FilterType type() default FilterType.ANNOTATION;
|
||||
|
||||
/**
|
||||
* The class or classes to use as the filter. In the case of
|
||||
* {@link FilterType#ANNOTATION}, the class will be the annotation itself. In the
|
||||
* case of {@link FilterType#ASSIGNABLE_TYPE}, the class will be the type that
|
||||
* detected components should be assignable to. And in the case of
|
||||
* {@link FilterType#CUSTOM}, the class will be an implementation of
|
||||
* {@link FilterType#ANNOTATION}, the class will be the annotation itself.
|
||||
* In the case of {@link FilterType#ASSIGNABLE_TYPE}, the class will be the
|
||||
* type that detected components should be assignable to. And in the case
|
||||
* of {@link FilterType#CUSTOM}, the class will be an implementation of
|
||||
* {@link TypeFilter}.
|
||||
* <p>When multiple classes are specified, OR logic is applied, e.g. "include
|
||||
* types annotated with {@code @Foo} OR {@code @Bar}".
|
||||
|
||||
+9
-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.
|
||||
@@ -28,6 +28,7 @@ import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
@@ -64,7 +65,7 @@ class ComponentScanAnnotationParser {
|
||||
}
|
||||
|
||||
|
||||
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, String declaringClass) {
|
||||
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
|
||||
ClassPathBeanDefinitionScanner scanner =
|
||||
new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"));
|
||||
|
||||
@@ -120,6 +121,12 @@ class ComponentScanAnnotationParser {
|
||||
basePackages.add(ClassUtils.getPackageName(declaringClass));
|
||||
}
|
||||
|
||||
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
|
||||
@Override
|
||||
protected boolean matchClassName(String className) {
|
||||
return declaringClass.equals(className);
|
||||
}
|
||||
});
|
||||
return scanner.doScan(StringUtils.toStringArray(basePackages));
|
||||
}
|
||||
|
||||
|
||||
+39
-44
@@ -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.
|
||||
@@ -36,8 +36,8 @@ import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Represents a user-defined {@link Configuration @Configuration} class.
|
||||
* Includes a set of {@link Bean} methods, including all such methods defined in the
|
||||
* ancestry of the class, in a 'flattened-out' manner.
|
||||
* Includes a set of {@link Bean} methods, including all such methods
|
||||
* defined in the ancestry of the class, in a 'flattened-out' manner.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
@@ -51,15 +51,15 @@ final class ConfigurationClass {
|
||||
|
||||
private final Resource resource;
|
||||
|
||||
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
|
||||
new LinkedHashMap<String, Class<? extends BeanDefinitionReader>>();
|
||||
|
||||
private final Set<BeanMethod> beanMethods = new LinkedHashSet<BeanMethod>();
|
||||
|
||||
private String beanName;
|
||||
|
||||
private final boolean imported;
|
||||
|
||||
private final Set<BeanMethod> beanMethods = new LinkedHashSet<BeanMethod>();
|
||||
|
||||
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
|
||||
new LinkedHashMap<String, Class<? extends BeanDefinitionReader>>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@link ConfigurationClass} with the given name.
|
||||
@@ -81,7 +81,7 @@ final class ConfigurationClass {
|
||||
* using the {@link Import} annotation or automatically processed as a nested
|
||||
* configuration class (if imported is {@code true}).
|
||||
* @param metadataReader reader used to parse the underlying {@link Class}
|
||||
* @param beanName name of the {@code @Configuration} class bean
|
||||
* @param imported whether the given configuration class is being imported
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public ConfigurationClass(MetadataReader metadataReader, boolean imported) {
|
||||
@@ -98,7 +98,7 @@ final class ConfigurationClass {
|
||||
* @see ConfigurationClass#ConfigurationClass(Class, boolean)
|
||||
*/
|
||||
public ConfigurationClass(Class<?> clazz, String beanName) {
|
||||
Assert.hasText(beanName, "bean name must not be null");
|
||||
Assert.hasText(beanName, "Bean name must not be null");
|
||||
this.metadata = new StandardAnnotationMetadata(clazz, true);
|
||||
this.resource = new DescriptiveResource(clazz.toString());
|
||||
this.beanName = beanName;
|
||||
@@ -110,7 +110,7 @@ final class ConfigurationClass {
|
||||
* using the {@link Import} annotation or automatically processed as a nested
|
||||
* configuration class (if imported is {@code true}).
|
||||
* @param clazz the underlying {@link Class} to represent
|
||||
* @param beanName name of the {@code @Configuration} class bean
|
||||
* @param imported whether the given configuration class is being imported
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public ConfigurationClass(Class<?> clazz, boolean imported) {
|
||||
@@ -119,6 +119,7 @@ final class ConfigurationClass {
|
||||
this.imported = imported;
|
||||
}
|
||||
|
||||
|
||||
public AnnotationMetadata getMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
@@ -131,6 +132,14 @@ final class ConfigurationClass {
|
||||
return ClassUtils.getShortName(getMetadata().getClassName());
|
||||
}
|
||||
|
||||
public void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
public String getBeanName() {
|
||||
return this.beanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this configuration class was registered via @{@link Import} or
|
||||
* automatically registered due to being nested within another configuration class.
|
||||
@@ -140,14 +149,6 @@ final class ConfigurationClass {
|
||||
return this.imported;
|
||||
}
|
||||
|
||||
public void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
public String getBeanName() {
|
||||
return this.beanName;
|
||||
}
|
||||
|
||||
public void addBeanMethod(BeanMethod method) {
|
||||
this.beanMethods.add(method);
|
||||
}
|
||||
@@ -156,8 +157,7 @@ final class ConfigurationClass {
|
||||
return this.beanMethods;
|
||||
}
|
||||
|
||||
public void addImportedResource(
|
||||
String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
|
||||
public void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
|
||||
this.importedResources.put(importedResource, readerClass);
|
||||
}
|
||||
|
||||
@@ -166,27 +166,6 @@ final class ConfigurationClass {
|
||||
}
|
||||
|
||||
public void validate(ProblemReporter problemReporter) {
|
||||
// An @Bean method may only be overloaded through inheritance. No single
|
||||
// @Configuration class may declare two @Bean methods with the same name.
|
||||
final char hashDelim = '#';
|
||||
Map<String, Integer> methodNameCounts = new HashMap<String, Integer>();
|
||||
for (BeanMethod beanMethod : beanMethods) {
|
||||
String dClassName = beanMethod.getMetadata().getDeclaringClassName();
|
||||
String methodName = beanMethod.getMetadata().getMethodName();
|
||||
String fqMethodName = dClassName + hashDelim + methodName;
|
||||
Integer currentCount = methodNameCounts.get(fqMethodName);
|
||||
int newCount = currentCount != null ? currentCount + 1 : 1;
|
||||
methodNameCounts.put(fqMethodName, newCount);
|
||||
}
|
||||
|
||||
for (String methodName : methodNameCounts.keySet()) {
|
||||
int count = methodNameCounts.get(methodName);
|
||||
if (count > 1) {
|
||||
String shortMethodName = methodName.substring(methodName.indexOf(hashDelim)+1);
|
||||
problemReporter.error(new BeanMethodOverloadingProblem(shortMethodName, count));
|
||||
}
|
||||
}
|
||||
|
||||
// A configuration class may not be final (CGLIB limitation)
|
||||
if (getMetadata().isAnnotated(Configuration.class.getName())) {
|
||||
if (getMetadata().isFinal()) {
|
||||
@@ -194,12 +173,28 @@ final class ConfigurationClass {
|
||||
}
|
||||
}
|
||||
|
||||
// An @Bean method may only be overloaded through inheritance. No single
|
||||
// @Configuration class may declare two @Bean methods with the same name.
|
||||
Map<String, Integer> methodNameCounts = new HashMap<String, Integer>();
|
||||
for (BeanMethod beanMethod : this.beanMethods) {
|
||||
String fqMethodName = beanMethod.getFullyQualifiedMethodName();
|
||||
Integer currentCount = methodNameCounts.get(fqMethodName);
|
||||
int newCount = currentCount != null ? currentCount + 1 : 1;
|
||||
methodNameCounts.put(fqMethodName, newCount);
|
||||
}
|
||||
for (String fqMethodName : methodNameCounts.keySet()) {
|
||||
int count = methodNameCounts.get(fqMethodName);
|
||||
if (count > 1) {
|
||||
String shortMethodName = ConfigurationMethod.getShortMethodName(fqMethodName);
|
||||
problemReporter.error(new BeanMethodOverloadingProblem(shortMethodName, count));
|
||||
}
|
||||
}
|
||||
|
||||
for (BeanMethod beanMethod : this.beanMethods) {
|
||||
beanMethod.validate(problemReporter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return (this == other || (other instanceof ConfigurationClass &&
|
||||
@@ -213,7 +208,7 @@ final class ConfigurationClass {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[ConfigurationClass:beanName=%s,resource=%s]", this.beanName, this.resource);
|
||||
return "ConfigurationClass:beanName=" + this.beanName + ",resource=" + this.resource;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+19
-10
@@ -134,8 +134,6 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
|
||||
AnnotationMetadata metadata = configClass.getMetadata();
|
||||
BeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
|
||||
String className = metadata.getClassName();
|
||||
configBeanDef.setBeanClassName(className);
|
||||
if (ConfigurationClassUtils.checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {
|
||||
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
|
||||
this.registry.registerBeanDefinition(configBeanName, configBeanDef);
|
||||
@@ -146,7 +144,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
}
|
||||
else {
|
||||
this.problemReporter.error(
|
||||
new InvalidConfigurationImportProblem(className, configClass.getResource(), metadata));
|
||||
new InvalidConfigurationImportProblem(metadata.getClassName(), configClass.getResource(), metadata));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +156,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
ConfigurationClass configClass = beanMethod.getConfigurationClass();
|
||||
MethodMetadata metadata = beanMethod.getMetadata();
|
||||
|
||||
RootBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass);
|
||||
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass);
|
||||
beanDef.setResource(configClass.getResource());
|
||||
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
|
||||
if (metadata.isStatic()) {
|
||||
@@ -190,9 +188,18 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
|
||||
// has this already been overridden (e.g. via XML)?
|
||||
if (this.registry.containsBeanDefinition(beanName)) {
|
||||
BeanDefinition existingBeanDef = registry.getBeanDefinition(beanName);
|
||||
// is the existing bean definition one that was created from a configuration class?
|
||||
if (!(existingBeanDef instanceof ConfigurationClassBeanDefinition)) {
|
||||
BeanDefinition existingBeanDef = this.registry.getBeanDefinition(beanName);
|
||||
// Is the existing bean definition one that was created from a configuration class?
|
||||
// -> allow the current bean method to override, since both are at second-pass level.
|
||||
// However, if the bean method is an overloaded case on the same configuration class,
|
||||
// preserve the existing bean definition.
|
||||
if (existingBeanDef instanceof ConfigurationClassBeanDefinition) {
|
||||
ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef;
|
||||
if (ccbd.getMetadata().getClassName().equals(beanMethod.getConfigurationClass().getMetadata().getClassName())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no -> then it's an external override, probably XML
|
||||
// overriding is legal, return immediately
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -240,7 +247,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
beanDef.setDestroyMethodName(destroyMethodName);
|
||||
}
|
||||
|
||||
// consider scoping
|
||||
// Consider scoping
|
||||
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
|
||||
AnnotationAttributes scope = attributesFor(metadata, Scope.class);
|
||||
if (scope != null) {
|
||||
@@ -251,7 +258,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
}
|
||||
}
|
||||
|
||||
// replace the original bean definition with the target one, if necessary
|
||||
// Replace the original bean definition with the target one, if necessary
|
||||
BeanDefinition beanDefToRegister = beanDef;
|
||||
if (proxyMode != ScopedProxyMode.NO) {
|
||||
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
|
||||
@@ -261,7 +268,8 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Registering bean definition for @Bean method %s.%s()", configClass.getMetadata().getClassName(), beanName));
|
||||
logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",
|
||||
configClass.getMetadata().getClassName(), beanName));
|
||||
}
|
||||
|
||||
registry.registerBeanDefinition(beanName, beanDefToRegister);
|
||||
@@ -312,6 +320,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
|
||||
public ConfigurationClassBeanDefinition(ConfigurationClass configClass) {
|
||||
this.annotationMetadata = configClass.getMetadata();
|
||||
setLenientConstructorResolution(false);
|
||||
}
|
||||
|
||||
public ConfigurationClassBeanDefinition(RootBeanDefinition original, ConfigurationClass configClass) {
|
||||
|
||||
+175
-106
@@ -17,11 +17,12 @@
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
@@ -42,6 +43,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.NestedIOException;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
@@ -54,7 +56,7 @@ import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.context.annotation.MetadataUtils.*;
|
||||
@@ -83,16 +85,6 @@ class ConfigurationClassParser {
|
||||
|
||||
private final ProblemReporter problemReporter;
|
||||
|
||||
private final ImportStack importStack = new ImportStack();
|
||||
|
||||
private final Set<String> knownSuperclasses = new LinkedHashSet<String>();
|
||||
|
||||
private final Set<ConfigurationClass> configurationClasses =
|
||||
new LinkedHashSet<ConfigurationClass>();
|
||||
|
||||
private final Stack<PropertySource<?>> propertySources =
|
||||
new Stack<PropertySource<?>>();
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
@@ -101,6 +93,14 @@ class ConfigurationClassParser {
|
||||
|
||||
private final ComponentScanAnnotationParser componentScanParser;
|
||||
|
||||
private final Set<ConfigurationClass> configurationClasses = new LinkedHashSet<ConfigurationClass>();
|
||||
|
||||
private final Map<String, ConfigurationClass> knownSuperclasses = new HashMap<String, ConfigurationClass>();
|
||||
|
||||
private final Stack<PropertySource<?>> propertySources = new Stack<PropertySource<?>>();
|
||||
|
||||
private final ImportStack importStack = new ImportStack();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@link ConfigurationClassParser} instance that will be used
|
||||
@@ -149,70 +149,42 @@ class ConfigurationClassParser {
|
||||
}
|
||||
}
|
||||
|
||||
// recursively process the configuration class and its superclass hierarchy
|
||||
if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) {
|
||||
// Explicit bean definition found, probably replacing an import.
|
||||
// Let's remove the old one and go with the new one.
|
||||
this.configurationClasses.remove(configClass);
|
||||
for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext();) {
|
||||
if (configClass.equals(it.next())) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively process the configuration class and its superclass hierarchy.
|
||||
do {
|
||||
metadata = doProcessConfigurationClass(configClass, metadata);
|
||||
}
|
||||
while (metadata != null);
|
||||
|
||||
if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) {
|
||||
// Explicit bean definition found, probably replacing an import.
|
||||
// Let's remove the old one and go with the new one.
|
||||
this.configurationClasses.remove(configClass);
|
||||
}
|
||||
|
||||
this.configurationClasses.add(configClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return annotation metadata of superclass, null if none found or previously processed
|
||||
* @return annotation metadata of superclass, {@code null} if none found or previously processed
|
||||
*/
|
||||
protected AnnotationMetadata doProcessConfigurationClass(
|
||||
ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
|
||||
|
||||
// recursively process any member (nested) classes first
|
||||
for (String memberClassName : metadata.getMemberClassNames()) {
|
||||
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(memberClassName);
|
||||
AnnotationMetadata memberClassMetadata = reader.getAnnotationMetadata();
|
||||
if (ConfigurationClassUtils.isConfigurationCandidate(memberClassMetadata)) {
|
||||
processConfigurationClass(new ConfigurationClass(reader, true));
|
||||
}
|
||||
}
|
||||
processMemberClasses(metadata);
|
||||
|
||||
// process any @PropertySource annotations
|
||||
AnnotationAttributes propertySource =
|
||||
attributesFor(metadata, org.springframework.context.annotation.PropertySource.class);
|
||||
AnnotationAttributes propertySource = attributesFor(metadata, org.springframework.context.annotation.PropertySource.class);
|
||||
if (propertySource != null) {
|
||||
String name = propertySource.getString("name");
|
||||
String[] locations = propertySource.getStringArray("value");
|
||||
int nLocations = locations.length;
|
||||
if (nLocations == 0) {
|
||||
throw new IllegalArgumentException("At least one @PropertySource(value) location is required");
|
||||
}
|
||||
for (int i = 0; i < nLocations; i++) {
|
||||
locations[i] = this.environment.resolveRequiredPlaceholders(locations[i]);
|
||||
}
|
||||
ClassLoader classLoader = this.resourceLoader.getClassLoader();
|
||||
if (!StringUtils.hasText(name)) {
|
||||
for (String location : locations) {
|
||||
this.propertySources.push(new ResourcePropertySource(location, classLoader));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (nLocations == 1) {
|
||||
this.propertySources.push(new ResourcePropertySource(name, locations[0], classLoader));
|
||||
}
|
||||
else {
|
||||
CompositePropertySource ps = new CompositePropertySource(name);
|
||||
for (String location : locations) {
|
||||
ps.addPropertySource(new ResourcePropertySource(location, classLoader));
|
||||
}
|
||||
this.propertySources.push(ps);
|
||||
}
|
||||
}
|
||||
processPropertySource(propertySource);
|
||||
}
|
||||
|
||||
// process any @ComponentScan annotions
|
||||
// process any @ComponentScan annotations
|
||||
AnnotationAttributes componentScan = attributesFor(metadata, ComponentScan.class);
|
||||
if (componentScan != null) {
|
||||
// the config class is annotated with @ComponentScan -> perform the scan immediately
|
||||
@@ -228,9 +200,11 @@ class ConfigurationClassParser {
|
||||
}
|
||||
|
||||
// process any @Import annotations
|
||||
Set<String> imports = getImports(metadata.getClassName(), null, new HashSet<String>());
|
||||
if (!CollectionUtils.isEmpty(imports)) {
|
||||
processImport(configClass, imports.toArray(new String[imports.size()]), true);
|
||||
Set<Object> imports = new LinkedHashSet<Object>();
|
||||
Set<Object> visited = new LinkedHashSet<Object>();
|
||||
collectImports(metadata, imports, visited);
|
||||
if (!imports.isEmpty()) {
|
||||
processImport(configClass, imports, true);
|
||||
}
|
||||
|
||||
// process any @ImportResource annotations
|
||||
@@ -239,7 +213,8 @@ class ConfigurationClassParser {
|
||||
String[] resources = importResource.getStringArray("value");
|
||||
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
|
||||
for (String resource : resources) {
|
||||
configClass.addImportedResource(resource, readerClass);
|
||||
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
|
||||
configClass.addImportedResource(resolvedResource, readerClass);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +227,8 @@ class ConfigurationClassParser {
|
||||
// process superclass, if any
|
||||
if (metadata.hasSuperClass()) {
|
||||
String superclass = metadata.getSuperClassName();
|
||||
if (this.knownSuperclasses.add(superclass)) {
|
||||
if (!this.knownSuperclasses.containsKey(superclass)) {
|
||||
this.knownSuperclasses.put(superclass, configClass);
|
||||
// superclass found, return its annotation metadata and recurse
|
||||
if (metadata instanceof StandardAnnotationMetadata) {
|
||||
Class<?> clazz = ((StandardAnnotationMetadata) metadata).getIntrospectedClass();
|
||||
@@ -279,6 +255,65 @@ class ConfigurationClassParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register member (nested) classes that happen to be configuration classes themselves.
|
||||
* @param metadata the metadata representation of the containing class
|
||||
* @throws IOException if there is any problem reading metadata from a member class
|
||||
*/
|
||||
private void processMemberClasses(AnnotationMetadata metadata) throws IOException {
|
||||
if (metadata instanceof StandardAnnotationMetadata) {
|
||||
for (Class<?> memberClass : ((StandardAnnotationMetadata) metadata).getIntrospectedClass().getDeclaredClasses()) {
|
||||
if (ConfigurationClassUtils.isConfigurationCandidate(new StandardAnnotationMetadata(memberClass))) {
|
||||
processConfigurationClass(new ConfigurationClass(memberClass, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (String memberClassName : metadata.getMemberClassNames()) {
|
||||
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(memberClassName);
|
||||
AnnotationMetadata memberClassMetadata = reader.getAnnotationMetadata();
|
||||
if (ConfigurationClassUtils.isConfigurationCandidate(memberClassMetadata)) {
|
||||
processConfigurationClass(new ConfigurationClass(reader, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the given <code>@PropertySource</code> annotation metadata.
|
||||
* @param propertySource metadata for the <code>@PropertySource</code> annotation found
|
||||
* @throws IOException if loading a property source failed
|
||||
*/
|
||||
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
|
||||
String name = propertySource.getString("name");
|
||||
String[] locations = propertySource.getStringArray("value");
|
||||
int locationCount = locations.length;
|
||||
if (locationCount == 0) {
|
||||
throw new IllegalArgumentException("At least one @PropertySource(value) location is required");
|
||||
}
|
||||
for (int i = 0; i < locationCount; i++) {
|
||||
locations[i] = this.environment.resolveRequiredPlaceholders(locations[i]);
|
||||
}
|
||||
ClassLoader classLoader = this.resourceLoader.getClassLoader();
|
||||
if (!StringUtils.hasText(name)) {
|
||||
for (String location : locations) {
|
||||
this.propertySources.push(new ResourcePropertySource(location, classLoader));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (locationCount == 1) {
|
||||
this.propertySources.push(new ResourcePropertySource(name, locations[0], classLoader));
|
||||
}
|
||||
else {
|
||||
CompositePropertySource ps = new CompositePropertySource(name);
|
||||
for (int i = locations.length - 1; i >= 0; i--) {
|
||||
ps.addPropertySource(new ResourcePropertySource(locations[i], classLoader));
|
||||
}
|
||||
this.propertySources.push(ps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively collect all declared {@code @Import} values. Unlike most
|
||||
* meta-annotations it is valid to have several {@code @Import}s declared with
|
||||
@@ -287,69 +322,103 @@ class ConfigurationClassParser {
|
||||
* <p>For example, it is common for a {@code @Configuration} class to declare direct
|
||||
* {@code @Import}s in addition to meta-imports originating from an {@code @Enable}
|
||||
* annotation.
|
||||
* @param className the class name to search
|
||||
* @param imports the imports collected so far or {@code null}
|
||||
* @param visited used to track visited classes to prevent infinite recursion (must not be null)
|
||||
* @return a set of all {@link Import#value() import values} or {@code null}
|
||||
* @param metadata the metadata representation of the class to search
|
||||
* @param imports the imports collected so far
|
||||
* @param visited used to track visited classes to prevent infinite recursion
|
||||
* @throws IOException if there is any problem reading metadata from the named class
|
||||
*/
|
||||
private Set<String> getImports(String className, Set<String> imports, Set<String> visited) throws IOException {
|
||||
if (visited.add(className) && !className.startsWith("java")) {
|
||||
AnnotationMetadata metadata = metadataReaderFactory.getMetadataReader(className).getAnnotationMetadata();
|
||||
for (String annotationType : metadata.getAnnotationTypes()) {
|
||||
imports = getImports(annotationType, imports, visited);
|
||||
private void collectImports(AnnotationMetadata metadata, Set<Object> imports, Set<Object> visited) throws IOException {
|
||||
String className = metadata.getClassName();
|
||||
if (visited.add(className)) {
|
||||
if (metadata instanceof StandardAnnotationMetadata) {
|
||||
StandardAnnotationMetadata stdMetadata = (StandardAnnotationMetadata) metadata;
|
||||
for (Annotation ann : stdMetadata.getIntrospectedClass().getAnnotations()) {
|
||||
if (!ann.annotationType().getName().startsWith("java") && !(ann instanceof Import)) {
|
||||
collectImports(new StandardAnnotationMetadata(ann.annotationType()), imports, visited);
|
||||
}
|
||||
}
|
||||
Map<String, Object> attributes = stdMetadata.getAnnotationAttributes(Import.class.getName(), false);
|
||||
if (attributes != null) {
|
||||
Class[] value = (Class[]) attributes.get("value");
|
||||
if (!ObjectUtils.isEmpty(value)) {
|
||||
imports.addAll(Arrays.asList(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<String, Object> attributes = metadata.getAnnotationAttributes(Import.class.getName(), true);
|
||||
if (attributes != null) {
|
||||
String[] value = (String[]) attributes.get("value");
|
||||
if (value != null && value.length > 0) {
|
||||
imports = (imports == null ? new LinkedHashSet<String>() : imports);
|
||||
imports.addAll(Arrays.asList(value));
|
||||
else {
|
||||
for (String annotationType : metadata.getAnnotationTypes()) {
|
||||
if (!className.startsWith("java") && !className.equals(Import.class.getName())) {
|
||||
try {
|
||||
collectImports(
|
||||
new StandardAnnotationMetadata(this.resourceLoader.getClassLoader().loadClass(annotationType)),
|
||||
imports, visited);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<String, Object> attributes = metadata.getAnnotationAttributes(Import.class.getName(), true);
|
||||
if (attributes != null) {
|
||||
String[] value = (String[]) attributes.get("value");
|
||||
if (!ObjectUtils.isEmpty(value)) {
|
||||
imports.addAll(Arrays.asList(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return imports;
|
||||
}
|
||||
|
||||
private void processImport(ConfigurationClass configClass, String[] classesToImport, boolean checkForCircularImports) throws IOException {
|
||||
private void processImport(ConfigurationClass configClass, Collection<?> classesToImport, boolean checkForCircularImports) throws IOException {
|
||||
if (checkForCircularImports && this.importStack.contains(configClass)) {
|
||||
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata()));
|
||||
}
|
||||
else {
|
||||
this.importStack.push(configClass);
|
||||
AnnotationMetadata importingClassMetadata = configClass.getMetadata();
|
||||
for (String candidate : classesToImport) {
|
||||
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(candidate);
|
||||
if (new AssignableTypeFilter(ImportSelector.class).match(reader, this.metadataReaderFactory)) {
|
||||
// the candidate class is an ImportSelector -> delegate to it to determine imports
|
||||
try {
|
||||
ImportSelector selector = BeanUtils.instantiateClass(
|
||||
this.resourceLoader.getClassLoader().loadClass(candidate), ImportSelector.class);
|
||||
processImport(configClass, selector.selectImports(importingClassMetadata), false);
|
||||
try {
|
||||
for (Object candidate : classesToImport) {
|
||||
Object candidateToCheck = (candidate instanceof Class ? (Class) candidate :
|
||||
this.metadataReaderFactory.getMetadataReader((String) candidate));
|
||||
if (checkAssignability(ImportSelector.class, candidateToCheck)) {
|
||||
// the candidate class is an ImportSelector -> delegate to it to determine imports
|
||||
Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
|
||||
this.resourceLoader.getClassLoader().loadClass((String) candidate));
|
||||
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
|
||||
processImport(configClass, Arrays.asList(selector.selectImports(importingClassMetadata)), false);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
else if (new AssignableTypeFilter(ImportBeanDefinitionRegistrar.class).match(reader, this.metadataReaderFactory)) {
|
||||
// the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
|
||||
try {
|
||||
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(
|
||||
this.resourceLoader.getClassLoader().loadClass(candidate), ImportBeanDefinitionRegistrar.class);
|
||||
else if (checkAssignability(ImportBeanDefinitionRegistrar.class, candidateToCheck)) {
|
||||
// the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
|
||||
Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
|
||||
this.resourceLoader.getClassLoader().loadClass((String) candidate));
|
||||
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
|
||||
invokeAwareMethods(registrar);
|
||||
registrar.registerBeanDefinitions(importingClassMetadata, registry);
|
||||
registrar.registerBeanDefinitions(importingClassMetadata, this.registry);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
else {
|
||||
// candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class
|
||||
this.importStack.registerImport(importingClassMetadata.getClassName(),
|
||||
(candidate instanceof Class ? ((Class) candidate).getName() : (String) candidate));
|
||||
processConfigurationClass(candidateToCheck instanceof Class ? new ConfigurationClass((Class) candidateToCheck, true) :
|
||||
new ConfigurationClass((MetadataReader) candidateToCheck, true));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// the candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class
|
||||
this.importStack.registerImport(importingClassMetadata.getClassName(), candidate);
|
||||
processConfigurationClass(new ConfigurationClass(reader, true));
|
||||
}
|
||||
}
|
||||
this.importStack.pop();
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new NestedIOException("Failed to load import candidate class", ex);
|
||||
}
|
||||
finally {
|
||||
this.importStack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkAssignability(Class<?> clazz, Object candidate) throws IOException {
|
||||
if (candidate instanceof Class) {
|
||||
return clazz.isAssignableFrom((Class) candidate);
|
||||
}
|
||||
else {
|
||||
return new AssignableTypeFilter(clazz).match((MetadataReader) candidate, this.metadataReaderFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,7 +462,7 @@ class ConfigurationClassParser {
|
||||
return this.propertySources;
|
||||
}
|
||||
|
||||
public ImportRegistry getImportRegistry() {
|
||||
ImportRegistry getImportRegistry() {
|
||||
return this.importStack;
|
||||
}
|
||||
|
||||
|
||||
+15
-11
@@ -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.
|
||||
@@ -27,7 +27,6 @@ import java.util.Stack;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
@@ -85,7 +84,7 @@ import static org.springframework.context.annotation.AnnotationConfigUtils.*;
|
||||
* @since 3.0
|
||||
*/
|
||||
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
|
||||
ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
|
||||
Ordered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
|
||||
|
||||
private static final String IMPORT_AWARE_PROCESSOR_BEAN_NAME =
|
||||
ConfigurationClassPostProcessor.class.getName() + ".importAwareProcessor";
|
||||
@@ -130,6 +129,10 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
};
|
||||
|
||||
|
||||
public int getOrder() {
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link SourceExtractor} to use for generated bean definitions
|
||||
* that correspond to {@link Bean} factory methods.
|
||||
@@ -369,15 +372,20 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
}
|
||||
|
||||
|
||||
private static class ImportAwareBeanPostProcessor implements PriorityOrdered, BeanFactoryAware, BeanPostProcessor {
|
||||
private static class ImportAwareBeanPostProcessor implements BeanPostProcessor, PriorityOrdered, BeanFactoryAware {
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
public int getOrder() {
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
if (bean instanceof ImportAware) {
|
||||
ImportRegistry importRegistry = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
|
||||
String importingClass = importRegistry.getImportingClassFor(bean.getClass().getSuperclass().getName());
|
||||
@@ -399,13 +407,9 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-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.
|
||||
@@ -20,6 +20,7 @@ import java.io.IOException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.core.Conventions;
|
||||
@@ -37,14 +38,14 @@ import org.springframework.stereotype.Component;
|
||||
*/
|
||||
abstract class ConfigurationClassUtils {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ConfigurationClassUtils.class);
|
||||
|
||||
private static final String CONFIGURATION_CLASS_FULL = "full";
|
||||
|
||||
private static final String CONFIGURATION_CLASS_LITE = "lite";
|
||||
|
||||
private static final String CONFIGURATION_CLASS_ATTRIBUTE =
|
||||
Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
|
||||
Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ConfigurationClassUtils.class);
|
||||
|
||||
|
||||
/**
|
||||
@@ -93,7 +94,7 @@ abstract class ConfigurationClassUtils {
|
||||
}
|
||||
|
||||
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
|
||||
return isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata);
|
||||
return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
|
||||
}
|
||||
|
||||
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
|
||||
@@ -101,12 +102,11 @@ abstract class ConfigurationClassUtils {
|
||||
}
|
||||
|
||||
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
|
||||
return !metadata.isInterface() && // not an interface or an annotation
|
||||
(metadata.isAnnotated(Component.class.getName()) ||
|
||||
metadata.hasAnnotatedMethods(Bean.class.getName()));
|
||||
// Do not consider an interface or an annotation...
|
||||
return (!metadata.isInterface() && (
|
||||
metadata.isAnnotated(Component.class.getName()) || metadata.hasAnnotatedMethods(Bean.class.getName())));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the given bean definition indicates a full @Configuration class.
|
||||
*/
|
||||
|
||||
+12
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -36,6 +36,7 @@ abstract class ConfigurationMethod {
|
||||
this.configurationClass = configurationClass;
|
||||
}
|
||||
|
||||
|
||||
public MethodMetadata getMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
@@ -48,13 +49,22 @@ abstract class ConfigurationMethod {
|
||||
return new Location(this.configurationClass.getResource(), this.metadata);
|
||||
}
|
||||
|
||||
String getFullyQualifiedMethodName() {
|
||||
return this.metadata.getDeclaringClassName() + "#" + this.metadata.getMethodName();
|
||||
}
|
||||
|
||||
static String getShortMethodName(String fullyQualifiedMethodName) {
|
||||
return fullyQualifiedMethodName.substring(fullyQualifiedMethodName.indexOf('#') + 1);
|
||||
}
|
||||
|
||||
public void validate(ProblemReporter problemReporter) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[%s:name=%s,declaringClass=%s]",
|
||||
this.getClass().getSimpleName(), this.getMetadata().getMethodName(), this.getMetadata().getDeclaringClassName());
|
||||
getClass().getSimpleName(), getMetadata().getMethodName(), getMetadata().getDeclaringClassName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
|
||||
|
||||
/**
|
||||
* Enumeration of the type filters that may be used in conjunction with
|
||||
* {@link ComponentScan @ComponentScan}.
|
||||
@@ -42,12 +39,12 @@ public enum FilterType {
|
||||
|
||||
/**
|
||||
* Filter candidates assignable to a given type.
|
||||
* @see AssignableTypeFilter
|
||||
* @see org.springframework.core.type.filter.AssignableTypeFilter
|
||||
*/
|
||||
ASSIGNABLE_TYPE,
|
||||
|
||||
/** Filter candidates using a given custom
|
||||
* {@link org.springframework.core.type.filter.TypeFilter} implementation
|
||||
* {@link org.springframework.core.type.filter.TypeFilter} implementation.
|
||||
*/
|
||||
CUSTOM
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -44,11 +45,11 @@ import org.springframework.core.env.ConfigurableEnvironment;
|
||||
*
|
||||
* <p>If a {@code @Configuration} class is marked with {@code @Profile}, all of the
|
||||
* {@code @Bean} methods and {@link Import @Import} annotations associated with that class
|
||||
* will be bypassed unless one or more the specified profiles are active. This is very
|
||||
* will be bypassed unless one or more of the specified profiles are active. This is very
|
||||
* similar to the behavior in Spring XML: if the {@code profile} attribute of the
|
||||
* {@code beans} element is supplied e.g., {@code <beans profile="p1,p2">}, the
|
||||
* {@code beans} element will not be parsed unless profiles 'p1' and/or 'p2' have been
|
||||
* activated. Likewise, if a {@code @Component} or {@code @Configuration} class is marked
|
||||
* activated. Likewise, if a {@code @Component} or {@code @Configuration} class is marked
|
||||
* with {@code @Profile({"p1", "p2"})}, that class will not be registered/processed unless
|
||||
* profiles 'p1' and/or 'p2' have been activated.
|
||||
*
|
||||
@@ -73,10 +74,11 @@ import org.springframework.core.env.ConfigurableEnvironment;
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
public @interface Profile {
|
||||
|
||||
/**
|
||||
* The set of profiles for which this component should be registered.
|
||||
* The set of profiles for which the annotated component should be registered.
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
|
||||
+10
-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.
|
||||
@@ -28,6 +28,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Abstract implementation of the {@link ApplicationEventMulticaster} interface,
|
||||
@@ -128,7 +129,8 @@ public abstract class AbstractApplicationEventMulticaster implements Application
|
||||
*/
|
||||
protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
|
||||
Class<? extends ApplicationEvent> eventType = event.getClass();
|
||||
Class sourceType = event.getSource().getClass();
|
||||
Object source = event.getSource();
|
||||
Class<?> sourceType = (source != null ? source.getClass() : null);
|
||||
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
|
||||
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
|
||||
if (retriever != null) {
|
||||
@@ -191,11 +193,11 @@ public abstract class AbstractApplicationEventMulticaster implements Application
|
||||
*/
|
||||
private static class ListenerCacheKey {
|
||||
|
||||
private final Class eventType;
|
||||
private final Class<?> eventType;
|
||||
|
||||
private final Class sourceType;
|
||||
private final Class<?> sourceType;
|
||||
|
||||
public ListenerCacheKey(Class eventType, Class sourceType) {
|
||||
public ListenerCacheKey(Class<?> eventType, Class<?> sourceType) {
|
||||
this.eventType = eventType;
|
||||
this.sourceType = sourceType;
|
||||
}
|
||||
@@ -206,12 +208,13 @@ public abstract class AbstractApplicationEventMulticaster implements Application
|
||||
return true;
|
||||
}
|
||||
ListenerCacheKey otherKey = (ListenerCacheKey) other;
|
||||
return (this.eventType.equals(otherKey.eventType) && this.sourceType.equals(otherKey.sourceType));
|
||||
return ObjectUtils.nullSafeEquals(this.eventType, otherKey.eventType) &&
|
||||
ObjectUtils.nullSafeEquals(this.sourceType, otherKey.sourceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.eventType.hashCode() * 29 + this.sourceType.hashCode();
|
||||
return ObjectUtils.nullSafeHashCode(this.eventType) * 29 + ObjectUtils.nullSafeHashCode(this.sourceType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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,9 +52,9 @@ public class GenericApplicationListenerAdapter implements SmartApplicationListen
|
||||
}
|
||||
|
||||
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
|
||||
Class typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
|
||||
Class<?> typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
|
||||
if (typeArg == null || typeArg.equals(ApplicationEvent.class)) {
|
||||
Class targetClass = AopUtils.getTargetClass(this.delegate);
|
||||
Class<?> targetClass = AopUtils.getTargetClass(this.delegate);
|
||||
if (targetClass != this.delegate.getClass()) {
|
||||
typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class);
|
||||
}
|
||||
|
||||
+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.
|
||||
@@ -74,7 +74,7 @@ public class SourceFilteringListener implements SmartApplicationListener {
|
||||
}
|
||||
|
||||
public boolean supportsSourceType(Class<?> sourceType) {
|
||||
return sourceType.isInstance(this.source);
|
||||
return (sourceType != null && sourceType.isInstance(this.source));
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
|
||||
+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.
|
||||
@@ -59,7 +59,8 @@ public abstract class LocaleContextHolder {
|
||||
/**
|
||||
* Associate the given LocaleContext with the current thread,
|
||||
* <i>not</i> exposing it as inheritable for child threads.
|
||||
* @param localeContext the current LocaleContext
|
||||
* @param localeContext the current LocaleContext,
|
||||
* or {@code null} to reset the thread-bound context
|
||||
*/
|
||||
public static void setLocaleContext(LocaleContext localeContext) {
|
||||
setLocaleContext(localeContext, false);
|
||||
|
||||
+3
-3
@@ -217,7 +217,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
* Create a new AbstractApplicationContext with no parent.
|
||||
*/
|
||||
public AbstractApplicationContext() {
|
||||
this(null);
|
||||
this.resourcePatternResolver = getResourcePatternResolver();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,8 +225,8 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
* @param parent the parent context
|
||||
*/
|
||||
public AbstractApplicationContext(ApplicationContext parent) {
|
||||
this.parent = parent;
|
||||
this.resourcePatternResolver = getResourcePatternResolver();
|
||||
this();
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+5
-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.
|
||||
@@ -45,10 +45,9 @@ public class GenericXmlApplicationContext extends GenericApplicationContext {
|
||||
|
||||
/**
|
||||
* Create a new GenericXmlApplicationContext that needs to be
|
||||
* {@linkplain #load loaded} and then manually {@link #refresh refreshed}.
|
||||
* {@link #load loaded} and then manually {@link #refresh refreshed}.
|
||||
*/
|
||||
public GenericXmlApplicationContext() {
|
||||
reader.setEnvironment(this.getEnvironment());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,14 +90,13 @@ public class GenericXmlApplicationContext extends GenericApplicationContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>Delegates the given environment to underlying {@link XmlBeanDefinitionReader}.
|
||||
* Should be called before any call to {@link #load}.
|
||||
* Delegates the given environment to underlying {@link XmlBeanDefinitionReader}.
|
||||
* Should be called before any call to {@code #load}.
|
||||
*/
|
||||
@Override
|
||||
public void setEnvironment(ConfigurableEnvironment environment) {
|
||||
super.setEnvironment(environment);
|
||||
this.reader.setEnvironment(this.getEnvironment());
|
||||
this.reader.setEnvironment(getEnvironment());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+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.
|
||||
@@ -108,8 +108,8 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS
|
||||
* <p>Processing occurs by replacing ${...} placeholders in bean definitions by resolving each
|
||||
* against this configurer's set of {@link PropertySources}, which includes:
|
||||
* <ul>
|
||||
* <li>all {@linkplain org.springframework.core.env.ConfigurableEnvironment#getPropertySources environment property sources}, if an
|
||||
* {@code Environment} {@linkplain #setEnvironment is present}
|
||||
* <li>all {@linkplain org.springframework.core.env.ConfigurableEnvironment#getPropertySources
|
||||
* environment property sources}, if an {@code Environment} {@linkplain #setEnvironment is present}
|
||||
* <li>{@linkplain #mergeProperties merged local properties}, if {@linkplain #setLocation any}
|
||||
* {@linkplain #setLocations have} {@linkplain #setProperties been}
|
||||
* {@linkplain #setPropertiesArray specified}
|
||||
@@ -135,7 +135,7 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS
|
||||
}
|
||||
try {
|
||||
PropertySource<?> localPropertySource =
|
||||
new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, this.mergeProperties());
|
||||
new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties());
|
||||
if (this.localOverride) {
|
||||
this.propertySources.addFirst(localPropertySource);
|
||||
}
|
||||
@@ -148,7 +148,7 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS
|
||||
}
|
||||
}
|
||||
|
||||
this.processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
|
||||
processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+30
-22
@@ -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,22 +23,26 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Declares that a field should be formatted as a date time.
|
||||
* Supports formatting by style pattern, ISO date time pattern, or custom format pattern string.
|
||||
* Can be applied to {@code java.util.Date}, {@code java.util.Calendar}, {@code java.long.Long}, or Joda Time fields.
|
||||
* <p>
|
||||
* For style-based formatting, set the {@link #style()} attribute to be the style pattern code.
|
||||
*
|
||||
* <p>Supports formatting by style pattern, ISO date time pattern, or custom format pattern string.
|
||||
* Can be applied to {@code java.util.Date}, {@code java.util.Calendar}, {@code java.long.Long},
|
||||
* Joda-Time value types; and as of Spring 4 and JDK 8, to JSR-310 <code>java.time</code> types too.
|
||||
*
|
||||
* <p>For style-based formatting, set the {@link #style()} attribute to be the style pattern code.
|
||||
* The first character of the code is the date style, and the second character is the time style.
|
||||
* Specify a character of 'S' for short style, 'M' for medium, 'L' for long, and 'F' for full.
|
||||
* A date or time may be omitted by specifying the style character '-'.
|
||||
* <p>
|
||||
* For ISO-based formatting, set the {@link #iso()} attribute to be the desired {@link ISO} format, such as {@link ISO#DATE}.
|
||||
<p>
|
||||
* For custom formatting, set the {@link #pattern()} attribute to be the DateTime pattern, such as {@code yyyy/MM/dd hh:mm:ss a}.
|
||||
* <p>
|
||||
* Each attribute is mutually exclusive, so only set one attribute per annotation instance (the one most convenient one for your formatting needs).
|
||||
*
|
||||
* <p>For ISO-based formatting, set the {@link #iso()} attribute to be the desired {@link ISO} format,
|
||||
* such as {@link ISO#DATE}. For custom formatting, set the {@link #pattern()} attribute to be the
|
||||
* DateTime pattern, such as {@code yyyy/MM/dd hh:mm:ss a}.
|
||||
*
|
||||
* <p>Each attribute is mutually exclusive, so only set one attribute per annotation instance
|
||||
* (the one most convenient one for your formatting needs).
|
||||
* When the pattern attribute is specified, it takes precedence over both the style and ISO attribute.
|
||||
* When the iso attribute is specified, if takes precedence over the style attribute.
|
||||
* When no annotation attributes are specified, the default format applied is style-based with a style code of 'SS' (short date, short time).
|
||||
* When no annotation attributes are specified, the default format applied is style-based
|
||||
* with a style code of 'SS' (short date, short time).
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
@@ -51,23 +55,24 @@ public @interface DateTimeFormat {
|
||||
|
||||
/**
|
||||
* The style pattern to use to format the field.
|
||||
* Defaults to 'SS' for short date time.
|
||||
* Set this attribute when you wish to format your field in accordance with a common style other than the default style.
|
||||
* <p>Defaults to 'SS' for short date time. Set this attribute when you wish to format
|
||||
* your field in accordance with a common style other than the default style.
|
||||
*/
|
||||
String style() default "SS";
|
||||
|
||||
/**
|
||||
* The ISO pattern to use to format the field.
|
||||
* The possible ISO patterns are defined in the {@link ISO} enum.
|
||||
* Defaults to ISO.NONE, indicating this attribute should be ignored.
|
||||
* Set this attribute when you wish to format your field in accordance with an ISO date time format.
|
||||
* <p>Defaults to {@link ISO#NONE}, indicating this attribute should be ignored.
|
||||
* Set this attribute when you wish to format your field in accordance with an ISO format.
|
||||
*/
|
||||
ISO iso() default ISO.NONE;
|
||||
|
||||
/**
|
||||
* The custom pattern to use to format the field.
|
||||
* Defaults to empty String, indicating no custom pattern String has been specified.
|
||||
* Set this attribute when you wish to format your field in accordance with a custom date time pattern not represented by a style or ISO format.
|
||||
* <p>Defaults to empty String, indicating no custom pattern String has been specified.
|
||||
* Set this attribute when you wish to format your field in accordance with a custom
|
||||
* date time pattern not represented by a style or ISO format.
|
||||
*/
|
||||
String pattern() default "";
|
||||
|
||||
@@ -78,18 +83,21 @@ public @interface DateTimeFormat {
|
||||
public enum ISO {
|
||||
|
||||
/**
|
||||
* The most common ISO Date Format {@code yyyy-MM-dd} e.g. 2000-10-31.
|
||||
* The most common ISO Date Format {@code yyyy-MM-dd},
|
||||
* e.g. 2000-10-31.
|
||||
*/
|
||||
DATE,
|
||||
|
||||
/**
|
||||
* The most common ISO Time Format {@code HH:mm:ss.SSSZ} e.g. 01:30:00.000-05:00.
|
||||
* The most common ISO Time Format {@code HH:mm:ss.SSSZ},
|
||||
* e.g. 01:30:00.000-05:00.
|
||||
*/
|
||||
TIME,
|
||||
|
||||
/**
|
||||
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSZ} e.g. 2000-10-31 01:30:00.000-05:00.
|
||||
* The default if no annotation value is specified.
|
||||
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSZ},
|
||||
* e.g. 2000-10-31 01:30:00.000-05:00.
|
||||
* <p>This is the default if no annotation value is specified.
|
||||
*/
|
||||
DATE_TIME,
|
||||
|
||||
|
||||
+27
-23
@@ -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,7 +29,6 @@ import java.util.TimeZone;
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -45,8 +44,9 @@ import org.springframework.util.StringUtils;
|
||||
public class DateFormatter implements Formatter<Date> {
|
||||
|
||||
private static final Map<ISO, String> ISO_PATTERNS;
|
||||
|
||||
static {
|
||||
Map<ISO, String> formats = new HashMap<DateTimeFormat.ISO, String>();
|
||||
Map<ISO, String> formats = new HashMap<DateTimeFormat.ISO, String>(4);
|
||||
formats.put(ISO.DATE, "yyyy-MM-dd");
|
||||
formats.put(ISO.TIME, "HH:mm:ss.SSSZ");
|
||||
formats.put(ISO.DATE_TIME, "yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
||||
@@ -89,6 +89,15 @@ public class DateFormatter implements Formatter<Date> {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ISO format used for this date.
|
||||
* @param iso the {@link ISO} format
|
||||
* @since 3.2
|
||||
*/
|
||||
public void setIso(ISO iso) {
|
||||
this.iso = iso;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the style to use to format date values.
|
||||
* <p>If not specified, DateFormat's default style will be used.
|
||||
@@ -112,7 +121,7 @@ public class DateFormatter implements Formatter<Date> {
|
||||
* <li>'F' = Full</li>
|
||||
* <li>'-' = Omitted</li>
|
||||
* <ul>
|
||||
* This method mimics the styles supported by Joda Time.
|
||||
* This method mimics the styles supported by Joda-Time.
|
||||
* @param stylePattern two characters from the set {"S", "M", "L", "F", "-"}
|
||||
* @since 3.2
|
||||
*/
|
||||
@@ -120,14 +129,6 @@ public class DateFormatter implements Formatter<Date> {
|
||||
this.stylePattern = stylePattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ISO format used for this date.
|
||||
* @param iso the {@link ISO} format
|
||||
* @since 3.2
|
||||
*/
|
||||
public void setIso(ISO iso) {
|
||||
this.iso = iso;
|
||||
}
|
||||
/**
|
||||
* Set the TimeZone to normalize the date values into, if any.
|
||||
*/
|
||||
@@ -167,34 +168,36 @@ public class DateFormatter implements Formatter<Date> {
|
||||
if (StringUtils.hasLength(this.pattern)) {
|
||||
return new SimpleDateFormat(this.pattern, locale);
|
||||
}
|
||||
if (iso != null && iso != ISO.NONE) {
|
||||
String pattern = ISO_PATTERNS.get(iso);
|
||||
Assert.state(pattern != null, "Unsupported ISO format " + iso);
|
||||
if (this.iso != null && this.iso != ISO.NONE) {
|
||||
String pattern = ISO_PATTERNS.get(this.iso);
|
||||
if (pattern == null) {
|
||||
throw new IllegalStateException("Unsupported ISO format " + this.iso);
|
||||
}
|
||||
SimpleDateFormat format = new SimpleDateFormat(pattern);
|
||||
format.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
return format;
|
||||
}
|
||||
if(StringUtils.hasLength(stylePattern)) {
|
||||
if (StringUtils.hasLength(this.stylePattern)) {
|
||||
int dateStyle = getStylePatternForChar(0);
|
||||
int timeStyle = getStylePatternForChar(1);
|
||||
if(dateStyle != -1 && timeStyle != -1) {
|
||||
if (dateStyle != -1 && timeStyle != -1) {
|
||||
return DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
|
||||
}
|
||||
if(dateStyle != -1) {
|
||||
if (dateStyle != -1) {
|
||||
return DateFormat.getDateInstance(dateStyle, locale);
|
||||
}
|
||||
if(timeStyle != -1) {
|
||||
if (timeStyle != -1) {
|
||||
return DateFormat.getTimeInstance(timeStyle, locale);
|
||||
}
|
||||
throw new IllegalStateException("Unsupported style pattern '"+ stylePattern+ "'");
|
||||
throw new IllegalStateException("Unsupported style pattern '"+ this.stylePattern+ "'");
|
||||
|
||||
}
|
||||
return DateFormat.getDateInstance(this.style, locale);
|
||||
}
|
||||
|
||||
private int getStylePatternForChar(int index) {
|
||||
if(stylePattern != null && stylePattern.length() > index) {
|
||||
switch (stylePattern.charAt(index)) {
|
||||
if (this.stylePattern != null && this.stylePattern.length() > index) {
|
||||
switch (this.stylePattern.charAt(index)) {
|
||||
case 'S': return DateFormat.SHORT;
|
||||
case 'M': return DateFormat.MEDIUM;
|
||||
case 'L': return DateFormat.LONG;
|
||||
@@ -202,6 +205,7 @@ public class DateFormatter implements Formatter<Date> {
|
||||
case '-': return -1;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Unsupported style pattern '"+ stylePattern+ "'");
|
||||
throw new IllegalStateException("Unsupported style pattern '" + this.stylePattern + "'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-14
@@ -27,8 +27,8 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Configures Date formatting for use with Spring.
|
||||
* <p>
|
||||
* Designed for direct instantiation but also exposes the static
|
||||
*
|
||||
* <p>Designed for direct instantiation but also exposes the static
|
||||
* {@link #addDateConverters(ConverterRegistry)} utility method for ad hoc use
|
||||
* against any {@code ConverterRegistry} instance.
|
||||
*
|
||||
@@ -39,10 +39,20 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
|
||||
private DateFormatter dateFormatter;
|
||||
|
||||
|
||||
/**
|
||||
* Set the date formatter to register. If not specified no formatter is registered.
|
||||
* This method can be used if global formatter configuration is required.
|
||||
* @param dateFormatter the date formatter
|
||||
*/
|
||||
public void setFormatter(DateFormatter dateFormatter) {
|
||||
Assert.notNull(dateFormatter, "DateFormatter must not be null");
|
||||
this.dateFormatter = dateFormatter;
|
||||
}
|
||||
|
||||
|
||||
public void registerFormatters(FormatterRegistry registry) {
|
||||
addDateConverters(registry);
|
||||
registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory());
|
||||
@@ -55,16 +65,6 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the date formatter to register. If not specified no formatter is registered.
|
||||
* This method can be used if global formatter configuration is required.
|
||||
* @param dateFormatter the date formatter
|
||||
*/
|
||||
public void setFormatter(DateFormatter dateFormatter) {
|
||||
Assert.notNull(dateFormatter, "DateFormatter must not be null");
|
||||
this.dateFormatter = dateFormatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add date converters to the specified registry.
|
||||
* @param converterRegistry the registry of converters to add to
|
||||
@@ -80,6 +80,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
|
||||
private static class DateToLongConverter implements Converter<Date, Long> {
|
||||
|
||||
public Long convert(Date source) {
|
||||
return source.getTime();
|
||||
}
|
||||
@@ -87,6 +88,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
|
||||
private static class DateToCalendarConverter implements Converter<Date, Calendar> {
|
||||
|
||||
public Calendar convert(Date source) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(source);
|
||||
@@ -96,6 +98,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
|
||||
private static class CalendarToDateConverter implements Converter<Calendar, Date> {
|
||||
|
||||
public Date convert(Calendar source) {
|
||||
return source.getTime();
|
||||
}
|
||||
@@ -103,6 +106,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
|
||||
private static class CalendarToLongConverter implements Converter<Calendar, Long> {
|
||||
|
||||
public Long convert(Calendar source) {
|
||||
return source.getTime().getTime();
|
||||
}
|
||||
@@ -110,6 +114,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
|
||||
private static class LongToDateConverter implements Converter<Long, Date> {
|
||||
|
||||
public Date convert(Long source) {
|
||||
return new Date(source);
|
||||
}
|
||||
@@ -118,10 +123,11 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
private static class LongToCalendarConverter implements Converter<Long, Calendar> {
|
||||
|
||||
private DateToCalendarConverter dateToCalendarConverter = new DateToCalendarConverter();
|
||||
private final DateToCalendarConverter dateToCalendarConverter = new DateToCalendarConverter();
|
||||
|
||||
public Calendar convert(Long source) {
|
||||
return this.dateToCalendarConverter.convert(new Date(source));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user