mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
215 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 58587159f0 | |||
| 69b9d00179 | |||
| 8aabc43dad | |||
| 4d3aa59028 | |||
| c6503ebbf7 | |||
| f42f2231a4 | |||
| 0313222bc7 | |||
| f524a5abe4 | |||
| f053ce52ea | |||
| 5e05a84d81 | |||
| c7b2ac7bac | |||
| cbff8b01bb | |||
| dc50001620 | |||
| faaf43677d | |||
| f6fddeb6eb | |||
| c3ba0a2c5b | |||
| 8fed2f0c6c | |||
| b0f7184f3f | |||
| 3ae6c0f401 | |||
| bc43f2e72a | |||
| 759bb33665 | |||
| a139670286 | |||
| 1fe477a273 | |||
| 0e710769c2 | |||
| a5606a6c46 | |||
| 3cb1cb5d2f | |||
| 79820e449b | |||
| 2f5d378d82 | |||
| 228a586efb | |||
| b13c5b2378 | |||
| 779a6b79eb | |||
| 9e2060707a | |||
| 2c1203dc9f | |||
| 6ee0596c3a | |||
| 93d13cfcb1 | |||
| de80cd9b3b | |||
| 470e9c8558 | |||
| dc934064a2 | |||
| 5d5f70473a | |||
| ac85eab372 | |||
| ffaac0ecf3 | |||
| 5aa93674a3 | |||
| 62941b7937 | |||
| 5fac6614b6 | |||
| a169c0e727 | |||
| 94caaedf84 | |||
| be6b54fe8b | |||
| 9ac46a965f | |||
| d8a0f7578d | |||
| 99a3e9cacb | |||
| f93bfa8f84 | |||
| b80dc9d642 | |||
| b31750fafb | |||
| a4a2e80f23 | |||
| e8c06c6d99 | |||
| d8180e1e20 | |||
| 88485dc1a7 | |||
| a25d67770e | |||
| 5c9fc09852 | |||
| e1602f7f83 | |||
| 20228e78c5 | |||
| 623b1fc0d5 | |||
| a2bdc284f9 | |||
| dbd5f67498 | |||
| ab85aa2096 | |||
| 5c3f6a1571 | |||
| b73a43972e | |||
| 9585752693 | |||
| 5c0fdb05bd | |||
| eeb82c409a | |||
| d317b637e0 | |||
| b1bcc5d6eb | |||
| f1ba789494 | |||
| d642cd21bb | |||
| 70155e9ff9 | |||
| 7e2a214f32 | |||
| 4c9c7634d0 | |||
| 69c54a053c | |||
| 4b9aad8f65 | |||
| 5fe436c9a9 | |||
| 082a564b9b | |||
| fb0683c066 | |||
| 09c57203bb | |||
| 4886bf0708 | |||
| 75e08695a0 | |||
| 5da79ebca6 | |||
| bb7a1372c0 | |||
| 7e3c722146 | |||
| d7591c6bd7 | |||
| 42dec02203 | |||
| 27ad1990e3 | |||
| 337b5ff5d6 | |||
| b40403cdc9 | |||
| 0972582880 | |||
| bc879100c4 | |||
| 9f77ef4102 | |||
| 7f95a27e6d | |||
| 4ac4630b0b | |||
| 29b40b9d0e | |||
| 85e336e6da | |||
| b223e6efec | |||
| d55a173e2e | |||
| 4d2d223b0c | |||
| c3d74b4521 | |||
| 61ab40cd7a | |||
| 3da9a3193c | |||
| 7e9cb5195a | |||
| 4233d0a99e | |||
| ad91610796 | |||
| f558396e91 | |||
| a2ec8f864e | |||
| 03e243a4ab | |||
| 60b24cffdb | |||
| 036bd791f0 | |||
| a53df0b2c1 | |||
| 1a011616d9 | |||
| 3af9d1f29b | |||
| b3fb81bf72 | |||
| dd5af764b5 | |||
| 3ffbb24211 | |||
| 4c385f0073 | |||
| 7d527f9771 | |||
| 3ba7ab15ab | |||
| 36ab65ace7 | |||
| 35753eb54d | |||
| 1cb9b9cf52 | |||
| fe4b57c199 | |||
| 2a3b29f98e | |||
| d26a570192 | |||
| ac3c670f70 | |||
| 398f91cb74 | |||
| b4115f3202 | |||
| 7e2167fd17 | |||
| 09ad8347be | |||
| 2ef39a5666 | |||
| 1a2033eb41 | |||
| 6162917b4e | |||
| e07ad5a19b | |||
| 5307a87d1a | |||
| 87179b075b | |||
| 23249cda98 | |||
| 341d645d09 | |||
| 9845d9eb21 | |||
| edb660863b | |||
| 866c7847e3 | |||
| fc361844ec | |||
| 52d050d21a | |||
| c1569d7ecd | |||
| fdd31c0e66 | |||
| cfa78a9b25 | |||
| d434ef9713 | |||
| c406c56d57 | |||
| d9ab6aaf6c | |||
| aa1babdfde | |||
| 09c9137b75 | |||
| 603d79ac9b | |||
| fdac4a7d18 | |||
| 11ef4308b8 | |||
| e0f9a85955 | |||
| b229d54172 | |||
| c77832ba6d | |||
| 59893d1f13 | |||
| 9aefa0334f | |||
| f532607d4b | |||
| 16bf501b30 | |||
| fd13c994c9 | |||
| 1f60738431 | |||
| 68b1eb1aba | |||
| 5fb2665d1c | |||
| 52c11eab41 | |||
| b6362c5016 | |||
| 6deb597cdf | |||
| bfecbaf88e | |||
| 3429a4186c | |||
| f18debb5a3 | |||
| 62fd12c527 | |||
| f8f6c5fd89 | |||
| 354917c53d | |||
| 1e0bf493cc | |||
| 0ea4f8ecb7 | |||
| 139adba96a | |||
| 7502ecd35e | |||
| 477e60f28a | |||
| 3db6a7f715 | |||
| 0606c98277 | |||
| dbfe68a6dc | |||
| ab6c6b104d | |||
| c2459b4a61 | |||
| 4f24643fd3 | |||
| 1a0a381559 | |||
| 8c8eead667 | |||
| b35050caf2 | |||
| 72a5737ab9 | |||
| be2d915cc2 | |||
| 6045914057 | |||
| 78646f1f32 | |||
| f88cbda6ef | |||
| c48da0d9a4 | |||
| e3344898cd | |||
| 2e123b01e5 | |||
| 57eedf33d6 | |||
| f477a024ad | |||
| 5dddb492b8 | |||
| ecee20f1fe | |||
| e08f743301 | |||
| a05c957d0e | |||
| a2de329db9 | |||
| 551364f668 | |||
| 08aa22ff1f | |||
| a115a7dad5 | |||
| f457319965 | |||
| 7ad6df8c75 | |||
| f5d5882f46 | |||
| 0a4d28d5d5 | |||
| 9002742873 |
@@ -0,0 +1,14 @@
|
||||
Juergen Hoeller <jhoeller@vmware.com> jhoeller <jhoeller@vmware.com>
|
||||
<rstoyanchev@gopivotal.com> <rstoyanchev@vmware.com>
|
||||
<pwebb@gopivotal.com> <pwebb@vmware.com>
|
||||
<cbeams@gopivotal.com> <cbeams@vmware.com>
|
||||
<cbeams@gopivotal.com> <cbeams@gmail.com>
|
||||
<apoutsma@gopivotal.com> <apoutsma@vmware.com>
|
||||
<apoutsma@gopivotal.com> <poutsma@mac.com>
|
||||
<ogierke@gopivotal.com> <ogierke@vmware.com>
|
||||
<dsyer@gopivotal.com> <david_syer@hotmail.com>
|
||||
<dsyer@gopivotal.com> <dsyer@vmware.com>
|
||||
<aclement@gopivotal.com> <andrew.clement@gmail.com>
|
||||
<aclement@gopivotal.com> <aclement@vmware.com>
|
||||
<dmitry.katsubo@gmail.com> <dmitry.katsubo@gmai.com>
|
||||
Nick Williams <nicholas@nicholaswilliams.net> Nicholas Williams <nicholas@nicholaswilliams.net>
|
||||
+196
-184
@@ -3,8 +3,8 @@ buildscript {
|
||||
maven { url "http://repo.springsource.org/plugins-release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.4")
|
||||
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.7")
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.6")
|
||||
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.8")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,15 +12,10 @@ 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.aspectjVersion = "1.7.4"
|
||||
ext.hsqldbVersion = "1.8.0.10"
|
||||
ext.junitVersion = "4.11"
|
||||
ext.slf4jVersion = "1.6.1"
|
||||
ext.slf4jVersion = "1.6.6"
|
||||
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"
|
||||
|
||||
apply plugin: "propdeps"
|
||||
@@ -64,12 +59,16 @@ configure(allprojects) { project ->
|
||||
systemProperty("java.awt.headless", "true")
|
||||
systemProperty("testGroups", project.properties.get("testGroups"))
|
||||
scanForTestClasses = false
|
||||
include '**/*Tests.*'
|
||||
exclude '**/*Abstract*.*'
|
||||
// Do not include "**/*Test.class" since some *Test classes are broken.
|
||||
include(["**/*Tests.class"])
|
||||
// Since we set scanForTestClasses to false, we need to filter out inner
|
||||
// classes with the "$" pattern; otherwise, using -Dtest.single=MyTests to
|
||||
// run MyTests by itself will fail if MyTests contains any inner classes.
|
||||
exclude(["**/Abstract*.class", '**/*$*'])
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url "http://repo.springsource.org/libs-release" }
|
||||
maven { url "http://repo.spring.io/libs-release" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -79,7 +78,7 @@ configure(allprojects) { project ->
|
||||
}
|
||||
|
||||
ext.javadocLinks = [
|
||||
"http://docs.oracle.com/javase/6/docs/api/",
|
||||
"http://docs.oracle.com/javase/7/docs/api/",
|
||||
"http://docs.oracle.com/javaee/6/api/",
|
||||
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
|
||||
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
|
||||
@@ -90,15 +89,17 @@ configure(allprojects) { project ->
|
||||
"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/tiles-request/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/",
|
||||
"http://quartz-scheduler.org/api/2.2.0/",
|
||||
"http://jackson.codehaus.org/1.9.4/javadoc/",
|
||||
"http://fasterxml.github.com/jackson-core/javadoc/2.3.0/",
|
||||
"http://fasterxml.github.com/jackson-databind/javadoc/2.3.0/",
|
||||
"http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs",
|
||||
"http://ibatis.apache.org/docs/java/dev/"
|
||||
] as String[]
|
||||
}
|
||||
|
||||
@@ -127,7 +128,7 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
|
||||
options.author = true
|
||||
options.header = project.name
|
||||
options.links(project.ext.javadocLinks)
|
||||
if(JavaVersion.current().isJava8Compatible()) {
|
||||
if (JavaVersion.current().isJava8Compatible()) {
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
}
|
||||
|
||||
@@ -169,14 +170,14 @@ project("spring-build-src") {
|
||||
project("spring-core") {
|
||||
description = "Spring Core"
|
||||
|
||||
// As of Spring 3.2 spring-core repackages both asm 4.0 and cglib 3.0 and inlines both
|
||||
// into the spring-core jar. cglib 3.0 itself depends on asm 4.0, and is therefore
|
||||
// As of Spring 3.2.9, spring-core repackages asm 5.0 and cglib 3.1, inlining both
|
||||
// into the spring-core jar. cglib 3.1 itself depends on asm 4+, and is therefore
|
||||
// further transformed by the JarJar task to depend on org.springframework.asm; this
|
||||
// avoids including two different copies of asm unnecessarily. If however future cglib
|
||||
// versions drift from the version of asm used by Spring internally, this duplication
|
||||
// will become necessary.
|
||||
def asmVersion = "4.0"
|
||||
def cglibVersion = "3.0"
|
||||
def asmVersion = "5.0.2"
|
||||
def cglibVersion = "3.1"
|
||||
|
||||
configurations {
|
||||
jarjar
|
||||
@@ -233,9 +234,9 @@ project("spring-core") {
|
||||
|
||||
compile(files(cglibRepackJar))
|
||||
compile(files(asmRepackJar))
|
||||
compile("commons-logging:commons-logging:1.1.1")
|
||||
compile("commons-logging:commons-logging:1.1.3")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("net.sf.jopt-simple:jopt-simple:3.0")
|
||||
optional("net.sf.jopt-simple:jopt-simple:3.3")
|
||||
optional("log4j:log4j:1.2.17")
|
||||
testCompile("xmlunit:xmlunit:1.3")
|
||||
testCompile("org.codehaus.woodstox:wstx-asl:3.2.7") {
|
||||
@@ -262,8 +263,8 @@ project("spring-beans") {
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
provided("javax.el:el-api:1.0")
|
||||
provided("javax.inject:javax.inject:1")
|
||||
optional("javax.el:el-api:1.0")
|
||||
optional("javax.inject:javax.inject:1")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
}
|
||||
}
|
||||
@@ -272,13 +273,13 @@ project("spring-aop") {
|
||||
description = "Spring AOP"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
compile(project(":spring-beans"))
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
optional("com.jamonapi:jamon:2.4")
|
||||
optional("commons-pool:commons-pool:1.5.3")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("commons-pool:commons-pool:1.5.7")
|
||||
optional("com.jamonapi:jamon:2.4")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,28 +315,27 @@ project("spring-context") {
|
||||
description = "Spring Context"
|
||||
|
||||
dependencies {
|
||||
optional(project(":spring-instrument"))
|
||||
compile(project(":spring-aop"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-expression"))
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
optional("backport-util-concurrent:backport-util-concurrent:3.0")
|
||||
optional("javax.ejb:ejb-api:3.0")
|
||||
optional(project(":spring-instrument"))
|
||||
optional("javax.inject:javax.inject:1")
|
||||
optional("javax.ejb:ejb-api:3.0")
|
||||
optional("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
|
||||
optional("backport-util-concurrent:backport-util-concurrent:3.0")
|
||||
optional("javax.persistence:persistence-api:1.0")
|
||||
optional("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.hibernate:hibernate-validator:4.3.1.Final")
|
||||
optional("joda-time:joda-time:2.2")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.2.2")
|
||||
optional("org.codehaus.groovy:groovy-all:1.8.9")
|
||||
optional("org.beanshell:bsh:2.0b4")
|
||||
optional("org.jruby:jruby:1.7.12")
|
||||
testCompile("javax.inject:javax.inject-tck:1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.3")
|
||||
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
}
|
||||
|
||||
// pick up RmiInvocationWrapperRTD.xml in src/main
|
||||
@@ -350,17 +350,17 @@ project("spring-tx") {
|
||||
description = "Spring Transaction"
|
||||
|
||||
dependencies {
|
||||
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
|
||||
optional(project(":spring-aop"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
provided("com.ibm.websphere:uow:6.0.2.17")
|
||||
optional("javax.resource:connector-api:1.5")
|
||||
optional(project(":spring-aop"))
|
||||
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
optional("javax.resource:connector-api:1.5")
|
||||
optional("javax.ejb:ejb-api:3.0")
|
||||
testCompile("javax.persistence:persistence-api:1.0")
|
||||
optional("com.ibm.websphere:uow:6.0.2.17")
|
||||
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile("javax.persistence:persistence-api:1.0")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,14 +378,24 @@ project("spring-oxm") {
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
optional("org.codehaus.castor:castor-xml:1.3.3") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
exclude group: "org.springframework", module: "spring-context"
|
||||
}
|
||||
optional("org.apache.xmlbeans:xmlbeans:2.6.0") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
}
|
||||
optional("com.thoughtworks.xstream:xstream:1.4.7") {
|
||||
exclude group: 'xpp3', module: 'xpp3_min'
|
||||
exclude group: 'xmlpull', module: 'xmlpull'
|
||||
}
|
||||
optional("org.jibx:jibx-run:1.2.5")
|
||||
testCompile(project(":spring-context"))
|
||||
optional("com.thoughtworks.xstream:xstream:1.3.1")
|
||||
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")
|
||||
testCompile("org.codehaus.jettison:jettison:1.0.1")
|
||||
testCompile("xmlunit:xmlunit:1.3")
|
||||
testCompile("xmlpull:xmlpull:1.1.3.4a")
|
||||
testCompile("org.codehaus.jettison:jettison:1.0.1") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
}
|
||||
testCompile(files(genCastor.classesDir).builtBy(genCastor))
|
||||
testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
|
||||
testCompile(files(genXmlbeans.classesDir).builtBy(genXmlbeans))
|
||||
@@ -401,13 +411,13 @@ project("spring-jms") {
|
||||
compile(project(":spring-aop"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-oxm"))
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
provided("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
|
||||
optional(project(":spring-oxm"))
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
optional("javax.resource:connector-api:1.5")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.1")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.7.9")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.6")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,16 +425,16 @@ project("spring-jdbc") {
|
||||
description = "Spring JDBC"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
optional(project(":spring-context")) // for JndiDataSourceLookup
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-context")) // for JndiDataSourceLookup
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
optional("c3p0:c3p0:0.9.1.2")
|
||||
optional("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
optional("com.h2database:h2:1.0.71")
|
||||
optional("com.h2database:h2:1.0.79")
|
||||
optional("org.apache.derby:derby:10.5.3.0_1")
|
||||
optional("org.apache.derby:derbyclient:10.5.3.0_1")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,23 +445,23 @@ project("spring-context-support") {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional(project(":spring-jdbc")) // for Quartz support
|
||||
optional(project(":spring-tx")) // for Quartz support
|
||||
optional("javax.mail:mail:1.4")
|
||||
optional("javax.mail:mail:1.4.7")
|
||||
optional("javax.cache:cache-api:0.5")
|
||||
optional("net.sf.ehcache:ehcache-core:2.0.0")
|
||||
optional("opensymphony:quartz:1.6.2")
|
||||
optional("net.sf.ehcache:ehcache-core:2.0.1")
|
||||
optional("org.quartz-scheduler:quartz:1.7.3")
|
||||
optional("org.codehaus.fabric3.api:commonj:1.1.0")
|
||||
optional("velocity:velocity:1.5")
|
||||
optional("org.freemarker:freemarker:2.3.15")
|
||||
optional("org.freemarker:freemarker:2.3.20")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("jasperreports:jasperreports:2.0.5")
|
||||
optional("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
provided("javax.activation:activation:1.1")
|
||||
testCompile("org.apache.poi:poi:3.0.2-FINAL")
|
||||
optional("net.sf.jasperreports:jasperreports:3.7.6")
|
||||
testCompile("org.apache.poi:poi:3.6")
|
||||
testCompile("commons-beanutils:commons-beanutils:1.8.0") // for Velocity/JasperReports
|
||||
testCompile("commons-digester:commons-digester:1.8.1") // for Velocity/JasperReports
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
}
|
||||
|
||||
// pick up **/*.types files in src/main
|
||||
@@ -460,29 +470,30 @@ project("spring-context-support") {
|
||||
|
||||
project("spring-web") {
|
||||
description = "Spring Web"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans")) // for MultiPartFilter
|
||||
compile(project(":spring-aop")) // for JaxWsPortProxyFactoryBean
|
||||
compile(project(":spring-beans")) // for MultiPartFilter
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional(project(":spring-oxm")) // for MarshallingHttpMessageConverter
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.portlet:portlet-api:2.0")
|
||||
optional("javax.el:el-api:1.0")
|
||||
optional("javax.faces:jsf-api:1.2_08")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.xml:jaxrpc-api:1.1")
|
||||
provided("javax.xml.soap:saaj-api:1.3")
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional("javax.xml.soap:saaj-api:1.3")
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("com.caucho:hessian:3.2.1")
|
||||
optional("rome:rome:1.0")
|
||||
optional("commons-fileupload:commons-fileupload:1.2")
|
||||
optional("commons-fileupload:commons-fileupload:1.3.1")
|
||||
optional("commons-io:commons-io:1.3")
|
||||
optional("commons-httpclient:commons-httpclient:3.1")
|
||||
optional("org.apache.httpcomponents:httpclient:4.2")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.1")
|
||||
optional("org.apache.httpcomponents:httpclient:4.2.6")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.7.9")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.6")
|
||||
optional("rome:rome:1.0")
|
||||
optional("taglibs:standard:1.1.2")
|
||||
optional("org.eclipse.jetty:jetty-servlet:8.1.5.v20120716") {
|
||||
exclude group: "org.eclipse.jetty.orbit", module: "javax.servlet"
|
||||
@@ -503,14 +514,20 @@ project("spring-orm") {
|
||||
description = "Spring Object/Relational Mapping"
|
||||
|
||||
compileTestJava {
|
||||
// necessary to avoid java.lang.VerifyError on toplink compilation
|
||||
// TODO: remove this block when we remove toplink
|
||||
// necessary to avoid java.lang.VerifyError on TopLink compilation
|
||||
sourceCompatibility=1.6
|
||||
targetCompatibility=1.6
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-jdbc"))
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-aop"))
|
||||
optional(project(":spring-context"))
|
||||
optional(project(":spring-web"))
|
||||
optional("aopalliance:aopalliance:1.0")
|
||||
optional("javax.persistence:persistence-api:1.0")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.core:1.0.1")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:1.0.1")
|
||||
@@ -521,20 +538,13 @@ project("spring-orm") {
|
||||
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")
|
||||
provided("javax.servlet:servlet-api:2.5")
|
||||
optional("javax.servlet:servlet-api:2.5")
|
||||
testCompile("javax.servlet:javax.servlet-api:3.0.1")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.2.2")
|
||||
testCompile("org.eclipse.persistence:org.eclipse.persistence.asm:1.0.1")
|
||||
testCompile("org.eclipse.persistence:org.eclipse.persistence.antlr:1.0.1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.3")
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
optional(project(":spring-aop"))
|
||||
optional(project(":spring-context"))
|
||||
compile(project(":spring-tx"))
|
||||
compile(project(":spring-jdbc"))
|
||||
optional(project(":spring-web"))
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,11 +553,11 @@ project("spring-orm-hibernate4") {
|
||||
merge.into = project(":spring-orm")
|
||||
|
||||
dependencies {
|
||||
provided(project(":spring-tx"))
|
||||
provided(project(":spring-jdbc"))
|
||||
optional("org.hibernate:hibernate-core:4.1.9.Final")
|
||||
optional("org.hibernate:hibernate-entitymanager:4.1.9.Final")
|
||||
provided(project(":spring-tx"))
|
||||
optional(project(":spring-web"))
|
||||
optional("org.hibernate:hibernate-core:4.2.12.Final")
|
||||
optional("org.hibernate:hibernate-entitymanager:4.2.12.Final")
|
||||
optional("javax.servlet:servlet-api:2.5")
|
||||
}
|
||||
}
|
||||
@@ -556,34 +566,33 @@ project("spring-webmvc") {
|
||||
description = "Spring Web MVC"
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-expression"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-web"))
|
||||
compile(project(":spring-context"))
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional(project(":spring-context-support")) // for Velocity support
|
||||
optional(project(":spring-oxm")) // for MarshallingView
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("net.sourceforge.jexcelapi:jxl:2.6.12")
|
||||
optional("org.apache.poi:poi:3.6")
|
||||
optional("velocity:velocity:1.5")
|
||||
optional("velocity-tools:velocity-tools-view:1.4")
|
||||
optional("org.freemarker:freemarker:2.3.20")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("net.sf.jasperreports:jasperreports:3.7.6") {
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
}
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.7.9")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.6")
|
||||
optional("rome:rome:1.0")
|
||||
optional("org.apache.tiles:tiles-api:2.1.2")
|
||||
optional("org.apache.tiles:tiles-core:2.1.2")
|
||||
optional("org.apache.tiles:tiles-jsp:2.1.2")
|
||||
optional("org.apache.tiles:tiles-servlet:2.1.2")
|
||||
optional("net.sourceforge.jexcelapi:jxl:2.6.3")
|
||||
optional("org.apache.poi:poi:3.0.2-FINAL")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("jasperreports:jasperreports:2.0.5") {
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
}
|
||||
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")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.servlet.jsp:jsp-api:2.1")
|
||||
testCompile(project(":spring-aop"))
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("rhino:js:1.7R1")
|
||||
testCompile("xmlunit:xmlunit:1.3")
|
||||
testCompile("dom4j:dom4j:1.6.1") {
|
||||
@@ -601,10 +610,11 @@ project("spring-webmvc") {
|
||||
exclude group: "org.eclipse.jetty.orbit", module: "javax.servlet"
|
||||
}
|
||||
testCompile("javax.validation:validation-api:1.0.0.GA")
|
||||
testCompile("commons-fileupload:commons-fileupload:1.2")
|
||||
testCompile("org.hibernate:hibernate-validator:4.3.1.Final")
|
||||
testCompile("org.apache.httpcomponents:httpclient:4.2.6")
|
||||
testCompile("commons-fileupload:commons-fileupload:1.3.1")
|
||||
testCompile("commons-io:commons-io:1.3")
|
||||
testCompile("org.hibernate:hibernate-validator:4.3.0.Final")
|
||||
testCompile("org.apache.httpcomponents:httpclient:4.2")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
|
||||
// pick up DispatcherServlet.properties in src/main
|
||||
@@ -618,27 +628,27 @@ project("spring-webmvc-tiles3") {
|
||||
dependencies {
|
||||
provided(project(":spring-context"))
|
||||
provided(project(":spring-web"))
|
||||
provided("javax.el:el-api:1.0")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
provided("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("org.apache.tiles:tiles-request-api:1.0.1")
|
||||
optional("org.apache.tiles:tiles-api:3.0.1")
|
||||
optional("org.apache.tiles:tiles-core:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-servlet:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-jsp:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-extras:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-el:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("javax.el:el-api:1.0")
|
||||
optional("org.apache.tiles:tiles-api:3.0.4")
|
||||
optional("org.apache.tiles:tiles-core:3.0.4") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-servlet:3.0.4") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-jsp:3.0.4") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-el:3.0.4") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-extras:3.0.4") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
exclude group: "org.springframework", module: "spring-web"
|
||||
}
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
}
|
||||
@@ -647,14 +657,14 @@ project("spring-webmvc-portlet") {
|
||||
description = "Spring Web Portlet"
|
||||
|
||||
dependencies {
|
||||
provided("javax.servlet:servlet-api:2.5")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-web"))
|
||||
compile(project(":spring-webmvc"))
|
||||
optional("commons-fileupload:commons-fileupload:1.2")
|
||||
provided("javax.servlet:servlet-api:2.5")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
optional("commons-fileupload:commons-fileupload:1.3.1")
|
||||
}
|
||||
|
||||
// pick up DispatcherPortlet.properties in src/main
|
||||
@@ -666,6 +676,7 @@ project("spring-test") {
|
||||
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional(project(":spring-beans"))
|
||||
optional(project(":spring-context"))
|
||||
optional(project(":spring-jdbc"))
|
||||
@@ -673,72 +684,73 @@ project("spring-test") {
|
||||
optional(project(":spring-orm"))
|
||||
optional(project(":spring-web"))
|
||||
optional(project(":spring-webmvc"))
|
||||
optional(project(":spring-webmvc-portlet"), )
|
||||
optional(project(":spring-webmvc-portlet"))
|
||||
optional("junit:junit:${junitVersion}")
|
||||
optional("org.testng:testng:6.5.2")
|
||||
optional("org.testng:testng:6.8.8")
|
||||
optional("javax.inject:javax.inject:1")
|
||||
optional("javax.servlet:servlet-api:2.5")
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.servlet:jstl:1.2")
|
||||
optional("javax.portlet:portlet-api:2.0")
|
||||
optional("javax.persistence:persistence-api:1.0")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile("org.hibernate:hibernate-core:3.3.2.GA")
|
||||
provided("javax.inject:javax.inject:1")
|
||||
provided("javax.activation:activation:1.1")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
testCompile "org.slf4j:slf4j-jcl:${slf4jVersion}"
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
testCompile "org.slf4j:slf4j-jcl:${slf4jVersion}"
|
||||
}
|
||||
|
||||
task testNG(type: Test) {
|
||||
useTestNG()
|
||||
// forkEvery 1
|
||||
scanForTestClasses = false
|
||||
include "**/testng/*.*"
|
||||
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
|
||||
getReports().getHtml().setEnabled(true)
|
||||
// show standard out and standard error of the test JVM(s) on the console
|
||||
// testLogging.showStandardStreams = true
|
||||
}
|
||||
|
||||
test {
|
||||
dependsOn testNG
|
||||
useJUnit()
|
||||
exclude "**/testng/*.*"
|
||||
exclude "**/testng/**/*.*"
|
||||
include "**/testng/FailingBeforeAndAfterMethodsTests"
|
||||
// "TestCase" classes are run by other test classes, not the build.
|
||||
exclude(["**/*TestCase.class", "**/*TestSuite.class"])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
project("spring-test-mvc") {
|
||||
description = "Spring Test MVC Framework"
|
||||
merge.into = project(":spring-test")
|
||||
dependencies {
|
||||
optional(project(":spring-context"))
|
||||
provided(project(":spring-webmvc"))
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional(project(":spring-context"))
|
||||
optional("org.hamcrest:hamcrest-core:1.3")
|
||||
optional("com.jayway.jsonpath:json-path:0.8.1")
|
||||
optional("xmlunit:xmlunit:1.3")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("javax.servlet:jstl:1.2")
|
||||
testCompile("org.hibernate:hibernate-validator:4.3.0.Final")
|
||||
testCompile("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
|
||||
testCompile("com.fasterxml.jackson.core:jackson-databind:2.0.1")
|
||||
testCompile(project(":spring-context-support"))
|
||||
testCompile(project(":spring-oxm"))
|
||||
testCompile("com.thoughtworks.xstream:xstream:1.3.1")
|
||||
testCompile("javax.servlet:jstl:1.2")
|
||||
testCompile("javax.mail:mail:1.4.7")
|
||||
testCompile("org.hibernate:hibernate-validator:4.3.1.Final")
|
||||
testCompile("com.thoughtworks.xstream:xstream:1.4.7")
|
||||
testCompile("org.codehaus.jackson:jackson-mapper-asl:1.7.9")
|
||||
testCompile("com.fasterxml.jackson.core:jackson-databind:2.0.6")
|
||||
testCompile("rome:rome:1.0")
|
||||
testCompile("javax.activation:activation:1.1")
|
||||
testCompile("javax.mail:mail:1.4")
|
||||
testCompile("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") {
|
||||
testCompile("org.apache.tiles:tiles-api:3.0.4")
|
||||
testCompile("org.apache.tiles:tiles-core:3.0.4") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
testCompile("org.apache.tiles:tiles-servlet:3.0.1") {
|
||||
testCompile("org.apache.tiles:tiles-servlet:3.0.4") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,21 +775,20 @@ project("spring-aspects") {
|
||||
apply from: "aspects.gradle"
|
||||
|
||||
dependencies {
|
||||
optional(project(":spring-beans")) // for @Configurable support
|
||||
optional(project(":spring-aop")) // for @Async support
|
||||
optional(project(":spring-context")) // for @Enable* support
|
||||
compile(project(":spring-context-support")) // for JavaMail support
|
||||
optional(project(":spring-tx")) // for JPA, @Transactional support
|
||||
optional(project(":spring-orm")) // for JPA exception translation support
|
||||
aspects(project(":spring-orm"))
|
||||
provided("javax.persistence:persistence-api:1.0")
|
||||
testCompile("javax.mail:mail:1.4")
|
||||
ajc("org.aspectj:aspectjtools:${aspectjVersion}")
|
||||
rt("org.aspectj:aspectjrt:${aspectjVersion}")
|
||||
compile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
provided("javax.persistence:persistence-api:1.0")
|
||||
optional(project(":spring-aop")) // for @Async support
|
||||
optional(project(":spring-beans")) // for @Configurable support
|
||||
optional(project(":spring-context")) // for @Enable* support
|
||||
optional(project(":spring-context-support")) // for JavaMail support
|
||||
optional(project(":spring-orm")) // for JPA exception translation support
|
||||
optional(project(":spring-tx")) // for JPA, @Transactional support
|
||||
testCompile(project(":spring-core")) // for CodeStyleAspect
|
||||
compile(project(":spring-beans")) // for "p" namespace visibility
|
||||
testCompile(project(":spring-test"))
|
||||
testCompile("javax.mail:mail:1.4.7")
|
||||
}
|
||||
|
||||
eclipse.project {
|
||||
@@ -827,6 +838,7 @@ configure(rootProject) {
|
||||
|
||||
apply plugin: "docbook-reference"
|
||||
apply plugin: "groovy"
|
||||
|
||||
// apply plugin: "detect-split-packages"
|
||||
apply from: "${gradleScriptDir}/jdiff.gradle"
|
||||
|
||||
@@ -845,23 +857,23 @@ configure(rootProject) {
|
||||
configurations.archives.artifacts.clear()
|
||||
|
||||
dependencies { // for integration tests
|
||||
testCompile(project(":spring-core"))
|
||||
testCompile(project(":spring-beans"))
|
||||
testCompile(project(":spring-aop"))
|
||||
testCompile(project(":spring-expression"))
|
||||
testCompile(project(":spring-beans"))
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile(project(":spring-tx"))
|
||||
testCompile(project(":spring-core"))
|
||||
testCompile(project(":spring-expression"))
|
||||
testCompile(project(":spring-jdbc"))
|
||||
testCompile(project(":spring-orm"))
|
||||
testCompile(project(":spring-test"))
|
||||
testCompile(project(":spring-tx"))
|
||||
testCompile(project(":spring-web"))
|
||||
testCompile(project(":spring-webmvc-portlet"))
|
||||
testCompile(project(":spring-orm"))
|
||||
testCompile("org.hibernate:hibernate-core:4.1.9.Final")
|
||||
testCompile("javax.servlet:servlet-api:2.5")
|
||||
testCompile("javax.portlet:portlet-api:2.0")
|
||||
testCompile("javax.inject:javax.inject:1")
|
||||
testCompile("javax.resource:connector-api:1.5")
|
||||
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile("org.hibernate:hibernate-core:4.2.12.Final")
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
}
|
||||
|
||||
@@ -882,7 +894,7 @@ configure(rootProject) {
|
||||
options.stylesheetFile = file("src/api/stylesheet.css")
|
||||
options.splitIndex = true
|
||||
options.links(project.ext.javadocLinks)
|
||||
if(JavaVersion.current().isJava8Compatible()) {
|
||||
if (JavaVersion.current().isJava8Compatible()) {
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
}
|
||||
|
||||
@@ -895,7 +907,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" },
|
||||
@@ -906,7 +918,7 @@ configure(rootProject) {
|
||||
}
|
||||
}
|
||||
|
||||
task docsZip(type: Zip) {
|
||||
task docsZip(type: Zip, dependsOn: 'reference') {
|
||||
group = "Distribution"
|
||||
baseName = "spring-framework"
|
||||
classifier = "docs"
|
||||
@@ -1032,7 +1044,7 @@ configure(rootProject) {
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
description = "Generates gradlew[.bat] scripts"
|
||||
gradleVersion = "1.6"
|
||||
gradleVersion = "1.12"
|
||||
|
||||
doLast() {
|
||||
def gradleOpts = "-XX:MaxPermSize=1024m -Xmx1024m"
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
version=3.2.6.RELEASE
|
||||
version=3.2.9.RELEASE
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+5
-5
@@ -1,6 +1,6 @@
|
||||
#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
|
||||
#Wed Apr 30 13:06:57 CEST 2014
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-bin.zip
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,9 +19,9 @@ package org.springframework.aop;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* A specialized type of MethodMatcher that takes into account introductions when
|
||||
* matching methods. If there are no introductions on the target class, a method
|
||||
* matcher may be able to optimize matching more effectively for example.
|
||||
* A specialized type of {@link MethodMatcher} that takes into account introductions
|
||||
* when matching methods. If there are no introductions on the target class,
|
||||
* a method matcher may be able to optimize matching more effectively for example.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
@@ -39,6 +39,6 @@ public interface IntroductionAwareMethodMatcher extends MethodMatcher {
|
||||
* asking is the subject on one or more introductions; {@code false} otherwise
|
||||
* @return whether or not this method matches statically
|
||||
*/
|
||||
boolean matches(Method method, Class targetClass, boolean hasIntroductions);
|
||||
boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions);
|
||||
|
||||
}
|
||||
|
||||
+101
-101
@@ -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 org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.aspectj.weaver.BCException;
|
||||
import org.aspectj.weaver.patterns.NamePattern;
|
||||
import org.aspectj.weaver.reflect.ReflectionWorld;
|
||||
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
|
||||
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
||||
import org.aspectj.weaver.tools.ContextBasedMatcher;
|
||||
@@ -42,6 +41,7 @@ import org.aspectj.weaver.tools.PointcutParameter;
|
||||
import org.aspectj.weaver.tools.PointcutParser;
|
||||
import org.aspectj.weaver.tools.PointcutPrimitive;
|
||||
import org.aspectj.weaver.tools.ShadowMatch;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.IntroductionAwareMethodMatcher;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
@@ -55,6 +55,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -98,14 +99,16 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class);
|
||||
|
||||
private Class pointcutDeclarationScope;
|
||||
private Class<?> pointcutDeclarationScope;
|
||||
|
||||
private String[] pointcutParameterNames = new String[0];
|
||||
|
||||
private Class[] pointcutParameterTypes = new Class[0];
|
||||
private Class<?>[] pointcutParameterTypes = new Class<?>[0];
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private transient ClassLoader pointcutClassLoader;
|
||||
|
||||
private transient PointcutExpression pointcutExpression;
|
||||
|
||||
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
@@ -123,7 +126,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
* @param paramNames the parameter names for the pointcut
|
||||
* @param paramTypes the parameter types for the pointcut
|
||||
*/
|
||||
public AspectJExpressionPointcut(Class declarationScope, String[] paramNames, Class[] paramTypes) {
|
||||
public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
|
||||
this.pointcutDeclarationScope = declarationScope;
|
||||
if (paramNames.length != paramTypes.length) {
|
||||
throw new IllegalStateException(
|
||||
@@ -137,21 +140,21 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
/**
|
||||
* Set the declaration scope for the pointcut.
|
||||
*/
|
||||
public void setPointcutDeclarationScope(Class pointcutDeclarationScope) {
|
||||
public void setPointcutDeclarationScope(Class<?> pointcutDeclarationScope) {
|
||||
this.pointcutDeclarationScope = pointcutDeclarationScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameter names for the pointcut.
|
||||
*/
|
||||
public void setParameterNames(String[] names) {
|
||||
public void setParameterNames(String... names) {
|
||||
this.pointcutParameterNames = names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameter types for the pointcut.
|
||||
*/
|
||||
public void setParameterTypes(Class[] types) {
|
||||
public void setParameterTypes(Class<?>... types) {
|
||||
this.pointcutParameterTypes = types;
|
||||
}
|
||||
|
||||
@@ -180,20 +183,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
throw new IllegalStateException("Must set property 'expression' before attempting to match");
|
||||
}
|
||||
if (this.pointcutExpression == null) {
|
||||
this.pointcutExpression = buildPointcutExpression();
|
||||
this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
private PointcutExpression buildPointcutExpression() {
|
||||
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ? ((ConfigurableBeanFactory) this.beanFactory)
|
||||
.getBeanClassLoader() : Thread.currentThread()
|
||||
.getContextClassLoader());
|
||||
return buildPointcutExpression(cl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
@@ -202,8 +198,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
|
||||
for (int i = 0; i < pointcutParameters.length; i++) {
|
||||
pointcutParameters[i] = parser.createPointcutParameter(
|
||||
this.pointcutParameterNames[i],
|
||||
this.pointcutParameterTypes[i]);
|
||||
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
|
||||
}
|
||||
return parser.parsePointcutExpression(
|
||||
replaceBooleanOperators(getExpression()),
|
||||
@@ -244,30 +239,28 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
return this.pointcutExpression;
|
||||
}
|
||||
|
||||
public boolean matches(Class targetClass) {
|
||||
public boolean matches(Class<?> targetClass) {
|
||||
checkReadyToMatch();
|
||||
try {
|
||||
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
|
||||
} catch (ReflectionWorldException e) {
|
||||
logger.debug("PointcutExpression matching rejected target class", e);
|
||||
try {
|
||||
// Actually this is still a "maybe" - treat the pointcut as dynamic if we
|
||||
// don't know enough yet
|
||||
return getFallbackPointcutExpression(targetClass).couldMatchJoinPointsInType(targetClass);
|
||||
} catch (BCException ex) {
|
||||
logger.debug(
|
||||
"Fallback PointcutExpression matching rejected target class",
|
||||
ex);
|
||||
return false;
|
||||
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
|
||||
}
|
||||
catch (ReflectionWorldException ex) {
|
||||
logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
|
||||
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
|
||||
PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
|
||||
if (fallbackExpression != null) {
|
||||
return fallbackExpression.couldMatchJoinPointsInType(targetClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (BCException ex) {
|
||||
logger.debug("PointcutExpression matching rejected target class", ex);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, boolean beanHasIntroductions) {
|
||||
public boolean matches(Method method, Class<?> targetClass, boolean beanHasIntroductions) {
|
||||
checkReadyToMatch();
|
||||
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);
|
||||
@@ -283,11 +276,19 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
else {
|
||||
// the maybe case
|
||||
return (beanHasIntroductions || matchesIgnoringSubtypes(shadowMatch) || matchesTarget(shadowMatch, targetClass));
|
||||
if (beanHasIntroductions) {
|
||||
return true;
|
||||
}
|
||||
// A match test returned maybe - if there are any subtype sensitive variables
|
||||
// involved in the test (this, target, at_this, at_target, at_annotation) then
|
||||
// we say this is not a match as in Spring there will never be a different
|
||||
// runtime subtype.
|
||||
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
|
||||
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return matches(method, targetClass, false);
|
||||
}
|
||||
|
||||
@@ -296,7 +297,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
return this.pointcutExpression.mayNeedDynamicTest();
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, Object[] args) {
|
||||
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
|
||||
checkReadyToMatch();
|
||||
ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
|
||||
ShadowMatch originalShadowMatch = getShadowMatch(method, method);
|
||||
@@ -336,46 +337,37 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (joinPointMatch.matches() && pmi != null) {
|
||||
bindParameters(pmi, joinPointMatch);
|
||||
if (joinPointMatch.matches()) {
|
||||
bindParameters(pmi, joinPointMatch);
|
||||
}
|
||||
}
|
||||
return joinPointMatch.matches();
|
||||
}
|
||||
|
||||
|
||||
protected String getCurrentProxiedBeanName() {
|
||||
return ProxyCreationContext.getCurrentProxiedBeanName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a new pointcut expression based on a target class's loader, rather
|
||||
* than the default.
|
||||
* Get a new pointcut expression based on a target class's loader rather than the default.
|
||||
*/
|
||||
private PointcutExpression getFallbackPointcutExpression(
|
||||
Class<?> targetClass) {
|
||||
ClassLoader classLoader = targetClass.getClassLoader();
|
||||
return classLoader == null ? this.pointcutExpression : buildPointcutExpression(classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* A match test returned maybe - if there are any subtype sensitive variables
|
||||
* involved in the test (this, target, at_this, at_target, at_annotation) then
|
||||
* we say this is not a match as in Spring there will never be a different
|
||||
* runtime subtype.
|
||||
*/
|
||||
private boolean matchesIgnoringSubtypes(ShadowMatch shadowMatch) {
|
||||
return !(getRuntimeTestWalker(shadowMatch).testsSubtypeSensitiveVars());
|
||||
}
|
||||
|
||||
private boolean matchesTarget(ShadowMatch shadowMatch, Class targetClass) {
|
||||
return getRuntimeTestWalker(shadowMatch).testTargetInstanceOfResidue(targetClass);
|
||||
private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
|
||||
try {
|
||||
ClassLoader classLoader = targetClass.getClassLoader();
|
||||
if (classLoader != null && classLoader != this.pointcutClassLoader) {
|
||||
return buildPointcutExpression(classLoader);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Failed to create fallback PointcutExpression", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
|
||||
if (shadowMatch instanceof DefensiveShadowMatch) {
|
||||
return new RuntimeTestWalker(((DefensiveShadowMatch)shadowMatch).primary);
|
||||
return new RuntimeTestWalker(((DefensiveShadowMatch) shadowMatch).primary);
|
||||
}
|
||||
return new RuntimeTestWalker(shadowMatch);
|
||||
}
|
||||
@@ -396,44 +388,51 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
if (shadowMatch == null) {
|
||||
synchronized (this.shadowMatchCache) {
|
||||
// Not found - now check again with full lock...
|
||||
PointcutExpression fallbackExpression = null;
|
||||
Method methodToMatch = targetMethod;
|
||||
PointcutExpression fallbackPointcutExpression = null;
|
||||
shadowMatch = this.shadowMatchCache.get(methodToMatch);
|
||||
shadowMatch = this.shadowMatchCache.get(targetMethod);
|
||||
if (shadowMatch == null) {
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(targetMethod);
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex) {
|
||||
catch (ReflectionWorldException ex) {
|
||||
// Failed to introspect target method, probably because it has been loaded
|
||||
// in a special ClassLoader. Let's try the original method instead...
|
||||
// in a special ClassLoader. Let's try the declaring ClassLoader instead...
|
||||
try {
|
||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
} catch (ReflectionWorld.ReflectionWorldException e) {
|
||||
if (targetMethod == originalMethod) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(originalMethod);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex2) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's simply consider this method as non-matching.
|
||||
methodToMatch = originalMethod;
|
||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
try {
|
||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
} catch (ReflectionWorld.ReflectionWorldException e2) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex2) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
if (shadowMatch == null && targetMethod != originalMethod) {
|
||||
methodToMatch = originalMethod;
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorldException ex3) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's try the original method's declaring class before we give up...
|
||||
try {
|
||||
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
if (fallbackExpression != null) {
|
||||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex4) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shadowMatch.maybeMatches() && fallbackPointcutExpression!=null) {
|
||||
if (shadowMatch == null) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
}
|
||||
else if (shadowMatch.maybeMatches() && fallbackExpression != null) {
|
||||
shadowMatch = new DefensiveShadowMatch(shadowMatch,
|
||||
fallbackPointcutExpression.matchesMethodExecution(methodToMatch));
|
||||
fallbackExpression.matchesMethodExecution(methodToMatch));
|
||||
}
|
||||
this.shadowMatchCache.put(targetMethod, shadowMatch);
|
||||
}
|
||||
@@ -551,7 +550,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
return false;
|
||||
}
|
||||
|
||||
private FuzzyBoolean contextMatch(Class targetType) {
|
||||
private FuzzyBoolean contextMatch(Class<?> targetType) {
|
||||
String advisedBeanName = getCurrentProxiedBeanName();
|
||||
if (advisedBeanName == null) { // no proxy creation in progress
|
||||
// abstain; can't return YES, since that will make pointcut with negation fail
|
||||
@@ -601,9 +600,11 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
this.shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
}
|
||||
|
||||
|
||||
private static class DefensiveShadowMatch implements ShadowMatch {
|
||||
|
||||
private final ShadowMatch primary;
|
||||
|
||||
private final ShadowMatch other;
|
||||
|
||||
public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) {
|
||||
@@ -612,31 +613,30 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
|
||||
public boolean alwaysMatches() {
|
||||
return primary.alwaysMatches();
|
||||
return this.primary.alwaysMatches();
|
||||
}
|
||||
|
||||
public boolean maybeMatches() {
|
||||
return primary.maybeMatches();
|
||||
return this.primary.maybeMatches();
|
||||
}
|
||||
|
||||
public boolean neverMatches() {
|
||||
return primary.neverMatches();
|
||||
return this.primary.neverMatches();
|
||||
}
|
||||
|
||||
public JoinPointMatch matchesJoinPoint(Object thisObject,
|
||||
Object targetObject, Object[] args) {
|
||||
public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
|
||||
try {
|
||||
return primary.matchesJoinPoint(thisObject, targetObject, args);
|
||||
} catch (ReflectionWorldException e) {
|
||||
return other.matchesJoinPoint(thisObject, targetObject, args);
|
||||
return this.primary.matchesJoinPoint(thisObject, targetObject, args);
|
||||
}
|
||||
catch (ReflectionWorldException ex) {
|
||||
return this.other.matchesJoinPoint(thisObject, targetObject, args);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMatchingContext(MatchingContext aMatchContext) {
|
||||
primary.setMatchingContext(aMatchContext);
|
||||
other.setMatchingContext(aMatchContext);
|
||||
this.primary.setMatchingContext(aMatchContext);
|
||||
this.other.setMatchingContext(aMatchContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,8 @@ package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.aspectj.weaver.ReferenceType;
|
||||
import org.aspectj.weaver.ReferenceTypeDelegate;
|
||||
import org.aspectj.weaver.ResolvedType;
|
||||
import org.aspectj.weaver.ast.And;
|
||||
import org.aspectj.weaver.ast.Call;
|
||||
@@ -30,6 +32,7 @@ import org.aspectj.weaver.ast.Not;
|
||||
import org.aspectj.weaver.ast.Or;
|
||||
import org.aspectj.weaver.ast.Test;
|
||||
import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
|
||||
import org.aspectj.weaver.reflect.ReflectionBasedReferenceTypeDelegate;
|
||||
import org.aspectj.weaver.reflect.ReflectionVar;
|
||||
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
||||
import org.aspectj.weaver.tools.ShadowMatch;
|
||||
@@ -55,25 +58,36 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
class RuntimeTestWalker {
|
||||
|
||||
private static final Field residualTestField;
|
||||
|
||||
private static final Field varTypeField;
|
||||
|
||||
private static final Field myClassField;
|
||||
|
||||
|
||||
static {
|
||||
try {
|
||||
residualTestField = ShadowMatchImpl.class.getDeclaredField("residualTest");
|
||||
varTypeField = ReflectionVar.class.getDeclaredField("varType");
|
||||
myClassField = ReflectionBasedReferenceTypeDelegate.class.getDeclaredField("myClass");
|
||||
}
|
||||
catch (NoSuchFieldException ex) {
|
||||
throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " +
|
||||
"on the classpath is incompatible with this version of Spring: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final Test runtimeTest;
|
||||
|
||||
|
||||
public RuntimeTestWalker(ShadowMatch shadowMatch) {
|
||||
ShadowMatchImpl shadowMatchImplementation = (ShadowMatchImpl) shadowMatch;
|
||||
try {
|
||||
Field testField = shadowMatchImplementation.getClass().getDeclaredField("residualTest");
|
||||
ReflectionUtils.makeAccessible(testField);
|
||||
this.runtimeTest = (Test) testField.get(shadowMatch);
|
||||
ReflectionUtils.makeAccessible(residualTestField);
|
||||
this.runtimeTest = (Test) residualTestField.get(shadowMatch);
|
||||
}
|
||||
catch (NoSuchFieldException noSuchFieldEx) {
|
||||
throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " +
|
||||
"on the classpath is incompatible with this version of Spring: Expected field " +
|
||||
"'runtimeTest' is not present on ShadowMatchImpl class.");
|
||||
}
|
||||
catch (IllegalAccessException illegalAccessEx) {
|
||||
// Famous last words... but I don't see how this can happen given the
|
||||
// makeAccessible call above
|
||||
throw new IllegalStateException("Unable to access ShadowMatchImpl.residualTest field");
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,12 +101,12 @@ class RuntimeTestWalker {
|
||||
new SubtypeSensitiveVarTypeTestVisitor().testsSubtypeSensitiveVars(this.runtimeTest));
|
||||
}
|
||||
|
||||
public boolean testThisInstanceOfResidue(Class thisClass) {
|
||||
public boolean testThisInstanceOfResidue(Class<?> thisClass) {
|
||||
return (this.runtimeTest != null &&
|
||||
new ThisInstanceOfResidueTestVisitor(thisClass).thisInstanceOfMatches(this.runtimeTest));
|
||||
}
|
||||
|
||||
public boolean testTargetInstanceOfResidue(Class targetClass) {
|
||||
public boolean testTargetInstanceOfResidue(Class<?> targetClass) {
|
||||
return (this.runtimeTest != null &&
|
||||
new TargetInstanceOfResidueTestVisitor(targetClass).targetInstanceOfMatches(this.runtimeTest));
|
||||
}
|
||||
@@ -140,19 +154,11 @@ class RuntimeTestWalker {
|
||||
|
||||
protected int getVarType(ReflectionVar v) {
|
||||
try {
|
||||
Field varTypeField = ReflectionVar.class.getDeclaredField("varType");
|
||||
ReflectionUtils.makeAccessible(varTypeField);
|
||||
return (Integer) varTypeField.get(v);
|
||||
}
|
||||
catch (NoSuchFieldException noSuchFieldEx) {
|
||||
throw new IllegalStateException("the version of aspectjtools.jar / aspectjweaver.jar " +
|
||||
"on the classpath is incompatible with this version of Spring:- expected field " +
|
||||
"'varType' is not present on ReflectionVar class");
|
||||
}
|
||||
catch (IllegalAccessException illegalAccessEx) {
|
||||
// Famous last words... but I don't see how this can happen given the
|
||||
// makeAccessible call above
|
||||
throw new IllegalStateException("Unable to access ReflectionVar.varType field");
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,11 +166,13 @@ class RuntimeTestWalker {
|
||||
|
||||
private static abstract class InstanceOfResidueTestVisitor extends TestVisitorAdapter {
|
||||
|
||||
private Class matchClass;
|
||||
private boolean matches;
|
||||
private int matchVarType;
|
||||
private final Class<?> matchClass;
|
||||
|
||||
public InstanceOfResidueTestVisitor(Class matchClass, boolean defaultMatches, int matchVarType) {
|
||||
private boolean matches;
|
||||
|
||||
private final int matchVarType;
|
||||
|
||||
public InstanceOfResidueTestVisitor(Class<?> matchClass, boolean defaultMatches, int matchVarType) {
|
||||
this.matchClass = matchClass;
|
||||
this.matches = defaultMatches;
|
||||
this.matchVarType = matchVarType;
|
||||
@@ -172,19 +180,34 @@ class RuntimeTestWalker {
|
||||
|
||||
public boolean instanceOfMatches(Test test) {
|
||||
test.accept(this);
|
||||
return matches;
|
||||
return this.matches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Instanceof i) {
|
||||
ResolvedType type = (ResolvedType) i.getType();
|
||||
int varType = getVarType((ReflectionVar) i.getVar());
|
||||
if (varType != this.matchVarType) {
|
||||
return;
|
||||
}
|
||||
Class<?> typeClass = null;
|
||||
ResolvedType type = (ResolvedType) i.getType();
|
||||
if (type instanceof ReferenceType) {
|
||||
ReferenceTypeDelegate delegate = ((ReferenceType) type).getDelegate();
|
||||
if (delegate instanceof ReflectionBasedReferenceTypeDelegate) {
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(myClassField);
|
||||
typeClass = (Class<?>) myClassField.get(delegate);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
Class typeClass = ClassUtils.forName(type.getName(), this.matchClass.getClassLoader());
|
||||
// Don't use ReflectionType.isAssignableFrom() as it won't be aware of (Spring) mixins
|
||||
// Don't use ResolvedType.isAssignableFrom() as it won't be aware of (Spring) mixins
|
||||
if (typeClass == null) {
|
||||
typeClass = ClassUtils.forName(type.getName(), this.matchClass.getClassLoader());
|
||||
}
|
||||
this.matches = typeClass.isAssignableFrom(this.matchClass);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -199,7 +222,7 @@ class RuntimeTestWalker {
|
||||
*/
|
||||
private static class TargetInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
|
||||
|
||||
public TargetInstanceOfResidueTestVisitor(Class targetClass) {
|
||||
public TargetInstanceOfResidueTestVisitor(Class<?> targetClass) {
|
||||
super(targetClass, false, TARGET_VAR);
|
||||
}
|
||||
|
||||
@@ -214,7 +237,7 @@ class RuntimeTestWalker {
|
||||
*/
|
||||
private static class ThisInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
|
||||
|
||||
public ThisInstanceOfResidueTestVisitor(Class thisClass) {
|
||||
public ThisInstanceOfResidueTestVisitor(Class<?> thisClass) {
|
||||
super(thisClass, true, THIS_VAR);
|
||||
}
|
||||
|
||||
@@ -228,8 +251,11 @@ class RuntimeTestWalker {
|
||||
private static class SubtypeSensitiveVarTypeTestVisitor extends TestVisitorAdapter {
|
||||
|
||||
private final Object thisObj = new Object();
|
||||
|
||||
private final Object targetObj = new Object();
|
||||
|
||||
private final Object[] argsObjs = new Object[0];
|
||||
|
||||
private boolean testsSubtypeSensitiveVars = false;
|
||||
|
||||
public boolean testsSubtypeSensitiveVars(Test aTest) {
|
||||
@@ -240,8 +266,8 @@ class RuntimeTestWalker {
|
||||
@Override
|
||||
public void visit(Instanceof i) {
|
||||
ReflectionVar v = (ReflectionVar) i.getVar();
|
||||
Object varUnderTest = v.getBindingAtJoinPoint(thisObj,targetObj,argsObjs);
|
||||
if ((varUnderTest == thisObj) || (varUnderTest == targetObj)) {
|
||||
Object varUnderTest = v.getBindingAtJoinPoint(this.thisObj, this.targetObj, this.argsObjs);
|
||||
if (varUnderTest == this.thisObj || varUnderTest == this.targetObj) {
|
||||
this.testsSubtypeSensitiveVars = true;
|
||||
}
|
||||
}
|
||||
@@ -251,7 +277,7 @@ class RuntimeTestWalker {
|
||||
// If you thought things were bad before, now we sink to new levels of horror...
|
||||
ReflectionVar v = (ReflectionVar) hasAnn.getVar();
|
||||
int varType = getVarType(v);
|
||||
if ((varType == AT_THIS_VAR) || (varType == AT_TARGET_VAR) || (varType == AT_ANNOTATION_VAR)) {
|
||||
if (varType == AT_THIS_VAR || varType == AT_TARGET_VAR || varType == AT_ANNOTATION_VAR) {
|
||||
this.testsSubtypeSensitiveVars = true;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -67,7 +67,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
}
|
||||
|
||||
public void setAspectJAdvisorFactory(AspectJAdvisorFactory aspectJAdvisorFactory) {
|
||||
Assert.notNull(this.aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null");
|
||||
Assert.notNull(aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null");
|
||||
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isInfrastructureClass(Class beanClass) {
|
||||
protected boolean isInfrastructureClass(Class<?> beanClass) {
|
||||
// Previously we setProxyTargetClass(true) in the constructor, but that has too
|
||||
// broad an impact. Instead we now override isInfrastructureClass to avoid proxying
|
||||
// aspects. I'm not entirely happy with that as there is no good reason not
|
||||
|
||||
+36
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -49,7 +49,7 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
|
||||
*/
|
||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||
|
||||
private final Map<Class, Boolean> eligibleBeans = new ConcurrentHashMap<Class, Boolean>(64);
|
||||
private final Map<Class<?>, Boolean> eligibleBeans = new ConcurrentHashMap<Class<?>, Boolean>(64);
|
||||
|
||||
|
||||
/**
|
||||
@@ -87,9 +87,11 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
|
||||
// Ignore AOP infrastructure such as scoped proxies.
|
||||
return bean;
|
||||
}
|
||||
if (isEligible(bean, beanName)) {
|
||||
if (bean instanceof Advised) {
|
||||
Advised advised = (Advised) bean;
|
||||
|
||||
if (bean instanceof Advised) {
|
||||
Advised advised = (Advised) bean;
|
||||
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
|
||||
// Add our local Advisor to the existing proxy's Advisor chain...
|
||||
if (this.beforeExistingAdvisors) {
|
||||
advised.addAdvisor(0, this.advisor);
|
||||
}
|
||||
@@ -98,32 +100,47 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
else {
|
||||
ProxyFactory proxyFactory = new ProxyFactory(bean);
|
||||
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
|
||||
proxyFactory.copyFrom(this);
|
||||
proxyFactory.addAdvisor(this.advisor);
|
||||
return proxyFactory.getProxy(this.beanClassLoader);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No async proxy needed.
|
||||
return bean;
|
||||
|
||||
if (isEligible(bean, beanName)) {
|
||||
ProxyFactory proxyFactory = new ProxyFactory(bean);
|
||||
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
|
||||
proxyFactory.copyFrom(this);
|
||||
proxyFactory.addAdvisor(this.advisor);
|
||||
return proxyFactory.getProxy(this.beanClassLoader);
|
||||
}
|
||||
|
||||
// No async proxy needed.
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given bean is eligible for advising with this
|
||||
* post-processor's {@link Advisor}.
|
||||
* <p>Implements caching of {@code canApply} results per bean target class.
|
||||
* <p>Delegates to {@link #isEligible(Class)} for target class checking.
|
||||
* Can be overridden e.g. to specifically exclude certain beans by name.
|
||||
* <p>Note: Only called for regular bean instances but not for existing
|
||||
* proxy instances which implement {@link Advised} and allow for adding
|
||||
* the local {@link Advisor} to the existing proxy's {@link Advisor} chain.
|
||||
* For the latter, {@link #isEligible(Class)} is being called directly,
|
||||
* with the actual target class behind the existing proxy (as determined
|
||||
* by {@link AopUtils#getTargetClass(Object)}).
|
||||
* @param bean the bean instance
|
||||
* @param beanName the name of the bean
|
||||
* @see AopUtils#getTargetClass(Object)
|
||||
* @see AopUtils#canApply(Advisor, Class)
|
||||
* @see #isEligible(Class)
|
||||
*/
|
||||
protected boolean isEligible(Object bean, String beanName) {
|
||||
Class<?> targetClass = AopUtils.getTargetClass(bean);
|
||||
return isEligible(bean.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given class is eligible for advising with this
|
||||
* post-processor's {@link Advisor}.
|
||||
* <p>Implements caching of {@code canApply} results per bean target class.
|
||||
* @param targetClass the class to check against
|
||||
* @see AopUtils#canApply(Advisor, Class)
|
||||
*/
|
||||
protected boolean isEligible(Class<?> targetClass) {
|
||||
Boolean eligible = this.eligibleBeans.get(targetClass);
|
||||
if (eligible != null) {
|
||||
return eligible;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,6 +37,7 @@ import org.springframework.aop.RawTargetAccess;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.cglib.core.CodeGenerationException;
|
||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.CallbackFilter;
|
||||
import org.springframework.cglib.proxy.Dispatcher;
|
||||
@@ -181,20 +182,20 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
}
|
||||
}
|
||||
enhancer.setSuperclass(proxySuperClass);
|
||||
enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
|
||||
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
|
||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||
enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
|
||||
enhancer.setInterceptDuringConstruction(false);
|
||||
|
||||
Callback[] callbacks = getCallbacks(rootClass);
|
||||
enhancer.setCallbacks(callbacks);
|
||||
enhancer.setCallbackFilter(new ProxyCallbackFilter(
|
||||
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
|
||||
|
||||
Class<?>[] types = new Class[callbacks.length];
|
||||
Class<?>[] types = new Class<?>[callbacks.length];
|
||||
for (int x = 0; x < types.length; x++) {
|
||||
types[x] = callbacks[x].getClass();
|
||||
}
|
||||
enhancer.setCallbackFilter(new ProxyCallbackFilter(
|
||||
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
|
||||
enhancer.setCallbackTypes(types);
|
||||
enhancer.setCallbacks(callbacks);
|
||||
|
||||
// Generate the proxy class and create a proxy instance.
|
||||
Object proxy;
|
||||
@@ -259,7 +260,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
if (!Object.class.equals(method.getDeclaringClass()) && !Modifier.isStatic(method.getModifiers()) &&
|
||||
Modifier.isFinal(method.getModifiers())) {
|
||||
logger.warn("Unable to proxy method [" + method + "] because it is final: " +
|
||||
"All calls to this method via a proxy will be routed directly to the proxy.");
|
||||
"All calls to this method via a proxy will NOT be routed to the target instance.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,8 +313,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
Callback[] fixedCallbacks = new Callback[methods.length];
|
||||
this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
|
||||
|
||||
// TODO: small memory optimisation here (can skip creation for
|
||||
// methods with no advice)
|
||||
// TODO: small memory optimisation here (can skip creation for methods with no advice)
|
||||
for (int x = 0; x < methods.length; x++) {
|
||||
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
|
||||
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
|
||||
@@ -340,16 +340,15 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
*/
|
||||
private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) {
|
||||
// Massage return value if necessary
|
||||
if (retVal != null && retVal == target &&
|
||||
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this".
|
||||
// Note that we can't help if the target sets a reference
|
||||
// to itself in another returned object.
|
||||
if (retVal != null && retVal == target && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||
// Special case: it returned "this". Note that we can't help
|
||||
// if the target sets a reference to itself in another returned object.
|
||||
retVal = proxy;
|
||||
}
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
|
||||
throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
|
||||
throw new AopInvocationException(
|
||||
"Null return value from advice does not match primitive return type for: " + method);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
@@ -595,7 +594,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
*/
|
||||
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
|
||||
|
||||
private AdvisedSupport advised;
|
||||
private final AdvisedSupport advised;
|
||||
|
||||
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
|
||||
this.advised = advised;
|
||||
@@ -612,8 +611,8 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
oldProxy = AopContext.setCurrentProxy(proxy);
|
||||
setProxyContext = true;
|
||||
}
|
||||
// May be null Get as late as possible to minimize the time we
|
||||
// "own" the target, in case it comes from a pool.
|
||||
// May be null. Get as late as possible to minimize the time we
|
||||
// "own" the target, in case it comes from a pool...
|
||||
target = getTarget();
|
||||
if (target != null) {
|
||||
targetClass = target.getClass();
|
||||
@@ -818,8 +817,8 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
// of the target type. If so we know it never needs to have return type
|
||||
// massage and can use a dispatcher.
|
||||
// If the proxy is being exposed, then must use the interceptor the
|
||||
// correct one is already configured. If the target is not static cannot
|
||||
// use a Dispatcher because the target can not then be released.
|
||||
// correct one is already configured. If the target is not static, then
|
||||
// cannot use a dispatcher because the target cannot be released.
|
||||
if (exposeProxy || !isStatic) {
|
||||
return INVOKE_TARGET;
|
||||
}
|
||||
@@ -851,7 +850,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof ProxyCallbackFilter)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,6 @@ package org.springframework.aop.framework;
|
||||
import org.aopalliance.intercept.Interceptor;
|
||||
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -47,9 +46,8 @@ public class ProxyFactory extends ProxyCreatorSupport {
|
||||
* @param target the target object to be proxied
|
||||
*/
|
||||
public ProxyFactory(Object target) {
|
||||
Assert.notNull(target, "Target object must not be null");
|
||||
setInterfaces(ClassUtils.getAllInterfaces(target));
|
||||
setTarget(target);
|
||||
setInterfaces(ClassUtils.getAllInterfaces(target));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,6 @@ import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
@@ -80,7 +79,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
/**
|
||||
* Set the {@link BeanFactory} to be used when looking up executors by qualifier.
|
||||
*/
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -62,11 +62,11 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
|
||||
|
||||
/**
|
||||
* Create a new {@code AsyncExecutionInterceptor}.
|
||||
* @param executor the {@link Executor} (typically a Spring {@link AsyncTaskExecutor}
|
||||
* or {@link java.util.concurrent.ExecutorService}) to delegate to.
|
||||
* @param defaultExecutor the {@link Executor} (typically a Spring {@link AsyncTaskExecutor}
|
||||
* or {@link java.util.concurrent.ExecutorService}) to delegate to
|
||||
*/
|
||||
public AsyncExecutionInterceptor(Executor executor) {
|
||||
super(executor);
|
||||
public AsyncExecutionInterceptor(Executor defaultExecutor) {
|
||||
super(defaultExecutor);
|
||||
}
|
||||
|
||||
|
||||
@@ -117,8 +117,8 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
|
||||
* Subclasses may override to provide support for extracting qualifier information,
|
||||
* e.g. via an annotation on the given method.
|
||||
* @return always {@code null}
|
||||
* @see #determineAsyncExecutor(Method)
|
||||
* @since 3.1.2
|
||||
* @see #determineAsyncExecutor(Method)
|
||||
*/
|
||||
@Override
|
||||
protected String getExecutorQualifier(Method method) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -90,7 +90,7 @@ public class ScopedProxyFactoryBean extends ProxyConfig implements FactoryBean<O
|
||||
pf.copyFrom(this);
|
||||
pf.setTargetSource(this.scopedTargetSource);
|
||||
|
||||
Class beanType = beanFactory.getType(this.targetBeanName);
|
||||
Class<?> beanType = beanFactory.getType(this.targetBeanName);
|
||||
if (beanType == null) {
|
||||
throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName +
|
||||
"': Target type could not be determined at the time of proxy creation.");
|
||||
@@ -122,10 +122,7 @@ public class ScopedProxyFactoryBean extends ProxyConfig implements FactoryBean<O
|
||||
if (this.proxy != null) {
|
||||
return this.proxy.getClass();
|
||||
}
|
||||
if (this.scopedTargetSource != null) {
|
||||
return this.scopedTargetSource.getTargetClass();
|
||||
}
|
||||
return null;
|
||||
return this.scopedTargetSource.getTargetClass();
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
|
||||
+28
-25
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,17 +29,16 @@ import org.springframework.util.StringUtils;
|
||||
* <ul>
|
||||
* <li>pattern: regular expression for the fully-qualified method names to match.
|
||||
* The exact regexp syntax will depend on the subclass (e.g. Perl5 regular expressions)
|
||||
* <li>patterns: alternative property taking a String array of patterns. The result will
|
||||
* be the union of these patterns.
|
||||
* <li>patterns: alternative property taking a String array of patterns.
|
||||
* The result will be the union of these patterns.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note: the regular expressions must be a match. For example,
|
||||
* {@code .*get.*} will match com.mycom.Foo.getBar().
|
||||
* {@code get.*} will not.
|
||||
*
|
||||
* <p>This base class is serializable. Subclasses should declare all fields transient
|
||||
* - the initPatternRepresentation method in this class will be invoked again on the
|
||||
* client side on deserialization.
|
||||
* <p>This base class is serializable. Subclasses should declare all fields transient;
|
||||
* the {@link #initPatternRepresentation} method will be invoked again on deserialization.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -51,10 +50,14 @@ import org.springframework.util.StringUtils;
|
||||
public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPointcut
|
||||
implements Serializable {
|
||||
|
||||
/** Regular expressions to match */
|
||||
/**
|
||||
* Regular expressions to match.
|
||||
*/
|
||||
private String[] patterns = new String[0];
|
||||
|
||||
/** Regular expressions <strong>not</strong> to match */
|
||||
/**
|
||||
* Regular expressions <strong>not</strong> to match.
|
||||
*/
|
||||
private String[] excludedPatterns = new String[0];
|
||||
|
||||
|
||||
@@ -64,15 +67,15 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
* @see #setPatterns
|
||||
*/
|
||||
public void setPattern(String pattern) {
|
||||
setPatterns(new String[] {pattern});
|
||||
setPatterns(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the regular expressions defining methods to match.
|
||||
* Matching will be the union of all these; if any match,
|
||||
* the pointcut matches.
|
||||
* Matching will be the union of all these; if any match, the pointcut matches.
|
||||
* @see #setPattern
|
||||
*/
|
||||
public void setPatterns(String[] patterns) {
|
||||
public void setPatterns(String... patterns) {
|
||||
Assert.notEmpty(patterns, "'patterns' must not be empty");
|
||||
this.patterns = new String[patterns.length];
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
@@ -94,15 +97,15 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
* @see #setExcludedPatterns
|
||||
*/
|
||||
public void setExcludedPattern(String excludedPattern) {
|
||||
setExcludedPatterns(new String[] {excludedPattern});
|
||||
setExcludedPatterns(excludedPattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the regular expressions defining methods to match for exclusion.
|
||||
* Matching will be the union of all these; if any match,
|
||||
* the pointcut matches.
|
||||
* Matching will be the union of all these; if any match, the pointcut matches.
|
||||
* @see #setExcludedPattern
|
||||
*/
|
||||
public void setExcludedPatterns(String[] excludedPatterns) {
|
||||
public void setExcludedPatterns(String... excludedPatterns) {
|
||||
Assert.notEmpty(excludedPatterns, "'excludedPatterns' must not be empty");
|
||||
this.excludedPatterns = new String[excludedPatterns.length];
|
||||
for (int i = 0; i < excludedPatterns.length; i++) {
|
||||
@@ -124,7 +127,7 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
* of the target class as well as against the method's declaring class,
|
||||
* plus the name of the method.
|
||||
*/
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return ((targetClass != null && matchesPattern(targetClass.getName() + "." + method.getName())) ||
|
||||
matchesPattern(method.getDeclaringClass().getName() + "." + method.getName()));
|
||||
}
|
||||
@@ -172,18 +175,18 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
|
||||
protected abstract void initExcludedPatternRepresentation(String[] patterns) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Does the pattern at the given index match this string?
|
||||
* @param pattern {@code String} pattern to match
|
||||
* @param patternIndex index of pattern from 0
|
||||
* @return {@code true} if there is a match, else {@code false}.
|
||||
* Does the pattern at the given index match the given String?
|
||||
* @param pattern the {@code String} pattern to match
|
||||
* @param patternIndex index of pattern (starting from 0)
|
||||
* @return {@code true} if there is a match, {@code false} otherwise
|
||||
*/
|
||||
protected abstract boolean matches(String pattern, int patternIndex);
|
||||
|
||||
/**
|
||||
* Does the exclusion pattern at the given index match this string?
|
||||
* @param pattern {@code String} pattern to match.
|
||||
* @param patternIndex index of pattern starting from 0.
|
||||
* @return {@code true} if there is a match, else {@code false}.
|
||||
* Does the exclusion pattern at the given index match the given String?
|
||||
* @param pattern the {@code String} pattern to match
|
||||
* @param patternIndex index of pattern (starting from 0)
|
||||
* @return {@code true} if there is a match, {@code false} otherwise
|
||||
*/
|
||||
protected abstract boolean matchesExclusion(String pattern, int patternIndex);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,8 +23,7 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Static utility methods for composing
|
||||
* {@link org.springframework.aop.ClassFilter ClassFilters}.
|
||||
* Static utility methods for composing {@link ClassFilter ClassFilters}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
@@ -96,9 +95,9 @@ public abstract class ClassFilters {
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
public boolean matches(Class clazz) {
|
||||
for (int i = 0; i < this.filters.length; i++) {
|
||||
if (this.filters[i].matches(clazz)) {
|
||||
public boolean matches(Class<?> clazz) {
|
||||
for (ClassFilter filter : this.filters) {
|
||||
if (filter.matches(clazz)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -130,9 +129,9 @@ public abstract class ClassFilters {
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
public boolean matches(Class clazz) {
|
||||
for (int i = 0; i < this.filters.length; i++) {
|
||||
if (!this.filters[i].matches(clazz)) {
|
||||
public boolean matches(Class<?> clazz) {
|
||||
for (ClassFilter filter : this.filters) {
|
||||
if (!filter.matches(clazz)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -178,7 +178,6 @@ public class ComposablePointcut implements Pointcut, Serializable {
|
||||
return this.methodMatcher;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
@@ -187,7 +186,6 @@ public class ComposablePointcut implements Pointcut, Serializable {
|
||||
if (!(other instanceof ComposablePointcut)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ComposablePointcut that = (ComposablePointcut) other;
|
||||
return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) &&
|
||||
ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher);
|
||||
@@ -207,8 +205,7 @@ public class ComposablePointcut implements Pointcut, Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ComposablePointcut: ClassFilter [" + this.classFilter +
|
||||
"], MethodMatcher [" + this.methodMatcher + "]";
|
||||
return "ComposablePointcut: " + this.classFilter + ", " +this.methodMatcher;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,12 +25,11 @@ import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Static utility methods for composing
|
||||
* {@link org.springframework.aop.MethodMatcher MethodMatchers}.
|
||||
* Static utility methods for composing {@link MethodMatcher MethodMatchers}.
|
||||
*
|
||||
* <p>A MethodMatcher may be evaluated statically (based on method
|
||||
* and target class) or need further evaluation dynamically
|
||||
* (based on arguments at the time of method invocation).
|
||||
* <p>A MethodMatcher may be evaluated statically (based on method and target
|
||||
* class) or need further evaluation dynamically (based on arguments at the
|
||||
* time of method invocation).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
@@ -88,7 +87,7 @@ public abstract class MethodMatchers {
|
||||
* asking is the subject on one or more introductions; {@code false} otherwise
|
||||
* @return whether or not this method matches statically
|
||||
*/
|
||||
public static boolean matches(MethodMatcher mm, Method method, Class targetClass, boolean hasIntroductions) {
|
||||
public static boolean matches(MethodMatcher mm, Method method, Class<?> targetClass, boolean hasIntroductions) {
|
||||
Assert.notNull(mm, "MethodMatcher must not be null");
|
||||
return ((mm instanceof IntroductionAwareMethodMatcher &&
|
||||
((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions)) ||
|
||||
@@ -113,21 +112,21 @@ public abstract class MethodMatchers {
|
||||
this.mm2 = mm2;
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, boolean hasIntroductions) {
|
||||
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
|
||||
return (matchesClass1(targetClass) && MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions)) ||
|
||||
(matchesClass2(targetClass) && MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions));
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return (matchesClass1(targetClass) && this.mm1.matches(method, targetClass)) ||
|
||||
(matchesClass2(targetClass) && this.mm2.matches(method, targetClass));
|
||||
}
|
||||
|
||||
protected boolean matchesClass1(Class targetClass) {
|
||||
protected boolean matchesClass1(Class<?> targetClass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean matchesClass2(Class targetClass) {
|
||||
protected boolean matchesClass2(Class<?> targetClass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -135,7 +134,7 @@ public abstract class MethodMatchers {
|
||||
return this.mm1.isRuntime() || this.mm2.isRuntime();
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, Object[] args) {
|
||||
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
|
||||
return this.mm1.matches(method, targetClass, args) || this.mm2.matches(method, targetClass, args);
|
||||
}
|
||||
|
||||
@@ -179,12 +178,12 @@ public abstract class MethodMatchers {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matchesClass1(Class targetClass) {
|
||||
protected boolean matchesClass1(Class<?> targetClass) {
|
||||
return this.cf1.matches(targetClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matchesClass2(Class targetClass) {
|
||||
protected boolean matchesClass2(Class<?> targetClass) {
|
||||
return this.cf2.matches(targetClass);
|
||||
}
|
||||
|
||||
@@ -225,12 +224,12 @@ public abstract class MethodMatchers {
|
||||
this.mm2 = mm2;
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, boolean hasIntroductions) {
|
||||
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
|
||||
return MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions) &&
|
||||
MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions);
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return this.mm1.matches(method, targetClass) && this.mm2.matches(method, targetClass);
|
||||
}
|
||||
|
||||
@@ -238,7 +237,7 @@ public abstract class MethodMatchers {
|
||||
return this.mm1.isRuntime() || this.mm2.isRuntime();
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, Object[] args) {
|
||||
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
|
||||
// Because a dynamic intersection may be composed of a static and dynamic part,
|
||||
// we must avoid calling the 3-arg matches method on a dynamic matcher, as
|
||||
// it will probably be an unsupported operation.
|
||||
|
||||
+24
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,10 +59,32 @@ public class AnnotationClassFilter implements ClassFilter {
|
||||
}
|
||||
|
||||
|
||||
public boolean matches(Class clazz) {
|
||||
public boolean matches(Class<?> clazz) {
|
||||
return (this.checkInherited ?
|
||||
(AnnotationUtils.findAnnotation(clazz, this.annotationType) != null) :
|
||||
clazz.isAnnotationPresent(this.annotationType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof AnnotationClassFilter)) {
|
||||
return false;
|
||||
}
|
||||
AnnotationClassFilter otherCf = (AnnotationClassFilter) other;
|
||||
return (this.annotationType.equals(otherCf.annotationType) && this.checkInherited == otherCf.checkInherited);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.annotationType.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + this.annotationType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+32
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,7 @@ import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Simple Pointcut that looks for a specific Java 5 annotation
|
||||
@@ -98,6 +99,36 @@ public class AnnotationMatchingPointcut implements Pointcut {
|
||||
return this.methodMatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof AnnotationMatchingPointcut)) {
|
||||
return false;
|
||||
}
|
||||
AnnotationMatchingPointcut that = (AnnotationMatchingPointcut) other;
|
||||
return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) &&
|
||||
ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = 17;
|
||||
if (this.classFilter != null) {
|
||||
code = 37 * code + this.classFilter.hashCode();
|
||||
}
|
||||
if (this.methodMatcher != null) {
|
||||
code = 37 * code + this.methodMatcher.hashCode();
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AnnotationMatchingPointcut: " + this.classFilter + ", " +this.methodMatcher;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory method for an AnnotationMatchingPointcut that matches
|
||||
|
||||
+6
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -73,4 +73,9 @@ public class AnnotationMethodMatcher extends StaticMethodMatcher {
|
||||
return this.annotationType.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + this.annotationType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,6 +50,7 @@ import org.springframework.beans.factory.DisposableBean;
|
||||
* @see #releaseTarget
|
||||
* @see #destroy
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class AbstractPoolingTargetSource extends AbstractPrototypeBasedTargetSource
|
||||
implements PoolingConfig, DisposableBean {
|
||||
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,6 +43,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
* @see ThreadLocalTargetSource
|
||||
* @see CommonsPoolTargetSource
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFactoryBasedTargetSource {
|
||||
|
||||
@Override
|
||||
|
||||
+10
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,8 +24,8 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.core.Constants;
|
||||
|
||||
/**
|
||||
* TargetSource implementation that holds objects in a configurable
|
||||
* Jakarta Commons Pool.
|
||||
* {@link org.springframework.aop.TargetSource} implementation that holds
|
||||
* objects in a configurable Apache Commons Pool.
|
||||
*
|
||||
* <p>By default, an instance of {@code GenericObjectPool} is created.
|
||||
* Subclasses may change the type of {@code ObjectPool} used by
|
||||
@@ -38,10 +38,12 @@ import org.springframework.core.Constants;
|
||||
* of configuration properties that are relevant to your chosen implementation.
|
||||
*
|
||||
* <p>The {@code testOnBorrow}, {@code testOnReturn} and {@code testWhileIdle}
|
||||
* properties are explictly not mirrored because the implementation of
|
||||
* properties are explicitly not mirrored because the implementation of
|
||||
* {@code PoolableObjectFactory} used by this class does not implement
|
||||
* meaningful validation. All exposed Commons Pool properties use the corresponding
|
||||
* Commons Pool defaults: for example,
|
||||
* meaningful validation. All exposed Commons Pool properties use the
|
||||
* corresponding Commons Pool defaults.
|
||||
*
|
||||
* <p>Compatible with Apache Commons Pool 1.5.x and 1.6.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
@@ -55,10 +57,8 @@ import org.springframework.core.Constants;
|
||||
* @see #setTimeBetweenEvictionRunsMillis
|
||||
* @see #setMinEvictableIdleTimeMillis
|
||||
*/
|
||||
public class CommonsPoolTargetSource extends AbstractPoolingTargetSource
|
||||
implements PoolableObjectFactory {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@SuppressWarnings("serial")
|
||||
public class CommonsPoolTargetSource extends AbstractPoolingTargetSource implements PoolableObjectFactory {
|
||||
|
||||
private static final Constants constants = new Constants(GenericObjectPool.class);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,9 +19,11 @@ package org.springframework.aop.target;
|
||||
import org.springframework.beans.BeansException;
|
||||
|
||||
/**
|
||||
* TargetSource that creates a new instance of the target bean for each
|
||||
* request, destroying each instance on release (after each request).
|
||||
* Obtains bean instances from its containing
|
||||
* {@link org.springframework.aop.TargetSource} implementation that
|
||||
* creates a new instance of the target bean for each request,
|
||||
* destroying each instance on release (after each request).
|
||||
*
|
||||
* <p>Obtains bean instances from its containing
|
||||
* {@link org.springframework.beans.factory.BeanFactory}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
@@ -29,10 +31,9 @@ import org.springframework.beans.BeansException;
|
||||
* @see #setBeanFactory
|
||||
* @see #setTargetBeanName
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class PrototypeTargetSource extends AbstractPrototypeBasedTargetSource {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Obtain a new prototype instance for every call.
|
||||
* @see #newPrototypeInstance()
|
||||
|
||||
+8
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,9 +27,10 @@ import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
|
||||
/**
|
||||
* Alternative to an object pool. This TargetSource uses a threading model in which
|
||||
* every thread has its own copy of the target. There's no contention for targets.
|
||||
* Target object creation is kept to a minimum on the running server.
|
||||
* Alternative to an object pool. This {@link org.springframework.aop.TargetSource}
|
||||
* uses a threading model in which every thread has its own copy of the target.
|
||||
* There's no contention for targets. Target object creation is kept to a minimum
|
||||
* on the running server.
|
||||
*
|
||||
* <p>Application code is written as to a normal pool; callers can't assume they
|
||||
* will be dealing with the same instance in invocations in different threads.
|
||||
@@ -47,11 +48,10 @@ import org.springframework.core.NamedThreadLocal;
|
||||
* @see ThreadLocalTargetSourceStats
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
|
||||
implements ThreadLocalTargetSourceStats, DisposableBean {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ThreadLocal holding the target associated with the current
|
||||
* thread. Unlike most ThreadLocals, which are static, this variable
|
||||
@@ -80,10 +80,8 @@ public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
|
||||
Object target = this.targetInThread.get();
|
||||
if (target == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No target for prototype '" + getTargetBeanName() +
|
||||
"' bound to thread: " +
|
||||
"creating one and binding it to thread '" +
|
||||
Thread.currentThread().getName() + "'");
|
||||
logger.debug("No target for prototype '" + getTargetBeanName() + "' bound to thread: " +
|
||||
"creating one and binding it to thread '" + Thread.currentThread().getName() + "'");
|
||||
}
|
||||
// Associate target with ThreadLocal.
|
||||
target = newPrototypeInstance();
|
||||
|
||||
+73
-41
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,16 +18,22 @@ package org.springframework.mock.staticmock;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Abstract aspect to enable mocking of methods picked out by a pointcut.
|
||||
* Sub-aspects must define the mockStaticsTestMethod() pointcut to
|
||||
* indicate call stacks when mocking should be triggered, and the
|
||||
* methodToMock() pointcut to pick out a method invocations to mock.
|
||||
*
|
||||
* <p>Sub-aspects must define:
|
||||
* <ul>
|
||||
* <li>the {@link #mockStaticsTestMethod()} pointcut to indicate call stacks
|
||||
* when mocking should be triggered
|
||||
* <li>the {@link #methodToMock()} pointcut to pick out method invocations to mock
|
||||
* </ul>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {
|
||||
|
||||
@@ -35,24 +41,34 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
|
||||
protected abstract pointcut methodToMock();
|
||||
|
||||
|
||||
private boolean recording = true;
|
||||
|
||||
static enum CallResponse { nothing, return_, throw_ };
|
||||
|
||||
// Represents a list of expected calls to static entity methods
|
||||
static enum CallResponse {
|
||||
nothing, return_, throw_
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a list of expected calls to methods.
|
||||
*/
|
||||
// Public to allow inserted code to access: is this normal??
|
||||
public class Expectations {
|
||||
|
||||
// Represents an expected call to a static entity method
|
||||
/**
|
||||
* Represents an expected call to a method.
|
||||
*/
|
||||
private class Call {
|
||||
|
||||
private final String signature;
|
||||
private final Object[] args;
|
||||
|
||||
private Object responseObject; // return value or throwable
|
||||
private CallResponse responseType = CallResponse.nothing;
|
||||
|
||||
public Call(String name, Object[] args) {
|
||||
this.signature = name;
|
||||
|
||||
public Call(String signature, Object[] args) {
|
||||
this.signature = signature;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
@@ -77,7 +93,7 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
|
||||
public Object throwException(String lastSig, Object[] args) {
|
||||
checkSignature(lastSig, args);
|
||||
throw (RuntimeException)responseObject;
|
||||
throw (RuntimeException) responseObject;
|
||||
}
|
||||
|
||||
private void checkSignature(String lastSig, Object[] args) {
|
||||
@@ -88,16 +104,29 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
throw new IllegalArgumentException("Arguments don't match");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Call with signature [%s] and arguments %s", this.signature,
|
||||
ObjectUtils.nullSafeToString(args));
|
||||
}
|
||||
}
|
||||
|
||||
private List<Call> calls = new LinkedList<Call>();
|
||||
|
||||
// Calls already verified
|
||||
/**
|
||||
* The list of recorded calls.
|
||||
*/
|
||||
private final LinkedList<Call> calls = new LinkedList<Call>();
|
||||
|
||||
/**
|
||||
* The number of calls already verified.
|
||||
*/
|
||||
private int verified;
|
||||
|
||||
|
||||
public void verify() {
|
||||
if (verified != calls.size()) {
|
||||
throw new IllegalStateException("Expected " + calls.size() + " calls, received " + verified);
|
||||
throw new IllegalStateException("Expected " + calls.size() + " calls, but received " + verified);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,31 +134,32 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
* 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);
|
||||
Call c = nextCall();
|
||||
|
||||
switch (c.responseType) {
|
||||
case return_: {
|
||||
return c.returnValue(lastSig, args);
|
||||
}
|
||||
case throw_: {
|
||||
return c.throwException(lastSig, args);
|
||||
}
|
||||
default: {
|
||||
throw new IllegalStateException("Behavior of " + c + " not specified");
|
||||
}
|
||||
}
|
||||
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() {
|
||||
verified++;
|
||||
if (verified > calls.size()) {
|
||||
throw new IllegalStateException("Expected " + calls.size() + " calls, received " + verified);
|
||||
throw new IllegalStateException("Expected " + calls.size() + " calls, but received " + verified);
|
||||
}
|
||||
return calls.get(verified);
|
||||
// The 'verified' count is 1-based; whereas, 'calls' is 0-based.
|
||||
return calls.get(verified - 1);
|
||||
}
|
||||
|
||||
public void expectCall(String lastSig, Object lastArgs[]) {
|
||||
Call call = new Call(lastSig, lastArgs);
|
||||
calls.add(call);
|
||||
public void expectCall(String lastSig, Object[] lastArgs) {
|
||||
calls.add(new Call(lastSig, lastArgs));
|
||||
}
|
||||
|
||||
public boolean hasCalls() {
|
||||
@@ -137,29 +167,31 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
|
||||
}
|
||||
|
||||
public void expectReturn(Object retVal) {
|
||||
Call call = calls.get(calls.size() - 1);
|
||||
if (call.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No static method invoked before setting return value");
|
||||
Call c = calls.getLast();
|
||||
if (c.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No method invoked before setting return value");
|
||||
}
|
||||
call.setReturnVal(retVal);
|
||||
c.setReturnVal(retVal);
|
||||
}
|
||||
|
||||
public void expectThrow(Throwable throwable) {
|
||||
Call call = calls.get(calls.size() - 1);
|
||||
if (call.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No static method invoked before setting throwable");
|
||||
Call c = calls.getLast();
|
||||
if (c.hasResponseSpecified()) {
|
||||
throw new IllegalStateException("No method invoked before setting throwable");
|
||||
}
|
||||
call.setThrow(throwable);
|
||||
c.setThrow(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private Expectations expectations = new Expectations();
|
||||
|
||||
private final Expectations expectations = new Expectations();
|
||||
|
||||
|
||||
after() returning : mockStaticsTestMethod() {
|
||||
if (recording && (expectations.hasCalls())) {
|
||||
throw new IllegalStateException(
|
||||
"Calls recorded, yet playback state never reached: Create expectations then call "
|
||||
+ this.getClass().getSimpleName() + ".playback()");
|
||||
"Calls recorded, yet playback state never reached: Create expectations then call "
|
||||
+ this.getClass().getSimpleName() + ".playback()");
|
||||
}
|
||||
expectations.verify();
|
||||
}
|
||||
|
||||
+41
-22
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,50 +17,69 @@
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
/**
|
||||
* Annotation-based aspect to use in test build to enable mocking static methods
|
||||
* on JPA-annotated {@code @Entity} classes, as used by Roo for finders.
|
||||
* Annotation-based aspect to use in test builds to enable mocking of static methods
|
||||
* on JPA-annotated {@code @Entity} classes, as used by Spring Roo for so-called
|
||||
* <em>finder methods</em>.
|
||||
*
|
||||
* <p>Mocking will occur in the call stack of any method in a class (typically a test class)
|
||||
* that is annotated with the @MockStaticEntityMethods annotation.
|
||||
* <p>Mocking will occur within the call stack of any method in a class (typically a
|
||||
* test class) that is annotated with {@code @MockStaticEntityMethods}.
|
||||
*
|
||||
* <p>Also provides static methods to simplify the programming model for
|
||||
* entering playback mode and setting expected return values.
|
||||
* <p>This aspect also provides static methods to simplify the programming model for
|
||||
* setting expectations and entering playback mode.
|
||||
*
|
||||
* <p>Usage:
|
||||
* <ol>
|
||||
* <li>Annotate a test class with @MockStaticEntityMethods.
|
||||
* <li>In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode.
|
||||
* Invoke static methods on Entity classes, with each recording-mode invocation
|
||||
* being followed by an invocation to the static expectReturn() or expectThrow()
|
||||
* method on AnnotationDrivenStaticEntityMockingControl.
|
||||
* <li>Invoke the static AnnotationDrivenStaticEntityMockingControl() method.
|
||||
* <li>Call the code you wish to test that uses the static methods. Verification will
|
||||
* occur automatically.
|
||||
* <li>Annotate a test class with {@code @MockStaticEntityMethods}.
|
||||
* <li>In each test method, {@code AnnotationDrivenStaticEntityMockingControl}
|
||||
* will begin in <em>recording</em> mode.
|
||||
* <li>Invoke static methods on JPA-annotated {@code @Entity} classes, with each
|
||||
* recording-mode invocation being followed by an invocation of either the static
|
||||
* {@link #expectReturn(Object)} method or the static {@link #expectThrow(Throwable)}
|
||||
* method on {@code AnnotationDrivenStaticEntityMockingControl}.
|
||||
* <li>Invoke the static {@link #playback()} method.
|
||||
* <li>Call the code you wish to test that uses the static methods.
|
||||
* <li>Verification will occur automatically.
|
||||
* </ol>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
* @see MockStaticEntityMethods
|
||||
*/
|
||||
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
|
||||
|
||||
/**
|
||||
* Stop recording mock calls and enter playback state
|
||||
* Expect the supplied {@link Object} to be returned by the previous static
|
||||
* method invocation.
|
||||
* @see #playback()
|
||||
*/
|
||||
public static void playback() {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal();
|
||||
}
|
||||
|
||||
public static void expectReturn(Object retVal) {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectReturnInternal(retVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect the supplied {@link Throwable} to be thrown by the previous static
|
||||
* method invocation.
|
||||
* @see #playback()
|
||||
*/
|
||||
public static void expectThrow(Throwable throwable) {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectThrowInternal(throwable);
|
||||
}
|
||||
|
||||
// Only matches directly annotated @Test methods, to allow methods in
|
||||
// @MockStatics classes to invoke each other without resetting the mocking environment
|
||||
/**
|
||||
* Stop recording mock expectations and enter <em>playback</em> mode.
|
||||
* @see #expectReturn(Object)
|
||||
* @see #expectThrow(Throwable)
|
||||
*/
|
||||
public static void playback() {
|
||||
AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal();
|
||||
}
|
||||
|
||||
// Apparently, the following pointcut was originally defined to only match
|
||||
// methods directly annotated with @Test (in order to allow methods in
|
||||
// @MockStaticEntityMethods classes to invoke each other without resetting
|
||||
// the mocking environment); however, this is no longer the case. The current
|
||||
// pointcut applies to all public methods in @MockStaticEntityMethods classes.
|
||||
protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..));
|
||||
|
||||
protected pointcut methodToMock() : execution(public static * (@javax.persistence.Entity *).*(..));
|
||||
|
||||
+6
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,11 +22,13 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to indicate a test class for whose @Test methods
|
||||
* static methods on Entity classes should be mocked. See
|
||||
* {@code AbstractMethodMockingControl}.
|
||||
* Annotation to indicate a test class for whose {@code @Test} methods
|
||||
* static methods on JPA-annotated {@code @Entity} classes should be mocked.
|
||||
*
|
||||
* <p>See {@link AnnotationDrivenStaticEntityMockingControl} for details.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,11 +32,11 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
||||
* @since 3.1
|
||||
* @see EnableAsync
|
||||
* @see org.springframework.scheduling.annotation.AsyncConfigurationSelector
|
||||
* @see org.springframework.scheduling.annotation.ProxyAsyncConfiguration
|
||||
*/
|
||||
@Configuration
|
||||
public class AspectJAsyncConfiguration extends AbstractAsyncConfiguration {
|
||||
|
||||
@Override
|
||||
@Bean(name=AnnotationConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public AnnotationAsyncExecutionAspect asyncAdvisor() {
|
||||
|
||||
-148
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.expectReturn;
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.expectThrow;
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.playback;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
|
||||
/**
|
||||
* Test for static entity mocking framework.
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
@MockStaticEntityMethods
|
||||
@RunWith(JUnit4.class)
|
||||
public class AnnotationDrivenStaticEntityMockingControlTest {
|
||||
|
||||
@Test
|
||||
public void testNoArgIntReturn() {
|
||||
int expectedCount = 13;
|
||||
Person.countPeople();
|
||||
expectReturn(expectedCount);
|
||||
playback();
|
||||
assertEquals(expectedCount, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected=PersistenceException.class)
|
||||
public void testNoArgThrows() {
|
||||
Person.countPeople();
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodMatches() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLongSeriesOfCalls() {
|
||||
long id1 = 13;
|
||||
long id2 = 24;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(id2);
|
||||
expectReturn(found2);
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person.countPeople();
|
||||
expectReturn(0);
|
||||
playback();
|
||||
|
||||
assertEquals(found1, Person.findPerson(id1));
|
||||
assertEquals(found2, Person.findPerson(id2));
|
||||
assertEquals(found1, Person.findPerson(id1));
|
||||
assertEquals(0, Person.countPeople());
|
||||
}
|
||||
|
||||
// Note delegation is used when tests are invalid and should fail, as otherwise
|
||||
// the failure will occur on the verify() method in the aspect after
|
||||
// this method returns, failing the test case
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
try {
|
||||
new Delegate().testArgMethodNoMatchExpectReturn();
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
new Delegate().testArgMethodNoMatchExpectThrow();
|
||||
}
|
||||
|
||||
private void called(Person found, long id) {
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReentrant() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
called(found, id);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testRejectUnexpectedCall() {
|
||||
new Delegate().rejectUnexpectedCall();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testFailTooFewCalls() {
|
||||
new Delegate().failTooFewCalls();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
// Test that verification check doesn't blow up if no replay() call happened
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverReplay() {
|
||||
new Delegate().doesntEverReplay();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoesntEverSetReturn() {
|
||||
new Delegate().doesntEverSetReturn();
|
||||
}
|
||||
}
|
||||
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*;
|
||||
|
||||
/**
|
||||
* Tests for Spring's static entity mocking framework (i.e., @{@link MockStaticEntityMethods}
|
||||
* and {@link AnnotationDrivenStaticEntityMockingControl}).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@MockStaticEntityMethods
|
||||
public class AnnotationDrivenStaticEntityMockingControlTests {
|
||||
|
||||
@Test
|
||||
public void noArgumentMethodInvocationReturnsInt() {
|
||||
int expectedCount = 13;
|
||||
Person.countPeople();
|
||||
expectReturn(expectedCount);
|
||||
playback();
|
||||
assertEquals(expectedCount, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected = PersistenceException.class)
|
||||
public void noArgumentMethodInvocationThrowsException() {
|
||||
Person.countPeople();
|
||||
expectThrow(new PersistenceException());
|
||||
playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodArgumentsMatch() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longSeriesOfCalls() {
|
||||
long id1 = 13;
|
||||
long id2 = 24;
|
||||
Person found1 = new Person();
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person found2 = new Person();
|
||||
Person.findPerson(id2);
|
||||
expectReturn(found2);
|
||||
Person.findPerson(id1);
|
||||
expectReturn(found1);
|
||||
Person.countPeople();
|
||||
expectReturn(0);
|
||||
playback();
|
||||
|
||||
assertEquals(found1, Person.findPerson(id1));
|
||||
assertEquals(found2, Person.findPerson(id2));
|
||||
assertEquals(found1, Person.findPerson(id1));
|
||||
assertEquals(0, Person.countPeople());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void methodArgumentsDoNotMatchAndReturnsObject() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void methodArgumentsDoNotMatchAndThrowsException() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reentrant() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
expectReturn(found);
|
||||
playback();
|
||||
called(found, id);
|
||||
}
|
||||
|
||||
private void called(Person found, long id) {
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void rejectUnexpectedCall() {
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void tooFewCalls() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void empty() {
|
||||
// Test that verification check doesn't blow up if no replay() call happened.
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void doesNotEnterPlaybackMode() {
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void doesNotSetExpectedReturnValue() {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: this test method currently does NOT actually verify that the mock
|
||||
* verification fails.
|
||||
*/
|
||||
// TODO Determine if it's possible for a mock verification failure to fail a test in
|
||||
// JUnit 4+ if the test method itself throws an expected exception.
|
||||
@Test(expected = RemoteException.class)
|
||||
public void verificationFailsEvenWhenTestFailsInExpectedManner() throws Exception {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
// No calls in order to allow verification failure
|
||||
throw new RemoteException();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.mock.staticmock;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl;
|
||||
import org.springframework.mock.staticmock.MockStaticEntityMethods;
|
||||
|
||||
//Used because verification failures occur after method returns,
|
||||
//so we can't test for them in the test case itself
|
||||
@MockStaticEntityMethods
|
||||
@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl
|
||||
public class Delegate {
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectReturn() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgMethodNoMatchExpectThrow() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failTooFewCalls() {
|
||||
long id = 13;
|
||||
Person found = new Person();
|
||||
Person.findPerson(id);
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
assertEquals(found, Person.findPerson(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverReplay() {
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntEverSetReturn() {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectUnexpectedCall() {
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
Person.countPeople();
|
||||
}
|
||||
|
||||
@Test(expected=RemoteException.class)
|
||||
public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException {
|
||||
Person.countPeople();
|
||||
AnnotationDrivenStaticEntityMockingControl.playback();
|
||||
// No calls to allow verification failure
|
||||
throw new RemoteException();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,33 +20,36 @@ import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
|
||||
/**
|
||||
* Strategy for creating {@link BeanInfo} instances.
|
||||
* Strategy interface for creating {@link BeanInfo} instances for Spring beans.
|
||||
* Can be used to plug in custom bean property resolution strategies (e.g. for other
|
||||
* languages on the JVM) or more efficient {@link BeanInfo} retrieval algorithms.
|
||||
*
|
||||
* <p>BeanInfoFactories are are instantiated by the {@link CachedIntrospectionResults},
|
||||
* by using the {@link org.springframework.core.io.support.SpringFactoriesLoader} utility
|
||||
* class.
|
||||
* by using the {@link org.springframework.core.io.support.SpringFactoriesLoader}
|
||||
* utility class.
|
||||
*
|
||||
* When a {@link BeanInfo} is to be created, the {@code CachedIntrospectionResults}
|
||||
* will iterate through the discovered factories, calling {@link
|
||||
* #getBeanInfo(Class)} on each one. If {@code null} is returned, the next factory will
|
||||
* be queried. If none of the factories support the class, an standard {@link BeanInfo}
|
||||
* is created as a default.
|
||||
* will iterate through the discovered factories, calling {@link #getBeanInfo(Class)}
|
||||
* on each one. If {@code null} is returned, the next factory will be queried.
|
||||
* If none of the factories support the class, a standard {@link BeanInfo} will be
|
||||
* created as a default.
|
||||
*
|
||||
* <p>Note that the {@link org.springframework.core.io.support.SpringFactoriesLoader}
|
||||
* sorts the {@code BeanInfoFactory} instances by
|
||||
* {@link org.springframework.core.annotation.Order @Order}, so that ones with
|
||||
* a higher precedence come first.
|
||||
* {@link org.springframework.core.annotation.Order @Order}, so that ones with a
|
||||
* higher precedence come first.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.2
|
||||
* @see CachedIntrospectionResults
|
||||
* @see org.springframework.core.io.support.SpringFactoriesLoader
|
||||
*/
|
||||
public interface BeanInfoFactory {
|
||||
|
||||
/**
|
||||
* Returns the bean info for the given class, if supported.
|
||||
*
|
||||
* Return the bean info for the given class, if supported.
|
||||
* @param beanClass the bean class
|
||||
* @return the bean info, or {@code null} if not the given class is not supported
|
||||
* @return the BeanInfo, or {@code null} if the given class is not supported
|
||||
* @throws IntrospectionException in case of exceptions
|
||||
*/
|
||||
BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException;
|
||||
|
||||
@@ -600,7 +600,7 @@ public abstract class BeanUtils {
|
||||
if (sourcePd != null) {
|
||||
Method readMethod = sourcePd.getReadMethod();
|
||||
if (readMethod != null &&
|
||||
writeMethod.getParameterTypes()[0].isAssignableFrom(readMethod.getReturnType())) {
|
||||
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
|
||||
try {
|
||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
|
||||
readMethod.setAccessible(true);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,7 +59,7 @@ public interface BeanWrapper extends ConfigurablePropertyAccessor {
|
||||
* @return the type of the wrapped bean instance,
|
||||
* or {@code null} if no wrapped object has been set
|
||||
*/
|
||||
Class getWrappedClass();
|
||||
Class<?> getWrappedClass();
|
||||
|
||||
/**
|
||||
* Obtain the PropertyDescriptors for the wrapped object
|
||||
@@ -79,11 +79,13 @@ public interface BeanWrapper extends ConfigurablePropertyAccessor {
|
||||
PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;
|
||||
|
||||
/**
|
||||
* Set whether this BeanWrapper should attempt to "auto-grow" a nested path that contains a null value.
|
||||
* <p>If "true", a null path location will be populated with a default object value and traversed
|
||||
* instead of resulting in a {@link NullValueInNestedPathException}. Turning this flag on also
|
||||
* enables auto-growth of collection elements when accessing an out-of-bounds index.
|
||||
* <p>Default is "false" on a plain BeanWrapper.
|
||||
* Set whether this BeanWrapper should attempt to "auto-grow" a
|
||||
* nested path that contains a {@code null} value.
|
||||
* <p>If {@code true}, a {@code null} path location will be populated
|
||||
* with a default object value and traversed instead of resulting in a
|
||||
* {@link NullValueInNestedPathException}. Turning this flag on also enables
|
||||
* auto-growth of collection elements when accessing an out-of-bounds index.
|
||||
* <p>Default is {@code false} on a plain BeanWrapper.
|
||||
*/
|
||||
void setAutoGrowNestedPaths(boolean autoGrowNestedPaths);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -223,7 +223,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
return this.object;
|
||||
}
|
||||
|
||||
public final Class getWrappedClass() {
|
||||
public final Class<?> getWrappedClass() {
|
||||
return (this.object != null ? this.object.getClass() : null);
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
* Return the class of the root object at the top of the path of this BeanWrapper.
|
||||
* @see #getNestedPath
|
||||
*/
|
||||
public final Class getRootClass() {
|
||||
public final Class<?> getRootClass() {
|
||||
return (this.rootObject != null ? this.rootObject.getClass() : null);
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
* Needs to be called when the target object changes.
|
||||
* @param clazz the class to introspect
|
||||
*/
|
||||
protected void setIntrospectionClass(Class clazz) {
|
||||
protected void setIntrospectionClass(Class<?> clazz) {
|
||||
if (this.cachedIntrospectionResults != null &&
|
||||
!clazz.equals(this.cachedIntrospectionResults.getBeanClass())) {
|
||||
this.cachedIntrospectionResults = null;
|
||||
@@ -352,7 +352,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getPropertyType(String propertyName) throws BeansException {
|
||||
public Class<?> getPropertyType(String propertyName) throws BeansException {
|
||||
try {
|
||||
PropertyDescriptor pd = getPropertyDescriptorInternal(propertyName);
|
||||
if (pd != null) {
|
||||
@@ -366,7 +366,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
// Check to see if there is a custom editor,
|
||||
// which might give an indication on the desired target type.
|
||||
Class editorType = guessPropertyTypeFromEditors(propertyName);
|
||||
Class<?> editorType = guessPropertyTypeFromEditors(propertyName);
|
||||
if (editorType != null) {
|
||||
return editorType;
|
||||
}
|
||||
@@ -485,13 +485,13 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"No property '" + propertyName + "' found");
|
||||
}
|
||||
return convertForProperty(propertyName, null, value, pd);
|
||||
return convertForProperty(propertyName, null, value, new TypeDescriptor(property(pd)));
|
||||
}
|
||||
|
||||
private Object convertForProperty(String propertyName, Object oldValue, Object newValue, PropertyDescriptor pd)
|
||||
private Object convertForProperty(String propertyName, Object oldValue, Object newValue, TypeDescriptor td)
|
||||
throws TypeMismatchException {
|
||||
|
||||
return convertIfNecessary(propertyName, oldValue, newValue, pd.getPropertyType(), new TypeDescriptor(property(pd)));
|
||||
return convertIfNecessary(propertyName, oldValue, newValue, td.getType(), td);
|
||||
}
|
||||
|
||||
private Property property(PropertyDescriptor pd) {
|
||||
@@ -699,7 +699,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
return nestedBw.getPropertyValue(tokens);
|
||||
}
|
||||
|
||||
private Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {
|
||||
String propertyName = tokens.canonicalName;
|
||||
String actualName = tokens.actualName;
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
|
||||
@@ -766,20 +767,20 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
else if (value instanceof List) {
|
||||
int index = Integer.parseInt(key);
|
||||
List list = (List) value;
|
||||
List<Object> list = (List<Object>) value;
|
||||
growCollectionIfNecessary(list, index, indexedPropertyName, pd, i + 1);
|
||||
value = list.get(index);
|
||||
}
|
||||
else if (value instanceof Set) {
|
||||
// Apply index to Iterator in case of a Set.
|
||||
Set set = (Set) value;
|
||||
Set<Object> set = (Set<Object>) value;
|
||||
int index = Integer.parseInt(key);
|
||||
if (index < 0 || index >= set.size()) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot get element with index " + index + " from Set of size " +
|
||||
set.size() + ", accessed using property path '" + propertyName + "'");
|
||||
}
|
||||
Iterator it = set.iterator();
|
||||
Iterator<Object> it = set.iterator();
|
||||
for (int j = 0; it.hasNext(); j++) {
|
||||
Object elem = it.next();
|
||||
if (j == index) {
|
||||
@@ -789,11 +790,12 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
else if (value instanceof Map) {
|
||||
Map map = (Map) value;
|
||||
Map<Object, Object> map = (Map<Object, Object>) value;
|
||||
Class<?> mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(pd.getReadMethod(), i + 1);
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
TypeDescriptor typeDescriptor = mapKeyType != null ? TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class);
|
||||
TypeDescriptor typeDescriptor = (mapKeyType != null ?
|
||||
TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class));
|
||||
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
|
||||
value = map.get(convertedMapKey);
|
||||
}
|
||||
@@ -850,16 +852,15 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void growCollectionIfNecessary(
|
||||
Collection collection, int index, String name, PropertyDescriptor pd, int nestingLevel) {
|
||||
private void growCollectionIfNecessary(Collection<Object> collection, int index, String name,
|
||||
PropertyDescriptor pd, int nestingLevel) {
|
||||
|
||||
if (!this.autoGrowNestedPaths) {
|
||||
return;
|
||||
}
|
||||
int size = collection.size();
|
||||
if (index >= size && index < this.autoGrowCollectionLimit) {
|
||||
Class elementType = GenericCollectionTypeResolver.getCollectionReturnType(pd.getReadMethod(), nestingLevel);
|
||||
Class<?> elementType = GenericCollectionTypeResolver.getCollectionReturnType(pd.getReadMethod(), nestingLevel);
|
||||
if (elementType != null) {
|
||||
for (int i = collection.size(); i < index + 1; i++) {
|
||||
collection.add(newValue(elementType, name));
|
||||
@@ -945,7 +946,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
if (propValue.getClass().isArray()) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
|
||||
Class requiredType = propValue.getClass().getComponentType();
|
||||
Class<?> requiredType = propValue.getClass().getComponentType();
|
||||
int arrayIndex = Integer.parseInt(key);
|
||||
Object oldValue = null;
|
||||
try {
|
||||
@@ -963,9 +964,9 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
else if (propValue instanceof List) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
|
||||
Class requiredType = GenericCollectionTypeResolver.getCollectionReturnType(
|
||||
Class<?> requiredType = GenericCollectionTypeResolver.getCollectionReturnType(
|
||||
pd.getReadMethod(), tokens.keys.length);
|
||||
List list = (List) propValue;
|
||||
List<Object> list = (List<Object>) propValue;
|
||||
int index = Integer.parseInt(key);
|
||||
Object oldValue = null;
|
||||
if (isExtractOldValueForEditor() && index < list.size()) {
|
||||
@@ -1000,11 +1001,11 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
else if (propValue instanceof Map) {
|
||||
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
|
||||
Class mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(
|
||||
Class<?> mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(
|
||||
pd.getReadMethod(), tokens.keys.length);
|
||||
Class mapValueType = GenericCollectionTypeResolver.getMapValueReturnType(
|
||||
Class<?> mapValueType = GenericCollectionTypeResolver.getMapValueReturnType(
|
||||
pd.getReadMethod(), tokens.keys.length);
|
||||
Map map = (Map) propValue;
|
||||
Map<Object, Object> map = (Map<Object, Object>) propValue;
|
||||
// IMPORTANT: Do not pass full property name in here - property editors
|
||||
// must not kick in for map keys but rather only for map values.
|
||||
TypeDescriptor typeDescriptor = (mapKeyType != null ?
|
||||
@@ -1094,7 +1095,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
}
|
||||
}
|
||||
valueToApply = convertForProperty(propertyName, oldValue, originalValue, pd);
|
||||
valueToApply = convertForProperty(
|
||||
propertyName, oldValue, originalValue, new TypeDescriptor(property(pd)));
|
||||
}
|
||||
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
|
||||
}
|
||||
|
||||
+57
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,6 +33,7 @@ import java.util.WeakHashMap;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.SpringProperties;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -50,6 +51,18 @@ import org.springframework.util.StringUtils;
|
||||
* implements the factory design pattern, using a private constructor and
|
||||
* a static {@link #forClass(Class)} factory method to obtain instances.
|
||||
*
|
||||
* <p>Note that for caching to work effectively, some preconditions need to be met:
|
||||
* Prefer an arrangement where the Spring jars live in the same ClassLoader as the
|
||||
* application classes, which allows for clean caching along with the application's
|
||||
* lifecycle in any case. For a web application, consider declaring a local
|
||||
* {@link org.springframework.web.util.IntrospectorCleanupListener} in {@code web.xml}
|
||||
* in case of a multi-ClassLoader layout, which will allow for effective caching as well.
|
||||
*
|
||||
* <p>In case of a non-clean ClassLoader arrangement without a cleanup listener having
|
||||
* been set up, this class will fall back to a weak-reference-based caching model that
|
||||
* recreates much-requested entries every time the garbage collector removed them. In
|
||||
* such a scenario, consider the {@link #IGNORE_BEANINFO_PROPERTY_NAME} system property.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 05 May 2001
|
||||
@@ -59,11 +72,34 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class CachedIntrospectionResults {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class);
|
||||
/**
|
||||
* System property that instructs Spring to use the {@link Introspector#IGNORE_ALL_BEANINFO}
|
||||
* mode when calling the JavaBeans {@link Introspector}: "spring.beaninfo.ignore", with a
|
||||
* value of "true" skipping the search for {@code BeanInfo} classes (typically for scenarios
|
||||
* where no such classes are being defined for beans in the application in the first place).
|
||||
* <p>The default is "false", considering all {@code BeanInfo} metadata classes, like for
|
||||
* standard {@link Introspector#getBeanInfo(Class)} calls. Consider switching this flag to
|
||||
* "true" if you experience repeated ClassLoader access for non-existing {@code BeanInfo}
|
||||
* classes, in case such access is expensive on startup or on lazy loading.
|
||||
* <p>Note that such an effect may also indicate a scenario where caching doesn't work
|
||||
* effectively: Prefer an arrangement where the Spring jars live in the same ClassLoader
|
||||
* as the application classes, which allows for clean caching along with the application's
|
||||
* lifecycle in any case. For a web application, consider declaring a local
|
||||
* {@link org.springframework.web.util.IntrospectorCleanupListener} in {@code web.xml}
|
||||
* in case of a multi-ClassLoader layout, which will allow for effective caching as well.
|
||||
* @see Introspector#getBeanInfo(Class, int)
|
||||
*/
|
||||
public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";
|
||||
|
||||
|
||||
private static final boolean shouldIntrospectorIgnoreBeaninfoClasses =
|
||||
SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME);
|
||||
|
||||
/** Stores the BeanInfoFactory instances */
|
||||
private static List<BeanInfoFactory> beanInfoFactories =
|
||||
SpringFactoriesLoader.loadFactories(BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());
|
||||
private static List<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories(
|
||||
BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class);
|
||||
|
||||
/**
|
||||
* Set of ClassLoaders that this CachedIntrospectionResults class will always
|
||||
@@ -179,8 +215,8 @@ public class CachedIntrospectionResults {
|
||||
synchronized (acceptedClassLoaders) {
|
||||
acceptedLoaderArray = acceptedClassLoaders.toArray(new ClassLoader[acceptedClassLoaders.size()]);
|
||||
}
|
||||
for (ClassLoader registeredLoader : acceptedLoaderArray) {
|
||||
if (isUnderneathClassLoader(classLoader, registeredLoader)) {
|
||||
for (ClassLoader acceptedLoader : acceptedLoaderArray) {
|
||||
if (isUnderneathClassLoader(classLoader, acceptedLoader)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -238,20 +274,25 @@ public class CachedIntrospectionResults {
|
||||
}
|
||||
if (beanInfo == null) {
|
||||
// If none of the factories supported the class, fall back to the default
|
||||
beanInfo = Introspector.getBeanInfo(beanClass);
|
||||
beanInfo = (shouldIntrospectorIgnoreBeaninfoClasses ?
|
||||
Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) :
|
||||
Introspector.getBeanInfo(beanClass));
|
||||
}
|
||||
this.beanInfo = beanInfo;
|
||||
|
||||
// Immediately remove class from Introspector cache, to allow for proper
|
||||
// garbage collection on class loader shutdown - we cache it here anyway,
|
||||
// in a GC-friendly manner. In contrast to CachedIntrospectionResults,
|
||||
// Introspector does not use WeakReferences as values of its WeakHashMap!
|
||||
Class<?> classToFlush = beanClass;
|
||||
do {
|
||||
Introspector.flushFromCaches(classToFlush);
|
||||
classToFlush = classToFlush.getSuperclass();
|
||||
// Only bother with flushFromCaches if the Introspector actually cached...
|
||||
if (!shouldIntrospectorIgnoreBeaninfoClasses) {
|
||||
// Immediately remove class from Introspector cache, to allow for proper
|
||||
// garbage collection on class loader shutdown - we cache it here anyway,
|
||||
// in a GC-friendly manner. In contrast to CachedIntrospectionResults,
|
||||
// Introspector does not use WeakReferences as values of its WeakHashMap!
|
||||
Class<?> classToFlush = beanClass;
|
||||
do {
|
||||
Introspector.flushFromCaches(classToFlush);
|
||||
classToFlush = classToFlush.getSuperclass();
|
||||
}
|
||||
while (classToFlush != null && classToFlush != Object.class);
|
||||
}
|
||||
while (classToFlush != null);
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,8 +25,8 @@ import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* {@link BeanInfoFactory} implementation that evaluates whether bean classes have
|
||||
* "non-standard" JavaBeans setter methods and are thus candidates for introspection by
|
||||
* Spring's {@link ExtendedBeanInfo}.
|
||||
* "non-standard" JavaBeans setter methods and are thus candidates for introspection
|
||||
* by Spring's (package-visible) {@code ExtendedBeanInfo} implementation.
|
||||
*
|
||||
* <p>Ordered at {@link Ordered#LOWEST_PRECEDENCE} to allow other user-defined
|
||||
* {@link BeanInfoFactory} types to take precedence.
|
||||
@@ -34,20 +34,20 @@ import org.springframework.core.Ordered;
|
||||
* @author Chris Beams
|
||||
* @since 3.2
|
||||
* @see BeanInfoFactory
|
||||
* @see CachedIntrospectionResults
|
||||
*/
|
||||
public class ExtendedBeanInfoFactory implements Ordered, BeanInfoFactory {
|
||||
public class ExtendedBeanInfoFactory implements BeanInfoFactory, Ordered {
|
||||
|
||||
/**
|
||||
* Return a new {@link ExtendedBeanInfo} for the given bean class.
|
||||
* Return an {@link ExtendedBeanInfo} for the given bean class, if applicable.
|
||||
*/
|
||||
public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
|
||||
return supports(beanClass) ?
|
||||
new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass)) : null;
|
||||
return (supports(beanClass) ? new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass)) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given bean class declares or inherits any non-void returning
|
||||
* JavaBeans or <em>indexed property</em> setter methods.
|
||||
* Return whether the given bean class declares or inherits any non-void
|
||||
* returning bean property or indexed property setter methods.
|
||||
*/
|
||||
private boolean supports(Class<?> beanClass) {
|
||||
for (Method method : beanClass.getMethods()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -220,8 +220,8 @@ class TypeConverterDelegate {
|
||||
else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
|
||||
if (firstAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
|
||||
try {
|
||||
Constructor strCtor = requiredType.getConstructor(String.class);
|
||||
return (T) BeanUtils.instantiateClass(strCtor, convertedValue);
|
||||
Constructor<T> strCtor = requiredType.getConstructor(String.class);
|
||||
return BeanUtils.instantiateClass(strCtor, convertedValue);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
// proceed with field lookup
|
||||
@@ -289,15 +289,15 @@ class TypeConverterDelegate {
|
||||
if (index > - 1) {
|
||||
String enumType = trimmedValue.substring(0, index);
|
||||
String fieldName = trimmedValue.substring(index + 1);
|
||||
ClassLoader loader = this.targetObject.getClass().getClassLoader();
|
||||
ClassLoader cl = this.targetObject.getClass().getClassLoader();
|
||||
try {
|
||||
Class<?> enumValueType = loader.loadClass(enumType);
|
||||
Class<?> enumValueType = ClassUtils.forName(enumType, cl);
|
||||
Field enumField = enumValueType.getField(fieldName);
|
||||
convertedValue = enumField.get(null);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
if(logger.isTraceEnabled()) {
|
||||
logger.trace("Enum class [" + enumType + "] cannot be loaded from [" + loader + "]", ex);
|
||||
logger.trace("Enum class [" + enumType + "] cannot be loaded", ex);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
@@ -331,7 +331,7 @@ class TypeConverterDelegate {
|
||||
* @param requiredType the type to find an editor for
|
||||
* @return the corresponding editor, or {@code null} if none
|
||||
*/
|
||||
private PropertyEditor findDefaultEditor(Class requiredType) {
|
||||
private PropertyEditor findDefaultEditor(Class<?> requiredType) {
|
||||
PropertyEditor editor = null;
|
||||
if (requiredType != null) {
|
||||
// No custom editor -> check BeanWrapperImpl's default editors.
|
||||
@@ -496,7 +496,7 @@ class TypeConverterDelegate {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Collection convertToTypedCollection(
|
||||
Collection original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
|
||||
Collection original, String propertyName, Class<?> requiredType, TypeDescriptor typeDescriptor) {
|
||||
|
||||
if (!Collection.class.isAssignableFrom(requiredType)) {
|
||||
return original;
|
||||
@@ -578,7 +578,7 @@ class TypeConverterDelegate {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map convertToTypedMap(
|
||||
Map original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
|
||||
Map original, String propertyName, Class<?> requiredType, TypeDescriptor typeDescriptor) {
|
||||
|
||||
if (!Map.class.isAssignableFrom(requiredType)) {
|
||||
return original;
|
||||
@@ -674,7 +674,7 @@ class TypeConverterDelegate {
|
||||
null);
|
||||
}
|
||||
|
||||
private boolean canCreateCopy(Class requiredType) {
|
||||
private boolean canCreateCopy(Class<?> requiredType) {
|
||||
return (!requiredType.isInterface() && !Modifier.isAbstract(requiredType.getModifiers()) &&
|
||||
Modifier.isPublic(requiredType.getModifiers()) && ClassUtils.hasConstructor(requiredType));
|
||||
}
|
||||
|
||||
+9
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.beans.factory.access.el;
|
||||
|
||||
import java.beans.FeatureDescriptor;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.el.ELContext;
|
||||
import javax.el.ELException;
|
||||
import javax.el.ELResolver;
|
||||
@@ -78,8 +77,14 @@ public abstract class SpringBeanELResolver extends ELResolver {
|
||||
String beanName = property.toString();
|
||||
BeanFactory bf = getBeanFactory(elContext);
|
||||
if (bf.containsBean(beanName)) {
|
||||
throw new PropertyNotWritableException(
|
||||
"Variable '" + beanName + "' refers to a Spring bean which by definition is not writable");
|
||||
if (value == bf.getBean(beanName)) {
|
||||
// Setting the bean reference to the same value is alright - can simply be ignored...
|
||||
elContext.setPropertyResolved(true);
|
||||
}
|
||||
else {
|
||||
throw new PropertyNotWritableException(
|
||||
"Variable '" + beanName + "' refers to a Spring bean which by definition is not writable");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -135,9 +135,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
public AutowiredAnnotationBeanPostProcessor() {
|
||||
this.autowiredAnnotationTypes.add(Autowired.class);
|
||||
this.autowiredAnnotationTypes.add(Value.class);
|
||||
ClassLoader cl = AutowiredAnnotationBeanPostProcessor.class.getClassLoader();
|
||||
try {
|
||||
this.autowiredAnnotationTypes.add((Class<? extends Annotation>) cl.loadClass("javax.inject.Inject"));
|
||||
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
|
||||
logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -265,10 +265,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
if (requiredConstructor == null && defaultConstructor != null) {
|
||||
candidates.add(defaultConstructor);
|
||||
}
|
||||
candidateConstructors = candidates.toArray(new Constructor[candidates.size()]);
|
||||
candidateConstructors = candidates.toArray(new Constructor<?>[candidates.size()]);
|
||||
}
|
||||
else {
|
||||
candidateConstructors = new Constructor[0];
|
||||
candidateConstructors = new Constructor<?>[0];
|
||||
}
|
||||
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
|
||||
}
|
||||
@@ -314,10 +314,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
// 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) {
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
synchronized (this.injectionMetadataCache) {
|
||||
metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
if (metadata == null) {
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
metadata = buildAutowiringMetadata(clazz);
|
||||
this.injectionMetadataCache.put(cacheKey, metadata);
|
||||
}
|
||||
|
||||
+5
@@ -90,6 +90,11 @@ public class InjectionMetadata {
|
||||
}
|
||||
|
||||
|
||||
public static boolean needsRefresh(InjectionMetadata metadata, Class<?> clazz) {
|
||||
return (metadata == null || !metadata.targetClass.equals(clazz));
|
||||
}
|
||||
|
||||
|
||||
public static abstract class InjectedElement {
|
||||
|
||||
protected final Member member;
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -71,9 +71,9 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
||||
@SuppressWarnings("unchecked")
|
||||
public QualifierAnnotationAutowireCandidateResolver() {
|
||||
this.qualifierTypes.add(Qualifier.class);
|
||||
ClassLoader cl = QualifierAnnotationAutowireCandidateResolver.class.getClassLoader();
|
||||
try {
|
||||
this.qualifierTypes.add((Class<? extends Annotation>) cl.loadClass("javax.inject.Qualifier"));
|
||||
this.qualifierTypes.add((Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.inject.Qualifier", QualifierAnnotationAutowireCandidateResolver.class.getClassLoader()));
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - simply skip.
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -206,7 +206,7 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
|
||||
visitor.visitBeanDefinition(bd);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage());
|
||||
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,8 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.core.Constants;
|
||||
import org.springframework.core.SpringProperties;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.util.PropertyPlaceholderHelper;
|
||||
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
@@ -82,7 +84,8 @@ public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport
|
||||
|
||||
private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK;
|
||||
|
||||
private boolean searchSystemEnvironment = true;
|
||||
private boolean searchSystemEnvironment =
|
||||
!SpringProperties.getFlag(AbstractEnvironment.IGNORE_GETENV_PROPERTY_NAME);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -1373,7 +1373,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
MutablePropertyValues mpvs = null;
|
||||
List<PropertyValue> original;
|
||||
|
||||
if (System.getSecurityManager()!= null) {
|
||||
if (System.getSecurityManager() != null) {
|
||||
if (bw instanceof BeanWrapperImpl) {
|
||||
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
|
||||
}
|
||||
@@ -1666,7 +1666,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
|
||||
|
||||
/**
|
||||
* Special DependencyDescriptor variant for autowire="byType".
|
||||
* Special DependencyDescriptor variant for Spring's good old autowire="byType" mode.
|
||||
* Always optional; never considering the parameter name for choosing a primary candidate.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
+20
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,8 +38,8 @@ import org.springframework.util.StringUtils;
|
||||
/**
|
||||
* Base class for concrete, full-fledged
|
||||
* {@link org.springframework.beans.factory.config.BeanDefinition} classes,
|
||||
* factoring out common properties of {@link RootBeanDefinition} and
|
||||
* {@link ChildBeanDefinition}.
|
||||
* factoring out common properties of {@link GenericBeanDefinition},
|
||||
* {@link RootBeanDefinition} and {@link ChildBeanDefinition}.
|
||||
*
|
||||
* <p>The autowire constants match the ones defined in the
|
||||
* {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory}
|
||||
@@ -123,11 +123,14 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
public static final int DEPENDENCY_CHECK_ALL = 3;
|
||||
|
||||
/**
|
||||
* Constant that indicates the container should attempt to infer the {@link
|
||||
* #setDestroyMethodName destroy method name} for a bean as opposed to explicit
|
||||
* specification of a method name. The value {@value} is specifically designed to
|
||||
* include characters otherwise illegal in a method name, ensuring no possibility of
|
||||
* collisions with legitimately named methods having the same name.
|
||||
* Constant that indicates the container should attempt to infer the
|
||||
* {@link #setDestroyMethodName destroy method name} for a bean as opposed to
|
||||
* explicit specification of a method name. The value {@value} is specifically
|
||||
* designed to include characters otherwise illegal in a method name, ensuring
|
||||
* no possibility of collisions with legitimately named methods having the same
|
||||
* name.
|
||||
* <p>Currently, the method names detected during destroy method inference
|
||||
* are "close" and "shutdown", if present on the specific bean class.
|
||||
*/
|
||||
public static final String INFER_METHOD = "(inferred)";
|
||||
|
||||
@@ -383,7 +386,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
throw new IllegalStateException(
|
||||
"Bean class name [" + beanClassObject + "] has not been resolved into an actual Class");
|
||||
}
|
||||
return (Class) beanClassObject;
|
||||
return (Class<?>) beanClassObject;
|
||||
}
|
||||
|
||||
public void setBeanClassName(String beanClassName) {
|
||||
@@ -393,7 +396,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
public String getBeanClassName() {
|
||||
Object beanClassObject = this.beanClass;
|
||||
if (beanClassObject instanceof Class) {
|
||||
return ((Class) beanClassObject).getName();
|
||||
return ((Class<?>) beanClassObject).getName();
|
||||
}
|
||||
else {
|
||||
return (String) beanClassObject;
|
||||
@@ -408,12 +411,12 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
* @return the resolved bean class
|
||||
* @throws ClassNotFoundException if the class name could be resolved
|
||||
*/
|
||||
public Class resolveBeanClass(ClassLoader classLoader) throws ClassNotFoundException {
|
||||
public Class<?> resolveBeanClass(ClassLoader classLoader) throws ClassNotFoundException {
|
||||
String className = getBeanClassName();
|
||||
if (className == null) {
|
||||
return null;
|
||||
}
|
||||
Class resolvedClass = ClassUtils.forName(className, classLoader);
|
||||
Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
|
||||
this.beanClass = resolvedClass;
|
||||
return resolvedClass;
|
||||
}
|
||||
@@ -551,8 +554,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
// Work out whether to apply setter autowiring or constructor autowiring.
|
||||
// If it has a no-arg constructor it's deemed to be setter autowiring,
|
||||
// otherwise we'll try constructor autowiring.
|
||||
Constructor[] constructors = getBeanClass().getConstructors();
|
||||
for (Constructor constructor : constructors) {
|
||||
Constructor<?>[] constructors = getBeanClass().getConstructors();
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
if (constructor.getParameterTypes().length == 0) {
|
||||
return AUTOWIRE_BY_TYPE;
|
||||
}
|
||||
@@ -677,7 +680,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
|
||||
/**
|
||||
* Specify whether to allow access to non-public constructors and methods,
|
||||
* for the case of externalized metadata pointing to those.
|
||||
* for the case of externalized metadata pointing to those. The default is
|
||||
* {@code true}; switch this to {@code false} for public access only.
|
||||
* <p>This applies to constructor resolution, factory method resolution,
|
||||
* and also init/destroy methods. Bean property accessors have to be public
|
||||
* in any case and are not affected by this setting.
|
||||
@@ -699,7 +703,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
/**
|
||||
* Specify whether to resolve constructors in lenient mode ({@code true},
|
||||
* which is the default) or to switch to strict resolution (throwing an exception
|
||||
* in case of ambigious constructors that all match when converting the arguments,
|
||||
* in case of ambiguous constructors that all match when converting the arguments,
|
||||
* whereas lenient mode would use the one with the 'closest' type matches).
|
||||
*/
|
||||
public void setLenientConstructorResolution(boolean lenientConstructorResolution) {
|
||||
|
||||
+18
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -81,6 +81,7 @@ class BeanDefinitionValueResolver {
|
||||
this.typeConverter = typeConverter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given a PropertyValue, return a value, resolving any references to other
|
||||
* beans in the factory if necessary. The value could be:
|
||||
@@ -123,7 +124,9 @@ class BeanDefinitionValueResolver {
|
||||
else if (value instanceof BeanDefinition) {
|
||||
// Resolve plain BeanDefinition, without contained name: use dummy name.
|
||||
BeanDefinition bd = (BeanDefinition) value;
|
||||
return resolveInnerBean(argName, "(inner bean)", bd);
|
||||
String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
|
||||
ObjectUtils.getIdentityHexString(bd);
|
||||
return resolveInnerBean(argName, innerBeanName, bd);
|
||||
}
|
||||
else if (value instanceof ManagedArray) {
|
||||
// May need to resolve contained runtime references.
|
||||
@@ -164,7 +167,7 @@ class BeanDefinitionValueResolver {
|
||||
else if (value instanceof ManagedProperties) {
|
||||
Properties original = (Properties) value;
|
||||
Properties copy = new Properties();
|
||||
for (Map.Entry propEntry : original.entrySet()) {
|
||||
for (Map.Entry<Object, Object> propEntry : original.entrySet()) {
|
||||
Object propKey = propEntry.getKey();
|
||||
Object propValue = propEntry.getValue();
|
||||
if (propKey instanceof TypedStringValue) {
|
||||
@@ -256,20 +259,25 @@ class BeanDefinitionValueResolver {
|
||||
mbd = this.beanFactory.getMergedBeanDefinition(innerBeanName, innerBd, this.beanDefinition);
|
||||
// Check given bean name whether it is unique. If not already unique,
|
||||
// add counter - increasing the counter until the name is unique.
|
||||
String actualInnerBeanName = adaptInnerBeanName(innerBeanName);
|
||||
String actualInnerBeanName = innerBeanName;
|
||||
if (mbd.isSingleton()) {
|
||||
actualInnerBeanName = adaptInnerBeanName(innerBeanName);
|
||||
}
|
||||
this.beanFactory.registerContainedBean(actualInnerBeanName, this.beanName);
|
||||
// Guarantee initialization of beans that the inner bean depends on.
|
||||
String[] dependsOn = mbd.getDependsOn();
|
||||
if (dependsOn != null) {
|
||||
for (String dependsOnBean : dependsOn) {
|
||||
this.beanFactory.getBean(dependsOnBean);
|
||||
this.beanFactory.registerDependentBean(dependsOnBean, actualInnerBeanName);
|
||||
this.beanFactory.getBean(dependsOnBean);
|
||||
}
|
||||
}
|
||||
// Actually create the inner bean instance now...
|
||||
Object innerBean = this.beanFactory.createBean(actualInnerBeanName, mbd, null);
|
||||
if (innerBean instanceof FactoryBean) {
|
||||
boolean synthetic = mbd.isSynthetic();
|
||||
return this.beanFactory.getObjectFromFactoryBean((FactoryBean) innerBean, actualInnerBeanName, !synthetic);
|
||||
return this.beanFactory.getObjectFromFactoryBean(
|
||||
(FactoryBean<?>) innerBean, actualInnerBeanName, !synthetic);
|
||||
}
|
||||
else {
|
||||
return innerBean;
|
||||
@@ -344,7 +352,7 @@ class BeanDefinitionValueResolver {
|
||||
/**
|
||||
* For each element in the managed list, resolve reference if necessary.
|
||||
*/
|
||||
private List resolveManagedList(Object argName, List<?> ml) {
|
||||
private List<?> resolveManagedList(Object argName, List<?> ml) {
|
||||
List<Object> resolved = new ArrayList<Object>(ml.size());
|
||||
for (int i = 0; i < ml.size(); i++) {
|
||||
resolved.add(
|
||||
@@ -356,7 +364,7 @@ class BeanDefinitionValueResolver {
|
||||
/**
|
||||
* For each element in the managed set, resolve reference if necessary.
|
||||
*/
|
||||
private Set resolveManagedSet(Object argName, Set<?> ms) {
|
||||
private Set<?> resolveManagedSet(Object argName, Set<?> ms) {
|
||||
Set<Object> resolved = new LinkedHashSet<Object>(ms.size());
|
||||
int i = 0;
|
||||
for (Object m : ms) {
|
||||
@@ -369,9 +377,9 @@ class BeanDefinitionValueResolver {
|
||||
/**
|
||||
* For each element in the managed map, resolve reference if necessary.
|
||||
*/
|
||||
private Map resolveManagedMap(Object argName, Map<?, ?> mm) {
|
||||
private Map<?, ?> resolveManagedMap(Object argName, Map<?, ?> mm) {
|
||||
Map<Object, Object> resolved = new LinkedHashMap<Object, Object>(mm.size());
|
||||
for (Map.Entry entry : mm.entrySet()) {
|
||||
for (Map.Entry<?, ?> entry : mm.entrySet()) {
|
||||
Object resolvedKey = resolveValueIfNecessary(argName, entry.getKey());
|
||||
Object resolvedValue = resolveValueIfNecessary(
|
||||
new KeyedArgName(argName, entry.getKey()), entry.getValue());
|
||||
|
||||
+6
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,7 +23,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
|
||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.CallbackFilter;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
@@ -72,7 +72,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
@Override
|
||||
protected Object instantiateWithMethodInjection(
|
||||
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||
Constructor ctor, Object[] args) {
|
||||
Constructor<?> ctor, Object[] args) {
|
||||
|
||||
return new CglibSubclassCreator(beanDefinition, owner).instantiate(ctor, args);
|
||||
}
|
||||
@@ -104,9 +104,10 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
* Ignored if the ctor parameter is {@code null}.
|
||||
* @return new instance of the dynamically generated class
|
||||
*/
|
||||
public Object instantiate(Constructor ctor, Object[] args) {
|
||||
public Object instantiate(Constructor<?> ctor, Object[] args) {
|
||||
Enhancer enhancer = new Enhancer();
|
||||
enhancer.setSuperclass(this.beanDefinition.getBeanClass());
|
||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||
enhancer.setCallbackFilter(new CallbackFilterImpl());
|
||||
enhancer.setCallbacks(new Callback[] {
|
||||
NoOp.INSTANCE,
|
||||
@@ -114,9 +115,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
new ReplaceOverrideMethodInterceptor()
|
||||
});
|
||||
|
||||
return (ctor == null) ?
|
||||
enhancer.create() :
|
||||
enhancer.create(ctor.getParameterTypes(), args);
|
||||
return (ctor != null ? enhancer.create(ctor.getParameterTypes(), args) : enhancer.create());
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@
|
||||
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;
|
||||
|
||||
@@ -127,7 +128,7 @@ public class ChildBeanDefinition extends AbstractBeanDefinition {
|
||||
* @param original the original bean definition to copy from
|
||||
*/
|
||||
public ChildBeanDefinition(ChildBeanDefinition original) {
|
||||
super(original);
|
||||
super((BeanDefinition) original);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+60
-46
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,12 +54,9 @@ import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Helper class for resolving constructors and factory methods.
|
||||
* Delegate for resolving constructors and factory methods.
|
||||
* Performs constructor resolution through argument matching.
|
||||
*
|
||||
* <p>Operates on an {@link AbstractBeanFactory} and an {@link InstantiationStrategy}.
|
||||
* Used by {@link AbstractAutowireCapableBeanFactory}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Mark Fisher
|
||||
@@ -103,12 +100,12 @@ class ConstructorResolver {
|
||||
* @return a BeanWrapper for the new instance
|
||||
*/
|
||||
public BeanWrapper autowireConstructor(
|
||||
final String beanName, final RootBeanDefinition mbd, Constructor[] chosenCtors, final Object[] explicitArgs) {
|
||||
final String beanName, final RootBeanDefinition mbd, Constructor<?>[] chosenCtors, final Object[] explicitArgs) {
|
||||
|
||||
BeanWrapperImpl bw = new BeanWrapperImpl();
|
||||
this.beanFactory.initBeanWrapper(bw);
|
||||
|
||||
Constructor constructorToUse = null;
|
||||
Constructor<?> constructorToUse = null;
|
||||
ArgumentsHolder argsHolderToUse = null;
|
||||
Object[] argsToUse = null;
|
||||
|
||||
@@ -118,7 +115,7 @@ class ConstructorResolver {
|
||||
else {
|
||||
Object[] argsToResolve = null;
|
||||
synchronized (mbd.constructorArgumentLock) {
|
||||
constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
|
||||
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
|
||||
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
|
||||
// Found a cached constructor...
|
||||
argsToUse = mbd.resolvedConstructorArguments;
|
||||
@@ -149,7 +146,7 @@ class ConstructorResolver {
|
||||
}
|
||||
|
||||
// Take specified constructors, if any.
|
||||
Constructor[] candidates = chosenCtors;
|
||||
Constructor<?>[] candidates = chosenCtors;
|
||||
if (candidates == null) {
|
||||
Class<?> beanClass = mbd.getBeanClass();
|
||||
try {
|
||||
@@ -164,7 +161,7 @@ class ConstructorResolver {
|
||||
}
|
||||
AutowireUtils.sortConstructors(candidates);
|
||||
int minTypeDiffWeight = Integer.MAX_VALUE;
|
||||
Set<Constructor> ambiguousConstructors = null;
|
||||
Set<Constructor<?>> ambiguousConstructors = null;
|
||||
List<Exception> causes = null;
|
||||
|
||||
for (int i = 0; i < candidates.length; i++) {
|
||||
@@ -185,7 +182,7 @@ class ConstructorResolver {
|
||||
try {
|
||||
String[] paramNames = null;
|
||||
if (constructorPropertiesAnnotationAvailable) {
|
||||
paramNames = ConstructorPropertiesChecker.evaluateAnnotation(candidate, paramTypes.length);
|
||||
paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
|
||||
}
|
||||
if (paramNames == null) {
|
||||
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
|
||||
@@ -239,7 +236,7 @@ class ConstructorResolver {
|
||||
}
|
||||
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
|
||||
if (ambiguousConstructors == null) {
|
||||
ambiguousConstructors = new LinkedHashSet<Constructor>();
|
||||
ambiguousConstructors = new LinkedHashSet<Constructor<?>>();
|
||||
ambiguousConstructors.add(constructorToUse);
|
||||
}
|
||||
ambiguousConstructors.add(candidate);
|
||||
@@ -267,7 +264,7 @@ class ConstructorResolver {
|
||||
Object beanInstance;
|
||||
|
||||
if (System.getSecurityManager() != null) {
|
||||
final Constructor ctorToUse = constructorToUse;
|
||||
final Constructor<?> ctorToUse = constructorToUse;
|
||||
final Object[] argumentsToUse = argsToUse;
|
||||
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
public Object run() {
|
||||
@@ -295,18 +292,22 @@ class ConstructorResolver {
|
||||
* @param mbd the bean definition to check
|
||||
*/
|
||||
public void resolveFactoryMethodIfPossible(RootBeanDefinition mbd) {
|
||||
Class factoryClass;
|
||||
Class<?> factoryClass;
|
||||
boolean isStatic;
|
||||
if (mbd.getFactoryBeanName() != null) {
|
||||
factoryClass = this.beanFactory.getType(mbd.getFactoryBeanName());
|
||||
isStatic = false;
|
||||
}
|
||||
else {
|
||||
factoryClass = mbd.getBeanClass();
|
||||
isStatic = true;
|
||||
}
|
||||
factoryClass = ClassUtils.getUserClass(factoryClass);
|
||||
Method[] candidates = ReflectionUtils.getAllDeclaredMethods(factoryClass);
|
||||
|
||||
Method[] candidates = getCandidateMethods(factoryClass, mbd);
|
||||
Method uniqueCandidate = null;
|
||||
for (Method candidate : candidates) {
|
||||
if (mbd.isFactoryMethod(candidate)) {
|
||||
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
|
||||
if (uniqueCandidate == null) {
|
||||
uniqueCandidate = candidate;
|
||||
}
|
||||
@@ -321,6 +322,27 @@ class ConstructorResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all candidate methods for the given class, considering
|
||||
* the {@link RootBeanDefinition#isNonPublicAccessAllowed()} flag.
|
||||
* Called as the starting point for factory method determination.
|
||||
*/
|
||||
private Method[] getCandidateMethods(final Class<?> factoryClass, final RootBeanDefinition mbd) {
|
||||
if (System.getSecurityManager() != null) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
|
||||
@Override
|
||||
public Method[] run() {
|
||||
return (mbd.isNonPublicAccessAllowed() ?
|
||||
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
return (mbd.isNonPublicAccessAllowed() ?
|
||||
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the bean using a named factory method. The method may be static, if the
|
||||
* bean definition parameter specifies a class, rather than a "factory-bean", or
|
||||
@@ -336,7 +358,9 @@ class ConstructorResolver {
|
||||
* method, or {@code null} if none (-> use constructor argument values from bean definition)
|
||||
* @return a BeanWrapper for the new instance
|
||||
*/
|
||||
public BeanWrapper instantiateUsingFactoryMethod(final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
|
||||
public BeanWrapper instantiateUsingFactoryMethod(
|
||||
final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
|
||||
|
||||
BeanWrapperImpl bw = new BeanWrapperImpl();
|
||||
this.beanFactory.initBeanWrapper(bw);
|
||||
|
||||
@@ -397,27 +421,11 @@ class ConstructorResolver {
|
||||
// Need to determine the factory method...
|
||||
// Try all methods with this name to see if they match the given arguments.
|
||||
factoryClass = ClassUtils.getUserClass(factoryClass);
|
||||
Method[] rawCandidates;
|
||||
|
||||
final Class<?> factoryClazz = factoryClass;
|
||||
if (System.getSecurityManager() != null) {
|
||||
rawCandidates = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
|
||||
public Method[] run() {
|
||||
return (mbd.isNonPublicAccessAllowed() ?
|
||||
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
rawCandidates = (mbd.isNonPublicAccessAllowed() ?
|
||||
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
|
||||
}
|
||||
|
||||
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
|
||||
List<Method> candidateSet = new ArrayList<Method>();
|
||||
for (Method candidate : rawCandidates) {
|
||||
if (Modifier.isStatic(candidate.getModifiers()) == isStatic &&
|
||||
candidate.getName().equals(mbd.getFactoryMethodName()) &&
|
||||
mbd.isFactoryMethod(candidate)) {
|
||||
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
|
||||
candidateSet.add(candidate);
|
||||
}
|
||||
}
|
||||
@@ -522,24 +530,30 @@ class ConstructorResolver {
|
||||
}
|
||||
|
||||
if (factoryMethodToUse == null) {
|
||||
boolean hasArgs = (resolvedValues.getArgumentCount() > 0);
|
||||
String argDesc = "";
|
||||
if (hasArgs) {
|
||||
List<String> argTypes = new ArrayList<String>();
|
||||
for (ValueHolder value : resolvedValues.getIndexedArgumentValues().values()) {
|
||||
String argType = (value.getType() != null ?
|
||||
ClassUtils.getShortName(value.getType()) : value.getValue().getClass().getSimpleName());
|
||||
List<String> argTypes = new ArrayList<String>(minNrOfArgs);
|
||||
if (explicitArgs != null) {
|
||||
for (Object arg : explicitArgs) {
|
||||
argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
|
||||
}
|
||||
}
|
||||
else {
|
||||
Set<ValueHolder> valueHolders = new LinkedHashSet<ValueHolder>(resolvedValues.getArgumentCount());
|
||||
valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
|
||||
valueHolders.addAll(resolvedValues.getGenericArgumentValues());
|
||||
for (ValueHolder value : valueHolders) {
|
||||
String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
|
||||
(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
|
||||
argTypes.add(argType);
|
||||
}
|
||||
argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
|
||||
}
|
||||
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"No matching factory method found: " +
|
||||
(mbd.getFactoryBeanName() != null ?
|
||||
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
|
||||
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
|
||||
"Check that a method with the specified name " +
|
||||
(hasArgs ? "and arguments " : "") +
|
||||
(minNrOfArgs > 0 ? "and arguments " : "") +
|
||||
"exists and that it is " +
|
||||
(isStatic ? "static" : "non-static") + ".");
|
||||
}
|
||||
@@ -759,7 +773,7 @@ class ConstructorResolver {
|
||||
String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) {
|
||||
|
||||
Class<?>[] paramTypes = (methodOrCtor instanceof Method ?
|
||||
((Method) methodOrCtor).getParameterTypes() : ((Constructor) methodOrCtor).getParameterTypes());
|
||||
((Method) methodOrCtor).getParameterTypes() : ((Constructor<?>) methodOrCtor).getParameterTypes());
|
||||
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
|
||||
this.beanFactory.getCustomTypeConverter() : bw);
|
||||
BeanDefinitionValueResolver valueResolver =
|
||||
@@ -881,7 +895,7 @@ class ConstructorResolver {
|
||||
*/
|
||||
private static class ConstructorPropertiesChecker {
|
||||
|
||||
public static String[] evaluateAnnotation(Constructor<?> candidate, int paramCount) {
|
||||
public static String[] evaluate(Constructor<?> candidate, int paramCount) {
|
||||
ConstructorProperties cp = candidate.getAnnotation(ConstructorProperties.class);
|
||||
if (cp != null) {
|
||||
String[] names = cp.value();
|
||||
|
||||
+11
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,6 +59,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -102,9 +103,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
private static Class<?> javaxInjectProviderClass = null;
|
||||
|
||||
static {
|
||||
ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
|
||||
try {
|
||||
javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");
|
||||
javaxInjectProviderClass =
|
||||
ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JSR-330 API not available - Provider interface simply not supported then.
|
||||
@@ -322,7 +323,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
|
||||
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
|
||||
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
|
||||
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
|
||||
return doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
|
||||
}
|
||||
Map<Class<?>, String[]> cache =
|
||||
@@ -332,7 +333,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
return resolvedBeanNames;
|
||||
}
|
||||
resolvedBeanNames = doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
|
||||
cache.put(type, resolvedBeanNames);
|
||||
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
|
||||
cache.put(type, resolvedBeanNames);
|
||||
}
|
||||
return resolvedBeanNames;
|
||||
}
|
||||
|
||||
@@ -480,7 +483,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
* found on the given class itself, as well as checking its raw bean class
|
||||
* if not found on the exposed bean reference (e.g. in case of a proxy).
|
||||
*/
|
||||
public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) {
|
||||
public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
|
||||
throws NoSuchBeanDefinitionException{
|
||||
|
||||
A ann = null;
|
||||
Class<?> beanType = getType(beanName);
|
||||
if (beanType != null) {
|
||||
|
||||
+7
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -65,11 +65,12 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DisposableBeanAdapter.class);
|
||||
|
||||
private static Class closeableInterface;
|
||||
private static Class<?> closeableInterface;
|
||||
|
||||
static {
|
||||
try {
|
||||
closeableInterface = DisposableBeanAdapter.class.getClassLoader().loadClass("java.lang.AutoCloseable");
|
||||
closeableInterface = ClassUtils.forName("java.lang.AutoCloseable",
|
||||
DisposableBeanAdapter.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
closeableInterface = Closeable.class;
|
||||
@@ -85,14 +86,14 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
|
||||
private final boolean nonPublicAccessAllowed;
|
||||
|
||||
private final AccessControlContext acc;
|
||||
|
||||
private String destroyMethodName;
|
||||
|
||||
private transient Method destroyMethod;
|
||||
|
||||
private List<DestructionAwareBeanPostProcessor> beanPostProcessors;
|
||||
|
||||
private final AccessControlContext acc;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new DisposableBeanAdapter for the given bean.
|
||||
@@ -149,9 +150,9 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
this.beanName = beanName;
|
||||
this.invokeDisposableBean = invokeDisposableBean;
|
||||
this.nonPublicAccessAllowed = nonPublicAccessAllowed;
|
||||
this.acc = null;
|
||||
this.destroyMethodName = destroyMethodName;
|
||||
this.beanPostProcessors = postProcessors;
|
||||
this.acc = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -87,7 +87,12 @@ public class GenericBeanDefinition extends AbstractBeanDefinition {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Generic bean: " + super.toString();
|
||||
StringBuilder sb = new StringBuilder("Generic bean");
|
||||
if (this.parentName != null) {
|
||||
sb.append(" with parent '").append(this.parentName).append("'");
|
||||
}
|
||||
sb.append(": ").append(super.toString());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,14 +23,15 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Object representing the override of a method on a managed
|
||||
* object by the IoC container.
|
||||
* Object representing the override of a method on a managed object by the IoC
|
||||
* container.
|
||||
*
|
||||
* <p>Note that the override mechanism is <i>not</i> intended as a
|
||||
* generic means of inserting crosscutting code: use AOP for that.
|
||||
* <p>Note that the override mechanism is <em>not</em> intended as a generic
|
||||
* means of inserting crosscutting code: use AOP for that.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 1.1
|
||||
*/
|
||||
public abstract class MethodOverride implements BeanMetadataElement {
|
||||
@@ -59,17 +60,18 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the overridden method has to be considered as overloaded
|
||||
* (that is, whether arg type matching has to happen).
|
||||
* <p>Default is "true"; can be switched to "false" to optimize runtime performance.
|
||||
* Set whether the overridden method is <em>overloaded</em> (i.e., whether argument
|
||||
* type matching needs to occur to disambiguate methods of the same name).
|
||||
* <p>Default is {@code true}; can be switched to {@code false} to optimize
|
||||
* runtime performance.
|
||||
*/
|
||||
protected void setOverloaded(boolean overloaded) {
|
||||
this.overloaded = overloaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the overridden method has to be considered as overloaded
|
||||
* (that is, whether arg type matching has to happen).
|
||||
* Return whether the overridden method is <em>overloaded</em> (i.e., whether argument
|
||||
* type matching needs to occur to disambiguate methods of the same name).
|
||||
*/
|
||||
protected boolean isOverloaded() {
|
||||
return this.overloaded;
|
||||
@@ -87,17 +89,15 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses must override this to indicate whether they match
|
||||
* the given method. This allows for argument list checking
|
||||
* as well as method name checking.
|
||||
* Subclasses must override this to indicate whether they <em>match</em> the
|
||||
* given method. This allows for argument list checking as well as method
|
||||
* name checking.
|
||||
* @param method the method to check
|
||||
* @return whether this override matches the given method
|
||||
*/
|
||||
public abstract boolean matches(Method method);
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
@@ -108,7 +108,6 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
}
|
||||
MethodOverride that = (MethodOverride) other;
|
||||
return (ObjectUtils.nullSafeEquals(this.methodName, that.methodName) &&
|
||||
this.overloaded == that.overloaded &&
|
||||
ObjectUtils.nullSafeEquals(this.source, that.source));
|
||||
}
|
||||
|
||||
@@ -116,7 +115,6 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
public int hashCode() {
|
||||
int hashCode = ObjectUtils.nullSafeHashCode(this.methodName);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.source);
|
||||
hashCode = 29 * hashCode + (this.overloaded ? 1 : 0);
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
|
||||
+55
-29
@@ -18,8 +18,8 @@ package org.springframework.beans.factory.support;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -48,19 +48,10 @@ import org.springframework.util.Assert;
|
||||
@SuppressWarnings("serial")
|
||||
public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
|
||||
// using a ConcurrentHashMap as a Set
|
||||
private final Map<Member, Boolean> externallyManagedConfigMembers = new ConcurrentHashMap<Member, Boolean>(0);
|
||||
|
||||
// using a ConcurrentHashMap as a Set
|
||||
private final Map<String, Boolean> externallyManagedInitMethods = new ConcurrentHashMap<String, Boolean>(0);
|
||||
|
||||
// using a ConcurrentHashMap as a Set
|
||||
private final Map<String, Boolean> externallyManagedDestroyMethods = new ConcurrentHashMap<String, Boolean>(0);
|
||||
boolean allowCaching = true;
|
||||
|
||||
private BeanDefinitionHolder decoratedDefinition;
|
||||
|
||||
boolean allowCaching = true;
|
||||
|
||||
private volatile Class<?> targetType;
|
||||
|
||||
boolean isFactoryMethodUnique = false;
|
||||
@@ -87,6 +78,12 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
/** Package-visible field that indicates a before-instantiation post-processor having kicked in */
|
||||
volatile Boolean beforeInstantiationResolved;
|
||||
|
||||
private Set<Member> externallyManagedConfigMembers;
|
||||
|
||||
private Set<String> externallyManagedInitMethods;
|
||||
|
||||
private Set<String> externallyManagedDestroyMethods;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new RootBeanDefinition, to be configured through its bean
|
||||
@@ -225,9 +222,9 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
* @param original the original bean definition to copy from
|
||||
*/
|
||||
public RootBeanDefinition(RootBeanDefinition original) {
|
||||
super(original);
|
||||
this.decoratedDefinition = original.decoratedDefinition;
|
||||
super((BeanDefinition) original);
|
||||
this.allowCaching = original.allowCaching;
|
||||
this.decoratedDefinition = original.decoratedDefinition;
|
||||
this.targetType = original.targetType;
|
||||
this.isFactoryMethodUnique = original.isFactoryMethodUnique;
|
||||
}
|
||||
@@ -252,6 +249,20 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a target definition that is being decorated by this bean definition.
|
||||
*/
|
||||
public void setDecoratedDefinition(BeanDefinitionHolder decoratedDefinition) {
|
||||
this.decoratedDefinition = decoratedDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the target definition that is being decorated by this bean definition, if any.
|
||||
*/
|
||||
public BeanDefinitionHolder getDecoratedDefinition() {
|
||||
return this.decoratedDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the target type of this bean definition, if known in advance.
|
||||
*/
|
||||
@@ -294,37 +305,52 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void registerExternallyManagedConfigMember(Member configMember) {
|
||||
this.externallyManagedConfigMembers.put(configMember, Boolean.TRUE);
|
||||
synchronized (this.postProcessingLock) {
|
||||
if (this.externallyManagedConfigMembers == null) {
|
||||
this.externallyManagedConfigMembers = new HashSet<Member>(1);
|
||||
}
|
||||
this.externallyManagedConfigMembers.add(configMember);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExternallyManagedConfigMember(Member configMember) {
|
||||
return this.externallyManagedConfigMembers.containsKey(configMember);
|
||||
synchronized (this.postProcessingLock) {
|
||||
return (this.externallyManagedConfigMembers != null &&
|
||||
this.externallyManagedConfigMembers.contains(configMember));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerExternallyManagedInitMethod(String initMethod) {
|
||||
this.externallyManagedInitMethods.put(initMethod, Boolean.TRUE);
|
||||
synchronized (this.postProcessingLock) {
|
||||
if (this.externallyManagedInitMethods == null) {
|
||||
this.externallyManagedInitMethods = new HashSet<String>(1);
|
||||
}
|
||||
this.externallyManagedInitMethods.add(initMethod);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExternallyManagedInitMethod(String initMethod) {
|
||||
return this.externallyManagedInitMethods.containsKey(initMethod);
|
||||
synchronized (this.postProcessingLock) {
|
||||
return (this.externallyManagedInitMethods != null &&
|
||||
this.externallyManagedInitMethods.contains(initMethod));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerExternallyManagedDestroyMethod(String destroyMethod) {
|
||||
this.externallyManagedDestroyMethods.put(destroyMethod, Boolean.TRUE);
|
||||
synchronized (this.postProcessingLock) {
|
||||
if (this.externallyManagedDestroyMethods == null) {
|
||||
this.externallyManagedDestroyMethods = new HashSet<String>(1);
|
||||
}
|
||||
this.externallyManagedDestroyMethods.add(destroyMethod);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExternallyManagedDestroyMethod(String destroyMethod) {
|
||||
return this.externallyManagedDestroyMethods.containsKey(destroyMethod);
|
||||
}
|
||||
|
||||
public void setDecoratedDefinition(BeanDefinitionHolder decoratedDefinition) {
|
||||
this.decoratedDefinition = decoratedDefinition;
|
||||
}
|
||||
|
||||
public BeanDefinitionHolder getDecoratedDefinition() {
|
||||
return this.decoratedDefinition;
|
||||
synchronized (this.postProcessingLock) {
|
||||
return (this.externallyManagedDestroyMethods != null &&
|
||||
this.externallyManagedDestroyMethods.contains(destroyMethod));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -62,14 +62,14 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||
synchronized (beanDefinition.constructorArgumentLock) {
|
||||
constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
|
||||
if (constructorToUse == null) {
|
||||
final Class clazz = beanDefinition.getBeanClass();
|
||||
final Class<?> clazz = beanDefinition.getBeanClass();
|
||||
if (clazz.isInterface()) {
|
||||
throw new BeanInstantiationException(clazz, "Specified class is an interface");
|
||||
}
|
||||
try {
|
||||
if (System.getSecurityManager() != null) {
|
||||
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
|
||||
public Constructor run() throws Exception {
|
||||
public Constructor<?> run() throws Exception {
|
||||
return clazz.getDeclaredConstructor((Class[]) null);
|
||||
}
|
||||
});
|
||||
@@ -132,7 +132,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||
* Instantiation should use the given constructor and parameters.
|
||||
*/
|
||||
protected Object instantiateWithMethodInjection(RootBeanDefinition beanDefinition,
|
||||
String beanName, BeanFactory owner, Constructor ctor, Object[] args) {
|
||||
String beanName, BeanFactory owner, Constructor<?> ctor, Object[] args) {
|
||||
|
||||
throw new UnsupportedOperationException(
|
||||
"Method Injection not supported in SimpleInstantiationStrategy");
|
||||
|
||||
@@ -189,9 +189,13 @@ public final class BeanUtilsTests {
|
||||
public void testCopyPropertiesWithInvalidProperty() {
|
||||
InvalidProperty source = new InvalidProperty();
|
||||
source.setName("name");
|
||||
source.setFlag1(true);
|
||||
source.setFlag2(true);
|
||||
InvalidProperty target = new InvalidProperty();
|
||||
BeanUtils.copyProperties(source, target);
|
||||
assertEquals(target.getName(), "name");
|
||||
assertTrue(target.getFlag1());
|
||||
assertTrue(target.getFlag2());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -308,6 +312,10 @@ public final class BeanUtilsTests {
|
||||
|
||||
private String value;
|
||||
|
||||
private boolean flag1;
|
||||
|
||||
private boolean flag2;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
@@ -323,6 +331,22 @@ public final class BeanUtilsTests {
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void setFlag1(boolean flag1) {
|
||||
this.flag1 = flag1;
|
||||
}
|
||||
|
||||
public Boolean getFlag1() {
|
||||
return this.flag1;
|
||||
}
|
||||
|
||||
public void setFlag2(Boolean flag2) {
|
||||
this.flag2 = flag2;
|
||||
}
|
||||
|
||||
public boolean getFlag2() {
|
||||
return this.flag2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +16,6 @@
|
||||
|
||||
package org.springframework.beans;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
@@ -44,11 +37,16 @@ import java.util.TreeSet;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.beans.propertyeditors.CustomNumberEditor;
|
||||
import org.springframework.beans.propertyeditors.StringArrayPropertyEditor;
|
||||
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
|
||||
import org.springframework.beans.support.DerivedFromProtectedBaseBean;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.tests.Assume;
|
||||
import org.springframework.tests.TestGroup;
|
||||
import org.springframework.tests.sample.beans.BooleanTestBean;
|
||||
@@ -56,18 +54,12 @@ import org.springframework.tests.sample.beans.ITestBean;
|
||||
import org.springframework.tests.sample.beans.IndexedTestBean;
|
||||
import org.springframework.tests.sample.beans.NumberTestBean;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -1557,28 +1549,55 @@ public final class BeanWrapperTests {
|
||||
@Test
|
||||
public void cornerSpr10115() {
|
||||
Spr10115Bean foo = new Spr10115Bean();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl();
|
||||
bwi.setWrappedInstance(foo);
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
|
||||
bwi.setPropertyValue("prop1", "val1");
|
||||
assertEquals("val1", Spr10115Bean.prop1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArrayToObject() throws Exception {
|
||||
public void testArrayToObject() {
|
||||
ArrayToObject foo = new ArrayToObject();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl();
|
||||
bwi.setWrappedInstance(foo);
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
|
||||
|
||||
Object[] array = new Object[] {"1","2"};
|
||||
bwi.setPropertyValue("object", array );
|
||||
bwi.setPropertyValue("object", array);
|
||||
assertThat(foo.getObject(), equalTo((Object) array));
|
||||
|
||||
array = new Object[] {"1"};
|
||||
bwi.setPropertyValue("object", array );
|
||||
bwi.setPropertyValue("object", array);
|
||||
assertThat(foo.getObject(), equalTo((Object) array));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyTypeMismatch() {
|
||||
PropertyTypeMismatch foo = new PropertyTypeMismatch();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
|
||||
bwi.setPropertyValue("object", "a String");
|
||||
assertEquals("a String", foo.value);
|
||||
assertEquals(8, bwi.getPropertyValue("object"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericArraySetter() {
|
||||
SkipReaderStub foo = new SkipReaderStub();
|
||||
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
|
||||
List<String> values = new LinkedList<String>();
|
||||
values.add("1");
|
||||
values.add("2");
|
||||
values.add("3");
|
||||
values.add("4");
|
||||
bwi.setPropertyValue("items", values);
|
||||
Object[] result = foo.items;
|
||||
assertEquals(4, result.length);
|
||||
assertEquals("1", result[0]);
|
||||
assertEquals("2", result[1]);
|
||||
assertEquals("3", result[2]);
|
||||
assertEquals("4", result[3]);
|
||||
}
|
||||
|
||||
|
||||
static class Spr10115Bean {
|
||||
|
||||
private static String prop1;
|
||||
|
||||
public static void setProp1(String prop1) {
|
||||
@@ -1963,11 +1982,10 @@ public final class BeanWrapperTests {
|
||||
}
|
||||
|
||||
|
||||
static class ArrayToObject {
|
||||
public static class ArrayToObject {
|
||||
|
||||
private Object object;
|
||||
|
||||
|
||||
public void setObject(Object object) {
|
||||
this.object = object;
|
||||
}
|
||||
@@ -1975,6 +1993,37 @@ public final class BeanWrapperTests {
|
||||
public Object getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class PropertyTypeMismatch {
|
||||
|
||||
public String value;
|
||||
|
||||
public void setObject(String object) {
|
||||
this.value = object;
|
||||
}
|
||||
|
||||
public Integer getObject() {
|
||||
return (this.value != null ? this.value.length() : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class SkipReaderStub<T> {
|
||||
|
||||
public T[] items;
|
||||
|
||||
public SkipReaderStub() {
|
||||
}
|
||||
|
||||
public SkipReaderStub(T... items) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public void setItems(T... items) {
|
||||
this.items = items;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+57
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,63 +16,95 @@
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@code equals()} and {@code hashCode()} in bean definitions.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class DefinitionMetadataEqualsHashCodeTests extends TestCase {
|
||||
@SuppressWarnings("serial")
|
||||
public class DefinitionMetadataEqualsHashCodeTests {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public void testRootBeanDefinitionEqualsAndHashCode() throws Exception {
|
||||
@Test
|
||||
public void rootBeanDefinition() {
|
||||
RootBeanDefinition master = new RootBeanDefinition(TestBean.class);
|
||||
RootBeanDefinition equal = new RootBeanDefinition(TestBean.class);
|
||||
RootBeanDefinition notEqual = new RootBeanDefinition(String.class);
|
||||
RootBeanDefinition subclass = new RootBeanDefinition(TestBean.class) {};
|
||||
RootBeanDefinition subclass = new RootBeanDefinition(TestBean.class) {
|
||||
};
|
||||
setBaseProperties(master);
|
||||
setBaseProperties(equal);
|
||||
setBaseProperties(notEqual);
|
||||
setBaseProperties(subclass);
|
||||
|
||||
assertEqualsContract(master, equal, notEqual, subclass);
|
||||
assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode());
|
||||
assertEqualsAndHashCodeContracts(master, equal, notEqual, subclass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public void testChildBeanDefinitionEqualsAndHashCode() throws Exception {
|
||||
/**
|
||||
* @since 3.2.8
|
||||
* @see <a href="https://jira.springsource.org/browse/SPR-11420">SPR-11420</a>
|
||||
*/
|
||||
@Test
|
||||
public void rootBeanDefinitionAndMethodOverridesWithDifferentOverloadedValues() {
|
||||
RootBeanDefinition master = new RootBeanDefinition(TestBean.class);
|
||||
RootBeanDefinition equal = new RootBeanDefinition(TestBean.class);
|
||||
|
||||
setBaseProperties(master);
|
||||
setBaseProperties(equal);
|
||||
|
||||
// Simulate AbstractBeanDefinition.validate() which delegates to
|
||||
// AbstractBeanDefinition.prepareMethodOverrides():
|
||||
master.getMethodOverrides().getOverrides().iterator().next().setOverloaded(false);
|
||||
// But do not simulate validation of the 'equal' bean. As a consequence, a method
|
||||
// override in 'equal' will be marked as overloaded, but the corresponding
|
||||
// override in 'master' will not. But... the bean definitions should still be
|
||||
// considered equal.
|
||||
|
||||
assertEquals("Should be equal", master, equal);
|
||||
assertEquals("Hash code for equal instances must match", master.hashCode(), equal.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void childBeanDefinition() {
|
||||
ChildBeanDefinition master = new ChildBeanDefinition("foo");
|
||||
ChildBeanDefinition equal = new ChildBeanDefinition("foo");
|
||||
ChildBeanDefinition notEqual = new ChildBeanDefinition("bar");
|
||||
ChildBeanDefinition subclass = new ChildBeanDefinition("foo"){};
|
||||
ChildBeanDefinition subclass = new ChildBeanDefinition("foo") {
|
||||
};
|
||||
setBaseProperties(master);
|
||||
setBaseProperties(equal);
|
||||
setBaseProperties(notEqual);
|
||||
setBaseProperties(subclass);
|
||||
|
||||
assertEqualsContract(master, equal, notEqual, subclass);
|
||||
assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode());
|
||||
assertEqualsAndHashCodeContracts(master, equal, notEqual, subclass);
|
||||
}
|
||||
|
||||
public void testRuntimeBeanReference() throws Exception {
|
||||
@Test
|
||||
public void runtimeBeanReference() {
|
||||
RuntimeBeanReference master = new RuntimeBeanReference("name");
|
||||
RuntimeBeanReference equal = new RuntimeBeanReference("name");
|
||||
RuntimeBeanReference notEqual = new RuntimeBeanReference("someOtherName");
|
||||
RuntimeBeanReference subclass = new RuntimeBeanReference("name"){};
|
||||
assertEqualsContract(master, equal, notEqual, subclass);
|
||||
RuntimeBeanReference subclass = new RuntimeBeanReference("name") {
|
||||
};
|
||||
assertEqualsAndHashCodeContracts(master, equal, notEqual, subclass);
|
||||
}
|
||||
|
||||
private void setBaseProperties(AbstractBeanDefinition definition) {
|
||||
definition.setAbstract(true);
|
||||
definition.setAttribute("foo", "bar");
|
||||
definition.setAutowireCandidate(false);
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
//definition.getConstructorArgumentValues().addGenericArgumentValue("foo");
|
||||
// definition.getConstructorArgumentValues().addGenericArgumentValue("foo");
|
||||
definition.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
|
||||
definition.setDependsOn(new String[]{"foo", "bar"});
|
||||
definition.setDependsOn(new String[] { "foo", "bar" });
|
||||
definition.setDestroyMethodName("destroy");
|
||||
definition.setEnforceDestroyMethod(false);
|
||||
definition.setEnforceInitMethod(true);
|
||||
@@ -89,10 +121,15 @@ public class DefinitionMetadataEqualsHashCodeTests extends TestCase {
|
||||
definition.setSource("foo");
|
||||
}
|
||||
|
||||
private void assertEqualsContract(Object master, Object equal, Object notEqual, Object subclass) {
|
||||
private void assertEqualsAndHashCodeContracts(Object master, Object equal, Object notEqual, Object subclass) {
|
||||
assertEquals("Should be equal", master, equal);
|
||||
assertFalse("Should not be equal", master.equals(notEqual));
|
||||
assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode());
|
||||
|
||||
assertNotEquals("Should not be equal", master, notEqual);
|
||||
assertNotEquals("Hash code for non-equal instances should not match", master.hashCode(), notEqual.hashCode());
|
||||
|
||||
assertEquals("Subclass should be equal", master, subclass);
|
||||
assertEquals("Hash code for subclass should match", master.hashCode(), subclass.hashCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+34
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
@@ -30,6 +29,8 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
@@ -259,6 +260,34 @@ public class FactoryMethodTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonExistingFactoryMethod() {
|
||||
DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
|
||||
reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass()));
|
||||
try {
|
||||
xbf.getBean("invalidPrototype");
|
||||
fail("Should have thrown BeanCreationException");
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
assertTrue(ex.getMessage().contains("nonExisting(TestBean)"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFactoryMethodArgumentsForNonExistingMethod() {
|
||||
DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
|
||||
reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass()));
|
||||
try {
|
||||
xbf.getBean("invalidPrototype", new TestBean());
|
||||
fail("Should have thrown BeanCreationException");
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
assertTrue(ex.getMessage().contains("nonExisting(TestBean)"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanSpecifyFactoryMethodArgumentsOnFactoryMethodPrototype() {
|
||||
DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
|
||||
@@ -360,7 +389,9 @@ public class FactoryMethodTests {
|
||||
|
||||
}
|
||||
|
||||
|
||||
class MailSession {
|
||||
|
||||
private Properties props;
|
||||
|
||||
private MailSession() {
|
||||
@@ -377,6 +408,6 @@ class MailSession {
|
||||
}
|
||||
|
||||
public Object getProperty(String key) {
|
||||
return props.get(key);
|
||||
return this.props.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -84,6 +84,11 @@
|
||||
<property name="stringValue"><value>testBeanOnlyPrototypeDISetterString</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="invalidPrototype" class="org.springframework.beans.factory.xml.FactoryMethods"
|
||||
factory-method="nonExisting" scope="prototype">
|
||||
<constructor-arg><ref local="juergen"/></constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="fullPrototype" class="org.springframework.beans.factory.xml.FactoryMethods"
|
||||
factory-method="newInstance" scope="prototype">
|
||||
<constructor-arg type="int"><value>27</value></constructor-arg>
|
||||
@@ -120,9 +125,7 @@
|
||||
<constructor-arg><value type="java.lang.Integer">33</value></constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="instanceFactoryMethodWithoutArgs"
|
||||
factory-bean="instanceFactory"
|
||||
factory-method="defaultInstance"/>
|
||||
<bean id="instanceFactoryMethodWithoutArgs" factory-bean="instanceFactory" factory-method="defaultInstance"/>
|
||||
|
||||
<!-- Unnamed bean with factory-bean declaration -->
|
||||
<bean factory-bean="instanceFactory" factory-method="defaultInstance"/>
|
||||
|
||||
Vendored
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,7 +46,7 @@ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManag
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new EhCacheCacheManager for the given backing EhCache.
|
||||
* Create a new EhCacheCacheManager for the given backing EhCache CacheManager.
|
||||
* @param cacheManager the backing EhCache {@link net.sf.ehcache.CacheManager}
|
||||
*/
|
||||
public EhCacheCacheManager(net.sf.ehcache.CacheManager cacheManager) {
|
||||
@@ -92,8 +92,8 @@ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManag
|
||||
// (in case the cache was added at runtime)
|
||||
Ehcache ehcache = this.cacheManager.getEhcache(name);
|
||||
if (ehcache != null) {
|
||||
cache = new EhCacheCache(ehcache);
|
||||
addCache(cache);
|
||||
addCache(new EhCacheCache(ehcache));
|
||||
cache = super.getCache(name); // potentially decorated
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
|
||||
Vendored
+20
-7
@@ -38,6 +38,7 @@ import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link FactoryBean} that creates a named EhCache {@link net.sf.ehcache.Cache} instance
|
||||
@@ -64,6 +65,11 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class EhCacheFactoryBean implements FactoryBean<Ehcache>, BeanNameAware, InitializingBean {
|
||||
|
||||
// EhCache's setStatisticsEnabled(boolean) available? Not anymore as of EhCache 2.7...
|
||||
private static final boolean setStatisticsAvailable =
|
||||
ClassUtils.hasMethod(Ehcache.class, "setStatisticsEnabled", boolean.class);
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private CacheManager cacheManager;
|
||||
@@ -275,7 +281,9 @@ public class EhCacheFactoryBean implements FactoryBean<Ehcache>, BeanNameAware,
|
||||
|
||||
/**
|
||||
* Set whether to enable EhCache statistics on this cache.
|
||||
* @see net.sf.ehcache.Cache#setStatisticsEnabled
|
||||
* <p>Note: As of EhCache 2.7, statistics are enabled by default, and cannot be turned off.
|
||||
* This setter therefore has no effect in such a scenario.
|
||||
* @see net.sf.ehcache.Ehcache#setStatisticsEnabled
|
||||
*/
|
||||
public void setStatisticsEnabled(boolean statisticsEnabled) {
|
||||
this.statisticsEnabled = statisticsEnabled;
|
||||
@@ -283,7 +291,9 @@ public class EhCacheFactoryBean implements FactoryBean<Ehcache>, BeanNameAware,
|
||||
|
||||
/**
|
||||
* Set whether to enable EhCache's sampled statistics on this cache.
|
||||
* @see net.sf.ehcache.Cache#setSampledStatisticsEnabled
|
||||
* <p>Note: As of EhCache 2.7, statistics are enabled by default, and cannot be turned off.
|
||||
* This setter therefore has no effect in such a scenario.
|
||||
* @see net.sf.ehcache.Ehcache#setSampledStatisticsEnabled
|
||||
*/
|
||||
public void setSampledStatisticsEnabled(boolean sampledStatisticsEnabled) {
|
||||
this.sampledStatisticsEnabled = sampledStatisticsEnabled;
|
||||
@@ -346,11 +356,14 @@ public class EhCacheFactoryBean implements FactoryBean<Ehcache>, BeanNameAware,
|
||||
this.cacheManager.addCache(rawCache);
|
||||
}
|
||||
|
||||
if (this.statisticsEnabled) {
|
||||
rawCache.setStatisticsEnabled(true);
|
||||
}
|
||||
if (this.sampledStatisticsEnabled) {
|
||||
rawCache.setSampledStatisticsEnabled(true);
|
||||
// Only necessary on EhCache <2.7: As of 2.7, statistics are on by default.
|
||||
if (setStatisticsAvailable) {
|
||||
if (this.statisticsEnabled) {
|
||||
rawCache.setStatisticsEnabled(true);
|
||||
}
|
||||
if (this.sampledStatisticsEnabled) {
|
||||
rawCache.setSampledStatisticsEnabled(true);
|
||||
}
|
||||
}
|
||||
if (this.disabled) {
|
||||
rawCache.setDisabled(true);
|
||||
|
||||
Vendored
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -110,8 +110,8 @@ public class JCacheCacheManager extends AbstractTransactionSupportingCacheManage
|
||||
// (in case the cache was added at runtime)
|
||||
javax.cache.Cache<?,?> jcache = this.cacheManager.getCache(name);
|
||||
if (jcache != null) {
|
||||
cache = new JCacheCache(jcache, this.allowNullValues);
|
||||
addCache(cache);
|
||||
addCache(new JCacheCache(jcache, this.allowNullValues));
|
||||
cache = super.getCache(name); // potentially decorated
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
|
||||
+10
-10
@@ -73,7 +73,7 @@ public class CronTriggerBean extends CronTrigger
|
||||
|
||||
private String beanName;
|
||||
|
||||
private long startDelay;
|
||||
private long startDelay = 0;
|
||||
|
||||
|
||||
/**
|
||||
@@ -108,9 +108,9 @@ public class CronTriggerBean extends CronTrigger
|
||||
* @see SchedulerFactoryBean#setTriggerListeners
|
||||
* @see org.quartz.TriggerListener#getName
|
||||
*/
|
||||
public void setTriggerListenerNames(String[] names) {
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
addTriggerListener(names[i]);
|
||||
public void setTriggerListenerNames(String... names) {
|
||||
for (String name : names) {
|
||||
addTriggerListener(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,19 +148,19 @@ public class CronTriggerBean extends CronTrigger
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note that this method's declaration of an Exception is deprecated
|
||||
* and will be removed in the Spring 4.0 line.
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.startDelay > 0) {
|
||||
setStartTime(new Date(System.currentTimeMillis() + this.startDelay));
|
||||
}
|
||||
|
||||
if (getName() == null) {
|
||||
setName(this.beanName);
|
||||
}
|
||||
if (getGroup() == null) {
|
||||
setGroup(Scheduler.DEFAULT_GROUP);
|
||||
}
|
||||
if (getStartTime() == null) {
|
||||
setStartTime(new Date());
|
||||
if (this.startDelay > 0 || getStartTime() == null) {
|
||||
setStartTime(new Date(System.currentTimeMillis() + this.startDelay));
|
||||
}
|
||||
if (getTimeZone() == null) {
|
||||
setTimeZone(TimeZone.getDefault());
|
||||
|
||||
+37
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,6 +34,7 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Constants;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -78,16 +79,20 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
|
||||
private Date startTime;
|
||||
|
||||
private long startDelay;
|
||||
private long startDelay = 0;
|
||||
|
||||
private String cronExpression;
|
||||
|
||||
private TimeZone timeZone;
|
||||
|
||||
private String calendarName;
|
||||
|
||||
private int priority;
|
||||
|
||||
private int misfireInstruction;
|
||||
|
||||
private String description;
|
||||
|
||||
private String beanName;
|
||||
|
||||
private CronTrigger cronTrigger;
|
||||
@@ -141,6 +146,15 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
this.jobDataMap.putAll(jobDataAsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific start time for the trigger.
|
||||
* <p>Note that a dynamically computed {@link #setStartDelay} specification
|
||||
* overrides a static timestamp set here.
|
||||
*/
|
||||
public void setStartTime(Date startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start delay in milliseconds.
|
||||
* <p>The start delay is added to the current system time (when the bean starts)
|
||||
@@ -165,6 +179,13 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
this.timeZone = timeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a specific calendar with this cron trigger.
|
||||
*/
|
||||
public void setCalendarName(String calendarName) {
|
||||
this.calendarName = calendarName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the priority of this trigger.
|
||||
*/
|
||||
@@ -191,6 +212,13 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
this.misfireInstruction = constants.asNumber(constantName).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a textual description with this trigger.
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
@@ -206,12 +234,9 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
if (this.jobDetail != null) {
|
||||
this.jobDataMap.put(JobDetailAwareTrigger.JOB_DETAIL_KEY, this.jobDetail);
|
||||
}
|
||||
if (this.startDelay > 0) {
|
||||
if (this.startDelay > 0 || this.startTime == null) {
|
||||
this.startTime = new Date(System.currentTimeMillis() + this.startDelay);
|
||||
}
|
||||
else if (this.startTime == null) {
|
||||
this.startTime = new Date();
|
||||
}
|
||||
if (this.timeZone == null) {
|
||||
this.timeZone = TimeZone.getDefault();
|
||||
}
|
||||
@@ -225,15 +250,17 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
cti.setStartTime(this.startTime);
|
||||
cti.setCronExpression(this.cronExpression);
|
||||
cti.setTimeZone(this.timeZone);
|
||||
cti.setCalendarName(this.calendarName);
|
||||
cti.setPriority(this.priority);
|
||||
cti.setMisfireInstruction(this.misfireInstruction);
|
||||
cti.setDescription(this.description);
|
||||
this.cronTrigger = cti;
|
||||
*/
|
||||
|
||||
Class cronTriggerClass;
|
||||
Class<?> cronTriggerClass;
|
||||
Method jobKeyMethod;
|
||||
try {
|
||||
cronTriggerClass = getClass().getClassLoader().loadClass("org.quartz.impl.triggers.CronTriggerImpl");
|
||||
cronTriggerClass = ClassUtils.forName("org.quartz.impl.triggers.CronTriggerImpl", getClass().getClassLoader());
|
||||
jobKeyMethod = JobDetail.class.getMethod("getKey");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -258,8 +285,10 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
|
||||
pvs.add("startTime", this.startTime);
|
||||
pvs.add("cronExpression", this.cronExpression);
|
||||
pvs.add("timeZone", this.timeZone);
|
||||
pvs.add("calendarName", this.calendarName);
|
||||
pvs.add("priority", this.priority);
|
||||
pvs.add("misfireInstruction", this.misfireInstruction);
|
||||
pvs.add("description", this.description);
|
||||
bw.setPropertyValues(pvs);
|
||||
this.cronTrigger = (CronTrigger) bw.getWrappedInstance();
|
||||
}
|
||||
|
||||
+6
-6
@@ -48,11 +48,11 @@ import org.springframework.context.ApplicationContextAware;
|
||||
* @see org.springframework.beans.factory.BeanNameAware
|
||||
* @see org.quartz.Scheduler#DEFAULT_GROUP
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
@SuppressWarnings({"serial", "rawtypes"})
|
||||
public class JobDetailBean extends JobDetail
|
||||
implements BeanNameAware, ApplicationContextAware, InitializingBean {
|
||||
|
||||
private Class actualJobClass;
|
||||
private Class<?> actualJobClass;
|
||||
|
||||
private String beanName;
|
||||
|
||||
@@ -97,7 +97,7 @@ public class JobDetailBean extends JobDetail
|
||||
* (for example Spring-managed beans)
|
||||
* @see SchedulerFactoryBean#setSchedulerContextAsMap
|
||||
*/
|
||||
public void setJobDataAsMap(Map jobDataAsMap) {
|
||||
public void setJobDataAsMap(Map<String, ?> jobDataAsMap) {
|
||||
getJobDataMap().putAll(jobDataAsMap);
|
||||
}
|
||||
|
||||
@@ -109,9 +109,9 @@ public class JobDetailBean extends JobDetail
|
||||
* @see SchedulerFactoryBean#setJobListeners
|
||||
* @see org.quartz.JobListener#getName
|
||||
*/
|
||||
public void setJobListenerNames(String[] names) {
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
addJobListener(names[i]);
|
||||
public void setJobListenerNames(String... names) {
|
||||
for (String name : names) {
|
||||
addJobListener(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,6 +30,7 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* A Spring {@link FactoryBean} for creating a Quartz {@link org.quartz.JobDetail}
|
||||
@@ -56,7 +57,7 @@ public class JobDetailFactoryBean
|
||||
|
||||
private String group;
|
||||
|
||||
private Class jobClass;
|
||||
private Class<?> jobClass;
|
||||
|
||||
private JobDataMap jobDataMap = new JobDataMap();
|
||||
|
||||
@@ -92,7 +93,7 @@ public class JobDetailFactoryBean
|
||||
/**
|
||||
* Specify the job's implementation class.
|
||||
*/
|
||||
public void setJobClass(Class jobClass) {
|
||||
public void setJobClass(Class<?> jobClass) {
|
||||
this.jobClass = jobClass;
|
||||
}
|
||||
|
||||
@@ -207,7 +208,7 @@ public class JobDetailFactoryBean
|
||||
|
||||
Class<?> jobDetailClass;
|
||||
try {
|
||||
jobDetailClass = getClass().getClassLoader().loadClass("org.quartz.impl.JobDetailImpl");
|
||||
jobDetailClass = ClassUtils.forName("org.quartz.impl.JobDetailImpl", getClass().getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
jobDetailClass = JobDetail.class;
|
||||
|
||||
+16
-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.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.quartz.SchedulerConfigException;
|
||||
@@ -108,14 +107,17 @@ public class LocalDataSourceJobStore extends JobStoreCMT {
|
||||
public void shutdown() {
|
||||
// Do nothing - a Spring-managed DataSource has its own lifecycle.
|
||||
}
|
||||
/* Quartz 2.2 initialize method */
|
||||
public void initialize() {
|
||||
// Do nothing - a Spring-managed DataSource has its own lifecycle.
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Non-transactional DataSource is optional: fall back to default
|
||||
// DataSource if not explicitly specified.
|
||||
DataSource nonTxDataSource = SchedulerFactoryBean.getConfigTimeNonTransactionalDataSource();
|
||||
final DataSource nonTxDataSourceToUse =
|
||||
(nonTxDataSource != null ? nonTxDataSource : this.dataSource);
|
||||
final DataSource nonTxDataSourceToUse = (nonTxDataSource != null ? nonTxDataSource : this.dataSource);
|
||||
|
||||
// Configure non-transactional connection settings for Quartz.
|
||||
setNonManagedTXDataSource(NON_TX_DATA_SOURCE_PREFIX + getInstanceName());
|
||||
@@ -131,21 +133,24 @@ public class LocalDataSourceJobStore extends JobStoreCMT {
|
||||
public void shutdown() {
|
||||
// Do nothing - a Spring-managed DataSource has its own lifecycle.
|
||||
}
|
||||
/* Quartz 2.2 initialize method */
|
||||
public void initialize() {
|
||||
// Do nothing - a Spring-managed DataSource has its own lifecycle.
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// No, if HSQL is the platform, we really don't want to use locks
|
||||
// No, if HSQL is the platform, we really don't want to use locks...
|
||||
try {
|
||||
String productName = JdbcUtils.extractDatabaseMetaData(dataSource,
|
||||
"getDatabaseProductName").toString();
|
||||
String productName = JdbcUtils.extractDatabaseMetaData(this.dataSource, "getDatabaseProductName").toString();
|
||||
productName = JdbcUtils.commonDatabaseName(productName);
|
||||
if (productName != null
|
||||
&& productName.toLowerCase().contains("hsql")) {
|
||||
if (productName != null && productName.toLowerCase().contains("hsql")) {
|
||||
setUseDBLocks(false);
|
||||
setLockHandler(new SimpleSemaphore());
|
||||
}
|
||||
} catch (MetaDataAccessException e) {
|
||||
logWarnIfNonZero(1, "Could not detect database type. Assuming locks can be taken.");
|
||||
}
|
||||
catch (MetaDataAccessException ex) {
|
||||
logWarnIfNonZero(1, "Could not detect database type. Assuming locks can be taken.");
|
||||
}
|
||||
|
||||
super.initialize(loadHelper, signaler);
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -80,7 +80,7 @@ public class LocalTaskExecutorThreadPool implements ThreadPool {
|
||||
}
|
||||
|
||||
public int blockForAvailableThreads() {
|
||||
// The present implementation always returns 1, making Quartz (1.6)
|
||||
// The present implementation always returns 1, making Quartz
|
||||
// always schedule any tasks that it feels like scheduling.
|
||||
// This could be made smarter for specific TaskExecutors,
|
||||
// for example calling {@code getMaximumPoolSize() - getActiveCount()}
|
||||
|
||||
+10
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -86,14 +86,15 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
|
||||
static {
|
||||
try {
|
||||
jobDetailImplClass = Class.forName("org.quartz.impl.JobDetailImpl");
|
||||
jobDetailImplClass = ClassUtils.forName("org.quartz.impl.JobDetailImpl",
|
||||
MethodInvokingJobDetailFactoryBean.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
jobDetailImplClass = null;
|
||||
}
|
||||
try {
|
||||
Class jobExecutionContextClass =
|
||||
QuartzJobBean.class.getClassLoader().loadClass("org.quartz.JobExecutionContext");
|
||||
Class<?> jobExecutionContextClass = ClassUtils.forName("org.quartz.JobExecutionContext",
|
||||
MethodInvokingJobDetailFactoryBean.class.getClassLoader());
|
||||
setResultMethod = jobExecutionContextClass.getMethod("setResult", Object.class);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
@@ -172,7 +173,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
* @see SchedulerFactoryBean#setJobListeners
|
||||
* @see org.quartz.JobListener#getName
|
||||
*/
|
||||
public void setJobListenerNames(String[] names) {
|
||||
public void setJobListenerNames(String... names) {
|
||||
this.jobListenerNames = names;
|
||||
}
|
||||
|
||||
@@ -189,7 +190,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class resolveClassName(String className) throws ClassNotFoundException {
|
||||
protected Class<?> resolveClassName(String className) throws ClassNotFoundException {
|
||||
return ClassUtils.forName(className, this.beanClassLoader);
|
||||
}
|
||||
|
||||
@@ -201,7 +202,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
String name = (this.name != null ? this.name : this.beanName);
|
||||
|
||||
// Consider the concurrent flag to choose between stateful and stateless job.
|
||||
Class jobClass = (this.concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class);
|
||||
Class<?> jobClass = (this.concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class);
|
||||
|
||||
// Build JobDetail instance.
|
||||
if (jobDetailImplClass != null) {
|
||||
@@ -249,8 +250,8 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
|
||||
* Overridden to support the {@link #setTargetBeanName "targetBeanName"} feature.
|
||||
*/
|
||||
@Override
|
||||
public Class getTargetClass() {
|
||||
Class targetClass = super.getTargetClass();
|
||||
public Class<?> getTargetClass() {
|
||||
Class<?> targetClass = super.getTargetClass();
|
||||
if (targetClass == null && this.targetBeanName != null) {
|
||||
Assert.state(this.beanFactory != null, "BeanFactory must be set when using 'targetBeanName'");
|
||||
targetClass = this.beanFactory.getType(this.targetBeanName);
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,6 +28,7 @@ import org.quartz.SchedulerException;
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyAccessorFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -79,8 +80,8 @@ public abstract class QuartzJobBean implements Job {
|
||||
|
||||
static {
|
||||
try {
|
||||
Class jobExecutionContextClass =
|
||||
QuartzJobBean.class.getClassLoader().loadClass("org.quartz.JobExecutionContext");
|
||||
Class<?> jobExecutionContextClass =
|
||||
ClassUtils.forName("org.quartz.JobExecutionContext", QuartzJobBean.class.getClassLoader());
|
||||
getSchedulerMethod = jobExecutionContextClass.getMethod("getScheduler");
|
||||
getMergedJobDataMapMethod = jobExecutionContextClass.getMethod("getMergedJobDataMap");
|
||||
}
|
||||
@@ -99,7 +100,7 @@ public abstract class QuartzJobBean implements Job {
|
||||
try {
|
||||
// Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...
|
||||
Scheduler scheduler = (Scheduler) ReflectionUtils.invokeMethod(getSchedulerMethod, context);
|
||||
Map mergedJobDataMap = (Map) ReflectionUtils.invokeMethod(getMergedJobDataMapMethod, context);
|
||||
Map<?, ?> mergedJobDataMap = (Map<?, ?>) ReflectionUtils.invokeMethod(getMergedJobDataMapMethod, context);
|
||||
|
||||
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
|
||||
+57
-32
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,6 +42,7 @@ import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -54,6 +55,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.5.6
|
||||
*/
|
||||
public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
@@ -63,9 +65,10 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
private static Class<?> triggerKeyClass;
|
||||
|
||||
static {
|
||||
// Quartz 2.0 job/trigger key available?
|
||||
try {
|
||||
jobKeyClass = Class.forName("org.quartz.JobKey");
|
||||
triggerKeyClass = Class.forName("org.quartz.TriggerKey");
|
||||
jobKeyClass = ClassUtils.forName("org.quartz.JobKey", SchedulerAccessor.class.getClassLoader());
|
||||
triggerKeyClass = ClassUtils.forName("org.quartz.TriggerKey", SchedulerAccessor.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
jobKeyClass = null;
|
||||
@@ -128,7 +131,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* to jobs defined directly on this SchedulerFactoryBean.
|
||||
* @see org.quartz.xml.XmlSchedulingDataProcessor
|
||||
*/
|
||||
public void setJobSchedulingDataLocations(String[] jobSchedulingDataLocations) {
|
||||
public void setJobSchedulingDataLocations(String... jobSchedulingDataLocations) {
|
||||
this.jobSchedulingDataLocations = jobSchedulingDataLocations;
|
||||
}
|
||||
|
||||
@@ -140,11 +143,8 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* in combination with the Trigger.
|
||||
* @see #setTriggers
|
||||
* @see org.quartz.JobDetail
|
||||
* @see JobDetailBean
|
||||
* @see JobDetailAwareTrigger
|
||||
* @see org.quartz.Trigger#setJobName
|
||||
*/
|
||||
public void setJobDetails(JobDetail[] jobDetails) {
|
||||
public void setJobDetails(JobDetail... jobDetails) {
|
||||
// Use modifiable ArrayList here, to allow for further adding of
|
||||
// JobDetail objects during autodetection of JobDetailAwareTriggers.
|
||||
this.jobDetails = new ArrayList<JobDetail>(Arrays.asList(jobDetails));
|
||||
@@ -156,7 +156,6 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* @param calendars Map with calendar names as keys as Calendar
|
||||
* objects as values
|
||||
* @see org.quartz.Calendar
|
||||
* @see org.quartz.Trigger#setCalendarName
|
||||
*/
|
||||
public void setCalendars(Map<String, Calendar> calendars) {
|
||||
this.calendars = calendars;
|
||||
@@ -171,19 +170,15 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* "jobDetails" property of this FactoryBean.
|
||||
* @see #setJobDetails
|
||||
* @see org.quartz.JobDetail
|
||||
* @see JobDetailAwareTrigger
|
||||
* @see CronTriggerBean
|
||||
* @see SimpleTriggerBean
|
||||
*/
|
||||
public void setTriggers(Trigger[] triggers) {
|
||||
public void setTriggers(Trigger... triggers) {
|
||||
this.triggers = Arrays.asList(triggers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify Quartz SchedulerListeners to be registered with the Scheduler.
|
||||
*/
|
||||
public void setSchedulerListeners(SchedulerListener[] schedulerListeners) {
|
||||
public void setSchedulerListeners(SchedulerListener... schedulerListeners) {
|
||||
this.schedulerListeners = schedulerListeners;
|
||||
}
|
||||
|
||||
@@ -191,7 +186,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* Specify global Quartz JobListeners to be registered with the Scheduler.
|
||||
* Such JobListeners will apply to all Jobs in the Scheduler.
|
||||
*/
|
||||
public void setGlobalJobListeners(JobListener[] globalJobListeners) {
|
||||
public void setGlobalJobListeners(JobListener... globalJobListeners) {
|
||||
this.globalJobListeners = globalJobListeners;
|
||||
}
|
||||
|
||||
@@ -199,11 +194,12 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* Specify named Quartz JobListeners to be registered with the Scheduler.
|
||||
* Such JobListeners will only apply to Jobs that explicitly activate
|
||||
* them via their name.
|
||||
* <p>Note that non-global JobListeners are not supported on Quartz 2.x -
|
||||
* manually register a Matcher against the Quartz ListenerManager instead.
|
||||
* @see org.quartz.JobListener#getName
|
||||
* @see org.quartz.JobDetail#addJobListener
|
||||
* @see JobDetailBean#setJobListenerNames
|
||||
*/
|
||||
public void setJobListeners(JobListener[] jobListeners) {
|
||||
public void setJobListeners(JobListener... jobListeners) {
|
||||
this.jobListeners = jobListeners;
|
||||
}
|
||||
|
||||
@@ -211,7 +207,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* Specify global Quartz TriggerListeners to be registered with the Scheduler.
|
||||
* Such TriggerListeners will apply to all Triggers in the Scheduler.
|
||||
*/
|
||||
public void setGlobalTriggerListeners(TriggerListener[] globalTriggerListeners) {
|
||||
public void setGlobalTriggerListeners(TriggerListener... globalTriggerListeners) {
|
||||
this.globalTriggerListeners = globalTriggerListeners;
|
||||
}
|
||||
|
||||
@@ -219,12 +215,13 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
* Specify named Quartz TriggerListeners to be registered with the Scheduler.
|
||||
* Such TriggerListeners will only apply to Triggers that explicitly activate
|
||||
* them via their name.
|
||||
* <p>Note that non-global TriggerListeners are not supported on Quartz 2.x -
|
||||
* manually register a Matcher against the Quartz ListenerManager instead.
|
||||
* @see org.quartz.TriggerListener#getName
|
||||
* @see org.quartz.Trigger#addTriggerListener
|
||||
* @see CronTriggerBean#setTriggerListenerNames
|
||||
* @see SimpleTriggerBean#setTriggerListenerNames
|
||||
*/
|
||||
public void setTriggerListeners(TriggerListener[] triggerListeners) {
|
||||
public void setTriggerListeners(TriggerListener... triggerListeners) {
|
||||
this.triggerListeners = triggerListeners;
|
||||
}
|
||||
|
||||
@@ -251,14 +248,14 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
if (this.transactionManager != null) {
|
||||
transactionStatus = this.transactionManager.getTransaction(new DefaultTransactionDefinition());
|
||||
}
|
||||
try {
|
||||
|
||||
try {
|
||||
if (this.jobSchedulingDataLocations != null) {
|
||||
ClassLoadHelper clh = new ResourceLoaderClassLoadHelper(this.resourceLoader);
|
||||
clh.initialize();
|
||||
try {
|
||||
// Quartz 1.8 or higher?
|
||||
Class dataProcessorClass = getClass().getClassLoader().loadClass("org.quartz.xml.XMLSchedulingDataProcessor");
|
||||
Class<?> dataProcessorClass = ClassUtils.forName("org.quartz.xml.XMLSchedulingDataProcessor", getClass().getClassLoader());
|
||||
logger.debug("Using Quartz 1.8 XMLSchedulingDataProcessor");
|
||||
Object dataProcessor = dataProcessorClass.getConstructor(ClassLoadHelper.class).newInstance(clh);
|
||||
Method processFileAndScheduleJobs = dataProcessorClass.getMethod("processFileAndScheduleJobs", String.class, Scheduler.class);
|
||||
@@ -268,7 +265,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Quartz 1.6
|
||||
Class dataProcessorClass = getClass().getClassLoader().loadClass("org.quartz.xml.JobSchedulingDataProcessor");
|
||||
Class<?> dataProcessorClass = ClassUtils.forName("org.quartz.xml.JobSchedulingDataProcessor", getClass().getClassLoader());
|
||||
logger.debug("Using Quartz 1.6 JobSchedulingDataProcessor");
|
||||
Object dataProcessor = dataProcessorClass.getConstructor(ClassLoadHelper.class, boolean.class, boolean.class).newInstance(clh, true, true);
|
||||
Method processFileAndScheduleJobs = dataProcessorClass.getMethod("processFileAndScheduleJobs", String.class, Scheduler.class, boolean.class);
|
||||
@@ -396,7 +393,8 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Map jobDataMap = (Map) ReflectionUtils.invokeMethod(Trigger.class.getMethod("getJobDataMap"), trigger);
|
||||
Map<?, ?> jobDataMap =
|
||||
(Map<?, ?>) ReflectionUtils.invokeMethod(Trigger.class.getMethod("getJobDataMap"), trigger);
|
||||
return (JobDetail) jobDataMap.remove(JobDetailAwareTrigger.JOB_DETAIL_KEY);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
@@ -473,19 +471,33 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
target = getScheduler();
|
||||
quartz2 = false;
|
||||
}
|
||||
Class<?> targetClass = target.getClass();
|
||||
|
||||
try {
|
||||
if (this.schedulerListeners != null) {
|
||||
Method addSchedulerListener = target.getClass().getMethod("addSchedulerListener", SchedulerListener.class);
|
||||
Method addSchedulerListener = targetClass.getMethod("addSchedulerListener", SchedulerListener.class);
|
||||
for (SchedulerListener listener : this.schedulerListeners) {
|
||||
ReflectionUtils.invokeMethod(addSchedulerListener, target, listener);
|
||||
}
|
||||
}
|
||||
if (this.globalJobListeners != null) {
|
||||
Method addJobListener = target.getClass().getMethod(
|
||||
(quartz2 ? "addJobListener" : "addGlobalJobListener"), JobListener.class);
|
||||
Method addJobListener;
|
||||
if (quartz2) {
|
||||
// addJobListener(JobListener) only introduced as late as Quartz 2.2, so we need
|
||||
// to fall back to the Quartz 2.0/2.1 compatible variant with an empty matchers List
|
||||
addJobListener = targetClass.getMethod("addJobListener", JobListener.class, List.class);
|
||||
}
|
||||
else {
|
||||
addJobListener = targetClass.getMethod("addGlobalJobListener", JobListener.class);
|
||||
}
|
||||
for (JobListener listener : this.globalJobListeners) {
|
||||
ReflectionUtils.invokeMethod(addJobListener, target, listener);
|
||||
if (quartz2) {
|
||||
List<?> emptyMatchers = new LinkedList<Object>();
|
||||
ReflectionUtils.invokeMethod(addJobListener, target, listener, emptyMatchers);
|
||||
}
|
||||
else {
|
||||
ReflectionUtils.invokeMethod(addJobListener, target, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.jobListeners != null) {
|
||||
@@ -498,10 +510,23 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
|
||||
}
|
||||
}
|
||||
if (this.globalTriggerListeners != null) {
|
||||
Method addTriggerListener = target.getClass().getMethod(
|
||||
(quartz2 ? "addTriggerListener" : "addGlobalTriggerListener"), TriggerListener.class);
|
||||
Method addTriggerListener;
|
||||
if (quartz2) {
|
||||
// addTriggerListener(TriggerListener) only introduced as late as Quartz 2.2, so we need
|
||||
// to fall back to the Quartz 2.0/2.1 compatible variant with an empty matchers List
|
||||
addTriggerListener = targetClass.getMethod("addTriggerListener", TriggerListener.class, List.class);
|
||||
}
|
||||
else {
|
||||
addTriggerListener = targetClass.getMethod("addGlobalTriggerListener", TriggerListener.class);
|
||||
}
|
||||
for (TriggerListener listener : this.globalTriggerListeners) {
|
||||
ReflectionUtils.invokeMethod(addTriggerListener, target, listener);
|
||||
if (quartz2) {
|
||||
List<?> emptyMatchers = new LinkedList<Object>();
|
||||
ReflectionUtils.invokeMethod(addTriggerListener, target, listener, emptyMatchers);
|
||||
}
|
||||
else {
|
||||
ReflectionUtils.invokeMethod(addTriggerListener, target, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.triggerListeners != null) {
|
||||
|
||||
+10
-15
@@ -43,6 +43,7 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
import org.springframework.scheduling.SchedulingException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
@@ -157,7 +158,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
}
|
||||
|
||||
|
||||
private Class<?> schedulerFactoryClass = StdSchedulerFactory.class;
|
||||
private Class<? extends SchedulerFactory> schedulerFactoryClass = StdSchedulerFactory.class;
|
||||
|
||||
private String schedulerName;
|
||||
|
||||
@@ -173,7 +174,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
private DataSource nonTransactionalDataSource;
|
||||
|
||||
|
||||
private Map schedulerContextMap;
|
||||
private Map<String, ?> schedulerContextMap;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@@ -200,7 +201,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
|
||||
/**
|
||||
* Set the Quartz SchedulerFactory implementation to use.
|
||||
* <p>Default is StdSchedulerFactory, reading in the standard
|
||||
* <p>Default is {@link StdSchedulerFactory}, reading in the standard
|
||||
* {@code quartz.properties} from {@code quartz.jar}.
|
||||
* To use custom Quartz properties, specify the "configLocation"
|
||||
* or "quartzProperties" bean property on this FactoryBean.
|
||||
@@ -208,10 +209,8 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
* @see #setConfigLocation
|
||||
* @see #setQuartzProperties
|
||||
*/
|
||||
public void setSchedulerFactoryClass(Class schedulerFactoryClass) {
|
||||
if (schedulerFactoryClass == null || !SchedulerFactory.class.isAssignableFrom(schedulerFactoryClass)) {
|
||||
throw new IllegalArgumentException("schedulerFactoryClass must implement [org.quartz.SchedulerFactory]");
|
||||
}
|
||||
public void setSchedulerFactoryClass(Class<? extends SchedulerFactory> schedulerFactoryClass) {
|
||||
Assert.isAssignable(SchedulerFactory.class, schedulerFactoryClass);
|
||||
this.schedulerFactoryClass = schedulerFactoryClass;
|
||||
}
|
||||
|
||||
@@ -313,7 +312,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
* values (for example Spring-managed beans)
|
||||
* @see JobDetailBean#setJobDataAsMap
|
||||
*/
|
||||
public void setSchedulerContextAsMap(Map schedulerContextAsMap) {
|
||||
public void setSchedulerContextAsMap(Map<String, ?> schedulerContextAsMap) {
|
||||
this.schedulerContextMap = schedulerContextAsMap;
|
||||
}
|
||||
|
||||
@@ -450,10 +449,8 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
this.resourceLoader = this.applicationContext;
|
||||
}
|
||||
|
||||
// Create SchedulerFactory instance.
|
||||
SchedulerFactory schedulerFactory = (SchedulerFactory)
|
||||
BeanUtils.instantiateClass(this.schedulerFactoryClass);
|
||||
|
||||
// Create SchedulerFactory instance...
|
||||
SchedulerFactory schedulerFactory = BeanUtils.instantiateClass(this.schedulerFactoryClass);
|
||||
initSchedulerFactory(schedulerFactory);
|
||||
|
||||
if (this.resourceLoader != null) {
|
||||
@@ -516,9 +513,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
|
||||
* Load and/or apply Quartz properties to the given SchedulerFactory.
|
||||
* @param schedulerFactory the SchedulerFactory to initialize
|
||||
*/
|
||||
private void initSchedulerFactory(SchedulerFactory schedulerFactory)
|
||||
throws SchedulerException, IOException {
|
||||
|
||||
private void initSchedulerFactory(SchedulerFactory schedulerFactory) throws SchedulerException, IOException {
|
||||
if (!(schedulerFactory instanceof StdSchedulerFactory)) {
|
||||
if (this.configLocation != null || this.quartzProperties != null ||
|
||||
this.taskExecutor != null || this.dataSource != null) {
|
||||
|
||||
+8
-4
@@ -114,9 +114,9 @@ public class SimpleTriggerBean extends SimpleTrigger
|
||||
* @see SchedulerFactoryBean#setTriggerListeners
|
||||
* @see org.quartz.TriggerListener#getName
|
||||
*/
|
||||
public void setTriggerListenerNames(String[] names) {
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
addTriggerListener(names[i]);
|
||||
public void setTriggerListenerNames(String... names) {
|
||||
for (String name : names) {
|
||||
addTriggerListener(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,6 +153,10 @@ public class SimpleTriggerBean extends SimpleTrigger
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note that this method's declaration of a ParseException is deprecated
|
||||
* and will be removed in the Spring 4.0 line.
|
||||
*/
|
||||
public void afterPropertiesSet() throws ParseException {
|
||||
if (getName() == null) {
|
||||
setName(this.beanName);
|
||||
@@ -160,7 +164,7 @@ public class SimpleTriggerBean extends SimpleTrigger
|
||||
if (getGroup() == null) {
|
||||
setGroup(Scheduler.DEFAULT_GROUP);
|
||||
}
|
||||
if (getStartTime() == null) {
|
||||
if (this.startDelay > 0 || getStartTime() == null) {
|
||||
setStartTime(new Date(System.currentTimeMillis() + this.startDelay));
|
||||
}
|
||||
if (this.jobDetail != null) {
|
||||
|
||||
+28
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -34,6 +33,7 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Constants;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -88,6 +88,8 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
|
||||
private int misfireInstruction;
|
||||
|
||||
private String description;
|
||||
|
||||
private String beanName;
|
||||
|
||||
private SimpleTrigger simpleTrigger;
|
||||
@@ -141,10 +143,20 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
this.jobDataMap.putAll(jobDataAsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific start time for the trigger.
|
||||
* <p>Note that a dynamically computed {@link #setStartDelay} specification
|
||||
* overrides a static timestamp set here.
|
||||
*/
|
||||
public void setStartTime(Date startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start delay in milliseconds.
|
||||
* <p>The start delay is added to the current system time (when the bean starts)
|
||||
* to control the start time of the trigger.
|
||||
* @see #setStartTime
|
||||
*/
|
||||
public void setStartDelay(long startDelay) {
|
||||
Assert.isTrue(startDelay >= 0, "Start delay cannot be negative");
|
||||
@@ -195,12 +207,19 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
this.misfireInstruction = constants.asNumber(constantName).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a textual description with this trigger.
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
|
||||
public void afterPropertiesSet() throws ParseException {
|
||||
public void afterPropertiesSet() {
|
||||
if (this.name == null) {
|
||||
this.name = this.beanName;
|
||||
}
|
||||
@@ -210,12 +229,9 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
if (this.jobDetail != null) {
|
||||
this.jobDataMap.put(JobDetailAwareTrigger.JOB_DETAIL_KEY, this.jobDetail);
|
||||
}
|
||||
if (this.startDelay > 0) {
|
||||
if (this.startDelay > 0 || this.startTime == null) {
|
||||
this.startTime = new Date(System.currentTimeMillis() + this.startDelay);
|
||||
}
|
||||
else if (this.startTime == null) {
|
||||
this.startTime = new Date();
|
||||
}
|
||||
|
||||
/*
|
||||
SimpleTriggerImpl sti = new SimpleTriggerImpl();
|
||||
@@ -228,13 +244,14 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
sti.setRepeatCount(this.repeatCount);
|
||||
sti.setPriority(this.priority);
|
||||
sti.setMisfireInstruction(this.misfireInstruction);
|
||||
sti.setDescription(this.description);
|
||||
this.simpleTrigger = sti;
|
||||
*/
|
||||
|
||||
Class simpleTriggerClass;
|
||||
Class<?> simpleTriggerClass;
|
||||
Method jobKeyMethod;
|
||||
try {
|
||||
simpleTriggerClass = getClass().getClassLoader().loadClass("org.quartz.impl.triggers.SimpleTriggerImpl");
|
||||
simpleTriggerClass = ClassUtils.forName("org.quartz.impl.triggers.SimpleTriggerImpl", getClass().getClassLoader());
|
||||
jobKeyMethod = JobDetail.class.getMethod("getKey");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -261,6 +278,7 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
pvs.add("repeatCount", this.repeatCount);
|
||||
pvs.add("priority", this.priority);
|
||||
pvs.add("misfireInstruction", this.misfireInstruction);
|
||||
pvs.add("description", this.description);
|
||||
bw.setPropertyValues(pvs);
|
||||
this.simpleTrigger = (SimpleTrigger) bw.getWrappedInstance();
|
||||
}
|
||||
@@ -277,4 +295,5 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ public class SpringBeanJobFactory extends AdaptableJobFactory implements Schedul
|
||||
* ignored if there is no corresponding property found on the particular
|
||||
* job class (all other unknown properties will still trigger an exception).
|
||||
*/
|
||||
public void setIgnoredUnknownProperties(String[] ignoredUnknownProperties) {
|
||||
public void setIgnoredUnknownProperties(String... ignoredUnknownProperties) {
|
||||
this.ignoredUnknownProperties = ignoredUnknownProperties;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -122,7 +122,7 @@ public class JasperReportsUtilsTests extends TestCase {
|
||||
public void testRenderAsPdfWithExporterParameters() throws Exception {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
Map<JRExporterParameter, Object> exporterParameters = new HashMap<JRExporterParameter, Object>();
|
||||
exporterParameters.put(JRPdfExporterParameter.PDF_VERSION, JRPdfExporterParameter.PDF_VERSION_1_6.toString());
|
||||
exporterParameters.put(JRPdfExporterParameter.PDF_VERSION, JRPdfExporterParameter.PDF_VERSION_1_6);
|
||||
JasperReportsUtils.renderAsPdf(getReport(), getParameters(), getData(), os, exporterParameters);
|
||||
byte[] output = os.toByteArray();
|
||||
assertPdfOutputCorrect(output);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,8 @@ package org.springframework.cache;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A manager for a set of {@link Cache}s.
|
||||
* Spring's central cache manager SPI.
|
||||
* Allows for retrieving named {@link Cache} regions.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
@@ -28,14 +29,14 @@ public interface CacheManager {
|
||||
|
||||
/**
|
||||
* Return the cache associated with the given name.
|
||||
* @param name cache identifier (must not be {@code null})
|
||||
* @return associated cache, or {@code null} if none is found
|
||||
* @param name the cache identifier (must not be {@code null})
|
||||
* @return the associated cache, or {@code null} if none found
|
||||
*/
|
||||
Cache getCache(String name);
|
||||
|
||||
/**
|
||||
* Return a collection of the caches known by this cache manager.
|
||||
* @return names of caches known by the cache manager.
|
||||
* Return a collection of the cache names known by this manager.
|
||||
* @return the names of all caches known by the cache manager
|
||||
*/
|
||||
Collection<String> getCacheNames();
|
||||
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -103,7 +103,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
* @param cacheOperationSources must not be {@code null}
|
||||
*/
|
||||
public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {
|
||||
Assert.notEmpty(cacheOperationSources);
|
||||
Assert.notEmpty(cacheOperationSources, "At least 1 CacheOperationSource needs to be specified");
|
||||
this.cacheOperationSource = (cacheOperationSources.length > 1 ?
|
||||
new CompositeCacheOperationSource(cacheOperationSources) : cacheOperationSources[0]);
|
||||
}
|
||||
@@ -132,10 +132,10 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (this.cacheManager == null) {
|
||||
throw new IllegalStateException("'cacheManager' is required");
|
||||
throw new IllegalStateException("Property 'cacheManager' is required");
|
||||
}
|
||||
if (this.cacheOperationSource == null) {
|
||||
throw new IllegalStateException("The 'cacheOperationSources' property is required: " +
|
||||
throw new IllegalStateException("Property 'cacheOperationSources' is required: " +
|
||||
"If there are no cacheable methods, then don't use a cache aspect.");
|
||||
}
|
||||
|
||||
|
||||
Vendored
+13
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,8 +17,7 @@
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Default key generator. Returns {@value #NO_PARAM_KEY} if no
|
||||
@@ -29,25 +28,29 @@ import org.springframework.cache.interceptor.KeyGenerator;
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class DefaultKeyGenerator implements KeyGenerator {
|
||||
|
||||
public static final int NO_PARAM_KEY = 0;
|
||||
|
||||
public static final int NULL_PARAM_KEY = 53;
|
||||
|
||||
public Object generate(Object target, Method method, Object... params) {
|
||||
if (params.length == 1) {
|
||||
return (params[0] == null ? NULL_PARAM_KEY : params[0]);
|
||||
}
|
||||
if (params.length == 0) {
|
||||
return NO_PARAM_KEY;
|
||||
}
|
||||
int hashCode = 17;
|
||||
for (Object object : params) {
|
||||
hashCode = 31 * hashCode + (object == null ? NULL_PARAM_KEY : object.hashCode());
|
||||
if (params.length == 1) {
|
||||
Object param = params[0];
|
||||
if (param == null) {
|
||||
return NULL_PARAM_KEY;
|
||||
}
|
||||
if (!param.getClass().isArray()) {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
return Integer.valueOf(hashCode);
|
||||
return Arrays.deepHashCode(params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+45
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,42 +17,73 @@
|
||||
package org.springframework.cache.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Composite {@link CacheManager} implementation that iterates
|
||||
* over a given collection of {@link CacheManager} instances.
|
||||
* Composite {@link CacheManager} implementation that iterates over
|
||||
* a given collection of delegate {@link CacheManager} instances.
|
||||
*
|
||||
* Allows {@link NoOpCacheManager} to be automatically added to the list for handling
|
||||
* the cache declarations without a backing store.
|
||||
* <p>Allows {@link NoOpCacheManager} to be automatically added to the end of
|
||||
* the list for handling cache declarations without a backing store. Otherwise,
|
||||
* any custom {@link CacheManager} may play that role of the last delegate as
|
||||
* well, lazily creating cache regions for any requested name.
|
||||
*
|
||||
* <p>Note: Regular CacheManagers that this composite manager delegates to need
|
||||
* to return {@code null} from {@link #getCache(String)} if they are unaware of
|
||||
* the specified cache name, allowing for iteration to the next delegate in line.
|
||||
* However, most {@link CacheManager} implementations fall back to lazy creation
|
||||
* of named caches once requested; check out the specific configuration details
|
||||
* for a 'static' mode with fixed cache names, if available.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see #setFallbackToNoOpCache
|
||||
* @see org.springframework.cache.concurrent.ConcurrentMapCacheManager#setCacheNames
|
||||
*/
|
||||
public class CompositeCacheManager implements InitializingBean, CacheManager {
|
||||
public class CompositeCacheManager implements CacheManager, InitializingBean {
|
||||
|
||||
private List<CacheManager> cacheManagers;
|
||||
private final List<CacheManager> cacheManagers = new ArrayList<CacheManager>();
|
||||
|
||||
private boolean fallbackToNoOpCache = false;
|
||||
|
||||
|
||||
/**
|
||||
* Construct an empty CompositeCacheManager, with delegate CacheManagers to
|
||||
* be added via the {@link #setCacheManagers "cacheManagers"} property.
|
||||
*/
|
||||
public CompositeCacheManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a CompositeCacheManager from the given delegate CacheManagers.
|
||||
* @param cacheManagers the CacheManagers to delegate to
|
||||
*/
|
||||
public CompositeCacheManager(CacheManager... cacheManagers) {
|
||||
setCacheManagers(Arrays.asList(cacheManagers));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the CacheManagers to delegate to.
|
||||
*/
|
||||
public void setCacheManagers(Collection<CacheManager> cacheManagers) {
|
||||
Assert.notEmpty(cacheManagers, "cacheManagers Collection must not be empty");
|
||||
this.cacheManagers = new ArrayList<CacheManager>();
|
||||
this.cacheManagers.clear(); // just here to preserve compatibility with previous behavior
|
||||
this.cacheManagers.addAll(cacheManagers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether a {@link NoOpCacheManager} should be added at the end of the manager lists.
|
||||
* In this case, any {@code getCache} requests not handled by the configured cache managers will
|
||||
* Indicate whether a {@link NoOpCacheManager} should be added at the end of the delegate list.
|
||||
* In this case, any {@code getCache} requests not handled by the configured CacheManagers will
|
||||
* be automatically handled by the {@link NoOpCacheManager} (and hence never return {@code null}).
|
||||
*/
|
||||
public void setFallbackToNoOpCache(boolean fallbackToNoOpCache) {
|
||||
@@ -77,11 +108,11 @@ public class CompositeCacheManager implements InitializingBean, CacheManager {
|
||||
}
|
||||
|
||||
public Collection<String> getCacheNames() {
|
||||
List<String> names = new ArrayList<String>();
|
||||
Set<String> names = new LinkedHashSet<String>();
|
||||
for (CacheManager manager : this.cacheManagers) {
|
||||
names.addAll(manager.getCacheNames());
|
||||
}
|
||||
return Collections.unmodifiableList(names);
|
||||
return Collections.unmodifiableSet(names);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,8 +23,6 @@ import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import static org.springframework.context.annotation.MetadataUtils.*;
|
||||
|
||||
/**
|
||||
* Convenient base class for {@link ImportSelector} implementations that select imports
|
||||
* based on an {@link AdviceMode} value from an annotation (such as the {@code @Enable*}
|
||||
@@ -40,6 +38,7 @@ public abstract class AdviceModeImportSelector<A extends Annotation> implements
|
||||
|
||||
public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode";
|
||||
|
||||
|
||||
/**
|
||||
* The name of the {@link AdviceMode} attribute for the annotation specified by the
|
||||
* generic type {@code A}. The default is {@value #DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME},
|
||||
@@ -50,47 +49,37 @@ public abstract class AdviceModeImportSelector<A extends Annotation> implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>This implementation resolves the type of annotation from generic metadata and
|
||||
* This implementation resolves the type of annotation from generic metadata and
|
||||
* validates that (a) the annotation is in fact present on the importing
|
||||
* {@code @Configuration} class and (b) that the given annotation has an
|
||||
* {@linkplain #getAdviceModeAttributeName() advice mode attribute} of type
|
||||
* {@link AdviceMode}.
|
||||
*
|
||||
* <p>The {@link #selectImports(AdviceMode)} method is then invoked, allowing the
|
||||
* concrete implementation to choose imports in a safe and convenient fashion.
|
||||
*
|
||||
* @throws IllegalArgumentException if expected annotation {@code A} is not present
|
||||
* on the importing {@code @Configuration} class or if {@link #selectImports(AdviceMode)}
|
||||
* returns {@code null}
|
||||
*/
|
||||
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||
Class<?> annoType = GenericTypeResolver.resolveTypeArgument(this.getClass(), AdviceModeImportSelector.class);
|
||||
|
||||
AnnotationAttributes attributes = attributesFor(importingClassMetadata, annoType);
|
||||
Class<?> annoType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
|
||||
AnnotationAttributes attributes = MetadataUtils.attributesFor(importingClassMetadata, annoType);
|
||||
Assert.notNull(attributes, String.format(
|
||||
"@%s is not present on importing class '%s' as expected",
|
||||
annoType.getSimpleName(), importingClassMetadata.getClassName()));
|
||||
|
||||
AdviceMode adviceMode = attributes.getEnum(this.getAdviceModeAttributeName());
|
||||
|
||||
String[] imports = selectImports(adviceMode);
|
||||
Assert.notNull(imports, String.format("Unknown AdviceMode: '%s'", adviceMode));
|
||||
|
||||
return imports;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine which classes should be imported based on the given {@code AdviceMode}.
|
||||
*
|
||||
* <p>Returning {@code null} from this method indicates that the {@code AdviceMode} could
|
||||
* not be handled or was unknown and that an {@code IllegalArgumentException} should
|
||||
* be thrown.
|
||||
*
|
||||
* @param adviceMode the value of the {@linkplain #getAdviceModeAttributeName()
|
||||
* advice mode attribute} for the annotation specified via generics.
|
||||
*
|
||||
* @return array containing classes to import; empty array if none, {@code null} if
|
||||
* the given {@code AdviceMode} is unknown.
|
||||
*/
|
||||
|
||||
+10
-9
@@ -88,13 +88,16 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
|
||||
for (String type : types) {
|
||||
AnnotationAttributes attributes = MetadataUtils.attributesFor(amd, type);
|
||||
if (isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
|
||||
String value = (String) attributes.get("value");
|
||||
if (StringUtils.hasLength(value)) {
|
||||
if (beanName != null && !value.equals(beanName)) {
|
||||
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
|
||||
"component names: '" + beanName + "' versus '" + value + "'");
|
||||
Object value = attributes.get("value");
|
||||
if (value instanceof String) {
|
||||
String strVal = (String) value;
|
||||
if (StringUtils.hasLength(strVal)) {
|
||||
if (beanName != null && !strVal.equals(beanName)) {
|
||||
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
|
||||
"component names: '" + beanName + "' versus '" + strVal + "'");
|
||||
}
|
||||
beanName = strVal;
|
||||
}
|
||||
beanName = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,9 +120,7 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
|
||||
annotationType.equals("javax.annotation.ManagedBean") ||
|
||||
annotationType.equals("javax.inject.Named");
|
||||
|
||||
return (isStereotype && attributes != null &&
|
||||
attributes.containsKey("value") &&
|
||||
attributes.get("value") instanceof String);
|
||||
return (isStereotype && attributes != null && attributes.containsKey("value"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -208,8 +208,8 @@ public class AnnotationConfigUtils {
|
||||
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
|
||||
RootBeanDefinition def = new RootBeanDefinition();
|
||||
try {
|
||||
ClassLoader cl = AnnotationConfigUtils.class.getClassLoader();
|
||||
def.setBeanClass(cl.loadClass(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME));
|
||||
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
|
||||
AnnotationConfigUtils.class.getClassLoader()));
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new IllegalStateException(
|
||||
|
||||
+9
-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.
|
||||
@@ -16,12 +16,11 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import static org.springframework.context.annotation.MetadataUtils.attributesFor;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.config.AopConfigUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
@@ -33,8 +32,8 @@ import org.springframework.core.type.AnnotationMetadata;
|
||||
* {@code proxyTargetClass} attributes set to the correct values.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @see EnableAspectJAutoProxy
|
||||
* @since 3.1
|
||||
* @see EnableAspectJAutoProxy
|
||||
*/
|
||||
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
@@ -47,7 +46,6 @@ public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
* attributes. If {@code mode} is set to {@code PROXY}, the APC is registered; if
|
||||
* {@code proxyTargetClass} is set to {@code true}, then the APC is forced to use
|
||||
* subclass (CGLIB) proxying.
|
||||
*
|
||||
* <p>Several {@code @Enable*} annotations expose both {@code mode} and
|
||||
* {@code proxyTargetClass} attributes. It is important to note that most of these
|
||||
* capabilities end up sharing a {@linkplain AopConfigUtils#AUTO_PROXY_CREATOR_BEAN_NAME
|
||||
@@ -60,16 +58,15 @@ public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
boolean candidateFound = false;
|
||||
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
|
||||
for (String annoType : annoTypes) {
|
||||
AnnotationAttributes candidate = attributesFor(importingClassMetadata, annoType);
|
||||
AnnotationAttributes candidate = MetadataUtils.attributesFor(importingClassMetadata, annoType);
|
||||
Object mode = candidate.get("mode");
|
||||
Object proxyTargetClass = candidate.get("proxyTargetClass");
|
||||
if (mode != null && proxyTargetClass != null
|
||||
&& mode.getClass().equals(AdviceMode.class)
|
||||
&& proxyTargetClass.getClass().equals(Boolean.class)) {
|
||||
if (mode != null && proxyTargetClass != null && mode.getClass().equals(AdviceMode.class) &&
|
||||
proxyTargetClass.getClass().equals(Boolean.class)) {
|
||||
candidateFound = true;
|
||||
if (mode == AdviceMode.PROXY) {
|
||||
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
|
||||
if ((Boolean)proxyTargetClass) {
|
||||
if ((Boolean) proxyTargetClass) {
|
||||
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
|
||||
return;
|
||||
}
|
||||
@@ -88,4 +85,5 @@ public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
"altogether.", name, name, name));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -197,25 +197,26 @@ public @interface Bean {
|
||||
/**
|
||||
* The optional name of a method to call on the bean instance during initialization.
|
||||
* Not commonly used, given that the method may be called programmatically directly
|
||||
* within the body of a Bean-annotated method. Default value is {@code ""}, indicating
|
||||
* that no init method should be called.
|
||||
* within the body of a Bean-annotated method.
|
||||
* <p>The default value is {@code ""}, indicating no init method to be called.
|
||||
*/
|
||||
String initMethod() default "";
|
||||
|
||||
/**
|
||||
* The optional name of a method to call on the bean instance upon closing the
|
||||
* application context, for example a {@code close()} method on a JDBC {@code
|
||||
* DataSource} implementation, or a Hibernate {@code SessionFactory} object.
|
||||
* application context, for example a {@code close()} method on a JDBC
|
||||
* {@code DataSource} implementation, or a Hibernate {@code SessionFactory} object.
|
||||
* The method must have no arguments but may throw any exception.
|
||||
* <p>As a convenience to the user, the container will attempt to infer a destroy
|
||||
* method against an object returned from the {@code @Bean} method. For example, given a
|
||||
* {@code @Bean} method returning an Apache Commons DBCP {@code BasicDataSource}, the
|
||||
* container will notice the {@code close()} method available on that object and
|
||||
* method against an object returned from the {@code @Bean} method. For example, given
|
||||
* an {@code @Bean} method returning an Apache Commons DBCP {@code BasicDataSource},
|
||||
* the container will notice the {@code close()} method available on that object and
|
||||
* automatically register it as the {@code destroyMethod}. This 'destroy method
|
||||
* inference' is currently limited to detecting only public, no-arg methods named
|
||||
* 'close'. The method may be declared at any level of the inheritance hierarchy and
|
||||
* will be detected regardless of the return type of the {@code @Bean} method (i.e.,
|
||||
* detection occurs reflectively against the bean instance itself at creation time).
|
||||
* 'close' or 'shutdown'. The method may be declared at any level of the inheritance
|
||||
* hierarchy and will be detected regardless of the return type of the {@code @Bean}
|
||||
* method (i.e., detection occurs reflectively against the bean instance itself at
|
||||
* creation time).
|
||||
* <p>To disable destroy method inference for a particular {@code @Bean}, specify an
|
||||
* empty string as the value, e.g. {@code @Bean(destroyMethod="")}. Note that the
|
||||
* {@link org.springframework.beans.factory.DisposableBean} and the
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -227,7 +227,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
|
||||
try {
|
||||
this.includeFilters.add(new AnnotationTypeFilter(
|
||||
((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));
|
||||
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
|
||||
logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -235,7 +235,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
}
|
||||
try {
|
||||
this.includeFilters.add(new AnnotationTypeFilter(
|
||||
((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));
|
||||
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
|
||||
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
|
||||
+8
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -145,10 +145,10 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
private static Class<? extends Annotation> ejbRefClass = null;
|
||||
|
||||
static {
|
||||
ClassLoader cl = CommonAnnotationBeanPostProcessor.class.getClassLoader();
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Annotation> clazz = (Class<? extends Annotation>) cl.loadClass("javax.xml.ws.WebServiceRef");
|
||||
Class<? extends Annotation> clazz = (Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.xml.ws.WebServiceRef", CommonAnnotationBeanPostProcessor.class.getClassLoader());
|
||||
webServiceRefClass = clazz;
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -156,7 +156,8 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
}
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Annotation> clazz = (Class<? extends Annotation>) cl.loadClass("javax.ejb.EJB");
|
||||
Class<? extends Annotation> clazz = (Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.ejb.EJB", CommonAnnotationBeanPostProcessor.class.getClassLoader());
|
||||
ejbRefClass = clazz;
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
@@ -314,10 +315,10 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
// 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) {
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
synchronized (this.injectionMetadataCache) {
|
||||
metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
if (metadata == null) {
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
Class<?> targetClass = clazz;
|
||||
|
||||
@@ -606,7 +607,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
}
|
||||
if (StringUtils.hasLength(this.wsdlLocation)) {
|
||||
try {
|
||||
Constructor<?> ctor = this.lookupType.getConstructor(new Class[] {URL.class, QName.class});
|
||||
Constructor<?> ctor = this.lookupType.getConstructor(new Class<?>[] {URL.class, QName.class});
|
||||
WebServiceClient clientAnn = this.lookupType.getAnnotation(WebServiceClient.class);
|
||||
if (clientAnn == null) {
|
||||
throw new IllegalStateException("JAX-WS Service class [" + this.lookupType.getName() +
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -239,7 +239,7 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return new RegexPatternTypeFilter(Pattern.compile(expression));
|
||||
}
|
||||
else if ("custom".equals(filterType)) {
|
||||
Class filterClass = classLoader.loadClass(expression);
|
||||
Class<?> filterClass = classLoader.loadClass(expression);
|
||||
if (!TypeFilter.class.isAssignableFrom(filterClass)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);
|
||||
@@ -256,8 +256,8 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object instantiateUserDefinedStrategy(String className, Class strategyType, ClassLoader classLoader) {
|
||||
Object result = null;
|
||||
private Object instantiateUserDefinedStrategy(String className, Class<?> strategyType, ClassLoader classLoader) {
|
||||
Object result;
|
||||
try {
|
||||
result = classLoader.loadClass(className).newInstance();
|
||||
}
|
||||
@@ -267,7 +267,7 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException("Unable to instantiate class [" + className + "] for strategy [" +
|
||||
strategyType.getName() + "]. A zero-argument constructor is required", ex);
|
||||
strategyType.getName() + "]: a zero-argument constructor is required", ex);
|
||||
}
|
||||
|
||||
if (!strategyType.isAssignableFrom(result.getClass())) {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -179,7 +179,7 @@ final class ConfigurationClass {
|
||||
for (BeanMethod beanMethod : this.beanMethods) {
|
||||
String fqMethodName = beanMethod.getFullyQualifiedMethodName();
|
||||
Integer currentCount = methodNameCounts.get(fqMethodName);
|
||||
int newCount = currentCount != null ? currentCount + 1 : 1;
|
||||
int newCount = (currentCount != null ? currentCount + 1 : 1);
|
||||
methodNameCounts.put(fqMethodName, newCount);
|
||||
}
|
||||
for (String fqMethodName : methodNameCounts.keySet()) {
|
||||
|
||||
+9
-10
@@ -51,8 +51,6 @@ import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.context.annotation.MetadataUtils.*;
|
||||
|
||||
/**
|
||||
* Reads a given fully-populated set of ConfigurationClass instances, registering bean
|
||||
* definitions with the given {@link BeanDefinitionRegistry} based on its contents.
|
||||
@@ -173,13 +171,13 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
|
||||
|
||||
// consider role
|
||||
AnnotationAttributes role = attributesFor(metadata, Role.class);
|
||||
AnnotationAttributes role = MetadataUtils.attributesFor(metadata, Role.class);
|
||||
if (role != null) {
|
||||
beanDef.setRole(role.<Integer>getNumber("value"));
|
||||
}
|
||||
|
||||
// consider name and any aliases
|
||||
AnnotationAttributes bean = attributesFor(metadata, Bean.class);
|
||||
AnnotationAttributes bean = MetadataUtils.attributesFor(metadata, Bean.class);
|
||||
List<String> names = new ArrayList<String>(Arrays.asList(bean.getStringArray("name")));
|
||||
String beanName = (names.size() > 0 ? names.remove(0) : beanMethod.getMetadata().getMethodName());
|
||||
for (String alias : names) {
|
||||
@@ -216,16 +214,16 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
|
||||
// is this bean to be instantiated lazily?
|
||||
if (metadata.isAnnotated(Lazy.class.getName())) {
|
||||
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
|
||||
AnnotationAttributes lazy = MetadataUtils.attributesFor(metadata, Lazy.class);
|
||||
beanDef.setLazyInit(lazy.getBoolean("value"));
|
||||
}
|
||||
else if (configClass.getMetadata().isAnnotated(Lazy.class.getName())){
|
||||
AnnotationAttributes lazy = attributesFor(configClass.getMetadata(), Lazy.class);
|
||||
AnnotationAttributes lazy = MetadataUtils.attributesFor(configClass.getMetadata(), Lazy.class);
|
||||
beanDef.setLazyInit(lazy.getBoolean("value"));
|
||||
}
|
||||
|
||||
if (metadata.isAnnotated(DependsOn.class.getName())) {
|
||||
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
|
||||
AnnotationAttributes dependsOn = MetadataUtils.attributesFor(metadata, DependsOn.class);
|
||||
String[] otherBeans = dependsOn.getStringArray("value");
|
||||
if (otherBeans.length > 0) {
|
||||
beanDef.setDependsOn(otherBeans);
|
||||
@@ -249,7 +247,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
|
||||
// Consider scoping
|
||||
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
|
||||
AnnotationAttributes scope = attributesFor(metadata, Scope.class);
|
||||
AnnotationAttributes scope = MetadataUtils.attributesFor(metadata, Scope.class);
|
||||
if (scope != null) {
|
||||
beanDef.setScope(scope.getString("value"));
|
||||
proxyMode = scope.getEnum("proxyMode");
|
||||
@@ -272,7 +270,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
configClass.getMetadata().getClassName(), beanName));
|
||||
}
|
||||
|
||||
registry.registerBeanDefinition(beanName, beanDefToRegister);
|
||||
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
|
||||
}
|
||||
|
||||
|
||||
@@ -297,7 +295,8 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
readerInstanceCache.put(readerClass, readerInstance);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
|
||||
throw new IllegalStateException(
|
||||
"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
|
||||
}
|
||||
}
|
||||
BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
|
||||
|
||||
+14
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,6 +29,7 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.support.SimpleInstantiationStrategy;
|
||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.CallbackFilter;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
@@ -39,8 +40,13 @@ import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Enhances {@link Configuration} classes by generating a CGLIB subclass capable of
|
||||
* interacting with the Spring container to respect bean semantics.
|
||||
* Enhances {@link Configuration} classes by generating a CGLIB subclass which
|
||||
* interacts with the Spring container to respect bean scoping semantics for
|
||||
* {@code @Bean} methods. Each such {@code @Bean} method will be overridden in
|
||||
* the generated subclass, only delegating to the actual {@code @Bean} method
|
||||
* implementation if the container actually requests the construction of a new
|
||||
* instance. Otherwise, a call to such an {@code @Bean} method serves as a
|
||||
* reference back to the container, obtaining the corresponding bean by name.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
@@ -105,6 +111,7 @@ class ConfigurationClassEnhancer {
|
||||
enhancer.setSuperclass(superclass);
|
||||
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
|
||||
enhancer.setUseFactory(false);
|
||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||
enhancer.setCallbackFilter(CALLBACK_FILTER);
|
||||
enhancer.setCallbackTypes(CALLBACK_TYPES);
|
||||
return enhancer;
|
||||
@@ -128,9 +135,9 @@ class ConfigurationClassEnhancer {
|
||||
* Facilitates idempotent behavior for {@link ConfigurationClassEnhancer#enhance(Class)}
|
||||
* through checking to see if candidate classes are already assignable to it, e.g.
|
||||
* have already been enhanced.
|
||||
* <p>Also extends {@link DisposableBean}, as all enhanced
|
||||
* {@code @Configuration} classes must de-register static CGLIB callbacks on
|
||||
* destruction, which is handled by the (private) {@code DisposableBeanMethodInterceptor}.
|
||||
* <p>Also extends {@link DisposableBean}, as all enhanced {@code @Configuration}
|
||||
* classes must de-register static CGLIB callbacks on destruction, which is handled
|
||||
* by the (private) {@code DisposableBeanMethodInterceptor}.
|
||||
* <p>Note that this interface is intended for framework-internal use only, however
|
||||
* must remain public in order to allow access to subclasses generated from other
|
||||
* packages (i.e. user code).
|
||||
@@ -353,7 +360,7 @@ class ConfigurationClassEnhancer {
|
||||
};
|
||||
enhancer.setCallbackTypes(CALLBACK_TYPES);
|
||||
Class<?> fbSubclass = enhancer.createClass();
|
||||
Enhancer.registerCallbacks(fbSubclass, callbackInstances);
|
||||
Enhancer.registerStaticCallbacks(fbSubclass, callbackInstances);
|
||||
return fbSubclass.newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
+20
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,6 +42,7 @@ import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
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.EnvironmentAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.NestedIOException;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
@@ -59,8 +60,6 @@ import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.context.annotation.MetadataUtils.*;
|
||||
|
||||
/**
|
||||
* Parses a {@link Configuration} class definition, populating a collection of
|
||||
* {@link ConfigurationClass} objects (parsing a single Configuration class may result in
|
||||
@@ -172,20 +171,19 @@ class ConfigurationClassParser {
|
||||
/**
|
||||
* @return annotation metadata of superclass, {@code null} if none found or previously processed
|
||||
*/
|
||||
protected AnnotationMetadata doProcessConfigurationClass(
|
||||
ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
|
||||
|
||||
protected AnnotationMetadata doProcessConfigurationClass(ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
|
||||
// recursively process any member (nested) classes first
|
||||
processMemberClasses(metadata);
|
||||
|
||||
// process any @PropertySource annotations
|
||||
AnnotationAttributes propertySource = attributesFor(metadata, org.springframework.context.annotation.PropertySource.class);
|
||||
AnnotationAttributes propertySource = MetadataUtils.attributesFor(metadata,
|
||||
org.springframework.context.annotation.PropertySource.class);
|
||||
if (propertySource != null) {
|
||||
processPropertySource(propertySource);
|
||||
}
|
||||
|
||||
// process any @ComponentScan annotations
|
||||
AnnotationAttributes componentScan = attributesFor(metadata, ComponentScan.class);
|
||||
AnnotationAttributes componentScan = MetadataUtils.attributesFor(metadata, ComponentScan.class);
|
||||
if (componentScan != null) {
|
||||
// the config class is annotated with @ComponentScan -> perform the scan immediately
|
||||
Set<BeanDefinitionHolder> scannedBeanDefinitions =
|
||||
@@ -204,12 +202,12 @@ class ConfigurationClassParser {
|
||||
Set<Object> visited = new LinkedHashSet<Object>();
|
||||
collectImports(metadata, imports, visited);
|
||||
if (!imports.isEmpty()) {
|
||||
processImport(configClass, imports, true);
|
||||
processImport(configClass, metadata, imports, true);
|
||||
}
|
||||
|
||||
// process any @ImportResource annotations
|
||||
if (metadata.isAnnotated(ImportResource.class.getName())) {
|
||||
AnnotationAttributes importResource = attributesFor(metadata, ImportResource.class);
|
||||
AnnotationAttributes importResource = MetadataUtils.attributesFor(metadata, ImportResource.class);
|
||||
String[] resources = importResource.getStringArray("value");
|
||||
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
|
||||
for (String resource : resources) {
|
||||
@@ -227,23 +225,13 @@ class ConfigurationClassParser {
|
||||
// process superclass, if any
|
||||
if (metadata.hasSuperClass()) {
|
||||
String superclass = metadata.getSuperClassName();
|
||||
if (!this.knownSuperclasses.containsKey(superclass)) {
|
||||
if (!superclass.startsWith("java") && !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();
|
||||
return new StandardAnnotationMetadata(clazz.getSuperclass(), true);
|
||||
}
|
||||
else if (superclass.startsWith("java")) {
|
||||
// never load core JDK classes via ASM, in particular not java.lang.Object!
|
||||
try {
|
||||
return new StandardAnnotationMetadata(
|
||||
this.resourceLoader.getClassLoader().loadClass(superclass), true);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(superclass);
|
||||
return reader.getAnnotationMetadata();
|
||||
@@ -369,13 +357,14 @@ class ConfigurationClassParser {
|
||||
}
|
||||
}
|
||||
|
||||
private void processImport(ConfigurationClass configClass, Collection<?> classesToImport, boolean checkForCircularImports) throws IOException {
|
||||
private void processImport(ConfigurationClass configClass, AnnotationMetadata metadata,
|
||||
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();
|
||||
try {
|
||||
for (Object candidate : classesToImport) {
|
||||
Object candidateToCheck = (candidate instanceof Class ? (Class) candidate :
|
||||
@@ -385,7 +374,7 @@ class ConfigurationClassParser {
|
||||
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);
|
||||
processImport(configClass, metadata, Arrays.asList(selector.selectImports(metadata)), false);
|
||||
}
|
||||
else if (checkAssignability(ImportBeanDefinitionRegistrar.class, candidateToCheck)) {
|
||||
// the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
|
||||
@@ -393,11 +382,11 @@ class ConfigurationClassParser {
|
||||
this.resourceLoader.getClassLoader().loadClass((String) candidate));
|
||||
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
|
||||
invokeAwareMethods(registrar);
|
||||
registrar.registerBeanDefinitions(importingClassMetadata, this.registry);
|
||||
registrar.registerBeanDefinitions(metadata, this.registry);
|
||||
}
|
||||
else {
|
||||
// candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class
|
||||
this.importStack.registerImport(importingClassMetadata,
|
||||
this.importStack.registerImport(metadata,
|
||||
(candidate instanceof Class ? ((Class) candidate).getName() : (String) candidate));
|
||||
processConfigurationClass(candidateToCheck instanceof Class ? new ConfigurationClass((Class) candidateToCheck, true) :
|
||||
new ConfigurationClass((MetadataReader) candidateToCheck, true));
|
||||
@@ -423,11 +412,14 @@ class ConfigurationClassParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke {@link ResourceLoaderAware}, {@link BeanClassLoaderAware} and
|
||||
* {@link BeanFactoryAware} contracts if implemented by the given {@code registrar}.
|
||||
* Invoke {@link EnvironmentAware}, {@link ResourceLoaderAware}, {@link BeanClassLoaderAware}
|
||||
* and {@link BeanFactoryAware} contracts if implemented by the given {@code registrar}.
|
||||
*/
|
||||
private void invokeAwareMethods(ImportBeanDefinitionRegistrar registrar) {
|
||||
if (registrar instanceof Aware) {
|
||||
if (registrar instanceof EnvironmentAware) {
|
||||
((EnvironmentAware) registrar).setEnvironment(this.environment);
|
||||
}
|
||||
if (registrar instanceof ResourceLoaderAware) {
|
||||
((ResourceLoaderAware) registrar).setResourceLoader(this.resourceLoader);
|
||||
}
|
||||
|
||||
+25
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -93,14 +93,36 @@ abstract class ConfigurationClassUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the given metadata for a configuration class candidate
|
||||
* (or nested component class declared within a configuration/component class).
|
||||
* @param metadata the metadata of the annotated class
|
||||
* @return {@code true} if the given class is to be registered as a
|
||||
* reflection-detected bean definition; {@code false} otherwise
|
||||
*/
|
||||
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
|
||||
return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the given metadata for a full configuration class candidate
|
||||
* (i.e. a class annotated with {@code @Configuration}).
|
||||
* @param metadata the metadata of the annotated class
|
||||
* @return {@code true} if the given class is to be processed as a full
|
||||
* configuration class, including cross-method call interception
|
||||
*/
|
||||
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
|
||||
return metadata.isAnnotated(Configuration.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the given metadata for a lite configuration class candidate
|
||||
* (e.g. a class annotated with {@code @Component} or just having
|
||||
* {@code @Bean methods}).
|
||||
* @param metadata the metadata of the annotated class
|
||||
* @return {@code true} if the given class is to be processed as a lite
|
||||
* configuration class, just registering it and scanning it for {@code @Bean} methods
|
||||
*/
|
||||
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
|
||||
// Do not consider an interface or an annotation...
|
||||
return (!metadata.isInterface() && (
|
||||
@@ -108,7 +130,8 @@ abstract class ConfigurationClassUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given bean definition indicates a full @Configuration class.
|
||||
* Determine whether the given bean definition indicates a full
|
||||
* {@code @Configuration} class.
|
||||
*/
|
||||
public static boolean isFullConfigurationClass(BeanDefinition beanDef) {
|
||||
return CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
|
||||
|
||||
+23
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,11 +23,14 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -49,13 +52,16 @@ import org.springframework.util.ObjectUtils;
|
||||
* @see #getApplicationListeners(ApplicationEvent)
|
||||
* @see SimpleApplicationEventMulticaster
|
||||
*/
|
||||
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {
|
||||
public abstract class AbstractApplicationEventMulticaster
|
||||
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
|
||||
|
||||
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
|
||||
|
||||
private final Map<ListenerCacheKey, ListenerRetriever> retrieverCache =
|
||||
new ConcurrentHashMap<ListenerCacheKey, ListenerRetriever>(64);
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
|
||||
@@ -95,8 +101,15 @@ public abstract class AbstractApplicationEventMulticaster implements Application
|
||||
}
|
||||
}
|
||||
|
||||
public final void setBeanFactory(BeanFactory beanFactory) {
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
if (this.beanClassLoader == null && beanFactory instanceof ConfigurableBeanFactory) {
|
||||
this.beanClassLoader = ((ConfigurableBeanFactory) beanFactory).getBeanClassLoader();
|
||||
}
|
||||
}
|
||||
|
||||
private BeanFactory getBeanFactory() {
|
||||
@@ -162,7 +175,11 @@ public abstract class AbstractApplicationEventMulticaster implements Application
|
||||
}
|
||||
}
|
||||
OrderComparator.sort(allListeners);
|
||||
this.retrieverCache.put(cacheKey, retriever);
|
||||
if (this.beanClassLoader == null ||
|
||||
(ClassUtils.isCacheSafe(eventType, this.beanClassLoader) &&
|
||||
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
|
||||
this.retrieverCache.put(cacheKey, retriever);
|
||||
}
|
||||
return allListeners;
|
||||
}
|
||||
}
|
||||
@@ -176,8 +193,8 @@ public abstract class AbstractApplicationEventMulticaster implements Application
|
||||
* @param listener the target listener to check
|
||||
* @param eventType the event type to check against
|
||||
* @param sourceType the source type to check against
|
||||
* @return whether the given listener should be included in the
|
||||
* candidates for the given event type
|
||||
* @return whether the given listener should be included in the candidates
|
||||
* for the given event type
|
||||
*/
|
||||
protected boolean supportsEvent(
|
||||
ApplicationListener listener, Class<? extends ApplicationEvent> eventType, Class sourceType) {
|
||||
|
||||
+6
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,6 +32,11 @@ import org.springframework.expression.TypedValue;
|
||||
*/
|
||||
public class BeanFactoryAccessor implements PropertyAccessor {
|
||||
|
||||
public Class<?>[] getSpecificTargetClasses() {
|
||||
return new Class<?>[] {BeanFactory.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return (((BeanFactory) target).containsBean(name));
|
||||
}
|
||||
@@ -48,8 +53,4 @@ public class BeanFactoryAccessor implements PropertyAccessor {
|
||||
throw new AccessException("Beans in a BeanFactory are read-only");
|
||||
}
|
||||
|
||||
public Class[] getSpecificTargetClasses() {
|
||||
return new Class[] {BeanFactory.class};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user