mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
352 Commits
v4.3.28.RELEASE
...
4.1.x
| Author | SHA1 | Date | |
|---|---|---|---|
| 11fc10282d | |||
| 91df01115d | |||
| 412cd83c3a | |||
| c0fd92c131 | |||
| 94f17f3e4b | |||
| 9652430f01 | |||
| 581b2b0b88 | |||
| 4fa4886e70 | |||
| 46016d090b | |||
| 241dfbf855 | |||
| bc492b9251 | |||
| 8c8380715d | |||
| b64d752906 | |||
| 1d0c2f6f0e | |||
| 4b27a6ddee | |||
| 3403e8d843 | |||
| d573bbc6b8 | |||
| f7492348ba | |||
| e4faaa3786 | |||
| d04f785094 | |||
| e37b75b165 | |||
| f54aac1003 | |||
| c2fed6e7f1 | |||
| 242acda970 | |||
| 66c44524d7 | |||
| 0230c49a82 | |||
| f7f801c501 | |||
| 83c9ec43da | |||
| d03d8cb456 | |||
| 6963e27c7a | |||
| 7a7877040f | |||
| e38cea610c | |||
| 57d980130e | |||
| ff8bbc93f3 | |||
| 6f11d4f06c | |||
| f53d01b00a | |||
| b3eefa2ae0 | |||
| 5ac42bf9f8 | |||
| 79ded1ca72 | |||
| fad0c9589d | |||
| 85863a5442 | |||
| 948ab21f43 | |||
| c56d1a6677 | |||
| e6d3c28ec2 | |||
| a730b6e1aa | |||
| 6c4f0a4d9f | |||
| 3bc2a97776 | |||
| ce315b223e | |||
| 5bfa82db12 | |||
| 97148ce889 | |||
| e410129aaf | |||
| 55494362ef | |||
| 393e36c29e | |||
| 5a95156dcc | |||
| 71fc2ba174 | |||
| 48838d48d2 | |||
| 5d6aab34cb | |||
| 90a288513c | |||
| df49b11758 | |||
| d1f5ee2643 | |||
| 0f4e4fcca6 | |||
| a8c7220fc7 | |||
| 92ca537d61 | |||
| f5f57e9544 | |||
| cde4431c80 | |||
| d500d523e7 | |||
| 71a9eb7102 | |||
| e190f26669 | |||
| 0f1897d376 | |||
| 563a120280 | |||
| 78fc5bbecc | |||
| a879897063 | |||
| 0016752ad8 | |||
| a95c3d820d | |||
| 271e5fd76a | |||
| 5d36ac08ef | |||
| 49393e54a1 | |||
| 302a069257 | |||
| c33c26ac5d | |||
| 0086dd830b | |||
| 799a03e98d | |||
| c0b6d320f1 | |||
| d7a418356e | |||
| 13283ec918 | |||
| ca60d796a8 | |||
| 16cb73673e | |||
| 196adbd459 | |||
| de932903ca | |||
| 57125c0adc | |||
| 50c59425d9 | |||
| fe36334232 | |||
| e0a139a0d4 | |||
| 3c549ef9fa | |||
| 8429c4be74 | |||
| be90f7ddd4 | |||
| 315a848e6e | |||
| 1239595672 | |||
| 4428c347a5 | |||
| ad167066e7 | |||
| 9c40adb0da | |||
| 1d698617f6 | |||
| 60d7a7f519 | |||
| f1acd2882c | |||
| aa0f11788b | |||
| 7202793db0 | |||
| 045016ebf9 | |||
| df3c3127a5 | |||
| 2c73c5a893 | |||
| 987d93f2ce | |||
| 8bf9257fe8 | |||
| 38db9fa855 | |||
| af5f4e6fb4 | |||
| 2dcf52797c | |||
| de0f3aec53 | |||
| fd2252a14e | |||
| 3402c13803 | |||
| cc741cdc51 | |||
| 8daa932e69 | |||
| f562eb5ff6 | |||
| 856561fa6e | |||
| c4a9abb6be | |||
| a6d17a6bd7 | |||
| 7aa3175a71 | |||
| 49161da403 | |||
| a35f71964a | |||
| 75187e3a8e | |||
| 4ff23f4708 | |||
| 42d5780cd3 | |||
| 33f9eadd6a | |||
| 7575271075 | |||
| ce50fc59ee | |||
| b77cc7ae4a | |||
| 4012b4df5e | |||
| ac4c278d3a | |||
| 35b257514d | |||
| 3a4085a286 | |||
| daf94ea576 | |||
| 65a5ce3fa4 | |||
| 4fbf6a3572 | |||
| 7c72a57a4d | |||
| ca9beeac9d | |||
| 3eb54cc0b3 | |||
| 2c32873309 | |||
| 40fc260d45 | |||
| c4e0f14ec4 | |||
| 38b8262e1e | |||
| 9c3580d04e | |||
| a837cbe81f | |||
| f1b42b7d8f | |||
| 3d131c9f3c | |||
| a8ac6db43b | |||
| bf94344139 | |||
| b3f01998d2 | |||
| 8dd182f76c | |||
| b731f7ad15 | |||
| 9dea9d57db | |||
| c85127d3f8 | |||
| 846fae241b | |||
| d08c0669da | |||
| 13a2ae27e1 | |||
| ef9910c3c4 | |||
| 33b9bd72cc | |||
| bccdefdf30 | |||
| 2109db0c02 | |||
| 6f7ad3b1c0 | |||
| 84ae28b2bb | |||
| d2621baf0a | |||
| 7a6ce1c265 | |||
| 063a720ac0 | |||
| 3227007816 | |||
| daf12a9723 | |||
| b5bb26b7c6 | |||
| ae3cc67391 | |||
| 55de4a69ae | |||
| bf38b3a4fc | |||
| aa3a78aa0e | |||
| 6cdc208c73 | |||
| fd1b5e80a7 | |||
| 3c6f1f8352 | |||
| c111bd7547 | |||
| 1177f5c0a3 | |||
| bd05e3ade2 | |||
| bd601ce2e4 | |||
| 24783303a7 | |||
| 9e8e7aa6b9 | |||
| c99cc53da1 | |||
| cd9b58b0ab | |||
| ae35e84c1e | |||
| 391f72d2e4 | |||
| 633d13ffab | |||
| ca17dc06a5 | |||
| 51c941ca11 | |||
| 9e925aa86c | |||
| a899e066f2 | |||
| 89694b009a | |||
| a8f75399f8 | |||
| 14cd3ef2d5 | |||
| ce4e795f09 | |||
| 0cd7fed050 | |||
| 8e074b6b67 | |||
| 5b10575ce5 | |||
| 6a7aab02aa | |||
| e95a7a47c3 | |||
| fb7476f543 | |||
| 56f8d17b0c | |||
| 6783ba2903 | |||
| 8f6ac19f50 | |||
| e67a63e1f7 | |||
| f1dbe8db27 | |||
| bf423b2ca0 | |||
| 581cf3a0a5 | |||
| b44044e36f | |||
| 34a5fb28c2 | |||
| 50f49774bc | |||
| e799554ab8 | |||
| e2a55ced50 | |||
| 35bf96763d | |||
| fc79ea3dd7 | |||
| e9e2b7369e | |||
| 89f5248189 | |||
| d506767202 | |||
| d0a9bd0696 | |||
| 97f779674f | |||
| 5f6ae13002 | |||
| 52ed9b7106 | |||
| ca09eb2c59 | |||
| 13a87453b6 | |||
| 673dac5620 | |||
| 6892ad42d6 | |||
| 1d5128ed1b | |||
| 34aac078b1 | |||
| f52702ea3c | |||
| d2d006b68f | |||
| 8d14e7736a | |||
| 2de5faf56c | |||
| 5f95ff6bfd | |||
| 4446b5fe8a | |||
| 76649a4455 | |||
| 98d00ea698 | |||
| ce84fafde4 | |||
| b352dbfdeb | |||
| f42c53d9be | |||
| 151e96cac4 | |||
| a522fa36af | |||
| 5c463a1680 | |||
| 0280a2a994 | |||
| b455626ce1 | |||
| cb6459c271 | |||
| 6b9e89118f | |||
| f2b9a0a117 | |||
| 406adb3381 | |||
| bac012f3e8 | |||
| f93394171a | |||
| ebe45cf079 | |||
| 7ed7f981c9 | |||
| f01a0303f1 | |||
| f2691901bb | |||
| 5f305759fa | |||
| 410fc6d763 | |||
| 3783591083 | |||
| 1259671f3f | |||
| 590b23ccb3 | |||
| 2d98988d5c | |||
| 364210b0e7 | |||
| b6f22aa514 | |||
| 522c1b1b3d | |||
| 55eb5b622c | |||
| 6c93745f35 | |||
| ca9f6a1e1e | |||
| 3570a9a94a | |||
| 91c47a9eb8 | |||
| 7eb4679f28 | |||
| 0f95c81712 | |||
| 2c47098b35 | |||
| b4d9fb9e6e | |||
| 4a332bd0b2 | |||
| 772552b9ef | |||
| 6be554cba5 | |||
| ce085a606f | |||
| c0e550cfb4 | |||
| 7a5b2e6a75 | |||
| d7dcf8d6f4 | |||
| d77af71e9c | |||
| 5db4e4bab0 | |||
| 7cc56e1630 | |||
| b5e80390de | |||
| 55a14eb684 | |||
| d8269dd9fe | |||
| aae7583141 | |||
| 6fafe63311 | |||
| f1e406c63b | |||
| c8a4d1649f | |||
| 8dbe753963 | |||
| 23fa37b08b | |||
| cc78d40c6b | |||
| 1dc39324b9 | |||
| 2a240b0dc8 | |||
| 3b8d878285 | |||
| d98f626be1 | |||
| b8dbf2345c | |||
| 2b135f0d51 | |||
| e5d41d91d5 | |||
| f398dd03a7 | |||
| f82c6635d7 | |||
| 9499e4166c | |||
| bf442c093c | |||
| fab8dd3d0b | |||
| 1646f62700 | |||
| c8d9bfadad | |||
| 0706889222 | |||
| 25644dbdb9 | |||
| 181b35243e | |||
| 6c47b5f5d3 | |||
| 4a423e50a8 | |||
| 0225a7776c | |||
| d57f7f8783 | |||
| 4550b4a254 | |||
| f902fb911c | |||
| 77c8aa53ae | |||
| bb5da15e1c | |||
| 0c8d07fcff | |||
| 47fdac9214 | |||
| 7ffa845aa8 | |||
| 09bd7037e9 | |||
| 49c21a0a06 | |||
| d9d8a79c30 | |||
| 04840166af | |||
| 6fce6d4668 | |||
| 0c856b3d22 | |||
| d63cfc8eeb | |||
| 7621cc787d | |||
| 2c1682af34 | |||
| dcaa0987ee | |||
| 14a3bf3941 | |||
| 23b09015fe | |||
| b82e9c4d46 | |||
| c158874d82 | |||
| 87b7cd6368 | |||
| 901d7d07db | |||
| bfba988a0d | |||
| a7975c685d | |||
| cdaf4497b6 | |||
| 84807c5d61 | |||
| a76a6509e5 | |||
| 7d171e6722 | |||
| 36da551280 | |||
| ed665a12a3 | |||
| adec0265a4 | |||
| 8c700b19da | |||
| 9542313710 | |||
| dcb821edb5 | |||
| daa4adf2ed |
@@ -22,14 +22,6 @@ do not find something similar, please create a new JIRA issue before submitting
|
||||
a pull request unless the change is truly trivial -- for example: typo fixes,
|
||||
removing compiler warnings, etc.
|
||||
|
||||
### Discuss non-trivial contribution ideas with committers
|
||||
|
||||
If you're considering anything more than correcting a typo or fixing a minor
|
||||
bug, please discuss it on the [spring-framework-contrib][] mailing list before
|
||||
submitting a pull request. We're happy to provide guidance, but please spend an
|
||||
hour or two researching the subject on your own, including searching the mailing
|
||||
list for prior discussions.
|
||||
|
||||
### Sign the Contributor License Agreement
|
||||
|
||||
If you have not previously done so, please fill out and submit the
|
||||
|
||||
+72
-70
@@ -5,7 +5,7 @@ buildscript {
|
||||
dependencies {
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
|
||||
classpath("org.asciidoctor:asciidoctor-gradle-plugin:0.7.0")
|
||||
classpath("io.spring.gradle:docbook-reference-plugin:0.3.0")
|
||||
classpath("io.spring.gradle:docbook-reference-plugin:0.3.1")
|
||||
classpath("ws.antonov.gradle.plugins:gradle-plugin-protobuf:0.9.1")
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ ext {
|
||||
linkScmConnection = 'scm:git:git://github.com/spring-projects/spring-framework.git'
|
||||
linkScmDevConnection = 'scm:git:ssh://git@github.com:spring-projects/spring-framework.git'
|
||||
|
||||
moduleProjects = subprojects.findAll {
|
||||
moduleProjects = subprojects.findAll {
|
||||
!it.name.equals('spring-build-src') && !it.name.equals('spring-framework-bom')
|
||||
}
|
||||
}
|
||||
@@ -27,34 +27,34 @@ configure(allprojects) { project ->
|
||||
group = "org.springframework"
|
||||
version = qualifyVersionIfNecessary(version)
|
||||
|
||||
ext.aspectjVersion = "1.8.4"
|
||||
ext.aspectjVersion = "1.8.7"
|
||||
ext.eclipseLinkVersion = "2.4.2"
|
||||
ext.ehcacheVersion = "2.9.0"
|
||||
ext.ehcacheJCacheVersion = "1.0.0"
|
||||
ext.groovyVersion = "2.3.9"
|
||||
ext.ehcacheVersion = "2.9.1"
|
||||
ext.ehcacheJCacheVersion = "1.0.1"
|
||||
ext.groovyVersion = "2.3.11"
|
||||
ext.gsonVersion = "2.3.1"
|
||||
ext.hibernate3Version = "3.6.10.Final"
|
||||
ext.hibernate4Version = "4.3.7.Final"
|
||||
ext.hibernate4Version = "4.3.11.Final"
|
||||
ext.hibVal4Version = "4.3.2.Final"
|
||||
ext.hibVal5Version = "5.1.3.Final"
|
||||
ext.hsqldbVersion = "2.3.2"
|
||||
ext.jackson2Version = "2.4.4"
|
||||
ext.jasperReportsVersion = "6.0.0"
|
||||
ext.jettyVersion = "9.2.6.v20141205"
|
||||
ext.jodaVersion = "2.6"
|
||||
ext.hsqldbVersion = "2.3.3"
|
||||
ext.jackson2Version = "2.4.6"
|
||||
ext.jasperReportsVersion = "6.0.4"
|
||||
ext.jettyVersion = "9.2.14.v20151106"
|
||||
ext.jodaVersion = "2.8.2"
|
||||
ext.junitVersion = "4.12"
|
||||
ext.nettyVersion = "4.0.24.Final"
|
||||
ext.nettyVersion = "4.0.33.Final"
|
||||
ext.openJpaVersion = "2.2.2" // 2.3.0 not Java 8 compatible (based on ASM 4)
|
||||
ext.protobufVersion = "2.6.1"
|
||||
ext.reactorVersion = "1.1.5.RELEASE"
|
||||
ext.slf4jVersion = "1.7.9"
|
||||
ext.snakeYamlVersion = "1.14"
|
||||
ext.reactorVersion = "1.1.6.RELEASE"
|
||||
ext.slf4jVersion = "1.7.13"
|
||||
ext.snakeYamlVersion = "1.16"
|
||||
ext.snifferVersion = "1.11"
|
||||
ext.tiles2Version = "2.2.2"
|
||||
ext.tiles3Version = "3.0.5"
|
||||
ext.tomcatVersion = "8.0.15"
|
||||
ext.tomcatVersion = "8.0.30"
|
||||
ext.tyrusVersion = "1.3.5" // constrained by WebLogic 12.1.3 support
|
||||
ext.undertowVersion = "1.1.1.Final"
|
||||
ext.undertowVersion = "1.1.9.Final"
|
||||
ext.woodstoxVersion = "4.4.1"
|
||||
ext.xstreamVersion = "1.4.7"
|
||||
|
||||
@@ -86,13 +86,13 @@ configure(allprojects) { project ->
|
||||
"-Xlint:-unchecked", "-Xlint:-options"]
|
||||
|
||||
compileJava {
|
||||
sourceCompatibility=1.6
|
||||
targetCompatibility=1.6
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
}
|
||||
|
||||
compileTestJava {
|
||||
sourceCompatibility=1.8
|
||||
targetCompatibility=1.8
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
options.compilerArgs += "-parameters"
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ configure(allprojects) { project ->
|
||||
testCompile("org.hamcrest:hamcrest-all:1.3")
|
||||
|
||||
sniffer("org.codehaus.mojo:animal-sniffer-ant-tasks:${snifferVersion}")
|
||||
javaApiSignature("org.codehaus.mojo.signature:java16:1.1@signature") // as from JDK 6 update 18
|
||||
javaApiSignature("org.codehaus.mojo.signature:java16:1.1@signature") // API level from JDK 6 update 18
|
||||
}
|
||||
|
||||
task copyJavaApiSignature(type: Copy) {
|
||||
@@ -143,7 +143,6 @@ configure(allprojects) { project ->
|
||||
|
||||
inputs.dir sourceSets.main.output.classesDir
|
||||
inputs.dir copyJavaApiSignature.to
|
||||
outputs.upToDateWhen { true }
|
||||
|
||||
doLast {
|
||||
ant.taskdef(
|
||||
@@ -164,27 +163,27 @@ configure(allprojects) { project ->
|
||||
}
|
||||
|
||||
ext.javadocLinks = [
|
||||
"http://docs.oracle.com/javase/8/docs/api/",
|
||||
"http://docs.oracle.com/javaee/7/api/",
|
||||
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
|
||||
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
|
||||
"http://glassfish.java.net/nonav/docs/v3/api/",
|
||||
"http://docs.jboss.org/jbossas/javadoc/4.0.5/connector/",
|
||||
"http://docs.jboss.org/jbossas/javadoc/7.1.2.Final/",
|
||||
"http://commons.apache.org/proper/commons-lang/javadocs/api-2.5/",
|
||||
"http://commons.apache.org/proper/commons-codec/apidocs/",
|
||||
"http://commons.apache.org/proper/commons-dbcp/apidocs/",
|
||||
"http://portals.apache.org/pluto/portlet-2.0-apidocs/",
|
||||
"http://tiles.apache.org/tiles-request/apidocs/",
|
||||
"http://tiles.apache.org/framework/apidocs/",
|
||||
"https://docs.oracle.com/javase/8/docs/api/",
|
||||
"https://docs.oracle.com/javaee/7/api/",
|
||||
"https://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
|
||||
"https://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
|
||||
"https://glassfish.java.net/nonav/docs/v3/api/",
|
||||
"https://docs.jboss.org/jbossas/javadoc/4.0.5/connector/",
|
||||
"https://docs.jboss.org/jbossas/javadoc/7.1.2.Final/",
|
||||
"https://commons.apache.org/proper/commons-lang/javadocs/api-2.5/",
|
||||
"https://commons.apache.org/proper/commons-codec/apidocs/",
|
||||
"https://commons.apache.org/proper/commons-dbcp/apidocs/",
|
||||
"https://portals.apache.org/pluto/portlet-2.0-apidocs/",
|
||||
"https://tiles.apache.org/tiles-request/apidocs/",
|
||||
"https://tiles.apache.org/framework/apidocs/",
|
||||
"http://aopalliance.sourceforge.net/doc/",
|
||||
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
|
||||
"http://ehcache.org/apidocs/",
|
||||
"http://quartz-scheduler.org/api/2.2.0/",
|
||||
"http://fasterxml.github.com/jackson-core/javadoc/2.3.0/",
|
||||
"http://fasterxml.github.com/jackson-databind/javadoc/2.3.0/",
|
||||
"http://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.3.0/",
|
||||
"http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/"
|
||||
"https://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
|
||||
"https://www.ehcache.org/apidocs/${ehcacheVersion}/",
|
||||
"https://www.quartz-scheduler.org/api/2.2.2/",
|
||||
"https://fasterxml.github.io/jackson-core/javadoc/2.3.0/",
|
||||
"https://fasterxml.github.io/jackson-databind/javadoc/2.3.0/",
|
||||
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.3.0/",
|
||||
"https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/"
|
||||
] as String[]
|
||||
}
|
||||
|
||||
@@ -331,10 +330,10 @@ project("spring-core") {
|
||||
compile("commons-logging:commons-logging:1.2")
|
||||
optional("commons-codec:commons-codec:1.10")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("net.sf.jopt-simple:jopt-simple:4.8")
|
||||
optional("net.sf.jopt-simple:jopt-simple:4.9")
|
||||
optional("log4j:log4j:1.2.17")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
testCompile("xmlunit:xmlunit:1.5")
|
||||
testCompile("xmlunit:xmlunit:1.6")
|
||||
testCompile("org.codehaus.woodstox:woodstox-core-asl:${woodstoxVersion}") {
|
||||
exclude group: "stax", module: "stax-api"
|
||||
}
|
||||
@@ -389,8 +388,8 @@ project("spring-beans-groovy") {
|
||||
}
|
||||
|
||||
compileGroovy {
|
||||
sourceCompatibility=1.6
|
||||
targetCompatibility=1.6
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,7 +404,7 @@ project("spring-aop") {
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("commons-pool:commons-pool:1.6")
|
||||
optional("com.jamonapi:jamon:2.79")
|
||||
optional("com.jamonapi:jamon:2.81")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,7 +459,7 @@ project("spring-context") {
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("org.beanshell:bsh:2.0b4")
|
||||
optional("org.jruby:jruby:1.7.17")
|
||||
optional("org.jruby:jruby:1.7.22")
|
||||
testCompile("javax.inject:javax.inject-tck:1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.4")
|
||||
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
@@ -533,9 +532,9 @@ project("spring-oxm") {
|
||||
|
||||
compileTestJava {
|
||||
// necessary to avoid java.lang.VerifyError on jibx compilation
|
||||
// see http://jira.codehaus.org/browse/JIBX-465
|
||||
sourceCompatibility=1.6
|
||||
targetCompatibility=1.6
|
||||
// see https://jira.codehaus.org/browse/JIBX-465
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -552,9 +551,9 @@ project("spring-oxm") {
|
||||
exclude group: 'xpp3', module: 'xpp3_min'
|
||||
exclude group: 'xmlpull', module: 'xmlpull'
|
||||
}
|
||||
optional("org.jibx:jibx-run:1.2.5")
|
||||
optional("org.jibx:jibx-run:1.2.6")
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile("xmlunit:xmlunit:1.5")
|
||||
testCompile("xmlunit:xmlunit:1.6")
|
||||
testCompile("xpp3:xpp3:1.1.4c")
|
||||
testCompile("org.codehaus.jettison:jettison:1.3.7") {
|
||||
exclude group: 'stax', module: 'stax-api'
|
||||
@@ -593,9 +592,9 @@ project("spring-jdbc") {
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-context")) // for JndiDataSourceLookup
|
||||
optional("javax.transaction:javax.transaction-api:1.2")
|
||||
optional("com.mchange:c3p0:0.9.2.1")
|
||||
optional("com.mchange:c3p0:0.9.5.1")
|
||||
optional("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
optional("com.h2database:h2:1.4.182")
|
||||
optional("com.h2database:h2:1.4.190")
|
||||
optional("org.apache.derby:derby:10.11.1.1")
|
||||
optional("org.apache.derby:derbyclient:10.11.1.1")
|
||||
}
|
||||
@@ -617,7 +616,7 @@ project("spring-context-support") {
|
||||
optional("org.quartz-scheduler:quartz:2.2.1")
|
||||
optional("org.codehaus.fabric3.api:commonj:1.1.0")
|
||||
optional("org.apache.velocity:velocity:1.7")
|
||||
optional("org.freemarker:freemarker:2.3.21")
|
||||
optional("org.freemarker:freemarker:2.3.22")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("net.sf.jasperreports:jasperreports:$jasperReportsVersion") {
|
||||
exclude group: "com.fasterxml.jackson.core", module: "jackson-annotations"
|
||||
@@ -625,9 +624,10 @@ project("spring-context-support") {
|
||||
exclude group: "com.fasterxml.jackson.core", module: "jackson-databind"
|
||||
exclude group: "org.olap4j", module: "olap4j"
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
exclude group: "org.springframework", module: "spring-context"
|
||||
}
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile("org.apache.poi:poi:3.10.1")
|
||||
testCompile("org.apache.poi:poi:3.11")
|
||||
testCompile("commons-beanutils:commons-beanutils:1.8.0") // for Velocity/JasperReports
|
||||
testCompile("commons-digester:commons-digester:1.8.1") // for Velocity/JasperReports
|
||||
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
|
||||
@@ -680,7 +680,7 @@ project("spring-web") {
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}")
|
||||
optional("com.google.code.gson:gson:${gsonVersion}")
|
||||
optional("com.rometools:rome:1.5.0")
|
||||
optional("com.rometools:rome:1.5.1")
|
||||
optional("org.eclipse.jetty:jetty-servlet:${jettyVersion}") {
|
||||
exclude group: "javax.servlet", module: "javax.servlet-api"
|
||||
}
|
||||
@@ -692,11 +692,12 @@ project("spring-web") {
|
||||
optional("com.google.protobuf:protobuf-java:${protobufVersion}")
|
||||
optional("javax.mail:javax.mail-api:1.5.2")
|
||||
testCompile(project(":spring-context-support")) // for JafMediaTypeFactory
|
||||
testCompile("xmlunit:xmlunit:1.5")
|
||||
testCompile("xmlunit:xmlunit:1.6")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("org.apache.taglibs:taglibs-standard-jstlel:1.2.1") {
|
||||
exclude group: "org.apache.taglibs", module: "taglibs-standard-spec"
|
||||
}
|
||||
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-joda:${jackson2Version}")
|
||||
testRuntime("com.sun.mail:javax.mail:1.5.2")
|
||||
}
|
||||
|
||||
@@ -826,10 +827,10 @@ project("spring-webmvc") {
|
||||
optional("javax.servlet.jsp:javax.servlet.jsp-api:2.2.1")
|
||||
optional("javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1")
|
||||
optional("net.sourceforge.jexcelapi:jxl:2.6.12")
|
||||
optional("org.apache.poi:poi:3.10.1")
|
||||
optional("org.apache.poi:poi:3.11")
|
||||
optional("org.apache.velocity:velocity:1.7")
|
||||
optional("velocity-tools:velocity-tools-view:1.4")
|
||||
optional("org.freemarker:freemarker:2.3.20")
|
||||
optional("org.freemarker:freemarker:2.3.22")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("net.sf.jasperreports:jasperreports:$jasperReportsVersion") {
|
||||
@@ -838,10 +839,11 @@ project("spring-webmvc") {
|
||||
exclude group: "com.fasterxml.jackson.core", module: "jackson-databind"
|
||||
exclude group: "org.olap4j", module: "olap4j"
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
exclude group: "org.springframework", module: "spring-context"
|
||||
}
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}")
|
||||
optional("com.rometools:rome:1.5.0")
|
||||
optional("com.rometools:rome:1.5.1")
|
||||
optional("javax.el:javax.el-api:2.2.5")
|
||||
optional("org.apache.tiles:tiles-api:${tiles3Version}")
|
||||
optional("org.apache.tiles:tiles-core:${tiles3Version}") {
|
||||
@@ -862,7 +864,7 @@ project("spring-webmvc") {
|
||||
}
|
||||
testCompile(project(":spring-aop"))
|
||||
testCompile("rhino:js:1.7R1")
|
||||
testCompile("xmlunit:xmlunit:1.5")
|
||||
testCompile("xmlunit:xmlunit:1.6")
|
||||
testCompile("dom4j:dom4j:1.6.1") {
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
}
|
||||
@@ -967,9 +969,9 @@ project("spring-test") {
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
|
||||
optional("org.hamcrest:hamcrest-core:1.3")
|
||||
optional("com.jayway.jsonpath:json-path:1.1.0")
|
||||
optional("com.jayway.jsonpath:json-path:1.2.0")
|
||||
optional("org.skyscreamer:jsonassert:1.2.3")
|
||||
optional("xmlunit:xmlunit:1.5")
|
||||
optional("xmlunit:xmlunit:1.6")
|
||||
testCompile(project(":spring-context-support"))
|
||||
testCompile(project(":spring-oxm"))
|
||||
testCompile("javax.mail:javax.mail-api:1.5.2")
|
||||
@@ -979,7 +981,7 @@ project("spring-test") {
|
||||
testCompile("org.hibernate:hibernate-validator:${hibVal5Version}")
|
||||
testCompile("com.thoughtworks.xstream:xstream:${xstreamVersion}")
|
||||
testCompile("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
|
||||
testCompile("com.rometools:rome:1.5.0")
|
||||
testCompile("com.rometools:rome:1.5.1")
|
||||
testCompile("org.apache.tiles:tiles-api:${tiles3Version}")
|
||||
testCompile("org.apache.tiles:tiles-core:${tiles3Version}") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
@@ -1206,7 +1208,7 @@ configure(rootProject) {
|
||||
baseName = "spring-framework"
|
||||
classifier = "docs"
|
||||
description = "Builds -${classifier} archive containing api and reference " +
|
||||
"for deployment at http://static.springframework.org/spring-framework/docs."
|
||||
"for deployment at https://docs.spring.io/spring-framework/docs."
|
||||
|
||||
from("src/dist") {
|
||||
include "changelog.txt"
|
||||
@@ -1226,7 +1228,7 @@ configure(rootProject) {
|
||||
baseName = "spring-framework"
|
||||
classifier = "schema"
|
||||
description = "Builds -${classifier} archive containing all " +
|
||||
"XSDs for deployment at http://springframework.org/schema."
|
||||
"XSDs for deployment at https://springframework.org/schema."
|
||||
duplicatesStrategy 'exclude'
|
||||
moduleProjects.each { subproject ->
|
||||
def Properties schemas = new Properties();
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
version=4.1.4.BUILD-SNAPSHOT
|
||||
version=4.1.10.BUILD-SNAPSHOT
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ eclipse.jdt {
|
||||
}
|
||||
|
||||
// Replace classpath entries with project dependencies (GRADLE-1116)
|
||||
// http://issues.gradle.org/browse/GRADLE-1116
|
||||
// https://issues.gradle.org/browse/GRADLE-1116
|
||||
eclipse.classpath.file.whenMerged { classpath ->
|
||||
def regexp = /.*?\/([^\/]+)\/build\/[^\/]+\/(?:main|test)/ // only match those that end in main or test (avoids removing necessary entries like build/classes/jaxb)
|
||||
def projectOutputDependencies = classpath.entries.findAll { entry -> entry.path =~ regexp }
|
||||
|
||||
@@ -25,12 +25,12 @@ def customizePom(pom, gradleProject) {
|
||||
url = "https://github.com/spring-projects/spring-framework"
|
||||
organization {
|
||||
name = "Spring IO"
|
||||
url = "http://projects.spring.io/spring-framework"
|
||||
url = "https://projects.spring.io/spring-framework"
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name "The Apache Software License, Version 2.0"
|
||||
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
url "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
distribution "repo"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ echo been tested against STS %STS_TEST_VERSION%), but at the minimum you will
|
||||
echo need Eclipse + AJDT.
|
||||
echo.
|
||||
echo If you need to download and install STS, please do that now by
|
||||
echo visiting http://spring.io/tools/sts/all
|
||||
echo visiting https://spring.io/tools/sts/all
|
||||
echo.
|
||||
echo Otherwise, press enter and we'll begin.
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@ This script has been tested against:
|
||||
If you need to download and install Eclipse or STS, please do that now
|
||||
by visiting one of the following sites:
|
||||
|
||||
- Eclipse downloads: http://download.eclipse.org/eclipse/downloads
|
||||
- STS downloads: http://spring.io/tools/sts/all
|
||||
- STS nightly builds: http://dist.springsource.com/snapshot/STS/nightly-distributions.html
|
||||
- Eclipse downloads: https://download.eclipse.org/eclipse/downloads
|
||||
- STS downloads: https://spring.io/tools/sts/all
|
||||
- STS nightly builds: https://dist.springsource.com/snapshot/STS/nightly-distributions.html
|
||||
|
||||
If you need to install a recent CI build for AJDT (i.e., so that the
|
||||
spring-aspects module properly compiles in Eclipse/STS), click on the
|
||||
|
||||
+36
-24
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.aop.aspectj;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -203,8 +204,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
pointcutParameters[i] = parser.createPointcutParameter(
|
||||
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
|
||||
}
|
||||
return parser.parsePointcutExpression(
|
||||
replaceBooleanOperators(getExpression()),
|
||||
return parser.parsePointcutExpression(replaceBooleanOperators(getExpression()),
|
||||
this.pointcutDeclarationScope, pointcutParameters);
|
||||
}
|
||||
|
||||
@@ -327,29 +327,41 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
catch (IllegalStateException ex) {
|
||||
// No current invocation...
|
||||
// TODO: Should we really proceed here?
|
||||
logger.debug("Couldn't access current invocation - matching with limited context: " + ex);
|
||||
}
|
||||
|
||||
JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);
|
||||
|
||||
/*
|
||||
* Do a final check to see if any this(TYPE) kind of residue match. For
|
||||
* this purpose, we use the original method's (proxy method's) shadow to
|
||||
* ensure that 'this' is correctly checked against. Without this check,
|
||||
* we get incorrect match on this(TYPE) where TYPE matches the target
|
||||
* type but not 'this' (as would be the case of JDK dynamic proxies).
|
||||
* <p>See SPR-2979 for the original bug.
|
||||
*/
|
||||
if (pmi != null) { // there is a current invocation
|
||||
RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(originalShadowMatch);
|
||||
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
|
||||
return false;
|
||||
}
|
||||
if (joinPointMatch.matches()) {
|
||||
bindParameters(pmi, joinPointMatch);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not access current invocation - matching with limited context: " + ex);
|
||||
}
|
||||
}
|
||||
return joinPointMatch.matches();
|
||||
|
||||
try {
|
||||
JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);
|
||||
|
||||
/*
|
||||
* Do a final check to see if any this(TYPE) kind of residue match. For
|
||||
* this purpose, we use the original method's (proxy method's) shadow to
|
||||
* ensure that 'this' is correctly checked against. Without this check,
|
||||
* we get incorrect match on this(TYPE) where TYPE matches the target
|
||||
* type but not 'this' (as would be the case of JDK dynamic proxies).
|
||||
* <p>See SPR-2979 for the original bug.
|
||||
*/
|
||||
if (pmi != null) { // there is a current invocation
|
||||
RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(originalShadowMatch);
|
||||
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
|
||||
return false;
|
||||
}
|
||||
if (joinPointMatch.matches()) {
|
||||
bindParameters(pmi, joinPointMatch);
|
||||
}
|
||||
}
|
||||
|
||||
return joinPointMatch.matches();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) +
|
||||
" - falling back to non-match", ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected String getCurrentProxiedBeanName() {
|
||||
|
||||
+5
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -243,6 +243,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
|
||||
|
||||
private String toString(boolean includeModifier, boolean includeReturnTypeAndArgs,
|
||||
boolean useLongReturnAndArgumentTypeName, boolean useLongTypeName) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (includeModifier) {
|
||||
sb.append(Modifier.toString(getModifiers()));
|
||||
@@ -262,8 +263,9 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void appendTypes(StringBuilder sb, Class<?>[] types,
|
||||
boolean includeArgs, boolean useLongReturnAndArgumentTypeName) {
|
||||
private void appendTypes(StringBuilder sb, Class<?>[] types, boolean includeArgs,
|
||||
boolean useLongReturnAndArgumentTypeName) {
|
||||
|
||||
if (includeArgs) {
|
||||
for (int size = types.length, i = 0; i < size; i++) {
|
||||
appendType(sb, types[i], useLongReturnAndArgumentTypeName);
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -76,7 +76,7 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
|
||||
* Create a new {@code AspectJProxyFactory}.
|
||||
* No target, only interfaces. Must add interceptors.
|
||||
*/
|
||||
public AspectJProxyFactory(Class<?>[] interfaces) {
|
||||
public AspectJProxyFactory(Class<?>... interfaces) {
|
||||
setInterfaces(interfaces);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,7 +93,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
|
||||
|
||||
/** Logger available to subclasses; static to optimize serialization */
|
||||
protected final static Log logger = LogFactory.getLog(CglibAopProxy.class);
|
||||
protected static final Log logger = LogFactory.getLog(CglibAopProxy.class);
|
||||
|
||||
/** Keeps track of the Classes that we have validated for final methods */
|
||||
private static final Map<Class<?>, Boolean> validatedClasses = new WeakHashMap<Class<?>, Boolean>();
|
||||
@@ -102,9 +102,9 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
/** The configuration used to configure this proxy */
|
||||
protected final AdvisedSupport advised;
|
||||
|
||||
private Object[] constructorArgs;
|
||||
protected Object[] constructorArgs;
|
||||
|
||||
private Class<?>[] constructorArgTypes;
|
||||
protected Class<?>[] constructorArgTypes;
|
||||
|
||||
/** Dispatcher used for methods on Advised */
|
||||
private final transient AdvisedDispatcher advisedDispatcher;
|
||||
@@ -304,13 +304,13 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
Callback targetDispatcher = isStatic ?
|
||||
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
|
||||
|
||||
Callback[] mainCallbacks = new Callback[]{
|
||||
aopInterceptor, // for normal advice
|
||||
targetInterceptor, // invoke target without considering advice, if optimized
|
||||
new SerializableNoOp(), // no override for methods mapped to this
|
||||
targetDispatcher, this.advisedDispatcher,
|
||||
new EqualsInterceptor(this.advised),
|
||||
new HashCodeInterceptor(this.advised)
|
||||
Callback[] mainCallbacks = new Callback[] {
|
||||
aopInterceptor, // for normal advice
|
||||
targetInterceptor, // invoke target without considering advice, if optimized
|
||||
new SerializableNoOp(), // no override for methods mapped to this
|
||||
targetDispatcher, this.advisedDispatcher,
|
||||
new EqualsInterceptor(this.advised),
|
||||
new HashCodeInterceptor(this.advised)
|
||||
};
|
||||
|
||||
Callback[] callbacks;
|
||||
@@ -702,6 +702,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
|
||||
public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
|
||||
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
|
||||
|
||||
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
|
||||
this.methodProxy = methodProxy;
|
||||
this.publicMethod = Modifier.isPublic(method.getModifiers());
|
||||
@@ -821,8 +822,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method has advice and optimisations are enabled: " + method);
|
||||
}
|
||||
// We know that we are optimising so we can use the
|
||||
// FixedStaticChainInterceptors.
|
||||
// We know that we are optimising so we can use the FixedStaticChainInterceptors.
|
||||
int index = this.fixedInterceptorMap.get(key);
|
||||
return (index + this.fixedInterceptorOffset);
|
||||
}
|
||||
|
||||
+28
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,14 +22,14 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.objenesis.ObjenesisException;
|
||||
import org.springframework.objenesis.ObjenesisStd;
|
||||
|
||||
/**
|
||||
* Objenesis based extension of {@link CglibAopProxy} to create proxy instances without
|
||||
* invoking the constructor of the class.
|
||||
* Objenesis-based extension of {@link CglibAopProxy} to create proxy instances
|
||||
* without invoking the constructor of the class.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
@@ -41,8 +41,8 @@ class ObjenesisCglibAopProxy extends CglibAopProxy {
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new {@link ObjenesisCglibAopProxy} using the given {@link AdvisedSupport}.
|
||||
* @param config must not be {@literal null}.
|
||||
* Create a new ObjenesisCglibAopProxy for the given AOP configuration.
|
||||
* @param config the AOP configuration as AdvisedSupport object
|
||||
*/
|
||||
public ObjenesisCglibAopProxy(AdvisedSupport config) {
|
||||
super(config);
|
||||
@@ -53,18 +53,32 @@ class ObjenesisCglibAopProxy extends CglibAopProxy {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
|
||||
Class<?> proxyClass = enhancer.createClass();
|
||||
Object proxyInstance = null;
|
||||
|
||||
try {
|
||||
Factory factory = (Factory) this.objenesis.newInstance(enhancer.createClass());
|
||||
factory.setCallbacks(callbacks);
|
||||
return factory;
|
||||
proxyInstance = this.objenesis.newInstance(proxyClass);
|
||||
}
|
||||
catch (ObjenesisException ex) {
|
||||
// Fallback to regular proxy construction on unsupported JVMs
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Unable to instantiate proxy using Objenesis, falling back to regular proxy construction", ex);
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Unable to instantiate proxy using Objenesis, " +
|
||||
"falling back to regular proxy construction", ex);
|
||||
}
|
||||
|
||||
if (proxyInstance == null) {
|
||||
// Regular instantiation via default constructor...
|
||||
try {
|
||||
proxyInstance = (this.constructorArgs != null ?
|
||||
proxyClass.getConstructor(this.constructorArgTypes).newInstance(this.constructorArgs) :
|
||||
proxyClass.newInstance());
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
|
||||
"and regular proxy instantiation via default constructor fails as well", ex);
|
||||
}
|
||||
return super.createProxyClassAndInstance(enhancer, callbacks);
|
||||
}
|
||||
|
||||
((Factory) proxyInstance).setCallbacks(callbacks);
|
||||
return proxyInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -125,8 +125,10 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
Executor executorToUse = this.defaultExecutor;
|
||||
String qualifier = getExecutorQualifier(method);
|
||||
if (StringUtils.hasLength(qualifier)) {
|
||||
Assert.notNull(this.beanFactory, "BeanFactory must be set on " + getClass().getSimpleName() +
|
||||
" to access qualified executor '" + qualifier + "'");
|
||||
if (this.beanFactory == null) {
|
||||
throw new IllegalStateException("BeanFactory must be set on " + getClass().getSimpleName() +
|
||||
" to access qualified executor '" + qualifier + "'");
|
||||
}
|
||||
executorToUse = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
|
||||
this.beanFactory, Executor.class, qualifier);
|
||||
}
|
||||
@@ -155,7 +157,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
/**
|
||||
* Handles a fatal error thrown while asynchronously invoking the specified
|
||||
* {@link Method}.
|
||||
* <p>If the return type of the method is a {@link java.util.concurrent.Future} object, the original
|
||||
* <p>If the return type of the method is a {@link Future} object, the original
|
||||
* exception can be propagated by just throwing it at the higher level. However,
|
||||
* for all other cases, the exception will not be transmitted back to the client.
|
||||
* In that later case, the current {@link AsyncUncaughtExceptionHandler} will be
|
||||
@@ -165,7 +167,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
|
||||
* @param params the parameters used to invoke the method
|
||||
*/
|
||||
protected void handleError(Throwable ex, Method method, Object... params) throws Exception {
|
||||
if (method.getReturnType().isAssignableFrom(Future.class)) {
|
||||
if (Future.class.isAssignableFrom(method.getReturnType())) {
|
||||
ReflectionUtils.rethrowException(ex);
|
||||
}
|
||||
else {
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ public class CommonsPoolTargetSource extends AbstractPoolingTargetSource impleme
|
||||
private byte whenExhaustedAction = GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION;
|
||||
|
||||
/**
|
||||
* The Jakarta Commons {@code ObjectPool} used to pool target objects
|
||||
* The Apache Commons {@code ObjectPool} used to pool target objects
|
||||
*/
|
||||
private ObjectPool pool;
|
||||
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,9 +32,9 @@ import static org.junit.Assert.*;
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public final class AspectProxyFactoryTests {
|
||||
public class AspectProxyFactoryTests {
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testWithNonAspect() {
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
|
||||
proxyFactory.addAspect(TestBean.class);
|
||||
@@ -70,7 +70,7 @@ public final class AspectProxyFactoryTests {
|
||||
assertEquals(2, proxy1.getAge());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testWithInstanceWithNonAspect() throws Exception {
|
||||
AspectJProxyFactory pf = new AspectJProxyFactory();
|
||||
pf.addAspect(new TestBean());
|
||||
@@ -96,14 +96,14 @@ public final class AspectProxyFactoryTests {
|
||||
assertEquals(target.getAge() * multiple, serializedProxy.getAge());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testWithNonSingletonAspectInstance() throws Exception {
|
||||
AspectJProxyFactory pf = new AspectJProxyFactory();
|
||||
pf.addAspect(new PerThisAspect());
|
||||
}
|
||||
|
||||
|
||||
public static interface ITestBean {
|
||||
public interface ITestBean {
|
||||
|
||||
int getAge();
|
||||
}
|
||||
|
||||
+38
-33
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,50 +32,55 @@ import static org.mockito.BDDMockito.*;
|
||||
*/
|
||||
public class JamonPerformanceMonitorInterceptorTests {
|
||||
|
||||
private JamonPerformanceMonitorInterceptor interceptor = new JamonPerformanceMonitorInterceptor();
|
||||
private final JamonPerformanceMonitorInterceptor interceptor = new JamonPerformanceMonitorInterceptor();
|
||||
|
||||
private MethodInvocation mi = mock(MethodInvocation.class);
|
||||
private final MethodInvocation mi = mock(MethodInvocation.class);
|
||||
|
||||
private Log log = mock(Log.class);
|
||||
private final Log log = mock(Log.class);
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MonitorFactory.reset();
|
||||
}
|
||||
@Before
|
||||
public void setUp() {
|
||||
MonitorFactory.reset();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
MonitorFactory.reset();
|
||||
}
|
||||
@After
|
||||
public void tearDown() {
|
||||
MonitorFactory.reset();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testInvokeUnderTraceWithNormalProcessing() throws Throwable {
|
||||
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
|
||||
@Test
|
||||
public void testInvokeUnderTraceWithNormalProcessing() throws Throwable {
|
||||
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
|
||||
|
||||
interceptor.invokeUnderTrace(mi, log);
|
||||
interceptor.invokeUnderTrace(mi, log);
|
||||
|
||||
assertEquals("jamon must track the method being invoked", 1, MonitorFactory.getNumRows());
|
||||
assertTrue("The jamon report must contain the toString method that was invoked", MonitorFactory.getReport().contains("toString"));
|
||||
}
|
||||
assertTrue("jamon must track the method being invoked", MonitorFactory.getNumRows() > 0);
|
||||
assertTrue("The jamon report must contain the toString method that was invoked",
|
||||
MonitorFactory.getReport().contains("toString"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvokeUnderTraceWithExceptionTracking() throws Throwable {
|
||||
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
|
||||
given(mi.proceed()).willThrow(new IllegalArgumentException());
|
||||
@Test
|
||||
public void testInvokeUnderTraceWithExceptionTracking() throws Throwable {
|
||||
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
|
||||
given(mi.proceed()).willThrow(new IllegalArgumentException());
|
||||
|
||||
try {
|
||||
interceptor.invokeUnderTrace(mi, log);
|
||||
fail("Must have propagated the IllegalArgumentException");
|
||||
}
|
||||
try {
|
||||
interceptor.invokeUnderTrace(mi, log);
|
||||
fail("Must have propagated the IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Monitors must exist for the method invocation and 2 exceptions", 3, MonitorFactory.getNumRows());
|
||||
assertTrue("The jamon report must contain the toString method that was invoked", MonitorFactory.getReport().contains("toString"));
|
||||
assertTrue("The jamon report must contain the generic exception: " + MonitorFactory.EXCEPTIONS_LABEL, MonitorFactory.getReport().contains(MonitorFactory.EXCEPTIONS_LABEL));
|
||||
assertTrue("The jamon report must contain the specific exception: IllegalArgumentException'", MonitorFactory.getReport().contains("IllegalArgumentException"));
|
||||
}
|
||||
assertEquals("Monitors must exist for the method invocation and 2 exceptions",
|
||||
3, MonitorFactory.getNumRows());
|
||||
assertTrue("The jamon report must contain the toString method that was invoked",
|
||||
MonitorFactory.getReport().contains("toString"));
|
||||
assertTrue("The jamon report must contain the generic exception: " + MonitorFactory.EXCEPTIONS_LABEL,
|
||||
MonitorFactory.getReport().contains(MonitorFactory.EXCEPTIONS_LABEL));
|
||||
assertTrue("The jamon report must contain the specific exception: IllegalArgumentException'",
|
||||
MonitorFactory.getReport().contains("IllegalArgumentException"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,9 +28,9 @@ import org.springframework.context.annotation.Role;
|
||||
* annotated with @{@link org.springframework.beans.factory.annotation.Configurable
|
||||
* Configurable}.
|
||||
*
|
||||
* <p>This configuration class is automatically imported when using the @{@link
|
||||
* EnableSpringConfigured} annotation. See {@code @EnableSpringConfigured} Javadoc for
|
||||
* complete usage details.
|
||||
* <p>This configuration class is automatically imported when using the
|
||||
* @{@link EnableSpringConfigured} annotation. See {@code @EnableSpringConfigured}'s
|
||||
* javadoc for complete usage details.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
@@ -42,9 +42,10 @@ public class SpringConfiguredConfiguration {
|
||||
public static final String BEAN_CONFIGURER_ASPECT_BEAN_NAME =
|
||||
"org.springframework.context.config.internalBeanConfigurerAspect";
|
||||
|
||||
@Bean(name=BEAN_CONFIGURER_ASPECT_BEAN_NAME)
|
||||
@Bean(name = BEAN_CONFIGURER_ASPECT_BEAN_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public AnnotationBeanConfigurerAspect beanConfigurerAspect() {
|
||||
return AnnotationBeanConfigurerAspect.aspectOf();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+23
-24
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,15 +23,15 @@ import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
/**
|
||||
* Aspect to route methods based on the {@link Async} annotation.
|
||||
* Aspect to route methods based on Spring's {@link Async} annotation.
|
||||
*
|
||||
* <p>This aspect routes methods marked with the {@link Async} annotation
|
||||
* as well as methods in classes marked with the same. Any method expected
|
||||
* to be routed asynchronously must return either {@code void}, {@link Future},
|
||||
* or a subtype of {@link Future}. This aspect, therefore, will produce
|
||||
* a compile-time error for methods that violate this constraint on the return type.
|
||||
* If, however, a class marked with {@code @Async} contains a method that violates this
|
||||
* constraint, it produces only a warning.
|
||||
* <p>This aspect routes methods marked with the {@link Async} annotation as well as methods
|
||||
* in classes marked with the same. Any method expected to be routed asynchronously must
|
||||
* return either {@code void}, {@link Future}, or a subtype of {@link Future} (in particular,
|
||||
* Spring's {@link org.springframework.util.concurrent.ListenableFuture}). This aspect,
|
||||
* therefore, will produce a compile-time error for methods that violate this constraint
|
||||
* on the return type. If, however, a class marked with {@code @Async} contains a method
|
||||
* that violates this constraint, it produces only a warning.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @author Chris Beams
|
||||
@@ -39,42 +39,41 @@ import org.springframework.scheduling.annotation.Async;
|
||||
*/
|
||||
public aspect AnnotationAsyncExecutionAspect extends AbstractAsyncExecutionAspect {
|
||||
|
||||
private pointcut asyncMarkedMethod()
|
||||
: execution(@Async (void || Future+) *(..));
|
||||
private pointcut asyncMarkedMethod() : execution(@Async (void || Future+) *(..));
|
||||
|
||||
private pointcut asyncTypeMarkedMethod()
|
||||
: execution((void || Future+) (@Async *).*(..));
|
||||
private pointcut asyncTypeMarkedMethod() : execution((void || Future+) (@Async *).*(..));
|
||||
|
||||
public pointcut asyncMethod() : asyncMarkedMethod() || asyncTypeMarkedMethod();
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>This implementation inspects the given method and its declaring class for the
|
||||
* {@code @Async} annotation, returning the qualifier value expressed by
|
||||
* {@link Async#value()}. If {@code @Async} is specified at both the method and class level, the
|
||||
* method's {@code #value} takes precedence (even if empty string, indicating that
|
||||
* the default executor should be used preferentially).
|
||||
* This implementation inspects the given method and its declaring class for the
|
||||
* {@code @Async} annotation, returning the qualifier value expressed by {@link Async#value()}.
|
||||
* If {@code @Async} is specified at both the method and class level, the method's
|
||||
* {@code #value} takes precedence (even if empty string, indicating that the default
|
||||
* executor should be used preferentially).
|
||||
* @return the qualifier if specified, otherwise empty string indicating that the
|
||||
* {@linkplain #setExecutor(Executor) default executor} should be used
|
||||
* {@linkplain #setExecutor default executor} should be used
|
||||
* @see #determineAsyncExecutor(Method)
|
||||
*/
|
||||
@Override
|
||||
protected String getExecutorQualifier(Method method) {
|
||||
// maintainer's note: changes made here should also be made in
|
||||
// Maintainer's note: changes made here should also be made in
|
||||
// AnnotationAsyncExecutionInterceptor#getExecutorQualifier
|
||||
Async async = AnnotationUtils.findAnnotation(method, Async.class);
|
||||
if (async == null) {
|
||||
async = AnnotationUtils.findAnnotation(method.getDeclaringClass(), Async.class);
|
||||
}
|
||||
return async == null ? null : async.value();
|
||||
return (async != null ? async.value() : null);
|
||||
}
|
||||
|
||||
|
||||
declare error:
|
||||
execution(@Async !(void||Future) *(..)):
|
||||
execution(@Async !(void || Future+) *(..)):
|
||||
"Only methods that return void or Future may have an @Async annotation";
|
||||
|
||||
declare warning:
|
||||
execution(!(void||Future) (@Async *).*(..)):
|
||||
execution(!(void || Future+) (@Async *).*(..)):
|
||||
"Methods in a class marked with @Async that do not return void or Future will " +
|
||||
"be routed synchronously";
|
||||
|
||||
|
||||
+13
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,6 +35,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.tests.Assume;
|
||||
import org.springframework.tests.TestGroup;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.startsWith;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
@@ -50,9 +51,10 @@ public class AnnotationAsyncExecutionAspectTests {
|
||||
|
||||
private static final long WAIT_TIME = 1000; //milliseconds
|
||||
|
||||
private final AsyncUncaughtExceptionHandler defaultExceptionHandler = new SimpleAsyncUncaughtExceptionHandler();
|
||||
|
||||
private CountingExecutor executor;
|
||||
|
||||
private AsyncUncaughtExceptionHandler defaultExceptionHandler = new SimpleAsyncUncaughtExceptionHandler();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -62,6 +64,7 @@ public class AnnotationAsyncExecutionAspectTests {
|
||||
AnnotationAsyncExecutionAspect.aspectOf().setExecutor(executor);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void asyncMethodGetsRoutedAsynchronously() {
|
||||
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
|
||||
@@ -184,7 +187,9 @@ public class AnnotationAsyncExecutionAspectTests {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class CountingExecutor extends SimpleAsyncTaskExecutor {
|
||||
|
||||
int submitStartCounter;
|
||||
|
||||
int submitCompleteCounter;
|
||||
|
||||
@Override
|
||||
@@ -209,6 +214,7 @@ public class AnnotationAsyncExecutionAspectTests {
|
||||
|
||||
|
||||
static class ClassWithoutAsyncAnnotation {
|
||||
|
||||
int counter;
|
||||
|
||||
@Async public void incrementAsync() {
|
||||
@@ -239,6 +245,7 @@ public class AnnotationAsyncExecutionAspectTests {
|
||||
|
||||
@Async
|
||||
static class ClassWithAsyncAnnotation {
|
||||
|
||||
int counter;
|
||||
|
||||
public void increment() {
|
||||
@@ -261,17 +268,19 @@ public class AnnotationAsyncExecutionAspectTests {
|
||||
|
||||
|
||||
static class ClassWithQualifiedAsyncMethods {
|
||||
|
||||
@Async
|
||||
public Future<Thread> defaultWork() {
|
||||
return new AsyncResult<Thread>(Thread.currentThread());
|
||||
}
|
||||
|
||||
@Async("e1")
|
||||
public Future<Thread> e1Work() {
|
||||
public ListenableFuture<Thread> e1Work() {
|
||||
return new AsyncResult<Thread>(Thread.currentThread());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class ClassWithException {
|
||||
|
||||
@Async
|
||||
@@ -279,4 +288,5 @@ public class AnnotationAsyncExecutionAspectTests {
|
||||
throw new UnsupportedOperationException("failWithVoid");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+64
-47
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,6 +31,7 @@ import groovy.lang.GroovyObjectSupport;
|
||||
import groovy.lang.GroovyShell;
|
||||
import groovy.lang.GroovySystem;
|
||||
import groovy.lang.MetaClass;
|
||||
|
||||
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
|
||||
import org.codehaus.groovy.runtime.InvokerHelper;
|
||||
|
||||
@@ -58,8 +59,17 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A Groovy-based reader for Spring bean definitions: like a Groovy builder,
|
||||
* but more of a DSL for Spring configuration. Allows syntax like:
|
||||
* but more of a DSL for Spring configuration.
|
||||
*
|
||||
* <p>This bean definition reader also understands XML bean definition files,
|
||||
* allowing for seamless mixing and matching with Groovy bean definition files.
|
||||
*
|
||||
* <p>Typically applied to a
|
||||
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
|
||||
* or a {@link org.springframework.context.support.GenericApplicationContext},
|
||||
* but can be used against any {@link BeanDefinitionRegistry} implementation.
|
||||
*
|
||||
* <h3>Example Syntax</h3>
|
||||
* <pre class="code">
|
||||
* import org.hibernate.SessionFactory
|
||||
* import org.apache.commons.dbcp.BasicDataSource
|
||||
@@ -84,8 +94,9 @@ import org.springframework.util.StringUtils;
|
||||
* }</pre>
|
||||
*
|
||||
* <p>You can also load resources containing beans defined in a Groovy script using
|
||||
* either the {@link #loadBeanDefinitions(org.springframework.core.io.Resource...)}
|
||||
* or {@link #loadBeanDefinitions(String...)} method, with a script looking as follows:
|
||||
* either the {@link #loadBeanDefinitions(Resource...)} or
|
||||
* {@link #loadBeanDefinitions(String...)} method, with a script looking similar to
|
||||
* the following.
|
||||
*
|
||||
* <pre class="code">
|
||||
* import org.hibernate.SessionFactory
|
||||
@@ -109,17 +120,10 @@ import org.springframework.util.StringUtils;
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p><b>This bean definition reader also understands XML bean definition files,
|
||||
* allowing for seamless mixing and matching with Groovy bean definition files.</b>
|
||||
*
|
||||
* <p>Typically applied to a
|
||||
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
|
||||
* or a {@link org.springframework.context.support.GenericApplicationContext},
|
||||
* but can be used against any {@link BeanDefinitionRegistry} implementation.
|
||||
*
|
||||
* @author Jeff Brown
|
||||
* @author Graeme Rocher
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 4.0
|
||||
* @see BeanDefinitionRegistry
|
||||
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory
|
||||
@@ -128,7 +132,21 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader implements GroovyObject {
|
||||
|
||||
private final XmlBeanDefinitionReader xmlBeanDefinitionReader;
|
||||
/**
|
||||
* Standard {@code XmlBeanDefinitionReader} created with default
|
||||
* settings for loading bean definitions from XML files.
|
||||
*/
|
||||
private final XmlBeanDefinitionReader standardXmlBeanDefinitionReader;
|
||||
|
||||
/**
|
||||
* Groovy DSL {@code XmlBeanDefinitionReader} for loading bean definitions
|
||||
* via the Groovy DSL, typically configured with XML validation disabled.
|
||||
*/
|
||||
private final XmlBeanDefinitionReader groovyDslXmlBeanDefinitionReader;
|
||||
|
||||
private final Map<String, String> namespaces = new HashMap<String, String>();
|
||||
|
||||
private final Map<String, DeferredProperty> deferredProperties = new HashMap<String, DeferredProperty>();
|
||||
|
||||
private MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass());
|
||||
|
||||
@@ -136,31 +154,28 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
|
||||
private GroovyBeanDefinitionWrapper currentBeanDefinition;
|
||||
|
||||
private final Map <String, String> namespaces = new HashMap<String, String>();
|
||||
|
||||
private final Map<String, DeferredProperty> deferredProperties = new HashMap<String, DeferredProperty>();
|
||||
|
||||
|
||||
/**
|
||||
* Create new GroovyBeanDefinitionReader for the given bean factory.
|
||||
* @param registry the BeanFactory to load bean definitions into,
|
||||
* in the form of a BeanDefinitionRegistry
|
||||
* Create a new {@code GroovyBeanDefinitionReader} for the given {@link BeanDefinitionRegistry}.
|
||||
* @param registry the {@code BeanDefinitionRegistry} to load bean definitions into
|
||||
*/
|
||||
public GroovyBeanDefinitionReader(BeanDefinitionRegistry registry) {
|
||||
super(registry);
|
||||
this.xmlBeanDefinitionReader = new XmlBeanDefinitionReader(registry);
|
||||
this.xmlBeanDefinitionReader.setValidating(false);
|
||||
this.standardXmlBeanDefinitionReader = new XmlBeanDefinitionReader(registry);
|
||||
this.groovyDslXmlBeanDefinitionReader = new XmlBeanDefinitionReader(registry);
|
||||
this.groovyDslXmlBeanDefinitionReader.setValidating(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new GroovyBeanDefinitionReader based on the given XmlBeanDefinitionReader,
|
||||
* using the same registry and delegating XML loading to it.
|
||||
* @param xmlBeanDefinitionReader the XmlBeanDefinitionReader to derive the registry
|
||||
* Create a new {@code GroovyBeanDefinitionReader} based on the given {@link XmlBeanDefinitionReader},
|
||||
* using its {@code BeanDefinitionRegistry} and delegating Groovy DSL loading to it.
|
||||
* @param xmlBeanDefinitionReader the {@code XmlBeanDefinitionReader} to derive the registry
|
||||
* from and to delegate XML loading to
|
||||
*/
|
||||
public GroovyBeanDefinitionReader(XmlBeanDefinitionReader xmlBeanDefinitionReader) {
|
||||
super(xmlBeanDefinitionReader.getRegistry());
|
||||
this.xmlBeanDefinitionReader = xmlBeanDefinitionReader;
|
||||
this.standardXmlBeanDefinitionReader = new XmlBeanDefinitionReader(xmlBeanDefinitionReader.getRegistry());
|
||||
this.groovyDslXmlBeanDefinitionReader = xmlBeanDefinitionReader;
|
||||
}
|
||||
|
||||
|
||||
@@ -174,7 +189,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
|
||||
/**
|
||||
* Set the binding, i.e. the Groovy variables available in the scope
|
||||
* of a GroovyBeanDefinitionReader closure.
|
||||
* of a {@code GroovyBeanDefinitionReader} closure.
|
||||
*/
|
||||
public void setBinding(Binding binding) {
|
||||
this.binding = binding;
|
||||
@@ -192,9 +207,9 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
|
||||
/**
|
||||
* Load bean definitions from the specified Groovy script or XML file.
|
||||
* <p>Note that ".xml" files will be parsed as XML content; all other kinds
|
||||
* <p>Note that {@code ".xml"} files will be parsed as XML content; all other kinds
|
||||
* of resources will be parsed as Groovy scripts.
|
||||
* @param resource the resource descriptor for the Groovy script
|
||||
* @param resource the resource descriptor for the Groovy script or XML file
|
||||
* @return the number of bean definitions found
|
||||
* @throws BeanDefinitionStoreException in case of loading or parsing errors
|
||||
*/
|
||||
@@ -204,18 +219,18 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
|
||||
/**
|
||||
* Load bean definitions from the specified Groovy script or XML file.
|
||||
* <p>Note that ".xml" files will be parsed as XML content; all other kinds
|
||||
* <p>Note that {@code ".xml"} files will be parsed as XML content; all other kinds
|
||||
* of resources will be parsed as Groovy scripts.
|
||||
* @param encodedResource the resource descriptor for the Groovy script,
|
||||
* allowing to specify an encoding to use for parsing the file
|
||||
* @param encodedResource the resource descriptor for the Groovy script or XML file,
|
||||
* allowing specification of an encoding to use for parsing the file
|
||||
* @return the number of bean definitions found
|
||||
* @throws BeanDefinitionStoreException in case of loading or parsing errors
|
||||
*/
|
||||
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
|
||||
// Check for XML files and redirect them to the XmlBeanDefinitionReader
|
||||
// Check for XML files and redirect them to the "standard" XmlBeanDefinitionReader
|
||||
String filename = encodedResource.getResource().getFilename();
|
||||
if (StringUtils.endsWithIgnoreCase(filename, ".xml")) {
|
||||
return this.xmlBeanDefinitionReader.loadBeanDefinitions(encodedResource);
|
||||
return this.standardXmlBeanDefinitionReader.loadBeanDefinitions(encodedResource);
|
||||
}
|
||||
|
||||
Closure beans = new Closure(this) {
|
||||
@@ -255,14 +270,14 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
/**
|
||||
* Defines a set of beans for the given block or closure.
|
||||
* @param closure the block or closure
|
||||
* @return this GroovyBeanDefinitionReader instance
|
||||
* @return this {@code GroovyBeanDefinitionReader} instance
|
||||
*/
|
||||
public GroovyBeanDefinitionReader beans(Closure closure) {
|
||||
return invokeBeanDefiningClosure(closure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an inner bean definition.
|
||||
* Define an inner bean definition.
|
||||
* @param type the bean type
|
||||
* @return the bean definition
|
||||
*/
|
||||
@@ -307,7 +322,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a Spring namespace definition to use.
|
||||
* Define a Spring XML namespace definition to use.
|
||||
* @param definition the namespace definition
|
||||
*/
|
||||
public void xmlns(Map<String, String> definition) {
|
||||
@@ -318,7 +333,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
if (uri == null) {
|
||||
throw new IllegalArgumentException("Namespace definition must supply a non-null URI");
|
||||
}
|
||||
NamespaceHandler namespaceHandler = this.xmlBeanDefinitionReader.getNamespaceHandlerResolver().resolve(uri);
|
||||
NamespaceHandler namespaceHandler = this.groovyDslXmlBeanDefinitionReader.getNamespaceHandlerResolver().resolve(
|
||||
uri);
|
||||
if (namespaceHandler == null) {
|
||||
throw new BeanDefinitionParsingException(new Problem("No namespace handler found for URI: " + uri,
|
||||
new Location(new DescriptiveResource(("Groovy")))));
|
||||
@@ -419,7 +435,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
/**
|
||||
* When a method argument is only a closure it is a set of bean definitions.
|
||||
* @param callable the closure argument
|
||||
* @return this GroovyBeanDefinitionReader instance
|
||||
* @return this {@code GroovyBeanDefinitionReader} instance
|
||||
*/
|
||||
protected GroovyBeanDefinitionReader invokeBeanDefiningClosure(Closure callable) {
|
||||
callable.setDelegate(this);
|
||||
@@ -534,8 +550,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether there are any {@link RuntimeBeanReference}s inside the Map
|
||||
* and converts it to a ManagedMap if necessary.
|
||||
* Checks whether there are any {@link RuntimeBeanReference}s inside the {@link Map}
|
||||
* and converts it to a {@link ManagedMap} if necessary.
|
||||
* @param map the original Map
|
||||
* @return either the original map or a managed copy of it
|
||||
*/
|
||||
@@ -556,8 +572,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether there are any {@link RuntimeBeanReference}s inside the List
|
||||
* and converts it to a ManagedList if necessary.
|
||||
* Checks whether there are any {@link RuntimeBeanReference}s inside the {@link List}
|
||||
* and converts it to a {@link ManagedList} if necessary.
|
||||
* @param list the original List
|
||||
* @return either the original list or a managed copy of it
|
||||
*/
|
||||
@@ -578,7 +594,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
/**
|
||||
* This method overrides property setting in the scope of the GroovyBeanDefinitionReader
|
||||
* This method overrides property setting in the scope of the {@code GroovyBeanDefinitionReader}
|
||||
* to set properties on the current bean definition.
|
||||
*/
|
||||
public void setProperty(String name, Object value) {
|
||||
@@ -619,12 +635,12 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
|
||||
/**
|
||||
* This method overrides property retrieval in the scope of the
|
||||
* GroovyBeanDefinitionReader to either:
|
||||
* {@code GroovyBeanDefinitionReader} to either:
|
||||
* <ul>
|
||||
* <li>Retrieve a variable from the bean builder's binding if it exists
|
||||
* <li>Retrieve a RuntimeBeanReference for a specific bean if it exists
|
||||
* <li>Otherwise just delegate to MetaClass.getProperty which will resolve
|
||||
* properties from the GroovyBeanDefinitionReader itself
|
||||
* properties from the {@code GroovyBeanDefinitionReader} itself
|
||||
* </ul>
|
||||
*/
|
||||
public Object getProperty(String name) {
|
||||
@@ -670,7 +686,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
}
|
||||
|
||||
private GroovyDynamicElementReader createDynamicElementReader(String namespace) {
|
||||
XmlReaderContext readerContext = this.xmlBeanDefinitionReader.createReaderContext(new DescriptiveResource("Groovy"));
|
||||
XmlReaderContext readerContext = this.groovyDslXmlBeanDefinitionReader.createReaderContext(new DescriptiveResource(
|
||||
"Groovy"));
|
||||
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
|
||||
boolean decorating = (this.currentBeanDefinition != null);
|
||||
if (!decorating) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -78,6 +78,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Stephane Nicoll
|
||||
* @since 15 April 2001
|
||||
* @see #registerCustomEditor
|
||||
* @see #setPropertyValues
|
||||
@@ -978,6 +979,14 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
}
|
||||
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
|
||||
requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
|
||||
int length = Array.getLength(propValue);
|
||||
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
|
||||
Class<?> componentType = propValue.getClass().getComponentType();
|
||||
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
|
||||
System.arraycopy(propValue, 0, newArray, 0, length);
|
||||
setPropertyValue(actualName, newArray);
|
||||
propValue = getPropertyValue(actualName);
|
||||
}
|
||||
Array.set(propValue, arrayIndex, convertedValue);
|
||||
}
|
||||
catch (IndexOutOfBoundsException ex) {
|
||||
@@ -1046,7 +1055,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||
else {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Property referenced in indexed property path '" + propertyName +
|
||||
"' is neither an array nor a List nor a Map; returned value was [" + pv.getValue() + "]");
|
||||
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,8 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
|
||||
Set<Method> ambiguousCandidates = new HashSet<Method>();
|
||||
for (Method method : beanClass.getMethods()) {
|
||||
if (method.getName().equals(writeMethodToUse.getName()) &&
|
||||
!method.equals(writeMethodToUse) && !method.isBridge()) {
|
||||
!method.equals(writeMethodToUse) && !method.isBridge() &&
|
||||
method.getParameterTypes().length == writeMethodToUse.getParameterTypes().length) {
|
||||
ambiguousCandidates.add(method);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,24 +17,31 @@
|
||||
package org.springframework.beans;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Helper class for calculating bean property matches, according to.
|
||||
* Used by BeanWrapperImpl to suggest alternatives for an invalid property name.
|
||||
* Helper class for calculating property matches, according to a configurable
|
||||
* distance. Provide the list of potential matches and an easy way to generate
|
||||
* an error message. Works for both java bean properties and fields.
|
||||
* <p>
|
||||
* Mainly for use within the framework and in particular the binding facility
|
||||
*
|
||||
* @author Alef Arendsen
|
||||
* @author Arjen Poutsma
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0
|
||||
* @see #forProperty(String, Class)
|
||||
* @see #forField(String, Class)
|
||||
*/
|
||||
final class PropertyMatches {
|
||||
public abstract class PropertyMatches {
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Static section
|
||||
@@ -60,7 +67,26 @@ final class PropertyMatches {
|
||||
* @param maxDistance the maximum property distance allowed for matches
|
||||
*/
|
||||
public static PropertyMatches forProperty(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
return new PropertyMatches(propertyName, beanClass, maxDistance);
|
||||
return new BeanPropertyMatches(propertyName, beanClass, maxDistance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create PropertyMatches for the given field property.
|
||||
* @param propertyName the name of the field to find possible matches for
|
||||
* @param beanClass the bean class to search for matches
|
||||
*/
|
||||
public static PropertyMatches forField(String propertyName, Class<?> beanClass) {
|
||||
return forField(propertyName, beanClass, DEFAULT_MAX_DISTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create PropertyMatches for the given field property.
|
||||
* @param propertyName the name of the field to find possible matches for
|
||||
* @param beanClass the bean class to search for matches
|
||||
* @param maxDistance the maximum property distance allowed for matches
|
||||
*/
|
||||
public static PropertyMatches forField(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
return new FieldPropertyMatches(propertyName, beanClass, maxDistance);
|
||||
}
|
||||
|
||||
|
||||
@@ -74,13 +100,19 @@ final class PropertyMatches {
|
||||
|
||||
|
||||
/**
|
||||
* Create a new PropertyMatches instance for the given property.
|
||||
* Create a new PropertyMatches instance for the given property and possible matches.
|
||||
*/
|
||||
private PropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
private PropertyMatches(String propertyName, String[] possibleMatches) {
|
||||
this.propertyName = propertyName;
|
||||
this.possibleMatches = calculateMatches(BeanUtils.getPropertyDescriptors(beanClass), maxDistance);
|
||||
this.possibleMatches = possibleMatches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the requested property.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the calculated possible matches.
|
||||
@@ -93,53 +125,21 @@ final class PropertyMatches {
|
||||
* Build an error message for the given invalid property name,
|
||||
* indicating the possible property matches.
|
||||
*/
|
||||
public String buildErrorMessage() {
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Bean property '");
|
||||
msg.append(this.propertyName);
|
||||
msg.append("' is not writable or has an invalid setter method. ");
|
||||
public abstract String buildErrorMessage();
|
||||
|
||||
if (ObjectUtils.isEmpty(this.possibleMatches)) {
|
||||
msg.append("Does the parameter type of the setter match the return type of the getter?");
|
||||
}
|
||||
else {
|
||||
msg.append("Did you mean ");
|
||||
for (int i = 0; i < this.possibleMatches.length; i++) {
|
||||
msg.append('\'');
|
||||
msg.append(this.possibleMatches[i]);
|
||||
if (i < this.possibleMatches.length - 2) {
|
||||
msg.append("', ");
|
||||
}
|
||||
else if (i == this.possibleMatches.length - 2){
|
||||
msg.append("', or ");
|
||||
}
|
||||
}
|
||||
msg.append("'?");
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate possible property alternatives for the given property and
|
||||
* class. Internally uses the {@code getStringDistance} method, which
|
||||
* in turn uses the Levenshtein algorithm to determine the distance between
|
||||
* two Strings.
|
||||
* @param propertyDescriptors the JavaBeans property descriptors to search
|
||||
* @param maxDistance the maximum distance to accept
|
||||
*/
|
||||
private String[] calculateMatches(PropertyDescriptor[] propertyDescriptors, int maxDistance) {
|
||||
List<String> candidates = new ArrayList<String>();
|
||||
for (PropertyDescriptor pd : propertyDescriptors) {
|
||||
if (pd.getWriteMethod() != null) {
|
||||
String possibleAlternative = pd.getName();
|
||||
if (calculateStringDistance(this.propertyName, possibleAlternative) <= maxDistance) {
|
||||
candidates.add(possibleAlternative);
|
||||
}
|
||||
protected void appendHintMessage(StringBuilder msg) {
|
||||
msg.append("Did you mean ");
|
||||
for (int i = 0; i < this.possibleMatches.length; i++) {
|
||||
msg.append('\'');
|
||||
msg.append(this.possibleMatches[i]);
|
||||
if (i < this.possibleMatches.length - 2) {
|
||||
msg.append("', ");
|
||||
}
|
||||
else if (i == this.possibleMatches.length - 2) {
|
||||
msg.append("', or ");
|
||||
}
|
||||
}
|
||||
Collections.sort(candidates);
|
||||
return StringUtils.toStringArray(candidates);
|
||||
msg.append("'?");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,7 +149,7 @@ final class PropertyMatches {
|
||||
* @param s2 the second String
|
||||
* @return the distance value
|
||||
*/
|
||||
private int calculateStringDistance(String s1, String s2) {
|
||||
private static int calculateStringDistance(String s1, String s2) {
|
||||
if (s1.length() == 0) {
|
||||
return s2.length();
|
||||
}
|
||||
@@ -184,4 +184,93 @@ final class PropertyMatches {
|
||||
return d[s1.length()][s2.length()];
|
||||
}
|
||||
|
||||
private static class BeanPropertyMatches extends PropertyMatches {
|
||||
|
||||
private BeanPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
super(propertyName, calculateMatches(propertyName,
|
||||
BeanUtils.getPropertyDescriptors(beanClass), maxDistance));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate possible property alternatives for the given property and
|
||||
* class. Internally uses the {@code getStringDistance} method, which
|
||||
* in turn uses the Levenshtein algorithm to determine the distance between
|
||||
* two Strings.
|
||||
* @param propertyDescriptors the JavaBeans property descriptors to search
|
||||
* @param maxDistance the maximum distance to accept
|
||||
*/
|
||||
private static String[] calculateMatches(String propertyName, PropertyDescriptor[] propertyDescriptors, int maxDistance) {
|
||||
List<String> candidates = new ArrayList<String>();
|
||||
for (PropertyDescriptor pd : propertyDescriptors) {
|
||||
if (pd.getWriteMethod() != null) {
|
||||
String possibleAlternative = pd.getName();
|
||||
if (calculateStringDistance(propertyName, possibleAlternative) <= maxDistance) {
|
||||
candidates.add(possibleAlternative);
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(candidates);
|
||||
return StringUtils.toStringArray(candidates);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String buildErrorMessage() {
|
||||
String propertyName = getPropertyName();
|
||||
String[] possibleMatches = getPossibleMatches();
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Bean property '");
|
||||
msg.append(propertyName);
|
||||
msg.append("' is not writable or has an invalid setter method. ");
|
||||
|
||||
if (ObjectUtils.isEmpty(possibleMatches)) {
|
||||
msg.append("Does the parameter type of the setter match the return type of the getter?");
|
||||
}
|
||||
else {
|
||||
appendHintMessage(msg);
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class FieldPropertyMatches extends PropertyMatches {
|
||||
|
||||
private FieldPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
|
||||
super(propertyName, calculateMatches(propertyName, beanClass, maxDistance));
|
||||
}
|
||||
|
||||
private static String[] calculateMatches(final String propertyName, Class<?> beanClass, final int maxDistance) {
|
||||
final List<String> candidates = new ArrayList<String>();
|
||||
ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
|
||||
@Override
|
||||
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
|
||||
String possibleAlternative = field.getName();
|
||||
if (calculateStringDistance(propertyName, possibleAlternative) <= maxDistance) {
|
||||
candidates.add(possibleAlternative);
|
||||
}
|
||||
}
|
||||
});
|
||||
Collections.sort(candidates);
|
||||
return StringUtils.toStringArray(candidates);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String buildErrorMessage() {
|
||||
String propertyName = getPropertyName();
|
||||
String[] possibleMatches = getPossibleMatches();
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Bean property '");
|
||||
msg.append(propertyName);
|
||||
msg.append("' has no matching field. ");
|
||||
|
||||
if (!ObjectUtils.isEmpty(possibleMatches)) {
|
||||
appendHintMessage(msg);
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -204,7 +204,7 @@ class TypeConverterDelegate {
|
||||
if (Object.class.equals(requiredType)) {
|
||||
return (T) convertedValue;
|
||||
}
|
||||
if (requiredType.isArray()) {
|
||||
else if (requiredType.isArray()) {
|
||||
// Array required -> apply appropriate conversion of elements.
|
||||
if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
|
||||
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
|
||||
@@ -339,7 +339,6 @@ class TypeConverterDelegate {
|
||||
catch (Throwable ex) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Field [" + convertedValue + "] isn't an enum value", ex);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -57,10 +57,10 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
*/
|
||||
public TypeMismatchException(PropertyChangeEvent propertyChangeEvent, Class<?> requiredType, Throwable cause) {
|
||||
super(propertyChangeEvent,
|
||||
"Failed to convert property value of type '" +
|
||||
ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "'" +
|
||||
"Failed to convert property value of type [" +
|
||||
ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "]" +
|
||||
(requiredType != null ?
|
||||
" to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : "") +
|
||||
" to required type [" + ClassUtils.getQualifiedName(requiredType) + "]" : "") +
|
||||
(propertyChangeEvent.getPropertyName() != null ?
|
||||
" for property '" + propertyChangeEvent.getPropertyName() + "'" : ""),
|
||||
cause);
|
||||
@@ -84,8 +84,8 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
* @param cause the root cause (may be {@code null})
|
||||
*/
|
||||
public TypeMismatchException(Object value, Class<?> requiredType, Throwable cause) {
|
||||
super("Failed to convert value of type '" + ClassUtils.getDescriptiveType(value) + "'" +
|
||||
(requiredType != null ? " to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : ""),
|
||||
super("Failed to convert value of type [" + ClassUtils.getDescriptiveType(value) + "]" +
|
||||
(requiredType != null ? " to required type [" + ClassUtils.getQualifiedName(requiredType) + "]" : ""),
|
||||
cause);
|
||||
this.value = value;
|
||||
this.requiredType = requiredType;
|
||||
@@ -93,7 +93,7 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
|
||||
|
||||
/**
|
||||
* Return the offending value (may be {@code null})
|
||||
* Return the offending value (may be {@code null}).
|
||||
*/
|
||||
@Override
|
||||
public Object getValue() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -114,6 +114,7 @@ public interface BeanFactory {
|
||||
*/
|
||||
String FACTORY_BEAN_PREFIX = "&";
|
||||
|
||||
|
||||
/**
|
||||
* Return an instance, which may be shared or independent, of the specified bean.
|
||||
* <p>This method allows a Spring BeanFactory to be used as a replacement for the
|
||||
@@ -160,6 +161,7 @@ public interface BeanFactory {
|
||||
* @return an instance of the single bean matching the required type
|
||||
* @throws NoSuchBeanDefinitionException if no bean of the given type was found
|
||||
* @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found
|
||||
* @throws BeansException if the bean could not be created
|
||||
* @since 3.0
|
||||
* @see ListableBeanFactory
|
||||
*/
|
||||
@@ -202,6 +204,7 @@ public interface BeanFactory {
|
||||
*/
|
||||
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
|
||||
|
||||
|
||||
/**
|
||||
* Does this bean factory contain a bean definition or externally registered singleton
|
||||
* instance with the given name?
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,7 +16,6 @@
|
||||
|
||||
package org.springframework.beans.factory;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
+6
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.beans.factory.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
@@ -77,20 +76,19 @@ public class BeanFactoryAnnotationUtils {
|
||||
* @throws NoSuchBeanDefinitionException if no matching bean of type {@code T} found
|
||||
*/
|
||||
private static <T> T qualifiedBeanOfType(ConfigurableListableBeanFactory bf, Class<T> beanType, String qualifier) {
|
||||
Map<String, T> candidateBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, beanType);
|
||||
T matchingBean = null;
|
||||
for (Map.Entry<String, T> entry : candidateBeans.entrySet()) {
|
||||
String beanName = entry.getKey();
|
||||
String[] candidateBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(bf, beanType);
|
||||
String matchingBean = null;
|
||||
for (String beanName : candidateBeans) {
|
||||
if (isQualifierMatch(qualifier, beanName, bf)) {
|
||||
if (matchingBean != null) {
|
||||
throw new NoSuchBeanDefinitionException(qualifier, "No unique " + beanType.getSimpleName() +
|
||||
" bean found for qualifier '" + qualifier + "'");
|
||||
}
|
||||
matchingBean = entry.getValue();
|
||||
matchingBean = beanName;
|
||||
}
|
||||
}
|
||||
if (matchingBean != null) {
|
||||
return matchingBean;
|
||||
return bf.getBean(matchingBean, beanType);
|
||||
}
|
||||
else if (bf.containsBean(qualifier)) {
|
||||
// Fallback: target bean at least found by bean name - probably a manually registered singleton.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,12 +38,15 @@ import java.lang.annotation.Target;
|
||||
* container to fill them in at runtime. In both cases, the container will generate
|
||||
* runtime subclasses of the method's containing class via CGLIB, which is why such
|
||||
* lookup methods can only work on beans that the container instantiates through
|
||||
* regular constructors (i.e. lookup methods cannot get replaced on beans returned
|
||||
* from factory methods where we can't dynamically provide a subclass for them).
|
||||
* regular constructors: i.e. lookup methods cannot get replaced on beans returned
|
||||
* from factory methods where we cannot dynamically provide a subclass for them.
|
||||
*
|
||||
* <p>Note: When used with component scanning or any other mechanism that filters
|
||||
* out abstract beans, provide stub implementations of your lookup methods to be
|
||||
* able to declare them as concrete classes.
|
||||
* <p><b>Concrete limitations in typical Spring configuration scenarios:</b>
|
||||
* When used with component scanning or any other mechanism that filters out abstract
|
||||
* beans, provide stub implementations of your lookup methods to be able to declare
|
||||
* them as concrete classes. And please remember that lookup methods won't work on
|
||||
* beans returned from {@code @Bean} methods in configuration classes; you'll have
|
||||
* to resort to {@code @Inject Provider<TargetBean>} or the like instead.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -48,8 +48,8 @@ public interface BeanPostProcessor {
|
||||
* The returned bean instance may be a wrapper around the original.
|
||||
* @param bean the new bean instance
|
||||
* @param beanName the name of the bean
|
||||
* @return the bean instance to use, either the original or a wrapped one; if
|
||||
* {@code null}, no subsequent BeanPostProcessors will be invoked
|
||||
* @return the bean instance to use, either the original or a wrapped one;
|
||||
* if {@code null}, no subsequent BeanPostProcessors will be invoked
|
||||
* @throws org.springframework.beans.BeansException in case of errors
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
|
||||
*/
|
||||
@@ -69,8 +69,8 @@ public interface BeanPostProcessor {
|
||||
* in contrast to all other BeanPostProcessor callbacks.
|
||||
* @param bean the new bean instance
|
||||
* @param beanName the name of the bean
|
||||
* @return the bean instance to use, either the original or a wrapped one; if
|
||||
* {@code null}, no subsequent BeanPostProcessors will be invoked
|
||||
* @return the bean instance to use, either the original or a wrapped one;
|
||||
* if {@code null}, no subsequent BeanPostProcessors will be invoked
|
||||
* @throws org.springframework.beans.BeansException in case of errors
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
|
||||
* @see org.springframework.beans.factory.FactoryBean
|
||||
|
||||
+22
-22
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,33 +30,33 @@ import org.springframework.util.StringValueResolver;
|
||||
*
|
||||
* <p>The default placeholder syntax follows the Ant / Log4J / JSP EL style:
|
||||
*
|
||||
*<pre class="code">${...}</pre>
|
||||
* <pre class="code">${...}</pre>
|
||||
*
|
||||
* Example XML bean definition:
|
||||
*
|
||||
*<pre class="code">{@code
|
||||
*<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>
|
||||
* <property name="driverClassName" value="}${driver}{@code "/>
|
||||
* <property name="url" value="jdbc:}${dbname}{@code "/>
|
||||
*</bean>
|
||||
*}</pre>
|
||||
* <pre class="code">
|
||||
* <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>
|
||||
* <property name="driverClassName" value="${driver}"/>
|
||||
* <property name="url" value="jdbc:${dbname}"/>
|
||||
* </bean>
|
||||
* </pre>
|
||||
*
|
||||
* Example properties file:
|
||||
*
|
||||
* <pre class="code"> driver=com.mysql.jdbc.Driver
|
||||
* <pre class="code">driver=com.mysql.jdbc.Driver
|
||||
* dbname=mysql:mydb</pre>
|
||||
*
|
||||
* Annotated bean definitions may take advantage of property replacement using
|
||||
* the {@link org.springframework.beans.factory.annotation.Value @Value} annotation:
|
||||
*
|
||||
*<pre class="code">@Value("${person.age}")</pre>
|
||||
* <pre class="code">@Value("${person.age}")</pre>
|
||||
*
|
||||
* Implementations check simple property values, lists, maps, props, and bean names
|
||||
* in bean references. Furthermore, placeholder values can also cross-reference
|
||||
* other placeholders, like:
|
||||
*
|
||||
*<pre class="code">rootPath=myrootdir
|
||||
*subPath=${rootPath}/subdir</pre>
|
||||
* <pre class="code">rootPath=myrootdir
|
||||
* subPath=${rootPath}/subdir</pre>
|
||||
*
|
||||
* In contrast to {@link PropertyOverrideConfigurer}, subclasses of this type allow
|
||||
* filling in of explicit placeholders in bean definitions.
|
||||
@@ -75,9 +75,9 @@ import org.springframework.util.StringValueResolver;
|
||||
*
|
||||
* <p>Example XML property with default value:
|
||||
*
|
||||
*<pre class="code">{@code
|
||||
* <property name="url" value="jdbc:}${dbname:defaultdb}{@code "/>
|
||||
*}</pre>
|
||||
* <pre class="code">
|
||||
* <property name="url" value="jdbc:${dbname:defaultdb}"/>
|
||||
* </pre>
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
@@ -107,14 +107,14 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
|
||||
/** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */
|
||||
protected String valueSeparator = DEFAULT_VALUE_SEPARATOR;
|
||||
|
||||
protected boolean ignoreUnresolvablePlaceholders = false;
|
||||
|
||||
protected String nullValue;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
protected boolean ignoreUnresolvablePlaceholders = false;
|
||||
|
||||
private String beanName;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Set the prefix that a placeholder string starts with.
|
||||
@@ -143,13 +143,13 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value that should be treated as {@code null} when
|
||||
* resolved as a placeholder value: e.g. "" (empty String) or "null".
|
||||
* Set a value that should be treated as {@code null} when resolved
|
||||
* as a placeholder value: e.g. "" (empty String) or "null".
|
||||
* <p>Note that this will only apply to full property values,
|
||||
* not to parts of concatenated values.
|
||||
* <p>By default, no such null value is defined. This means that
|
||||
* there is no way to express {@code null} as a property
|
||||
* value unless you explicitly map a corresponding value here.
|
||||
* there is no way to express {@code null} as a property value
|
||||
* unless you explicitly map a corresponding value here.
|
||||
*/
|
||||
public void setNullValue(String nullValue) {
|
||||
this.nullValue = nullValue;
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -219,8 +219,7 @@ public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport
|
||||
throws BeansException {
|
||||
|
||||
StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
|
||||
|
||||
this.doProcessProperties(beanFactoryToProcess, valueResolver);
|
||||
doProcessProperties(beanFactoryToProcess, valueResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+48
-39
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,7 @@
|
||||
package org.springframework.beans.factory.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -35,13 +35,14 @@ import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.nodes.MappingNode;
|
||||
import org.yaml.snakeyaml.parser.ParserException;
|
||||
import org.yaml.snakeyaml.reader.UnicodeReader;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base class for Yaml factories.
|
||||
* Base class for YAML factories.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 4.1
|
||||
@@ -64,7 +65,6 @@ public abstract class YamlProcessor {
|
||||
* some of the documents in a YAML resource. In YAML documents are
|
||||
* separated by <code>---<code> lines, and each document is converted
|
||||
* to properties before the match is made. E.g.
|
||||
*
|
||||
* <pre class="code">
|
||||
* environment: dev
|
||||
* url: http://dev.bar.com
|
||||
@@ -74,11 +74,9 @@ public abstract class YamlProcessor {
|
||||
* url:http://foo.bar.com
|
||||
* name: My Cool App
|
||||
* </pre>
|
||||
*
|
||||
* when mapped with
|
||||
* <code>documentMatchers = YamlProcessor.mapMatcher({"environment": "prod"})</code>
|
||||
* would end up as
|
||||
*
|
||||
* <pre class="code">
|
||||
* environment=prod
|
||||
* url=http://foo.bar.com
|
||||
@@ -102,9 +100,9 @@ public abstract class YamlProcessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to use for resolving resources. Each resource will be converted to a Map, so
|
||||
* this property is used to decide which map entries to keep in the final output from
|
||||
* this factory.
|
||||
* Method to use for resolving resources. Each resource will be converted to a Map,
|
||||
* so this property is used to decide which map entries to keep in the final output
|
||||
* from this factory.
|
||||
* @param resolutionMethod the resolution method to set (defaults to
|
||||
* {@link ResolutionMethod#OVERRIDE}).
|
||||
*/
|
||||
@@ -126,13 +124,14 @@ public abstract class YamlProcessor {
|
||||
* Provide an opportunity for subclasses to process the Yaml parsed from the supplied
|
||||
* resources. Each resource is parsed in turn and the documents inside checked against
|
||||
* the {@link #setDocumentMatchers(DocumentMatcher...) matchers}. If a document
|
||||
* matches it is passed into the callback, along with its representation as
|
||||
* Properties. Depending on the {@link #setResolutionMethod(ResolutionMethod)} not all
|
||||
* of the documents will be parsed.
|
||||
* matches it is passed into the callback, along with its representation as Properties.
|
||||
* Depending on the {@link #setResolutionMethod(ResolutionMethod)} not all of the
|
||||
* documents will be parsed.
|
||||
* @param callback a callback to delegate to once matching documents are found
|
||||
* @see #createYaml()
|
||||
*/
|
||||
protected void process(MatchCallback callback) {
|
||||
Yaml yaml = new Yaml(new StrictMapAppenderConstructor());
|
||||
Yaml yaml = createYaml();
|
||||
for (Resource resource : this.resources) {
|
||||
boolean found = process(callback, yaml, resource);
|
||||
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND && found) {
|
||||
@@ -141,15 +140,22 @@ public abstract class YamlProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link Yaml} instance to use.
|
||||
*/
|
||||
protected Yaml createYaml() {
|
||||
return new Yaml(new StrictMapAppenderConstructor());
|
||||
}
|
||||
|
||||
private boolean process(MatchCallback callback, Yaml yaml, Resource resource) {
|
||||
int count = 0;
|
||||
try {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Loading from YAML: " + resource);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loading from YAML: " + resource);
|
||||
}
|
||||
InputStream stream = resource.getInputStream();
|
||||
Reader reader = new UnicodeReader(resource.getInputStream());
|
||||
try {
|
||||
for (Object object : yaml.loadAll(stream)) {
|
||||
for (Object object : yaml.loadAll(reader)) {
|
||||
if (object != null && process(asMap(object), callback)) {
|
||||
count++;
|
||||
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND) {
|
||||
@@ -157,13 +163,13 @@ public abstract class YamlProcessor {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Loaded " + count + " document" + (count > 1 ? "s" : "") +
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loaded " + count + " document" + (count > 1 ? "s" : "") +
|
||||
" from YAML resource: " + resource);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stream.close();
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
@@ -177,8 +183,8 @@ public abstract class YamlProcessor {
|
||||
this.resolutionMethod != ResolutionMethod.OVERRIDE_AND_IGNORE) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
if (this.logger.isWarnEnabled()) {
|
||||
this.logger.warn("Could not load map from " + resource + ": " + ex.getMessage());
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Could not load map from " + resource + ": " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,8 +221,8 @@ public abstract class YamlProcessor {
|
||||
properties.putAll(getFlattenedMap(map));
|
||||
|
||||
if (this.documentMatchers.isEmpty()) {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Merging document (no matchers set)" + map);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Merging document (no matchers set): " + map);
|
||||
}
|
||||
callback.process(properties, map);
|
||||
return true;
|
||||
@@ -227,8 +233,8 @@ public abstract class YamlProcessor {
|
||||
MatchStatus match = matcher.matches(properties);
|
||||
result = MatchStatus.getMostSpecific(match, result);
|
||||
if (match == MatchStatus.FOUND) {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Matched document with document matcher: " + properties);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Matched document with document matcher: " + properties);
|
||||
}
|
||||
callback.process(properties, map);
|
||||
return true;
|
||||
@@ -236,14 +242,16 @@ public abstract class YamlProcessor {
|
||||
}
|
||||
|
||||
if (result == MatchStatus.ABSTAIN && this.matchDefault) {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Matched document with default matcher: " + map);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Matched document with default matcher: " + map);
|
||||
}
|
||||
callback.process(properties, map);
|
||||
return true;
|
||||
}
|
||||
|
||||
this.logger.debug("Unmatched document");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Unmatched document: " + map);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -294,7 +302,7 @@ public abstract class YamlProcessor {
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.put(key, value == null ? "" : value);
|
||||
result.put(key, value != null ? value : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,7 +330,7 @@ public abstract class YamlProcessor {
|
||||
/**
|
||||
* Test if the given properties match.
|
||||
* @param properties the properties to test
|
||||
* @return the status of the match.
|
||||
* @return the status of the match
|
||||
*/
|
||||
MatchStatus matches(Properties properties);
|
||||
}
|
||||
@@ -331,7 +339,7 @@ public abstract class YamlProcessor {
|
||||
/**
|
||||
* Status returned from {@link DocumentMatcher#matches(java.util.Properties)}
|
||||
*/
|
||||
public static enum MatchStatus {
|
||||
public enum MatchStatus {
|
||||
|
||||
/**
|
||||
* A match was found.
|
||||
@@ -360,7 +368,7 @@ public abstract class YamlProcessor {
|
||||
/**
|
||||
* Method to use for resolving resources.
|
||||
*/
|
||||
public static enum ResolutionMethod {
|
||||
public enum ResolutionMethod {
|
||||
|
||||
/**
|
||||
* Replace values from earlier in the list.
|
||||
@@ -382,9 +390,10 @@ public abstract class YamlProcessor {
|
||||
/**
|
||||
* A specialized {@link Constructor} that checks for duplicate keys.
|
||||
*/
|
||||
private static class StrictMapAppenderConstructor extends Constructor {
|
||||
protected static class StrictMapAppenderConstructor extends Constructor {
|
||||
|
||||
public StrictMapAppenderConstructor() {
|
||||
// Declared as public for use in subclasses
|
||||
public StrictMapAppenderConstructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -392,9 +401,10 @@ public abstract class YamlProcessor {
|
||||
protected Map<Object, Object> constructMapping(MappingNode node) {
|
||||
try {
|
||||
return super.constructMapping(node);
|
||||
} catch (IllegalStateException e) {
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw new ParserException("while parsing MappingNode",
|
||||
node.getStartMark(), e.getMessage(), node.getEndMark());
|
||||
node.getStartMark(), ex.getMessage(), node.getEndMark());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,7 +415,7 @@ public abstract class YamlProcessor {
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
if (delegate.containsKey(key)) {
|
||||
throw new IllegalStateException("duplicate key: " + key);
|
||||
throw new IllegalStateException("Duplicate key: " + key);
|
||||
}
|
||||
return delegate.put(key, value);
|
||||
}
|
||||
@@ -415,7 +425,6 @@ public abstract class YamlProcessor {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -679,7 +679,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
if (Modifier.isStatic(factoryMethod.getModifiers()) == isStatic &&
|
||||
factoryMethod.getName().equals(mbd.getFactoryMethodName()) &&
|
||||
factoryMethod.getParameterTypes().length >= minNrOfArgs) {
|
||||
// No declared type variables to inspect, so just process the standard return type.
|
||||
// Declared type variables to inspect?
|
||||
if (factoryMethod.getTypeParameters().length > 0) {
|
||||
try {
|
||||
// Fully resolve parameter names and argument values.
|
||||
@@ -833,8 +833,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
|
||||
/**
|
||||
* Obtain a "shortcut" singleton FactoryBean instance to use for a
|
||||
* {@code getObjectType()} call, without full initialization
|
||||
* of the FactoryBean.
|
||||
* {@code getObjectType()} call, without full initialization of the FactoryBean.
|
||||
* @param beanName the name of the bean
|
||||
* @param mbd the bean definition for the bean
|
||||
* @return the FactoryBean instance, or {@code null} to indicate
|
||||
@@ -875,8 +874,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
|
||||
/**
|
||||
* Obtain a "shortcut" non-singleton FactoryBean instance to use for a
|
||||
* {@code getObjectType()} call, without full initialization
|
||||
* of the FactoryBean.
|
||||
* {@code getObjectType()} call, without full initialization of the FactoryBean.
|
||||
* @param beanName the name of the bean
|
||||
* @param mbd the bean definition for the bean
|
||||
* @return the FactoryBean instance, or {@code null} to indicate
|
||||
@@ -897,6 +895,14 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
instance = bw.getWrappedInstance();
|
||||
}
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
// Can only happen when getting a FactoryBean.
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Bean creation exception on non-singleton FactoryBean type check: " + ex);
|
||||
}
|
||||
onSuppressedException(ex);
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
// Finished partial creation of this bean.
|
||||
afterPrototypeCreation(beanName);
|
||||
|
||||
+17
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -331,7 +331,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
String scopeName = mbd.getScope();
|
||||
final Scope scope = this.scopes.get(scopeName);
|
||||
if (scope == null) {
|
||||
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
|
||||
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
|
||||
}
|
||||
try {
|
||||
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
|
||||
@@ -350,8 +350,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Scope '" + scopeName + "' is not active for the current thread; " +
|
||||
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
|
||||
"Scope '" + scopeName + "' is not active for the current thread; consider " +
|
||||
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
|
||||
ex);
|
||||
}
|
||||
}
|
||||
@@ -1055,7 +1055,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
String scopeName = mbd.getScope();
|
||||
Scope scope = this.scopes.get(scopeName);
|
||||
if (scope == null) {
|
||||
throw new IllegalStateException("No Scope SPI registered for scope '" + scopeName + "'");
|
||||
throw new IllegalStateException("No Scope SPI registered for scope name '" + scopeName + "'");
|
||||
}
|
||||
Object bean = scope.remove(beanName);
|
||||
if (bean != null) {
|
||||
@@ -1334,6 +1334,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
|
||||
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch) throws ClassNotFoundException {
|
||||
if (!ObjectUtils.isEmpty(typesToMatch)) {
|
||||
// When just doing type checks (i.e. not creating an actual instance yet),
|
||||
// use the specified temporary class loader (e.g. in a weaving scenario).
|
||||
ClassLoader tempClassLoader = getTempClassLoader();
|
||||
if (tempClassLoader != null) {
|
||||
if (tempClassLoader instanceof DecoratingClassLoader) {
|
||||
@@ -1422,9 +1424,15 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
return getTypeForFactoryBean(factoryBean);
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
// Can only happen when getting a FactoryBean.
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Bean creation exception on FactoryBean type check: " + ex);
|
||||
if (ex instanceof BeanCurrentlyInCreationException) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Bean currently in creation on FactoryBean type check: " + ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Bean creation exception on FactoryBean type check: " + ex);
|
||||
}
|
||||
}
|
||||
onSuppressedException(ex);
|
||||
return null;
|
||||
@@ -1570,7 +1578,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
// A bean with a custom scope...
|
||||
Scope scope = this.scopes.get(mbd.getScope());
|
||||
if (scope == null) {
|
||||
throw new IllegalStateException("No Scope registered for scope '" + mbd.getScope() + "'");
|
||||
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
|
||||
}
|
||||
scope.registerDestructionCallback(beanName,
|
||||
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -279,7 +279,7 @@ public class BeanDefinitionBuilder {
|
||||
*/
|
||||
public BeanDefinitionBuilder addDependsOn(String beanName) {
|
||||
if (this.beanDefinition.getDependsOn() == null) {
|
||||
this.beanDefinition.setDependsOn(new String[] {beanName});
|
||||
this.beanDefinition.setDependsOn(beanName);
|
||||
}
|
||||
else {
|
||||
String[] added = ObjectUtils.addObjectToArray(this.beanDefinition.getDependsOn(), beanName);
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -150,8 +150,8 @@ public class BeanDefinitionReaderUtils {
|
||||
// Register aliases for bean name, if any.
|
||||
String[] aliases = definitionHolder.getAliases();
|
||||
if (aliases != null) {
|
||||
for (String aliase : aliases) {
|
||||
registry.registerAlias(beanName, aliase);
|
||||
for (String alias : aliases) {
|
||||
registry.registerAlias(beanName, alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -323,7 +323,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of ListableBeanFactory interface
|
||||
// Implementation of remaining BeanFactory methods
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
@@ -562,17 +562,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) {
|
||||
Map<String, Object> results = new LinkedHashMap<String, Object>();
|
||||
for (String beanName : this.beanDefinitionNames) {
|
||||
BeanDefinition beanDefinition = getBeanDefinition(beanName);
|
||||
if (!beanDefinition.isAbstract() && findAnnotationOnBean(beanName, annotationType) != null) {
|
||||
results.put(beanName, getBean(beanName));
|
||||
}
|
||||
}
|
||||
for (String beanName : this.manualSingletonNames) {
|
||||
if (!results.containsKey(beanName) && findAnnotationOnBean(beanName, annotationType) != null) {
|
||||
results.put(beanName, getBean(beanName));
|
||||
}
|
||||
String[] beanNames = getBeanNamesForAnnotation(annotationType);
|
||||
Map<String, Object> results = new LinkedHashMap<String, Object>(beanNames.length);
|
||||
for (String beanName : beanNames) {
|
||||
results.put(beanName, getBean(beanName));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
@@ -811,7 +804,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
|
||||
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
|
||||
if (oldBeanDefinition != null) {
|
||||
if (!this.allowBeanDefinitionOverriding) {
|
||||
if (!isAllowBeanDefinitionOverriding()) {
|
||||
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
|
||||
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
|
||||
"': There is already [" + oldBeanDefinition + "] bound.");
|
||||
@@ -820,7 +813,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
|
||||
if (this.logger.isWarnEnabled()) {
|
||||
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
|
||||
" with a framework-generated bean definition ': replacing [" +
|
||||
"' with a framework-generated bean definition: replacing [" +
|
||||
oldBeanDefinition + "] with [" + beanDefinition + "]");
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -607,13 +607,13 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose the singleton mutex to subclasses.
|
||||
* Exposes the singleton mutex to subclasses and external collaborators.
|
||||
* <p>Subclasses should synchronize on the given Object if they perform
|
||||
* any sort of extended singleton creation phase. In particular, subclasses
|
||||
* should <i>not</i> have their own mutexes involved in singleton creation,
|
||||
* to avoid the potential for deadlocks in lazy-init situations.
|
||||
*/
|
||||
protected final Object getSingletonMutex() {
|
||||
public final Object getSingletonMutex() {
|
||||
return this.singletonObjects;
|
||||
}
|
||||
|
||||
|
||||
+8
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,11 +37,12 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Adapter that implements the {@link DisposableBean} and {@link Runnable} interfaces
|
||||
* performing various destruction steps on a given bean instance:
|
||||
* Adapter that implements the {@link DisposableBean} and {@link Runnable}
|
||||
* interfaces performing various destruction steps on a given bean instance:
|
||||
* <ul>
|
||||
* <li>DestructionAwareBeanPostProcessors;
|
||||
* <li>the bean implementing DisposableBean itself;
|
||||
@@ -175,8 +176,8 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
/**
|
||||
* If the current value of the given beanDefinition's "destroyMethodName" property is
|
||||
* {@link AbstractBeanDefinition#INFER_METHOD}, then attempt to infer a destroy method.
|
||||
* Candidate methods are currently limited to public, no-arg methods named "close"
|
||||
* (whether declared locally or inherited). The given BeanDefinition's
|
||||
* Candidate methods are currently limited to public, no-arg methods named "close" or
|
||||
* "shutdown" (whether declared locally or inherited). The given BeanDefinition's
|
||||
* "destroyMethodName" is updated to be null if no such method is found, otherwise set
|
||||
* to the name of the inferred method. This constant serves as the default for the
|
||||
* {@code @Bean#destroyMethod} attribute and the value of the constant may also be
|
||||
@@ -215,7 +216,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
*/
|
||||
private List<DestructionAwareBeanPostProcessor> filterPostProcessors(List<BeanPostProcessor> postProcessors) {
|
||||
List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
|
||||
if (postProcessors != null && !postProcessors.isEmpty()) {
|
||||
if (!CollectionUtils.isEmpty(postProcessors)) {
|
||||
filteredPostProcessors = new ArrayList<DestructionAwareBeanPostProcessor>(postProcessors.size());
|
||||
for (BeanPostProcessor postProcessor : postProcessors) {
|
||||
if (postProcessor instanceof DestructionAwareBeanPostProcessor) {
|
||||
@@ -234,7 +235,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (this.beanPostProcessors != null && !this.beanPostProcessors.isEmpty()) {
|
||||
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
|
||||
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
|
||||
processor.postProcessBeforeDestruction(this.bean, this.beanName);
|
||||
}
|
||||
|
||||
+22
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,12 +49,13 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
/** Constant for the id attribute */
|
||||
/** Constant for the "id" attribute */
|
||||
public static final String ID_ATTRIBUTE = "id";
|
||||
|
||||
/** Constant for the name attribute */
|
||||
/** Constant for the "name" attribute */
|
||||
public static final String NAME_ATTRIBUTE = "name";
|
||||
|
||||
|
||||
@Override
|
||||
public final BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
AbstractBeanDefinition definition = parseInternal(element, parserContext);
|
||||
@@ -66,10 +67,12 @@ public abstract class AbstractBeanDefinitionParser implements BeanDefinitionPars
|
||||
"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
|
||||
+ "' when used as a top-level tag", element);
|
||||
}
|
||||
String[] aliases = new String[0];
|
||||
String name = element.getAttribute(NAME_ATTRIBUTE);
|
||||
if (StringUtils.hasLength(name)) {
|
||||
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
|
||||
String[] aliases = null;
|
||||
if (shouldParseNameAsAliases()) {
|
||||
String name = element.getAttribute(NAME_ATTRIBUTE);
|
||||
if (StringUtils.hasLength(name)) {
|
||||
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
|
||||
}
|
||||
}
|
||||
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
|
||||
registerBeanDefinition(holder, parserContext.getRegistry());
|
||||
@@ -170,7 +173,18 @@ public abstract class AbstractBeanDefinitionParser implements BeanDefinitionPars
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls whether this parser is supposed to fire a
|
||||
* Determine whether the element's "name" attribute should get parsed as
|
||||
* bean definition aliases, i.e. alternative bean definition names.
|
||||
* <p>The default implementation returns {@code true}.
|
||||
* @return whether the parser should evaluate the "name" attribute as aliases
|
||||
* @since 4.1.5
|
||||
*/
|
||||
protected boolean shouldParseNameAsAliases() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this parser is supposed to fire a
|
||||
* {@link org.springframework.beans.factory.parsing.BeanComponentDefinition}
|
||||
* event after parsing the bean definition.
|
||||
* <p>This implementation returns {@code true} by default; that is,
|
||||
|
||||
+26
-27
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.beans.factory.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -45,7 +44,9 @@ public class BeansDtdResolver implements EntityResolver {
|
||||
|
||||
private static final String DTD_EXTENSION = ".dtd";
|
||||
|
||||
private static final String[] DTD_NAMES = {"spring-beans-2.0", "spring-beans"};
|
||||
private static final String DTD_FILENAME = "spring-beans-2.0";
|
||||
|
||||
private static final String DTD_NAME = "spring-beans";
|
||||
|
||||
private static final Log logger = LogFactory.getLog(BeansDtdResolver.class);
|
||||
|
||||
@@ -58,30 +59,28 @@ public class BeansDtdResolver implements EntityResolver {
|
||||
}
|
||||
if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
|
||||
int lastPathSeparator = systemId.lastIndexOf("/");
|
||||
for (String DTD_NAME : DTD_NAMES) {
|
||||
int dtdNameStart = systemId.indexOf(DTD_NAME);
|
||||
if (dtdNameStart > lastPathSeparator) {
|
||||
String dtdFile = systemId.substring(dtdNameStart);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Trying to locate [" + dtdFile + "] in Spring jar");
|
||||
}
|
||||
try {
|
||||
Resource resource = new ClassPathResource(dtdFile, getClass());
|
||||
InputSource source = new InputSource(resource.getInputStream());
|
||||
source.setPublicId(publicId);
|
||||
source.setSystemId(systemId);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in class path", ex);
|
||||
}
|
||||
}
|
||||
|
||||
int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator);
|
||||
if (dtdNameStart != -1) {
|
||||
String dtdFile = DTD_FILENAME + DTD_EXTENSION;
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath");
|
||||
}
|
||||
try {
|
||||
Resource resource = new ClassPathResource(dtdFile, getClass());
|
||||
InputSource source = new InputSource(resource.getInputStream());
|
||||
source.setPublicId(publicId);
|
||||
source.setSystemId(systemId);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +91,7 @@ public class BeansDtdResolver implements EntityResolver {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EntityResolver for DTDs " + Arrays.toString(DTD_NAMES);
|
||||
return "EntityResolver for spring-beans DTD";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -95,6 +95,7 @@ public class CustomBooleanEditor extends PropertyEditorSupport {
|
||||
this.allowEmpty = allowEmpty;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
String input = (text != null ? text.trim() : null);
|
||||
@@ -102,20 +103,20 @@ public class CustomBooleanEditor extends PropertyEditorSupport {
|
||||
// Treat empty String as null value.
|
||||
setValue(null);
|
||||
}
|
||||
else if (this.trueString != null && input.equalsIgnoreCase(this.trueString)) {
|
||||
else if (this.trueString != null && this.trueString.equalsIgnoreCase(input)) {
|
||||
setValue(Boolean.TRUE);
|
||||
}
|
||||
else if (this.falseString != null && input.equalsIgnoreCase(this.falseString)) {
|
||||
else if (this.falseString != null && this.falseString.equalsIgnoreCase(input)) {
|
||||
setValue(Boolean.FALSE);
|
||||
}
|
||||
else if (this.trueString == null &&
|
||||
(input.equalsIgnoreCase(VALUE_TRUE) || input.equalsIgnoreCase(VALUE_ON) ||
|
||||
input.equalsIgnoreCase(VALUE_YES) || input.equals(VALUE_1))) {
|
||||
(VALUE_TRUE.equalsIgnoreCase(input) || VALUE_ON.equalsIgnoreCase(input) ||
|
||||
VALUE_YES.equalsIgnoreCase(input) || VALUE_1.equals(input))) {
|
||||
setValue(Boolean.TRUE);
|
||||
}
|
||||
else if (this.falseString == null &&
|
||||
(input.equalsIgnoreCase(VALUE_FALSE) || input.equalsIgnoreCase(VALUE_OFF) ||
|
||||
input.equalsIgnoreCase(VALUE_NO) || input.equals(VALUE_0))) {
|
||||
(VALUE_FALSE.equalsIgnoreCase(input) || VALUE_OFF.equalsIgnoreCase(input) ||
|
||||
VALUE_NO.equalsIgnoreCase(input) || VALUE_0.equals(input))) {
|
||||
setValue(Boolean.FALSE);
|
||||
}
|
||||
else {
|
||||
|
||||
+27
-17
@@ -31,8 +31,8 @@
|
||||
(or an ancestor factory).
|
||||
|
||||
As alternative to bean references, "inner bean definitions" can be used.
|
||||
Singleton flags of such inner bean definitions are effectively ignored:
|
||||
inner beans are typically anonymous prototypes.
|
||||
Such inner beans do not have an independent lifecycle; they are typically
|
||||
anonymous nested objects that share the scope of their containing bean.
|
||||
|
||||
There is also support for lists, sets, maps, and java.util.Properties
|
||||
as bean property types or constructor argument types.
|
||||
@@ -113,16 +113,19 @@
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The default 'lazy-init' value; see the documentation for the
|
||||
'lazy-init' attribute of the 'bean' element.
|
||||
'lazy-init' attribute of the 'bean' element. The default is "default",
|
||||
indicating inheritance from outer 'beans' sections in case of nesting,
|
||||
otherwise falling back to "false".
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="default-merge" default="default" type="defaultable-boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The default 'merge' value; see the documentation for the
|
||||
'merge' attribute of the various collection elements. The default
|
||||
is 'false'.
|
||||
The default 'merge' value; see the documentation for the 'merge'
|
||||
attribute of the various collection elements. The default is "default",
|
||||
indicating inheritance from outer 'beans' sections in case of nesting,
|
||||
otherwise falling back to "false".
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
@@ -130,7 +133,9 @@
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The default 'autowire' value; see the documentation for the
|
||||
'autowire' attribute of the 'bean' element. The default is 'default'.
|
||||
'autowire' attribute of the 'bean' element. The default is "default",
|
||||
indicating inheritance from outer 'beans' sections in case of nesting,
|
||||
otherwise falling back to "no" (i.e. no externally driven autowiring).
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
@@ -305,10 +310,10 @@
|
||||
service objects. Further scopes, such as "request" or "session", might
|
||||
be supported by extended bean factories (e.g. in a web environment).
|
||||
|
||||
Inner bean definitions inherit the singleton status of their containing
|
||||
bean definition, unless explicitly specified: The inner bean will be a
|
||||
Inner bean definitions inherit the scope of their containing bean
|
||||
definition, unless explicitly specified: The inner bean will be a
|
||||
singleton if the containing bean is a singleton, and a prototype if
|
||||
the containing bean has any other scope.
|
||||
the containing bean is a prototype, etc.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
@@ -328,13 +333,15 @@
|
||||
<xsd:attribute name="lazy-init" default="default" type="defaultable-boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicates whether or not this bean is to be lazily initialized.
|
||||
If false, it will be instantiated on startup by bean factories
|
||||
that perform eager initialization of singletons. The default is
|
||||
"false".
|
||||
Indicates whether this bean is to be lazily initialized. If "false",
|
||||
it will be instantiated on startup by bean factories that perform eager
|
||||
initialization of singletons. The effective default is "false".
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
Hence, it needs to be specified per concrete bean definition. It can be
|
||||
shared through the 'default-lazy-init' attribute at the 'beans' level
|
||||
and potentially inherited from outer 'beans' defaults in case of nested
|
||||
'beans' sections (e.g. with different profiles).
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
@@ -344,7 +351,7 @@
|
||||
Controls whether bean properties are "autowired".
|
||||
This is an automagical process in which bean references don't need
|
||||
to be coded explicitly in the XML bean definition file, but rather the
|
||||
Spring container works out dependencies.
|
||||
Spring container works out dependencies. The effective default is "no".
|
||||
|
||||
There are 4 modes:
|
||||
|
||||
@@ -379,7 +386,10 @@
|
||||
elements, always override autowiring.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
Hence, it needs to be specified per concrete bean definition. It can be
|
||||
shared through the 'default-autowire' attribute at the 'beans' level
|
||||
and potentially inherited from outer 'beans' defaults in case of nested
|
||||
'beans' sections (e.g. with different profiles).
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -518,6 +518,36 @@ public final class BeanWrapperTests extends AbstractConfigurablePropertyAccessor
|
||||
assertTrue("correct values", pt.stringArray[0].equals("a1") && pt.stringArray[1].equals("b2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringArrayAutoGrow() throws Exception {
|
||||
StringArrayBean target = new StringArrayBean();
|
||||
BeanWrapper bw = new BeanWrapperImpl(target);
|
||||
bw.setAutoGrowNestedPaths(true);
|
||||
|
||||
bw.setPropertyValue("array[0]", "Test0");
|
||||
assertEquals(1, target.getArray().length);
|
||||
|
||||
bw.setPropertyValue("array[2]", "Test2");
|
||||
assertEquals(3, target.getArray().length);
|
||||
assertTrue("correct values", target.getArray()[0].equals("Test0") && target.getArray()[1] == null &&
|
||||
target.getArray()[2].equals("Test2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrimitiveArrayAutoGrow() throws Exception {
|
||||
PrimitiveArrayBean target = new PrimitiveArrayBean();
|
||||
BeanWrapper bw = new BeanWrapperImpl(target);
|
||||
bw.setAutoGrowNestedPaths(true);
|
||||
|
||||
bw.setPropertyValue("array[0]", 1);
|
||||
assertEquals(1, target.getArray().length);
|
||||
|
||||
bw.setPropertyValue("array[2]", 3);
|
||||
assertEquals(3, target.getArray().length);
|
||||
assertTrue("correct values", target.getArray()[0] == 1 && target.getArray()[1] == 0 &&
|
||||
target.getArray()[2] == 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringPropertyWithCustomEditor() throws Exception {
|
||||
TestBean tb = new TestBean();
|
||||
@@ -1723,6 +1753,20 @@ public final class BeanWrapperTests extends AbstractConfigurablePropertyAccessor
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class StringArrayBean {
|
||||
|
||||
private String[] array;
|
||||
|
||||
public String[] getArray() {
|
||||
return array;
|
||||
}
|
||||
|
||||
public void setArray(String[] array) {
|
||||
this.array = array;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class NumberPropertyBean {
|
||||
|
||||
@@ -841,19 +841,24 @@ public class ExtendedBeanInfoTests {
|
||||
public String getAddress(int index){ return null; }
|
||||
}
|
||||
|
||||
{ // baseline. ExtendedBeanInfo needs to behave exactly like the following
|
||||
// Baseline: ExtendedBeanInfo needs to behave exactly like the following...
|
||||
boolean hasReadMethod;
|
||||
boolean hasWriteMethod;
|
||||
boolean hasIndexedReadMethod;
|
||||
boolean hasIndexedWriteMethod;
|
||||
{
|
||||
BeanInfo bi = Introspector.getBeanInfo(A.class);
|
||||
assertThat(hasReadMethodForProperty(bi, "address"), is(false));
|
||||
assertThat(hasWriteMethodForProperty(bi, "address"), is(false));
|
||||
assertThat(hasIndexedReadMethodForProperty(bi, "address"), is(true));
|
||||
assertThat(hasIndexedWriteMethodForProperty(bi, "address"), is(true));
|
||||
hasReadMethod = hasReadMethodForProperty(bi, "address");
|
||||
hasWriteMethod = hasWriteMethodForProperty(bi, "address");
|
||||
hasIndexedReadMethod = hasIndexedReadMethodForProperty(bi, "address");
|
||||
hasIndexedWriteMethod = hasIndexedWriteMethodForProperty(bi, "address");
|
||||
}
|
||||
{
|
||||
BeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(A.class));
|
||||
assertThat(hasReadMethodForProperty(bi, "address"), is(false));
|
||||
assertThat(hasWriteMethodForProperty(bi, "address"), is(false));
|
||||
assertThat(hasIndexedReadMethodForProperty(bi, "address"), is(true));
|
||||
assertThat(hasIndexedWriteMethodForProperty(bi, "address"), is(true));
|
||||
assertEquals(hasReadMethodForProperty(bi, "address"), hasReadMethod);
|
||||
assertEquals(hasWriteMethodForProperty(bi, "address"), hasWriteMethod);
|
||||
assertEquals(hasIndexedReadMethodForProperty(bi, "address"), hasIndexedReadMethod);
|
||||
assertEquals(hasIndexedWriteMethodForProperty(bi, "address"), hasIndexedWriteMethod);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests for {@link PropertyMatches}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class PropertyMatchesTests {
|
||||
|
||||
@Test
|
||||
public void simpleBeanPropertyTypo() {
|
||||
PropertyMatches matches = PropertyMatches.forProperty("naem", SampleBeanProperties.class);
|
||||
assertThat(matches.getPossibleMatches(), hasItemInArray("name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void complexBeanPropertyTypo() {
|
||||
PropertyMatches matches = PropertyMatches.forProperty("desriptn", SampleBeanProperties.class);
|
||||
assertThat(matches.getPossibleMatches(), emptyArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unknownBeanProperty() {
|
||||
PropertyMatches matches = PropertyMatches.forProperty("unknown", SampleBeanProperties.class);
|
||||
assertThat(matches.getPossibleMatches(), emptyArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void severalMatchesBeanProperty() {
|
||||
PropertyMatches matches = PropertyMatches.forProperty("counter", SampleBeanProperties.class);
|
||||
assertThat(matches.getPossibleMatches(), hasItemInArray("counter1"));
|
||||
assertThat(matches.getPossibleMatches(), hasItemInArray("counter2"));
|
||||
assertThat(matches.getPossibleMatches(), hasItemInArray("counter3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleBeanPropertyErrorMessage() {
|
||||
PropertyMatches matches = PropertyMatches.forProperty("naem", SampleBeanProperties.class);
|
||||
String msg = matches.buildErrorMessage();
|
||||
assertThat(msg, containsString("naem"));
|
||||
assertThat(msg, containsString("name"));
|
||||
assertThat(msg, containsString("setter"));
|
||||
assertThat(msg, not(containsString("field")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void complexBeanPropertyErrorMessage() {
|
||||
PropertyMatches matches = PropertyMatches.forProperty("counter", SampleBeanProperties.class);
|
||||
String msg = matches.buildErrorMessage();
|
||||
assertThat(msg, containsString("counter"));
|
||||
assertThat(msg, containsString("counter1"));
|
||||
assertThat(msg, containsString("counter2"));
|
||||
assertThat(msg, containsString("counter3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleFieldPropertyTypo() {
|
||||
PropertyMatches matches = PropertyMatches.forField("naem", SampleFieldProperties.class);
|
||||
assertThat(matches.getPossibleMatches(), hasItemInArray("name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void complexFieldPropertyTypo() {
|
||||
PropertyMatches matches = PropertyMatches.forField("desriptn", SampleFieldProperties.class);
|
||||
assertThat(matches.getPossibleMatches(), emptyArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unknownFieldProperty() {
|
||||
PropertyMatches matches = PropertyMatches.forField("unknown", SampleFieldProperties.class);
|
||||
assertThat(matches.getPossibleMatches(), emptyArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void severalMatchesFieldProperty() {
|
||||
PropertyMatches matches = PropertyMatches.forField("counter", SampleFieldProperties.class);
|
||||
assertThat(matches.getPossibleMatches(), hasItemInArray("counter1"));
|
||||
assertThat(matches.getPossibleMatches(), hasItemInArray("counter2"));
|
||||
assertThat(matches.getPossibleMatches(), hasItemInArray("counter3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleFieldPropertyErrorMessage() {
|
||||
PropertyMatches matches = PropertyMatches.forField("naem", SampleFieldProperties.class);
|
||||
String msg = matches.buildErrorMessage();
|
||||
assertThat(msg, containsString("naem"));
|
||||
assertThat(msg, containsString("name"));
|
||||
assertThat(msg, containsString("field"));
|
||||
assertThat(msg, not(containsString("setter")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void complexFieldPropertyErrorMessage() {
|
||||
PropertyMatches matches = PropertyMatches.forField("counter", SampleFieldProperties.class);
|
||||
String msg = matches.buildErrorMessage();
|
||||
assertThat(msg, containsString("counter"));
|
||||
assertThat(msg, containsString("counter1"));
|
||||
assertThat(msg, containsString("counter2"));
|
||||
assertThat(msg, containsString("counter3"));
|
||||
}
|
||||
|
||||
|
||||
private static class SampleBeanProperties {
|
||||
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
private int counter1;
|
||||
|
||||
private int counter2;
|
||||
|
||||
private int counter3;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public int getCounter1() {
|
||||
return counter1;
|
||||
}
|
||||
|
||||
public void setCounter1(int counter1) {
|
||||
this.counter1 = counter1;
|
||||
}
|
||||
|
||||
public int getCounter2() {
|
||||
return counter2;
|
||||
}
|
||||
|
||||
public void setCounter2(int counter2) {
|
||||
this.counter2 = counter2;
|
||||
}
|
||||
|
||||
public int getCounter3() {
|
||||
return counter3;
|
||||
}
|
||||
|
||||
public void setCounter3(int counter3) {
|
||||
this.counter3 = counter3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class SampleFieldProperties {
|
||||
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
private int counter1;
|
||||
|
||||
private int counter2;
|
||||
|
||||
private int counter3;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+29
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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 java.util.Map;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.StaticListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
@@ -53,16 +51,16 @@ public final class BeanFactoryUtilsTests {
|
||||
private static final Resource LEAF_CONTEXT = qualifiedResource(CLASS, "leaf.xml");
|
||||
private static final Resource DEPENDENT_BEANS_CONTEXT = qualifiedResource(CLASS, "dependentBeans.xml");
|
||||
|
||||
private ConfigurableListableBeanFactory listableBeanFactory;
|
||||
private DefaultListableBeanFactory listableBeanFactory;
|
||||
|
||||
private DefaultListableBeanFactory dependentBeansFactory;
|
||||
|
||||
private ConfigurableListableBeanFactory dependentBeansBF;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// Interesting hierarchical factory to test counts.
|
||||
// Slow to read so we cache it.
|
||||
|
||||
|
||||
DefaultListableBeanFactory grandParent = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(grandParent).loadBeanDefinitions(ROOT_CONTEXT);
|
||||
DefaultListableBeanFactory parent = new DefaultListableBeanFactory(grandParent);
|
||||
@@ -70,12 +68,13 @@ public final class BeanFactoryUtilsTests {
|
||||
DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
|
||||
new XmlBeanDefinitionReader(child).loadBeanDefinitions(LEAF_CONTEXT);
|
||||
|
||||
this.dependentBeansBF = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader((BeanDefinitionRegistry) this.dependentBeansBF).loadBeanDefinitions(DEPENDENT_BEANS_CONTEXT);
|
||||
dependentBeansBF.preInstantiateSingletons();
|
||||
this.dependentBeansFactory = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(this.dependentBeansFactory).loadBeanDefinitions(DEPENDENT_BEANS_CONTEXT);
|
||||
dependentBeansFactory.preInstantiateSingletons();
|
||||
this.listableBeanFactory = child;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHierarchicalCountBeansWithNonHierarchicalFactory() {
|
||||
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
|
||||
@@ -92,22 +91,21 @@ public final class BeanFactoryUtilsTests {
|
||||
// Leaf count
|
||||
assertTrue(this.listableBeanFactory.getBeanDefinitionCount() == 1);
|
||||
// Count minus duplicate
|
||||
assertTrue("Should count 7 beans, not "
|
||||
+ BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory),
|
||||
BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory) == 7);
|
||||
assertTrue("Should count 7 beans, not " + BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory),
|
||||
BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory) == 7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesWithNoMatch() throws Exception {
|
||||
List<String> names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory,
|
||||
NoOp.class));
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, NoOp.class));
|
||||
assertEquals(0, names.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesWithMatchOnlyInRoot() throws Exception {
|
||||
List<String> names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory,
|
||||
IndexedTestBean.class));
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, IndexedTestBean.class));
|
||||
assertEquals(1, names.size());
|
||||
assertTrue(names.contains("indexedBean"));
|
||||
// Distinguish from default ListableBeanFactory behavior
|
||||
@@ -116,8 +114,8 @@ public final class BeanFactoryUtilsTests {
|
||||
|
||||
@Test
|
||||
public void testGetBeanNamesForTypeWithOverride() throws Exception {
|
||||
List<String> names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory,
|
||||
ITestBean.class));
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class));
|
||||
// includes 2 TestBeans from FactoryBeans (DummyFactory definitions)
|
||||
assertEquals(4, names.size());
|
||||
assertTrue(names.contains("test"));
|
||||
@@ -130,7 +128,7 @@ public final class BeanFactoryUtilsTests {
|
||||
public void testNoBeansOfType() {
|
||||
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
|
||||
lbf.addBean("foo", new Object());
|
||||
Map<?, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
|
||||
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
|
||||
assertTrue(beans.isEmpty());
|
||||
}
|
||||
|
||||
@@ -147,7 +145,7 @@ public final class BeanFactoryUtilsTests {
|
||||
lbf.addBean("t3", t3);
|
||||
lbf.addBean("t4", t4);
|
||||
|
||||
Map<?, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
|
||||
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
|
||||
assertEquals(2, beans.size());
|
||||
assertEquals(t1, beans.get("t1"));
|
||||
assertEquals(t2, beans.get("t2"));
|
||||
@@ -191,8 +189,8 @@ public final class BeanFactoryUtilsTests {
|
||||
this.listableBeanFactory.registerSingleton("t3", t3);
|
||||
this.listableBeanFactory.registerSingleton("t4", t4);
|
||||
|
||||
Map<?, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true,
|
||||
false);
|
||||
Map<String, ?> beans =
|
||||
BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true, false);
|
||||
assertEquals(6, beans.size());
|
||||
assertEquals(test3, beans.get("test3"));
|
||||
assertEquals(test, beans.get("test"));
|
||||
@@ -200,12 +198,9 @@ public final class BeanFactoryUtilsTests {
|
||||
assertEquals(t2, beans.get("t2"));
|
||||
assertEquals(t3.getObject(), beans.get("t3"));
|
||||
assertTrue(beans.get("t4") instanceof TestBean);
|
||||
// t3 and t4 are found here as of Spring 2.0, since they are
|
||||
// pre-registered
|
||||
// singleton instances, while testFactory1 and testFactory are *not*
|
||||
// found
|
||||
// because they are FactoryBean definitions that haven't been
|
||||
// initialized yet.
|
||||
// t3 and t4 are found here as of Spring 2.0, since they are pre-registered
|
||||
// singleton instances, while testFactory1 and testFactory are *not* found
|
||||
// because they are FactoryBean definitions that haven't been initialized yet.
|
||||
|
||||
beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, false, true);
|
||||
Object testFactory1 = this.listableBeanFactory.getBean("testFactory1");
|
||||
@@ -247,8 +242,8 @@ public final class BeanFactoryUtilsTests {
|
||||
Object test3 = this.listableBeanFactory.getBean("test3");
|
||||
Object test = this.listableBeanFactory.getBean("test");
|
||||
|
||||
Map<?, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true,
|
||||
false);
|
||||
Map<String, ?> beans =
|
||||
BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true, false);
|
||||
assertEquals(2, beans.size());
|
||||
assertEquals(test3, beans.get("test3"));
|
||||
assertEquals(test, beans.get("test"));
|
||||
@@ -283,25 +278,25 @@ public final class BeanFactoryUtilsTests {
|
||||
|
||||
@Test
|
||||
public void testADependencies() {
|
||||
String[] deps = this.dependentBeansBF.getDependentBeans("a");
|
||||
String[] deps = this.dependentBeansFactory.getDependentBeans("a");
|
||||
assertTrue(ObjectUtils.isEmpty(deps));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBDependencies() {
|
||||
String[] deps = this.dependentBeansBF.getDependentBeans("b");
|
||||
String[] deps = this.dependentBeansFactory.getDependentBeans("b");
|
||||
assertTrue(Arrays.equals(new String[] { "c" }, deps));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCDependencies() {
|
||||
String[] deps = this.dependentBeansBF.getDependentBeans("c");
|
||||
String[] deps = this.dependentBeansFactory.getDependentBeans("c");
|
||||
assertTrue(Arrays.equals(new String[] { "int", "long" }, deps));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntDependencies() {
|
||||
String[] deps = this.dependentBeansBF.getDependentBeans("int");
|
||||
String[] deps = this.dependentBeansFactory.getDependentBeans("int");
|
||||
assertTrue(Arrays.equals(new String[] { "buffer" }, deps));
|
||||
}
|
||||
|
||||
|
||||
+91
-86
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -200,7 +200,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrototypeSingletonFactoryBeanIgnoredByNonEagerTypeMatching() {
|
||||
public void testSingletonFactoryBeanIgnoredByNonEagerTypeMatching() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
Properties p = new Properties();
|
||||
p.setProperty("x1.(class)", DummyFactory.class.getName());
|
||||
@@ -713,7 +713,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
RootBeanDefinition parentDefinition = new RootBeanDefinition(TestBean.class);
|
||||
parentDefinition.setAbstract(true);
|
||||
parentDefinition.getPropertyValues().add("name", EXPECTED_NAME);
|
||||
parentDefinition.getPropertyValues().add("age", new Integer(EXPECTED_AGE));
|
||||
parentDefinition.getPropertyValues().add("age", EXPECTED_AGE);
|
||||
|
||||
ChildBeanDefinition childDefinition = new ChildBeanDefinition("alias");
|
||||
|
||||
@@ -1201,7 +1201,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(PropertiesFactoryBean.class);
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.add("locations", new String[] {"#{foo}"});
|
||||
pvs.add("locations", new String[]{"#{foo}"});
|
||||
rbd.setPropertyValues(pvs);
|
||||
bf.registerBeanDefinition("myProperties", rbd);
|
||||
Properties properties = (Properties) bf.getBean("myProperties");
|
||||
@@ -1340,10 +1340,10 @@ public class DefaultListableBeanFactoryTests {
|
||||
public void testDependsOnCycle() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
|
||||
bd1.setDependsOn(new String[] {"tb2"});
|
||||
bd1.setDependsOn("tb2");
|
||||
lbf.registerBeanDefinition("tb1", bd1);
|
||||
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
|
||||
bd2.setDependsOn(new String[] {"tb1"});
|
||||
bd2.setDependsOn("tb1");
|
||||
lbf.registerBeanDefinition("tb2", bd2);
|
||||
try {
|
||||
lbf.preInstantiateSingletons();
|
||||
@@ -1361,13 +1361,13 @@ public class DefaultListableBeanFactoryTests {
|
||||
public void testImplicitDependsOnCycle() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
|
||||
bd1.setDependsOn(new String[] {"tb2"});
|
||||
bd1.setDependsOn("tb2");
|
||||
lbf.registerBeanDefinition("tb1", bd1);
|
||||
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
|
||||
bd2.setDependsOn(new String[] {"tb3"});
|
||||
bd2.setDependsOn("tb3");
|
||||
lbf.registerBeanDefinition("tb2", bd2);
|
||||
RootBeanDefinition bd3 = new RootBeanDefinition(TestBean.class);
|
||||
bd3.setDependsOn(new String[] {"tb1"});
|
||||
bd3.setDependsOn("tb1");
|
||||
lbf.registerBeanDefinition("tb3", bd3);
|
||||
try {
|
||||
lbf.preInstantiateSingletons();
|
||||
@@ -1381,7 +1381,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=NoSuchBeanDefinitionException.class)
|
||||
@Test(expected = NoSuchBeanDefinitionException.class)
|
||||
public void testGetBeanByTypeWithNoneFound() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
lbf.getBean(TestBean.class);
|
||||
@@ -1397,7 +1397,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
assertThat(bean.getBeanName(), equalTo("bd1"));
|
||||
}
|
||||
|
||||
@Test(expected=NoUniqueBeanDefinitionException.class)
|
||||
@Test(expected = NoUniqueBeanDefinitionException.class)
|
||||
public void testGetBeanByTypeWithAmbiguity() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
|
||||
@@ -1540,7 +1540,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanByTypeInstanceWithPrimary() throws Exception {
|
||||
public void testGetBeanByTypeInstanceWithPrimary() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition bd1 = createConstructorDependencyBeanDefinition(99);
|
||||
RootBeanDefinition bd2 = createConstructorDependencyBeanDefinition(43);
|
||||
@@ -1553,7 +1553,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanByTypeInstanceWithMultiplePrimary() throws Exception {
|
||||
public void testGetBeanByTypeInstanceWithMultiplePrimary() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition bd1 = createConstructorDependencyBeanDefinition(99);
|
||||
RootBeanDefinition bd2 = createConstructorDependencyBeanDefinition(43);
|
||||
@@ -1584,16 +1584,35 @@ public class DefaultListableBeanFactoryTests {
|
||||
try {
|
||||
lbf.getBean(TestBean.class, 67);
|
||||
fail("Should have thrown NoSuchBeanDefinitionException");
|
||||
} catch (NoSuchBeanDefinitionException ex) {
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) {
|
||||
@Test
|
||||
public void testGetBeanWithArgsNotCreatedForFactoryBeanChecking() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(ConstructorDependency.class);
|
||||
bd1.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
bd1.getConstructorArgumentValues().addGenericArgumentValue(String.valueOf(age));
|
||||
return bd1;
|
||||
lbf.registerBeanDefinition("bd1", bd1);
|
||||
RootBeanDefinition bd2 = new RootBeanDefinition(ConstructorDependencyFactoryBean.class);
|
||||
bd2.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
lbf.registerBeanDefinition("bd2", bd2);
|
||||
|
||||
ConstructorDependency bean = lbf.getBean(ConstructorDependency.class, 42);
|
||||
assertThat(bean.beanName, equalTo("bd1"));
|
||||
assertThat(bean.spouseAge, equalTo(42));
|
||||
|
||||
assertEquals(1, lbf.getBeanNamesForType(ConstructorDependency.class).length);
|
||||
assertEquals(1, lbf.getBeanNamesForType(ConstructorDependencyFactoryBean.class).length);
|
||||
}
|
||||
|
||||
private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependency.class);
|
||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
bd.getConstructorArgumentValues().addGenericArgumentValue(String.valueOf(age));
|
||||
return bd;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1641,7 +1660,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
* Java method names. In other words, you can't name a method
|
||||
* {@code set&FactoryBean(...)}.
|
||||
*/
|
||||
@Test(expected=TypeMismatchException.class)
|
||||
@Test(expected = TypeMismatchException.class)
|
||||
public void testAutowireBeanWithFactoryBeanByName() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition bd = new RootBeanDefinition(LazyInitFactory.class);
|
||||
@@ -1664,8 +1683,8 @@ public class DefaultListableBeanFactoryTests {
|
||||
}
|
||||
catch (UnsatisfiedDependencyException ex) {
|
||||
// expected
|
||||
assertTrue(ex.getMessage().indexOf("test") != -1);
|
||||
assertTrue(ex.getMessage().indexOf("spouse") != -1);
|
||||
assertTrue(ex.getMessage().contains("test"));
|
||||
assertTrue(ex.getMessage().contains("spouse"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1682,8 +1701,8 @@ public class DefaultListableBeanFactoryTests {
|
||||
}
|
||||
catch (UnsatisfiedDependencyException ex) {
|
||||
// expected
|
||||
assertTrue(ex.getMessage().indexOf("test") != -1);
|
||||
assertTrue(ex.getMessage().indexOf("spouse") != -1);
|
||||
assertTrue(ex.getMessage().contains("test"));
|
||||
assertTrue(ex.getMessage().contains("spouse"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2245,32 +2264,6 @@ public class DefaultListableBeanFactoryTests {
|
||||
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Test
|
||||
* public void testPrototypeCreationWithConstructorArgumentsIsFastEnough2() throws Exception {
|
||||
* if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) {
|
||||
* // Skip this test: Trace logging blows the time limit.
|
||||
* return;
|
||||
* }
|
||||
* DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
* Constructor<TestBean> ctor = TestBean.class.getConstructor(String.class, int.class);
|
||||
* Method setBeanNameMethod = TestBean.class.getMethod("setBeanName", String.class);
|
||||
* Method setBeanFactoryMethod = TestBean.class.getMethod("setBeanFactory", BeanFactory.class);
|
||||
* StopWatch sw = new StopWatch();
|
||||
* sw.start("prototype");
|
||||
* for (int i = 0; i < 100000; i++) {
|
||||
* TestBean tb = ctor.newInstance("juergen", 99);
|
||||
* setBeanNameMethod.invoke(tb, "test");
|
||||
* setBeanFactoryMethod.invoke(tb, lbf);
|
||||
* assertEquals("juergen", tb.getName());
|
||||
* assertEquals(99, tb.getAge());
|
||||
* }
|
||||
* sw.stop();
|
||||
* // System.out.println(sw.getTotalTimeMillis());
|
||||
* assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 1500);
|
||||
* }
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testPrototypeCreationWithResolvedConstructorArgumentsIsFastEnough() {
|
||||
Assume.group(TestGroup.PERFORMANCE);
|
||||
@@ -2315,31 +2308,6 @@ public class DefaultListableBeanFactoryTests {
|
||||
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000);
|
||||
}
|
||||
|
||||
/**
|
||||
* public void testPrototypeCreationWithPropertiesIsFastEnough2() throws Exception {
|
||||
* if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) {
|
||||
* // Skip this test: Trace logging blows the time limit.
|
||||
* return;
|
||||
* }
|
||||
* DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
* StopWatch sw = new StopWatch();
|
||||
* Method setBeanNameMethod = TestBean.class.getMethod("setBeanName", String.class);
|
||||
* Method setBeanFactoryMethod = TestBean.class.getMethod("setBeanFactory", BeanFactory.class);
|
||||
* Method setNameMethod = TestBean.class.getMethod("setName", String.class);
|
||||
* Method setAgeMethod = TestBean.class.getMethod("setAge", int.class);
|
||||
* sw.start("prototype");
|
||||
* for (int i = 0; i < 100000; i++) {
|
||||
* TestBean tb = TestBean.class.newInstance();
|
||||
* setBeanNameMethod.invoke(tb, "test");
|
||||
* setBeanFactoryMethod.invoke(tb, lbf);
|
||||
* setNameMethod.invoke(tb, "juergen");
|
||||
* setAgeMethod.invoke(tb, 99);
|
||||
* }
|
||||
* sw.stop();
|
||||
* // System.out.println(sw.getTotalTimeMillis());
|
||||
* assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 750);
|
||||
* }
|
||||
*/
|
||||
@Test
|
||||
public void testPrototypeCreationWithResolvedPropertiesIsFastEnough() {
|
||||
Assume.group(TestGroup.PERFORMANCE);
|
||||
@@ -2420,10 +2388,41 @@ public class DefaultListableBeanFactoryTests {
|
||||
return bean;
|
||||
}
|
||||
});
|
||||
BeanWithDestroyMethod.closed = false;
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
assertTrue("Destroy method invoked", BeanWithDestroyMethod.closed);
|
||||
assertEquals("Destroy methods invoked", 1, BeanWithDestroyMethod.closeCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDestroyMethodOnInnerBean() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition innerBd = new RootBeanDefinition(BeanWithDestroyMethod.class);
|
||||
innerBd.setDestroyMethodName("close");
|
||||
RootBeanDefinition bd = new RootBeanDefinition(BeanWithDestroyMethod.class);
|
||||
bd.setDestroyMethodName("close");
|
||||
bd.getPropertyValues().add("inner", innerBd);
|
||||
lbf.registerBeanDefinition("test", bd);
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
assertEquals("Destroy methods invoked", 2, BeanWithDestroyMethod.closeCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDestroyMethodOnInnerBeanAsPrototype() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition innerBd = new RootBeanDefinition(BeanWithDestroyMethod.class);
|
||||
innerBd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
innerBd.setDestroyMethodName("close");
|
||||
RootBeanDefinition bd = new RootBeanDefinition(BeanWithDestroyMethod.class);
|
||||
bd.setDestroyMethodName("close");
|
||||
bd.getPropertyValues().add("inner", innerBd);
|
||||
lbf.registerBeanDefinition("test", bd);
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
assertEquals("Destroy methods invoked", 1, BeanWithDestroyMethod.closeCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2518,7 +2517,7 @@ public class DefaultListableBeanFactoryTests {
|
||||
assertEquals(expectedNameFromArgs, tb2.getName());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testScopingBeanToUnregisteredScopeResultsInAnException() throws Exception {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class);
|
||||
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
|
||||
@@ -2660,10 +2659,6 @@ public class DefaultListableBeanFactoryTests {
|
||||
verify(r3, never()).resolveStringValue(isNull(String.class));
|
||||
}
|
||||
|
||||
|
||||
static class A { }
|
||||
static class B { }
|
||||
|
||||
/**
|
||||
* Test that by-type bean lookup caching is working effectively by searching for a
|
||||
* bean of type B 10K times within a container having 1K additional beans of type A.
|
||||
@@ -2674,24 +2669,29 @@ public class DefaultListableBeanFactoryTests {
|
||||
* under the 1000 ms timeout, usually ~= 300ms. With caching removed and on the same
|
||||
* hardware the method will take ~13000 ms. See SPR-6870.
|
||||
*/
|
||||
@Test(timeout=1000)
|
||||
@Test(timeout = 1000)
|
||||
public void testByTypeLookupIsFastEnough() {
|
||||
Assume.group(TestGroup.PERFORMANCE);
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
bf.registerBeanDefinition("a"+i, new RootBeanDefinition(A.class));
|
||||
bf.registerBeanDefinition("a" + i, new RootBeanDefinition(A.class));
|
||||
}
|
||||
bf.registerBeanDefinition("b", new RootBeanDefinition(B.class));
|
||||
|
||||
bf.freezeConfiguration();
|
||||
|
||||
for (int i=0; i<10000; i++) {
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
bf.getBean(B.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class A { }
|
||||
|
||||
static class B { }
|
||||
|
||||
|
||||
public static class NoDependencies {
|
||||
|
||||
private NoDependencies() {
|
||||
@@ -2797,10 +2797,16 @@ public class DefaultListableBeanFactoryTests {
|
||||
|
||||
public static class BeanWithDestroyMethod {
|
||||
|
||||
private static boolean closed;
|
||||
private static int closeCount = 0;
|
||||
|
||||
private BeanWithDestroyMethod inner;
|
||||
|
||||
public void setInner(BeanWithDestroyMethod inner) {
|
||||
this.inner = inner;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
closed = true;
|
||||
closeCount++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2962,7 +2968,6 @@ public class DefaultListableBeanFactoryTests {
|
||||
|
||||
private FactoryBean<?> factoryBean;
|
||||
|
||||
|
||||
public final FactoryBean<?> getFactoryBean() {
|
||||
return this.factoryBean;
|
||||
}
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
|
||||
<bean id="gamma" class="org.springframework.beans.factory.FactoryBeanTests$Gamma"/>
|
||||
|
||||
<bean id="betaFactory" class="org.springframework.beans.factory.FactoryBeanTests$BetaFactoryBean">
|
||||
<bean id="betaFactory" class="org.springframework.beans.factory.FactoryBeanTests$BetaFactoryBean" autowire="constructor">
|
||||
<property name="beta" ref="beta"/>
|
||||
</bean>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
@@ -39,7 +38,7 @@ import static org.springframework.tests.TestResourceUtils.*;
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public final class FactoryBeanTests {
|
||||
public class FactoryBeanTests {
|
||||
|
||||
private static final Class<?> CLASS = FactoryBeanTests.class;
|
||||
private static final Resource RETURNS_NULL_CONTEXT = qualifiedResource(CLASS, "returnsNull.xml");
|
||||
@@ -47,6 +46,7 @@ public final class FactoryBeanTests {
|
||||
private static final Resource ABSTRACT_CONTEXT = qualifiedResource(CLASS, "abstract.xml");
|
||||
private static final Resource CIRCULAR_CONTEXT = qualifiedResource(CLASS, "circular.xml");
|
||||
|
||||
|
||||
@Test
|
||||
public void testFactoryBeanReturnsNull() throws Exception {
|
||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||
@@ -63,10 +63,13 @@ public final class FactoryBeanTests {
|
||||
BeanFactoryPostProcessor ppc = (BeanFactoryPostProcessor) factory.getBean("propertyPlaceholderConfigurer");
|
||||
ppc.postProcessBeanFactory(factory);
|
||||
|
||||
assertNull(factory.getType("betaFactory"));
|
||||
|
||||
Alpha alpha = (Alpha) factory.getBean("alpha");
|
||||
Beta beta = (Beta) factory.getBean("beta");
|
||||
Gamma gamma = (Gamma) factory.getBean("gamma");
|
||||
Gamma gamma2 = (Gamma) factory.getBean("gammaFactory");
|
||||
|
||||
assertSame(beta, alpha.getBeta());
|
||||
assertSame(gamma, beta.getGamma());
|
||||
assertSame(gamma2, beta.getGamma());
|
||||
@@ -194,6 +197,9 @@ public final class FactoryBeanTests {
|
||||
@Component
|
||||
public static class BetaFactoryBean implements FactoryBean<Object> {
|
||||
|
||||
public BetaFactoryBean(Alpha alpha) {
|
||||
}
|
||||
|
||||
private Beta beta;
|
||||
|
||||
public void setBeta(Beta beta) {
|
||||
@@ -238,12 +244,12 @@ public final class FactoryBeanTests {
|
||||
public void setInstanceName(String instanceName) {
|
||||
this.instanceName = instanceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public T getObject() {
|
||||
if (instance == null) {
|
||||
|
||||
+88
-127
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,7 +27,6 @@ import java.util.prefs.BackingStoreException;
|
||||
import java.util.prefs.Preferences;
|
||||
import java.util.prefs.PreferencesFactory;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
@@ -53,13 +52,13 @@ import static org.springframework.tests.TestResourceUtils.*;
|
||||
* {@link PropertyPlaceholderConfigurer}, {@link PropertyOverrideConfigurer} and
|
||||
* {@link PreferencesPlaceholderConfigurer}.
|
||||
*
|
||||
* @see PropertyPlaceholderConfigurerTests
|
||||
* @since 02.10.2003
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @since 02.10.2003
|
||||
* @see PropertyPlaceholderConfigurerTests
|
||||
*/
|
||||
public final class PropertyResourceConfigurerTests {
|
||||
public class PropertyResourceConfigurerTests {
|
||||
|
||||
static {
|
||||
System.setProperty("java.util.prefs.PreferencesFactory", MockPreferencesFactory.class.getName());
|
||||
@@ -70,23 +69,15 @@ public final class PropertyResourceConfigurerTests {
|
||||
private static final Resource XTEST_PROPS = qualifiedResource(CLASS, "xtest.properties"); // does not exist
|
||||
private static final Resource TEST_PROPS_XML = qualifiedResource(CLASS, "test.properties.xml");
|
||||
|
||||
private DefaultListableBeanFactory factory;
|
||||
private final DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
factory = new DefaultListableBeanFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyOverrideConfigurer() {
|
||||
BeanDefinition def1 = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(TestBean.class)
|
||||
.getBeanDefinition();
|
||||
BeanDefinition def1 = BeanDefinitionBuilder.genericBeanDefinition(TestBean.class).getBeanDefinition();
|
||||
factory.registerBeanDefinition("tb1", def1);
|
||||
|
||||
BeanDefinition def2 = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(TestBean.class)
|
||||
.getBeanDefinition();
|
||||
BeanDefinition def2 = BeanDefinitionBuilder.genericBeanDefinition(TestBean.class).getBeanDefinition();
|
||||
factory.registerBeanDefinition("tb2", def2);
|
||||
|
||||
PropertyOverrideConfigurer poc1;
|
||||
@@ -123,9 +114,7 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyOverrideConfigurerWithNestedProperty() {
|
||||
BeanDefinition def = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(IndexedTestBean.class)
|
||||
.getBeanDefinition();
|
||||
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
|
||||
factory.registerBeanDefinition("tb", def);
|
||||
|
||||
PropertyOverrideConfigurer poc;
|
||||
@@ -143,9 +132,7 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyOverrideConfigurerWithNestedPropertyAndDotInBeanName() {
|
||||
BeanDefinition def = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(IndexedTestBean.class)
|
||||
.getBeanDefinition();
|
||||
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
|
||||
factory.registerBeanDefinition("my.tb", def);
|
||||
|
||||
PropertyOverrideConfigurer poc;
|
||||
@@ -164,9 +151,7 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyOverrideConfigurerWithNestedMapPropertyAndDotInMapKey() {
|
||||
BeanDefinition def = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(IndexedTestBean.class)
|
||||
.getBeanDefinition();
|
||||
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
|
||||
factory.registerBeanDefinition("tb", def);
|
||||
|
||||
PropertyOverrideConfigurer poc;
|
||||
@@ -184,9 +169,7 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyOverrideConfigurerWithHeldProperties() {
|
||||
BeanDefinition def = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(PropertiesHolder.class)
|
||||
.getBeanDefinition();
|
||||
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(PropertiesHolder.class).getBeanDefinition();
|
||||
factory.registerBeanDefinition("tb", def);
|
||||
|
||||
PropertyOverrideConfigurer poc;
|
||||
@@ -200,23 +183,9 @@ public final class PropertyResourceConfigurerTests {
|
||||
assertEquals("true", tb.getHeldProperties().getProperty("mail.smtp.auth"));
|
||||
}
|
||||
|
||||
static class PropertiesHolder {
|
||||
private Properties props = new Properties();
|
||||
|
||||
public Properties getHeldProperties() {
|
||||
return props;
|
||||
}
|
||||
|
||||
public void setHeldProperties(Properties props) {
|
||||
this.props = props;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyOverrideConfigurerWithPropertiesFile() {
|
||||
BeanDefinition def = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(IndexedTestBean.class)
|
||||
.getBeanDefinition();
|
||||
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
|
||||
factory.registerBeanDefinition("tb", def);
|
||||
|
||||
PropertyOverrideConfigurer poc = new PropertyOverrideConfigurer();
|
||||
@@ -230,13 +199,11 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyOverrideConfigurerWithInvalidPropertiesFile() {
|
||||
BeanDefinition def = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(IndexedTestBean.class)
|
||||
.getBeanDefinition();
|
||||
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
|
||||
factory.registerBeanDefinition("tb", def);
|
||||
|
||||
PropertyOverrideConfigurer poc = new PropertyOverrideConfigurer();
|
||||
poc.setLocations(new Resource[] { TEST_PROPS, XTEST_PROPS });
|
||||
poc.setLocations(TEST_PROPS, XTEST_PROPS);
|
||||
poc.setIgnoreResourceNotFound(true);
|
||||
poc.postProcessBeanFactory(factory);
|
||||
|
||||
@@ -247,9 +214,7 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyOverrideConfigurerWithPropertiesXmlFile() {
|
||||
BeanDefinition def = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(IndexedTestBean.class)
|
||||
.getBeanDefinition();
|
||||
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
|
||||
factory.registerBeanDefinition("tb", def);
|
||||
|
||||
PropertyOverrideConfigurer poc = new PropertyOverrideConfigurer();
|
||||
@@ -263,9 +228,7 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyOverrideConfigurerWithConvertProperties() {
|
||||
BeanDefinition def = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(IndexedTestBean.class)
|
||||
.getBeanDefinition();
|
||||
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
|
||||
factory.registerBeanDefinition("tb", def);
|
||||
|
||||
ConvertingOverrideConfigurer bfpp = new ConvertingOverrideConfigurer();
|
||||
@@ -389,7 +352,6 @@ public final class PropertyResourceConfigurerTests {
|
||||
cas.addGenericArgumentValue("${var}name${age}");
|
||||
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
|
||||
pvs.add("stringArray", new String[] {"${os.name}", "${age}"});
|
||||
|
||||
List<Object> friends = new ManagedList<Object>();
|
||||
@@ -409,7 +371,7 @@ public final class PropertyResourceConfigurerTests {
|
||||
someMap.put("key1", new RuntimeBeanReference("${ref}"));
|
||||
someMap.put("key2", "${age}name");
|
||||
MutablePropertyValues innerPvs = new MutablePropertyValues();
|
||||
innerPvs.add("touchy", "${os.name}");
|
||||
innerPvs.add("country", "${os.name}");
|
||||
RootBeanDefinition innerBd = new RootBeanDefinition(TestBean.class);
|
||||
innerBd.setPropertyValues(innerPvs);
|
||||
someMap.put("key3", innerBd);
|
||||
@@ -459,30 +421,28 @@ public final class PropertyResourceConfigurerTests {
|
||||
TestBean inner2 = (TestBean) tb2.getSomeMap().get("mykey4");
|
||||
assertEquals(0, inner1.getAge());
|
||||
assertEquals(null, inner1.getName());
|
||||
assertEquals(System.getProperty("os.name"), inner1.getTouchy());
|
||||
assertEquals(System.getProperty("os.name"), inner1.getCountry());
|
||||
assertEquals(98, inner2.getAge());
|
||||
assertEquals("namemyvarmyvar${", inner2.getName());
|
||||
assertEquals(System.getProperty("os.name"), inner2.getTouchy());
|
||||
assertEquals(System.getProperty("os.name"), inner2.getCountry());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithSystemPropertyFallback() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("touchy", "${os.name}").getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("country", "${os.name}").getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
ppc.postProcessBeanFactory(factory);
|
||||
|
||||
TestBean tb = (TestBean) factory.getBean("tb");
|
||||
assertEquals(System.getProperty("os.name"), tb.getTouchy());
|
||||
assertEquals(System.getProperty("os.name"), tb.getCountry());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithSystemPropertyNotUsed() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("touchy", "${os.name}").getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("country", "${os.name}").getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
Properties props = new Properties();
|
||||
@@ -491,14 +451,13 @@ public final class PropertyResourceConfigurerTests {
|
||||
ppc.postProcessBeanFactory(factory);
|
||||
|
||||
TestBean tb = (TestBean) factory.getBean("tb");
|
||||
assertEquals("myos", tb.getTouchy());
|
||||
assertEquals("myos", tb.getCountry());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithOverridingSystemProperty() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("touchy", "${os.name}").getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("country", "${os.name}").getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
Properties props = new Properties();
|
||||
@@ -508,14 +467,13 @@ public final class PropertyResourceConfigurerTests {
|
||||
ppc.postProcessBeanFactory(factory);
|
||||
|
||||
TestBean tb = (TestBean) factory.getBean("tb");
|
||||
assertEquals(System.getProperty("os.name"), tb.getTouchy());
|
||||
assertEquals(System.getProperty("os.name"), tb.getCountry());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithUnresolvableSystemProperty() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("touchy", "${user.dir}").getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("touchy", "${user.dir}").getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
ppc.setSystemPropertiesMode(PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_NEVER);
|
||||
@@ -532,9 +490,8 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithUnresolvablePlaceholder() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${ref}").getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${ref}").getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
|
||||
@@ -550,9 +507,8 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithIgnoreUnresolvablePlaceholder() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${ref}").getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${ref}").getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
ppc.setIgnoreUnresolvablePlaceholders(true);
|
||||
@@ -564,9 +520,8 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithEmptyStringAsNull() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "").getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "").getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
ppc.setNullValue("");
|
||||
@@ -578,9 +533,8 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithEmptyStringInPlaceholderAsNull() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${ref}").getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${ref}").getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
ppc.setNullValue("");
|
||||
@@ -595,9 +549,8 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithNestedPlaceholderInKey() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${my${key}key}").getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${my${key}key}").getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
Properties props = new Properties();
|
||||
@@ -612,8 +565,7 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithPlaceholderInAlias() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class).getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class).getBeanDefinition());
|
||||
factory.registerAlias("tb", "${alias}");
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
@@ -629,8 +581,7 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithSelfReferencingPlaceholderInAlias() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class).getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class).getBeanDefinition());
|
||||
factory.registerAlias("tb", "${alias}");
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
@@ -646,11 +597,10 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithCircularReference() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("age", "${age}")
|
||||
.addPropertyValue("name", "name${var}")
|
||||
.getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("age", "${age}")
|
||||
.addPropertyValue("name", "name${var}")
|
||||
.getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
Properties props = new Properties();
|
||||
@@ -670,9 +620,8 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithDefaultProperties() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("touchy", "${test}").getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("touchy", "${test}").getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
Properties props = new Properties();
|
||||
@@ -686,9 +635,8 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithInlineDefault() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("touchy", "${test:mytest}").getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("touchy", "${test:mytest}").getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||
ppc.postProcessBeanFactory(factory);
|
||||
@@ -699,9 +647,8 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPropertyPlaceholderConfigurerWithAliases() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("touchy", "${test}").getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("touchy", "${test}").getBeanDefinition());
|
||||
|
||||
factory.registerAlias("tb", "${myAlias}");
|
||||
factory.registerAlias("${myTarget}", "alias2");
|
||||
@@ -724,12 +671,11 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPreferencesPlaceholderConfigurer() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${myName}")
|
||||
.addPropertyValue("age", "${myAge}")
|
||||
.addPropertyValue("touchy", "${myTouchy}")
|
||||
.getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${myName}")
|
||||
.addPropertyValue("age", "${myAge}")
|
||||
.addPropertyValue("touchy", "${myTouchy}")
|
||||
.getBeanDefinition());
|
||||
|
||||
PreferencesPlaceholderConfigurer ppc = new PreferencesPlaceholderConfigurer();
|
||||
Properties props = new Properties();
|
||||
@@ -752,12 +698,11 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPreferencesPlaceholderConfigurerWithCustomTreePaths() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${myName}")
|
||||
.addPropertyValue("age", "${myAge}")
|
||||
.addPropertyValue("touchy", "${myTouchy}")
|
||||
.getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${myName}")
|
||||
.addPropertyValue("age", "${myAge}")
|
||||
.addPropertyValue("touchy", "${myTouchy}")
|
||||
.getBeanDefinition());
|
||||
|
||||
PreferencesPlaceholderConfigurer ppc = new PreferencesPlaceholderConfigurer();
|
||||
Properties props = new Properties();
|
||||
@@ -782,12 +727,11 @@ public final class PropertyResourceConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testPreferencesPlaceholderConfigurerWithPathInPlaceholder() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${mypath/myName}")
|
||||
.addPropertyValue("age", "${myAge}")
|
||||
.addPropertyValue("touchy", "${myotherpath/myTouchy}")
|
||||
.getBeanDefinition());
|
||||
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${mypath/myName}")
|
||||
.addPropertyValue("age", "${myAge}")
|
||||
.addPropertyValue("touchy", "${myotherpath/myTouchy}")
|
||||
.getBeanDefinition());
|
||||
|
||||
PreferencesPlaceholderConfigurer ppc = new PreferencesPlaceholderConfigurer();
|
||||
Properties props = new Properties();
|
||||
@@ -811,6 +755,20 @@ public final class PropertyResourceConfigurerTests {
|
||||
}
|
||||
|
||||
|
||||
static class PropertiesHolder {
|
||||
|
||||
private Properties props = new Properties();
|
||||
|
||||
public Properties getHeldProperties() {
|
||||
return props;
|
||||
}
|
||||
|
||||
public void setHeldProperties(Properties props) {
|
||||
this.props = props;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class ConvertingOverrideConfigurer extends PropertyOverrideConfigurer {
|
||||
|
||||
@Override
|
||||
@@ -819,26 +777,28 @@ public final class PropertyResourceConfigurerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link PreferencesFactory} to create {@link MockPreferences}.
|
||||
*/
|
||||
public static class MockPreferencesFactory implements PreferencesFactory {
|
||||
|
||||
private Preferences systemRoot = new MockPreferences();
|
||||
private final Preferences userRoot = new MockPreferences();
|
||||
|
||||
private Preferences userRoot = new MockPreferences();
|
||||
private final Preferences systemRoot = new MockPreferences();
|
||||
|
||||
@Override
|
||||
public Preferences systemRoot() {
|
||||
return systemRoot;
|
||||
return this.systemRoot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Preferences userRoot() {
|
||||
return userRoot;
|
||||
return this.userRoot;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mock implementation of {@link Preferences} that behaves the same regardless of the
|
||||
* underlying operating system and will never throw security exceptions.
|
||||
@@ -904,4 +864,5 @@ public final class PropertyResourceConfigurerTests {
|
||||
protected void flushSpi() throws BackingStoreException {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+27
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -770,7 +770,7 @@ public class BeanFactoryGenericsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpr11250() {
|
||||
public void testGenericMatchingWithBeanNameDifferentiation() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
|
||||
|
||||
@@ -780,8 +780,23 @@ public class BeanFactoryGenericsTests {
|
||||
new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
|
||||
|
||||
NumberBean nb = bf.getBean(NumberBean.class);
|
||||
assertNotNull(nb.getDoubleStore());
|
||||
assertNotNull(nb.getFloatStore());
|
||||
assertSame(bf.getBean("doubleStore"), nb.getDoubleStore());
|
||||
assertSame(bf.getBean("floatStore"), nb.getFloatStore());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericMatchingWithFullTypeDifferentiation() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
|
||||
|
||||
bf.registerBeanDefinition("store1", new RootBeanDefinition(DoubleStore.class));
|
||||
bf.registerBeanDefinition("store2", new RootBeanDefinition(FloatStore.class));
|
||||
bf.registerBeanDefinition("numberBean",
|
||||
new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
|
||||
|
||||
NumberBean nb = bf.getBean(NumberBean.class);
|
||||
assertSame(bf.getBean("store1"), nb.getDoubleStore());
|
||||
assertSame(bf.getBean("store2"), nb.getFloatStore());
|
||||
}
|
||||
|
||||
|
||||
@@ -851,6 +866,14 @@ public class BeanFactoryGenericsTests {
|
||||
}
|
||||
|
||||
|
||||
public static class DoubleStore extends NumberStore<Double> {
|
||||
}
|
||||
|
||||
|
||||
public static class FloatStore extends NumberStore<Float> {
|
||||
}
|
||||
|
||||
|
||||
public static class NumberBean {
|
||||
|
||||
private final NumberStore<Double> doubleStore;
|
||||
|
||||
+30
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,6 @@ import static org.junit.Assert.*;
|
||||
* @author Rob Harrop
|
||||
* @author Arjen Poutsma
|
||||
* @author Chris Beams
|
||||
*
|
||||
* @since 10.06.2003
|
||||
*/
|
||||
public class CustomEditorTests {
|
||||
@@ -302,8 +301,8 @@ public class CustomEditorTests {
|
||||
|
||||
@Test
|
||||
public void testCustomBooleanEditorWithSpecialTrueAndFalseStrings() throws Exception {
|
||||
final String trueString = "pechorin";
|
||||
final String falseString = "nash";
|
||||
String trueString = "pechorin";
|
||||
String falseString = "nash";
|
||||
|
||||
CustomBooleanEditor editor = new CustomBooleanEditor(trueString, falseString, false);
|
||||
|
||||
@@ -320,6 +319,14 @@ public class CustomEditorTests {
|
||||
editor.setAsText(falseString.toUpperCase());
|
||||
assertFalse(((Boolean) editor.getValue()).booleanValue());
|
||||
assertEquals(falseString, editor.getAsText());
|
||||
|
||||
try {
|
||||
editor.setAsText(null);
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -423,7 +430,7 @@ public class CustomEditorTests {
|
||||
assertTrue("Correct bigDecimal value", new BigDecimal("4.5").equals(tb.getBigDecimal()));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCustomNumberEditorCtorWithNullNumberType() throws Exception {
|
||||
new CustomNumberEditor(null, true);
|
||||
}
|
||||
@@ -543,7 +550,7 @@ public class CustomEditorTests {
|
||||
assertNull(cb.getMyCharacter());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCharacterEditorSetAsTextWithStringLongerThanOneCharacter() throws Exception {
|
||||
PropertyEditor charEditor = new CharacterEditor(false);
|
||||
charEditor.setAsText("ColdWaterCanyon");
|
||||
@@ -562,7 +569,7 @@ public class CustomEditorTests {
|
||||
assertEquals(" ", charEditor.getAsText());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCharacterEditorSetAsTextWithNullNotAllowingEmptyAsNull() throws Exception {
|
||||
PropertyEditor charEditor = new CharacterEditor(false);
|
||||
charEditor.setAsText(null);
|
||||
@@ -583,7 +590,7 @@ public class CustomEditorTests {
|
||||
assertEquals("", classEditor.getAsText());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testClassEditorWithNonExistentClass() throws Exception {
|
||||
PropertyEditor classEditor = new ClassEditor();
|
||||
classEditor.setAsText("hairdresser.on.Fire");
|
||||
@@ -685,26 +692,40 @@ public class CustomEditorTests {
|
||||
@Test
|
||||
public void testCustomBooleanEditor() {
|
||||
CustomBooleanEditor editor = new CustomBooleanEditor(false);
|
||||
|
||||
editor.setAsText("true");
|
||||
assertEquals(Boolean.TRUE, editor.getValue());
|
||||
assertEquals("true", editor.getAsText());
|
||||
|
||||
editor.setAsText("false");
|
||||
assertEquals(Boolean.FALSE, editor.getValue());
|
||||
assertEquals("false", editor.getAsText());
|
||||
|
||||
editor.setValue(null);
|
||||
assertEquals(null, editor.getValue());
|
||||
assertEquals("", editor.getAsText());
|
||||
|
||||
try {
|
||||
editor.setAsText(null);
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomBooleanEditorWithEmptyAsNull() {
|
||||
CustomBooleanEditor editor = new CustomBooleanEditor(true);
|
||||
|
||||
editor.setAsText("true");
|
||||
assertEquals(Boolean.TRUE, editor.getValue());
|
||||
assertEquals("true", editor.getAsText());
|
||||
|
||||
editor.setAsText("false");
|
||||
assertEquals(Boolean.FALSE, editor.getValue());
|
||||
assertEquals("false", editor.getAsText());
|
||||
|
||||
editor.setValue(null);
|
||||
assertEquals(null, editor.getValue());
|
||||
assertEquals("", editor.getAsText());
|
||||
@@ -750,7 +771,7 @@ public class CustomEditorTests {
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
assertTrue(ex.getMessage().indexOf("10") != -1);
|
||||
assertTrue(ex.getMessage().contains("10"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,9 +30,9 @@ import static org.junit.Assert.*;
|
||||
* @author Rick Evans
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public final class InputStreamEditorTests {
|
||||
public class InputStreamEditorTests {
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCtorWithNullResourceEditor() throws Exception {
|
||||
new InputStreamEditor(null);
|
||||
}
|
||||
@@ -41,7 +41,8 @@ public final class InputStreamEditorTests {
|
||||
public void testSunnyDay() throws Exception {
|
||||
InputStream stream = null;
|
||||
try {
|
||||
String resource = "classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + "/" + ClassUtils.getShortName(getClass()) + ".class";
|
||||
String resource = "classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) +
|
||||
"/" + ClassUtils.getShortName(getClass()) + ".class";
|
||||
InputStreamEditor editor = new InputStreamEditor();
|
||||
editor.setAsText(resource);
|
||||
Object value = editor.getValue();
|
||||
@@ -49,14 +50,15 @@ public final class InputStreamEditorTests {
|
||||
assertTrue(value instanceof InputStream);
|
||||
stream = (InputStream) value;
|
||||
assertTrue(stream.available() > 0);
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
if (stream != null) {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testWhenResourceDoesNotExist() throws Exception {
|
||||
String resource = "classpath:bingo!";
|
||||
InputStreamEditor editor = new InputStreamEditor();
|
||||
@@ -66,7 +68,8 @@ public final class InputStreamEditorTests {
|
||||
@Test
|
||||
public void testGetAsTextReturnsNullByDefault() throws Exception {
|
||||
assertNull(new InputStreamEditor().getAsText());
|
||||
String resource = "classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + "/" + ClassUtils.getShortName(getClass()) + ".class";
|
||||
String resource = "classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) +
|
||||
"/" + ClassUtils.getShortName(getClass()) + ".class";
|
||||
InputStreamEditor editor = new InputStreamEditor();
|
||||
editor.setAsText(resource);
|
||||
assertNull(editor.getAsText());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
|
||||
Vendored
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,7 +24,6 @@ import net.sf.ehcache.Status;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* CacheManager backed by an EhCache {@link net.sf.ehcache.CacheManager}.
|
||||
@@ -81,8 +80,10 @@ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManag
|
||||
@Override
|
||||
protected Collection<Cache> loadCaches() {
|
||||
Status status = getCacheManager().getStatus();
|
||||
Assert.isTrue(Status.STATUS_ALIVE.equals(status),
|
||||
"An 'alive' EhCache CacheManager is required - current cache is " + status.toString());
|
||||
if (!Status.STATUS_ALIVE.equals(status)) {
|
||||
throw new IllegalStateException(
|
||||
"An 'alive' EhCache CacheManager is required - current cache is " + status.toString());
|
||||
}
|
||||
|
||||
String[] names = getCacheManager().getCacheNames();
|
||||
Collection<Cache> caches = new LinkedHashSet<Cache>(names.length);
|
||||
@@ -94,8 +95,7 @@ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManag
|
||||
|
||||
@Override
|
||||
protected Cache getMissingCache(String name) {
|
||||
// check the EhCache cache again
|
||||
// (in case the cache was added at runtime)
|
||||
// Check the EhCache cache again (in case the cache was added at runtime)
|
||||
Ehcache ehcache = getCacheManager().getEhcache(name);
|
||||
if (ehcache != null) {
|
||||
return new EhCacheCache(ehcache);
|
||||
|
||||
+20
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,13 +20,16 @@ import java.io.Serializable;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.SimpleValueWrapper;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Spring {@link Cache} adapter implementation on top of a
|
||||
* Guava {@link com.google.common.cache.Cache} instance.
|
||||
* Spring {@link org.springframework.cache.Cache} adapter implementation
|
||||
* on top of a Guava {@link com.google.common.cache.Cache} instance.
|
||||
*
|
||||
* <p>Requires Google Guava 12.0 or higher.
|
||||
*
|
||||
@@ -88,8 +91,16 @@ public class GuavaCache implements Cache {
|
||||
|
||||
@Override
|
||||
public ValueWrapper get(Object key) {
|
||||
Object value = this.cache.getIfPresent(key);
|
||||
return toWrapper(value);
|
||||
if (this.cache instanceof LoadingCache) {
|
||||
try {
|
||||
Object value = ((LoadingCache<Object, Object>) this.cache).get(key);
|
||||
return toWrapper(value);
|
||||
}
|
||||
catch (ExecutionException ex) {
|
||||
throw new UncheckedExecutionException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
return toWrapper(this.cache.getIfPresent(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -163,6 +174,10 @@ public class GuavaCache implements Cache {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class NullHolder implements Serializable {
|
||||
|
||||
private Object readResolve() {
|
||||
return NULL_HOLDER;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+5
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -142,6 +142,10 @@ public class JCacheCache implements Cache {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class NullHolder implements Serializable {
|
||||
|
||||
private Object readResolve() {
|
||||
return NULL_HOLDER;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.cache.jcache.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.cache.annotation.AbstractCachingConfiguration;
|
||||
import org.springframework.cache.annotation.CachingConfigurer;
|
||||
import org.springframework.cache.interceptor.CacheResolver;
|
||||
import org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource;
|
||||
import org.springframework.cache.jcache.interceptor.JCacheOperationSource;
|
||||
@@ -34,14 +35,16 @@ import org.springframework.context.annotation.Role;
|
||||
* @see JCacheConfigurer
|
||||
*/
|
||||
@Configuration
|
||||
public class AbstractJCacheConfiguration extends AbstractCachingConfiguration<JCacheConfigurer> {
|
||||
public class AbstractJCacheConfiguration extends AbstractCachingConfiguration {
|
||||
|
||||
protected CacheResolver exceptionCacheResolver;
|
||||
|
||||
@Override
|
||||
protected void useCachingConfigurer(JCacheConfigurer config) {
|
||||
protected void useCachingConfigurer(CachingConfigurer config) {
|
||||
super.useCachingConfigurer(config);
|
||||
this.exceptionCacheResolver = config.exceptionCacheResolver();
|
||||
if (config instanceof JCacheConfigurer) {
|
||||
this.exceptionCacheResolver = ((JCacheConfigurer) config).exceptionCacheResolver();
|
||||
}
|
||||
}
|
||||
|
||||
@Bean(name = "jCacheOperationSource")
|
||||
|
||||
+18
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,19 +29,18 @@ import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Abstract implementation of {@link JCacheOperationSource} that caches
|
||||
* attributes for methods and implements a fallback policy: 1. specific
|
||||
* target method; 2. declaring method.
|
||||
* Abstract implementation of {@link JCacheOperationSource} that caches attributes
|
||||
* for methods and implements a fallback policy: 1. specific target method;
|
||||
* 2. declaring method.
|
||||
*
|
||||
* <p>This implementation caches attributes by method after they are
|
||||
* first used.
|
||||
* <p>This implementation caches attributes by method after they are first used.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
* @see org.springframework.cache.interceptor.AbstractFallbackCacheOperationSource
|
||||
*/
|
||||
public abstract class AbstractFallbackJCacheOperationSource
|
||||
implements JCacheOperationSource {
|
||||
public abstract class AbstractFallbackJCacheOperationSource implements JCacheOperationSource {
|
||||
|
||||
/**
|
||||
* Canonical value held in cache to indicate no caching attribute was
|
||||
@@ -49,34 +48,31 @@ public abstract class AbstractFallbackJCacheOperationSource
|
||||
*/
|
||||
private final static Object NULL_CACHING_ATTRIBUTE = new Object();
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final Map<Object, Object> cache =
|
||||
new ConcurrentHashMap<Object, Object>(1024);
|
||||
private final Map<Object, Object> cache = new ConcurrentHashMap<Object, Object>(1024);
|
||||
|
||||
|
||||
@Override
|
||||
public JCacheOperation<?> getCacheOperation(Method method, Class<?> targetClass) {
|
||||
// First, see if we have a cached value.
|
||||
Object cacheKey = new MethodCacheKey(method, targetClass);
|
||||
Object cached = this.cache.get(cacheKey);
|
||||
|
||||
if (cached != null) {
|
||||
if (cached == NULL_CACHING_ATTRIBUTE) {
|
||||
return null;
|
||||
}
|
||||
return (JCacheOperation<?>) cached;
|
||||
return (cached != NULL_CACHING_ATTRIBUTE ? (JCacheOperation<?>) cached : null);
|
||||
}
|
||||
else {
|
||||
JCacheOperation<?> operation = computeCacheOperation(method, targetClass);
|
||||
if (operation == null) {
|
||||
this.cache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
|
||||
}
|
||||
else {
|
||||
if (operation != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding cacheable method '" + method.getName()
|
||||
+ "' with operation: " + operation);
|
||||
logger.debug("Adding cacheable method '" + method.getName() + "' with operation: " + operation);
|
||||
}
|
||||
this.cache.put(cacheKey, operation);
|
||||
}
|
||||
else {
|
||||
this.cache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
|
||||
}
|
||||
return operation;
|
||||
}
|
||||
}
|
||||
@@ -108,6 +104,7 @@ public abstract class AbstractFallbackJCacheOperationSource
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses need to implement this to return the caching operation
|
||||
* for the given method, if any.
|
||||
|
||||
+31
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cache.jcache.interceptor;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
@@ -23,7 +25,9 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
|
||||
import org.springframework.cache.interceptor.CacheResolver;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.cache.interceptor.SimpleCacheResolver;
|
||||
@@ -128,9 +132,9 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
|
||||
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
// Make sure those are initialized on startup...
|
||||
// Make sure that the cache resolver is initialized. An exception cache resolver is only
|
||||
// required if the exceptionCacheName attribute is set on an operation
|
||||
Assert.notNull(getDefaultCacheResolver(), "Cache resolver should have been initialized");
|
||||
Assert.notNull(getDefaultExceptionCacheResolver(), "Exception cache resolver should have been initialized");
|
||||
}
|
||||
|
||||
|
||||
@@ -179,7 +183,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
|
||||
@Override
|
||||
protected CacheResolver getDefaultExceptionCacheResolver() {
|
||||
if (this.exceptionCacheResolver == null) {
|
||||
this.exceptionCacheResolver = new SimpleExceptionCacheResolver(getDefaultCacheManager());
|
||||
this.exceptionCacheResolver = new LazyCacheResolver();
|
||||
}
|
||||
return this.exceptionCacheResolver;
|
||||
}
|
||||
@@ -189,4 +193,27 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
|
||||
return this.adaptedKeyGenerator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Only resolve the default exception cache resolver when an exception needs to be handled.
|
||||
* <p>A non-JSR-107 setup requires either a {@link CacheManager} or a {@link CacheResolver}. If only
|
||||
* the latter is specified, it is not possible to extract a default exception {@code CacheResolver}
|
||||
* from a custom {@code CacheResolver} implementation so we have to fallback on the {@code CacheManager}.
|
||||
* <p>This gives this weird situation of a perfectly valid configuration that breaks all the sudden
|
||||
* because the JCache support is enabled. To avoid this we resolve the default exception {@code CacheResolver}
|
||||
* as late as possible to avoid such hard requirement in other cases.
|
||||
*/
|
||||
class LazyCacheResolver implements CacheResolver {
|
||||
|
||||
private CacheResolver cacheResolver;
|
||||
|
||||
@Override
|
||||
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
|
||||
if (this.cacheResolver == null) {
|
||||
this.cacheResolver = new SimpleExceptionCacheResolver(getDefaultCacheManager());
|
||||
}
|
||||
return this.cacheResolver.resolveCaches(context);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,21 +28,21 @@ import org.springframework.cache.interceptor.CacheResolver;
|
||||
* <p>A cache operation can be statically cached as it does not contain
|
||||
* any runtime operation of a specific cache invocation.
|
||||
*
|
||||
* @param <A> the type of the JSR-107 annotation
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.1
|
||||
* @param <A> the type of the JSR-107 annotation
|
||||
*/
|
||||
public interface JCacheOperation<A extends Annotation> extends BasicOperation, CacheMethodDetails<A> {
|
||||
|
||||
/**
|
||||
* Return the {@link CacheResolver} instance to use to resolve the cache to
|
||||
* use for this operation.
|
||||
* Return the {@link CacheResolver} instance to use to resolve the cache
|
||||
* to use for this operation.
|
||||
*/
|
||||
CacheResolver getCacheResolver();
|
||||
|
||||
/**
|
||||
* Return the {@link CacheInvocationParameter} instances based on the specified
|
||||
* method arguments.
|
||||
* Return the {@link CacheInvocationParameter} instances based on the
|
||||
* specified method arguments.
|
||||
* <p>The method arguments must match the signature of the related method invocation
|
||||
* @param values the parameters value for a particular invocation
|
||||
*/
|
||||
|
||||
spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheCacheManagerTests.java
Vendored
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,9 +30,12 @@ import org.springframework.cache.transaction.AbstractTransactionSupportingCacheM
|
||||
public class EhCacheCacheManagerTests extends AbstractTransactionSupportingCacheManagerTests<EhCacheCacheManager> {
|
||||
|
||||
private CacheManager nativeCacheManager;
|
||||
|
||||
private EhCacheCacheManager cacheManager;
|
||||
|
||||
private EhCacheCacheManager transactionalCacheManager;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
nativeCacheManager = new CacheManager(new Configuration().name("EhCacheCacheManagerTests")
|
||||
@@ -58,7 +61,8 @@ public class EhCacheCacheManagerTests extends AbstractTransactionSupportingCache
|
||||
protected EhCacheCacheManager getCacheManager(boolean transactionAware) {
|
||||
if (transactionAware) {
|
||||
return transactionalCacheManager;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return cacheManager;
|
||||
}
|
||||
}
|
||||
@@ -77,4 +81,5 @@ public class EhCacheCacheManagerTests extends AbstractTransactionSupportingCache
|
||||
protected void removeNativeCache(String cacheName) {
|
||||
nativeCacheManager.removeCache(cacheName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vendored
+29
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,10 @@ package org.springframework.cache.guava;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
@@ -32,6 +35,9 @@ import static org.mockito.Mockito.*;
|
||||
*/
|
||||
public class GuavaCacheManagerTests {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void testDynamicMode() {
|
||||
CacheManager cm = new GuavaCacheManager();
|
||||
@@ -150,6 +156,28 @@ public class GuavaCacheManagerTests {
|
||||
assertNotNull(cm.getCache("someCache"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheLoaderUseLoadingCache() {
|
||||
GuavaCacheManager cm = new GuavaCacheManager("c1");
|
||||
cm.setCacheLoader(new CacheLoader<Object, Object>() {
|
||||
@Override
|
||||
public Object load(Object key) throws Exception {
|
||||
if ("ping".equals(key)) {
|
||||
return "pong";
|
||||
}
|
||||
throw new IllegalArgumentException("I only know ping");
|
||||
}
|
||||
});
|
||||
Cache cache1 = cm.getCache("c1");
|
||||
Cache.ValueWrapper value = cache1.get("ping");
|
||||
assertNotNull(value);
|
||||
assertEquals("pong", value.get());
|
||||
|
||||
thrown.expect(UncheckedExecutionException.class);
|
||||
thrown.expectMessage("I only know ping");
|
||||
assertNull(cache1.get("foo"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private CacheLoader<Object, Object> mockCacheLoader() {
|
||||
return mock(CacheLoader.class);
|
||||
|
||||
Vendored
+9
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,9 +33,12 @@ import static org.mockito.BDDMockito.*;
|
||||
public class JCacheCacheManagerTests extends AbstractTransactionSupportingCacheManagerTests<JCacheCacheManager> {
|
||||
|
||||
private CacheManagerMock cacheManagerMock;
|
||||
|
||||
private JCacheCacheManager cacheManager;
|
||||
|
||||
private JCacheCacheManager transactionalCacheManager;
|
||||
|
||||
|
||||
@Before
|
||||
public void setupOnce() {
|
||||
cacheManagerMock = new CacheManagerMock();
|
||||
@@ -55,7 +58,8 @@ public class JCacheCacheManagerTests extends AbstractTransactionSupportingCacheM
|
||||
protected JCacheCacheManager getCacheManager(boolean transactionAware) {
|
||||
if (transactionAware) {
|
||||
return transactionalCacheManager;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return cacheManager;
|
||||
}
|
||||
}
|
||||
@@ -75,9 +79,11 @@ public class JCacheCacheManagerTests extends AbstractTransactionSupportingCacheM
|
||||
cacheManagerMock.removeCache(cacheName);
|
||||
}
|
||||
|
||||
|
||||
private static class CacheManagerMock {
|
||||
|
||||
private final List<String> cacheNames;
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
|
||||
private CacheManagerMock() {
|
||||
@@ -103,4 +109,5 @@ public class JCacheCacheManagerTests extends AbstractTransactionSupportingCacheM
|
||||
given(cacheManager.getCache(name)).willReturn(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+51
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,12 +18,15 @@ package org.springframework.cache.jcache.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
|
||||
import org.springframework.cache.config.SomeKeyGenerator;
|
||||
import org.springframework.cache.interceptor.CacheErrorHandler;
|
||||
import org.springframework.cache.interceptor.CacheResolver;
|
||||
@@ -35,7 +38,6 @@ import org.springframework.cache.interceptor.SimpleKeyGenerator;
|
||||
import org.springframework.cache.jcache.interceptor.AnnotatedJCacheableService;
|
||||
import org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource;
|
||||
import org.springframework.cache.jcache.interceptor.JCacheInterceptor;
|
||||
import org.springframework.cache.jcache.interceptor.SimpleExceptionCacheResolver;
|
||||
import org.springframework.cache.support.NoOpCacheManager;
|
||||
import org.springframework.cache.support.SimpleCacheManager;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -51,15 +53,20 @@ import static org.junit.Assert.*;
|
||||
*/
|
||||
public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Override
|
||||
protected ApplicationContext getApplicationContext() {
|
||||
return new AnnotationConfigApplicationContext(EnableCachingConfig.class);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void fullCachingConfig() throws Exception {
|
||||
AnnotationConfigApplicationContext context =
|
||||
new AnnotationConfigApplicationContext(FullCachingConfig.class);
|
||||
|
||||
DefaultJCacheOperationSource cos = context.getBean(DefaultJCacheOperationSource.class);
|
||||
assertSame(context.getBean(KeyGenerator.class), cos.getKeyGenerator());
|
||||
assertSame(context.getBean("cacheResolver", CacheResolver.class),
|
||||
@@ -80,10 +87,7 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
|
||||
assertEquals(SimpleCacheResolver.class, cos.getCacheResolver().getClass());
|
||||
assertSame(context.getBean(CacheManager.class),
|
||||
((SimpleCacheResolver) cos.getCacheResolver()).getCacheManager());
|
||||
assertNotNull(cos.getExceptionCacheResolver());
|
||||
assertEquals(SimpleExceptionCacheResolver.class, cos.getExceptionCacheResolver().getClass());
|
||||
assertSame(context.getBean(CacheManager.class),
|
||||
((SimpleExceptionCacheResolver) cos.getExceptionCacheResolver()).getCacheManager());
|
||||
assertNull(cos.getExceptionCacheResolver());
|
||||
context.close();
|
||||
}
|
||||
|
||||
@@ -99,6 +103,27 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exceptionCacheResolverLazilyRequired() {
|
||||
ConfigurableApplicationContext context =
|
||||
new AnnotationConfigApplicationContext(NoExceptionCacheResolverConfig.class);
|
||||
|
||||
try {
|
||||
DefaultJCacheOperationSource cos = context.getBean(DefaultJCacheOperationSource.class);
|
||||
assertSame(context.getBean("cacheResolver"), cos.getCacheResolver());
|
||||
|
||||
JCacheableService<?> service = context.getBean(JCacheableService.class);
|
||||
service.cache("id");
|
||||
|
||||
// This call requires the cache manager to be set
|
||||
thrown.expect(IllegalStateException.class);
|
||||
service.cacheWithException("test", false);
|
||||
}
|
||||
finally {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
@@ -126,11 +151,11 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public static class FullCachingConfig implements JCacheConfigurer {
|
||||
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public CacheManager cacheManager() {
|
||||
@@ -162,6 +187,7 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public static class EmptyConfigSupportConfig extends JCacheConfigurerSupport {
|
||||
@@ -171,6 +197,7 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
static class FullCachingConfigSupport extends JCacheConfigurerSupport {
|
||||
@@ -200,4 +227,21 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
static class NoExceptionCacheResolverConfig extends JCacheConfigurerSupport {
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public CacheResolver cacheResolver() {
|
||||
return new NamedCacheResolver(new ConcurrentMapCacheManager(), "default");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JCacheableService<?> cacheableService() {
|
||||
return new AnnotatedJCacheableService(new ConcurrentMapCache("default"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,11 +42,10 @@ public abstract class AbstractTransactionSupportingCacheManagerTests<T extends C
|
||||
|
||||
/**
|
||||
* Returns the {@link CacheManager} to use.
|
||||
*
|
||||
* @param transactionAware if the requested cache manager should be aware
|
||||
* of the transaction
|
||||
* @return the cache manager to use
|
||||
* @see org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager#setTransactionAware(boolean)
|
||||
* @see org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager#setTransactionAware
|
||||
*/
|
||||
protected abstract T getCacheManager(boolean transactionAware);
|
||||
|
||||
@@ -65,6 +64,7 @@ public abstract class AbstractTransactionSupportingCacheManagerTests<T extends C
|
||||
*/
|
||||
protected abstract void removeNativeCache(String cacheName);
|
||||
|
||||
|
||||
@Test
|
||||
public void getOnExistingCache() {
|
||||
assertThat(getCacheManager(false).getCache(CACHE_NAME), is(instanceOf(getCacheType())));
|
||||
@@ -77,10 +77,10 @@ public abstract class AbstractTransactionSupportingCacheManagerTests<T extends C
|
||||
addNativeCache(cacheName);
|
||||
assertFalse(cacheManager.getCacheNames().contains(cacheName));
|
||||
try {
|
||||
assertThat(cacheManager.getCache(cacheName),
|
||||
is(instanceOf(getCacheType())));
|
||||
assertThat(cacheManager.getCache(cacheName), is(instanceOf(getCacheType())));
|
||||
assertTrue(cacheManager.getCacheNames().contains(cacheName));
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
removeNativeCache(cacheName);
|
||||
}
|
||||
}
|
||||
@@ -109,8 +109,10 @@ public abstract class AbstractTransactionSupportingCacheManagerTests<T extends C
|
||||
assertThat(cacheManager.getCache(cacheName),
|
||||
is(instanceOf(TransactionAwareCacheDecorator.class)));
|
||||
assertTrue(cacheManager.getCacheNames().contains(cacheName));
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
removeNativeCache(cacheName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-2
@@ -381,17 +381,20 @@ public class QuartzSupportTests {
|
||||
|
||||
/**
|
||||
* SPR-6038: detect HSQL and stop illegal locks being taken.
|
||||
* TODO: Against Quartz 2.2, this test's job doesn't actually execute anymore...
|
||||
*/
|
||||
@Test
|
||||
public void schedulerWithHsqlDataSource() throws Exception {
|
||||
Assume.group(TestGroup.PERFORMANCE);
|
||||
// Assume.group(TestGroup.PERFORMANCE);
|
||||
|
||||
DummyJob.param = 0;
|
||||
DummyJob.count = 0;
|
||||
|
||||
ClassPathXmlApplicationContext ctx = context("databasePersistence.xml");
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(ctx.getBean(DataSource.class));
|
||||
assertTrue("No triggers were persisted", jdbcTemplate.queryForList("SELECT * FROM qrtz_triggers").size()>0);
|
||||
assertFalse("No triggers were persisted", jdbcTemplate.queryForList("SELECT * FROM qrtz_triggers").isEmpty());
|
||||
|
||||
/*
|
||||
Thread.sleep(3000);
|
||||
try {
|
||||
assertTrue(DummyJob.count > 0);
|
||||
@@ -399,6 +402,7 @@ public class QuartzSupportTests {
|
||||
finally {
|
||||
ctx.close();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private ClassPathXmlApplicationContext context(String path) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,7 @@
|
||||
package org.springframework.cache;
|
||||
|
||||
/**
|
||||
* Interface that defines the common cache operations.
|
||||
* Interface that defines common cache operations.
|
||||
*
|
||||
* <b>Note:</b> Due to the generic use of caching, it is recommended that
|
||||
* implementations allow storage of <tt>null</tt> values (for example to
|
||||
@@ -68,8 +68,8 @@ public interface Cache {
|
||||
* the cache contains no mapping for this key
|
||||
* @throws IllegalStateException if a cache entry has been found
|
||||
* but failed to match the specified type
|
||||
* @see #get(Object)
|
||||
* @since 4.0
|
||||
* @see #get(Object)
|
||||
*/
|
||||
<T> T get(Object key, Class<T> type);
|
||||
|
||||
|
||||
Vendored
+12
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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.cache.annotation;
|
||||
|
||||
import java.util.Collection;
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.CacheManager;
|
||||
@@ -28,12 +27,11 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Abstract base {@code @Configuration} class providing common structure for enabling
|
||||
* Spring's annotation-driven cache management capability.
|
||||
* Abstract base {@code @Configuration} class providing common structure
|
||||
* for enabling Spring's annotation-driven cache management capability.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Stephane Nicoll
|
||||
@@ -41,7 +39,7 @@ import org.springframework.util.CollectionUtils;
|
||||
* @see EnableCaching
|
||||
*/
|
||||
@Configuration
|
||||
public abstract class AbstractCachingConfiguration<C extends CachingConfigurer> implements ImportAware {
|
||||
public abstract class AbstractCachingConfiguration implements ImportAware {
|
||||
|
||||
protected AnnotationAttributes enableCaching;
|
||||
|
||||
@@ -53,17 +51,19 @@ public abstract class AbstractCachingConfiguration<C extends CachingConfigurer>
|
||||
|
||||
protected CacheErrorHandler errorHandler;
|
||||
|
||||
|
||||
@Override
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
this.enableCaching = AnnotationAttributes.fromMap(
|
||||
importMetadata.getAnnotationAttributes(EnableCaching.class.getName(), false));
|
||||
Assert.notNull(this.enableCaching,
|
||||
"@EnableCaching is not present on importing class " +
|
||||
importMetadata.getClassName());
|
||||
if (this.enableCaching == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"@EnableCaching is not present on importing class " + importMetadata.getClassName());
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
void setConfigurers(Collection<C> configurers) {
|
||||
void setConfigurers(Collection<CachingConfigurer> configurers) {
|
||||
if (CollectionUtils.isEmpty(configurers)) {
|
||||
return;
|
||||
}
|
||||
@@ -73,14 +73,14 @@ public abstract class AbstractCachingConfiguration<C extends CachingConfigurer>
|
||||
"Refactor the configuration such that CachingConfigurer is " +
|
||||
"implemented only once or not at all.");
|
||||
}
|
||||
C configurer = configurers.iterator().next();
|
||||
CachingConfigurer configurer = configurers.iterator().next();
|
||||
useCachingConfigurer(configurer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the configuration from the nominated {@link CachingConfigurer}.
|
||||
*/
|
||||
protected void useCachingConfigurer(C config) {
|
||||
protected void useCachingConfigurer(CachingConfigurer config) {
|
||||
this.cacheManager = config.cacheManager();
|
||||
this.cacheResolver = config.cacheResolver();
|
||||
this.keyGenerator = config.keyGenerator();
|
||||
|
||||
+60
-22
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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 java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method (or all methods on a class) trigger(s)
|
||||
* a cache invalidate operation.
|
||||
* Annotation indicating that a method (or all methods on a class) triggers a
|
||||
* {@link org.springframework.cache.Cache#evict(Object) cache evict} operation.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Stephane Nicoll
|
||||
@@ -39,22 +39,39 @@ import java.lang.annotation.Target;
|
||||
public @interface CacheEvict {
|
||||
|
||||
/**
|
||||
* Qualifier value for the specified cached operation.
|
||||
* <p>May be used to determine the target cache (or caches), matching the qualifier
|
||||
* value (or the bean name(s)) of (a) specific bean definition.
|
||||
* Names of the caches to use for the cache eviction operation.
|
||||
* <p>Names may be used to determine the target cache (or caches), matching
|
||||
* the qualifier value or bean name of a specific bean definition.
|
||||
* @see CacheConfig#cacheNames
|
||||
*/
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||
* <p>Default is "", meaning all method parameters are considered as a key, unless
|
||||
* a custom {@link #keyGenerator()} has been set.
|
||||
* Spring Expression Language (SpEL) expression for computing the key dynamically.
|
||||
* <p>Default is {@code ""}, meaning all method parameters are considered as a key,
|
||||
* unless a custom {@link #keyGenerator} has been set.
|
||||
* <p>The SpEL expression evaluates again a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #result} for a reference to the result of the method invocation, which
|
||||
* can only be used if {@link #beforeInvocation()} is {@code false}.</li>
|
||||
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
|
||||
* reference to the {@link java.lang.reflect.Method method}, target object and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.KeyGenerator} to use.
|
||||
* <p>Mutually exclusive with the {@link #key()} attribute.
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.KeyGenerator}
|
||||
* to use.
|
||||
* <p>Mutually exclusive with the {@link #key} attribute.
|
||||
* @see CacheConfig#keyGenerator
|
||||
*/
|
||||
String keyGenerator() default "";
|
||||
|
||||
@@ -62,34 +79,55 @@ public @interface CacheEvict {
|
||||
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use to
|
||||
* create a default {@link org.springframework.cache.interceptor.CacheResolver} if none
|
||||
* is set already.
|
||||
* <p>Mutually exclusive with the {@link #cacheResolver()} attribute.
|
||||
* <p>Mutually exclusive with the {@link #cacheResolver} attribute.
|
||||
* @see org.springframework.cache.interceptor.SimpleCacheResolver
|
||||
* @see CacheConfig#cacheManager
|
||||
*/
|
||||
String cacheManager() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver} to use.
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver}
|
||||
* to use.
|
||||
* @see CacheConfig#cacheResolver
|
||||
*/
|
||||
String cacheResolver() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
|
||||
* <p>Default is "", meaning the method is always cached.
|
||||
* Spring Expression Language (SpEL) expression used for making the cache
|
||||
* eviction operation conditional.
|
||||
* <p>Default is {@code ""}, meaning the cache eviction is always performed.
|
||||
* <p>The SpEL expression evaluates again a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
|
||||
* reference to the {@link java.lang.reflect.Method method}, target object and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
*/
|
||||
String condition() default "";
|
||||
|
||||
/**
|
||||
* Whether or not all the entries inside the cache(s) are removed or not. By
|
||||
* default, only the value under the associated key is removed.
|
||||
* <p>Note that setting this parameter to {@code true} and specifying a {@link #key()}
|
||||
* is not allowed.
|
||||
* Whether all the entries inside the cache(s) are removed.
|
||||
* <p>By default, only the value under the associated key is removed.
|
||||
* <p>Note that setting this parameter to {@code true} and specifying a
|
||||
* {@link #key} is not allowed.
|
||||
*/
|
||||
boolean allEntries() default false;
|
||||
|
||||
/**
|
||||
* Whether the eviction should occur after the method is successfully invoked (default)
|
||||
* or before. The latter causes the eviction to occur irrespective of the method outcome (whether
|
||||
* it threw an exception or not) while the former does not.
|
||||
* Whether the eviction should occur before the method is invoked.
|
||||
* <p>Setting this attribute to {@code true}, causes the eviction to
|
||||
* occur irrespective of the method outcome (i.e., whether it threw an
|
||||
* exception or not).
|
||||
* <p>Defaults to {@code false}, meaning that the cache eviction operation
|
||||
* will occur <em>after</em> the advised method is invoked successfully (i.e.,
|
||||
* only if the invocation did not throw an exception).
|
||||
*/
|
||||
boolean beforeInvocation() default false;
|
||||
|
||||
}
|
||||
|
||||
+70
-24
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,13 +23,13 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method (or all methods on a class) trigger(s)
|
||||
* a {@link Cache#put(Object, Object)} operation. As opposed to {@link Cacheable} annotation,
|
||||
* this annotation does not cause the target method to be skipped - rather it
|
||||
* always causes the method to be invoked and its result to be placed into the cache.
|
||||
* Annotation indicating that a method (or all methods on a class) triggers a
|
||||
* {@link org.springframework.cache.Cache#put(Object, Object) cache put} operation.
|
||||
*
|
||||
* <p>In contrast to the {@link Cacheable @Cacheable} annotation, this annotation
|
||||
* does not cause the advised method to be skipped. Rather, it always causes the
|
||||
* method to be invoked and its result to be stored in the associated cache.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Phillip Webb
|
||||
@@ -37,29 +37,45 @@ import org.springframework.cache.Cache;
|
||||
* @since 3.1
|
||||
* @see CacheConfig
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface CachePut {
|
||||
|
||||
/**
|
||||
* Name of the caches in which the update takes place.
|
||||
* <p>May be used to determine the target cache (or caches), matching the
|
||||
* qualifier value (or the bean name(s)) of (a) specific bean definition.
|
||||
* Names of the caches to use for the cache put operation.
|
||||
* <p>Names may be used to determine the target cache (or caches), matching
|
||||
* the qualifier value or bean name of a specific bean definition.
|
||||
* @see CacheConfig#cacheNames
|
||||
*/
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||
* <p>Default is "", meaning all method parameters are considered as a key, unless
|
||||
* a custom {@link #keyGenerator()} has been set.
|
||||
* Spring Expression Language (SpEL) expression for computing the key dynamically.
|
||||
* <p>Default is {@code ""}, meaning all method parameters are considered as a key,
|
||||
* unless a custom {@link #keyGenerator} has been set.
|
||||
* <p>The SpEL expression evaluates again a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #result} for a reference to the result of the method invocation.</li>
|
||||
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
|
||||
* reference to the {@link java.lang.reflect.Method method}, target object and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.KeyGenerator} to use.
|
||||
* <p>Mutually exclusive with the {@link #key()} attribute.
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.KeyGenerator}
|
||||
* to use.
|
||||
* <p>Mutually exclusive with the {@link #key} attribute.
|
||||
* @see CacheConfig#keyGenerator
|
||||
*/
|
||||
String keyGenerator() default "";
|
||||
|
||||
@@ -67,28 +83,58 @@ public @interface CachePut {
|
||||
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use to
|
||||
* create a default {@link org.springframework.cache.interceptor.CacheResolver} if none
|
||||
* is set already.
|
||||
* <p>Mutually exclusive with the {@link #cacheResolver()} attribute.
|
||||
* <p>Mutually exclusive with the {@link #cacheResolver} attribute.
|
||||
* @see org.springframework.cache.interceptor.SimpleCacheResolver
|
||||
* @see CacheConfig#cacheManager
|
||||
*/
|
||||
String cacheManager() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver} to use.
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver}
|
||||
* to use.
|
||||
* @see CacheConfig#cacheResolver
|
||||
*/
|
||||
String cacheResolver() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the cache update.
|
||||
* <p>Default is "", meaning the method result is always cached.
|
||||
* Spring Expression Language (SpEL) expression used for making the cache
|
||||
* put operation conditional.
|
||||
* <p>Default is {@code ""}, meaning the method result is always cached.
|
||||
* <p>The SpEL expression evaluates again a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
|
||||
* reference to the {@link java.lang.reflect.Method method}, target object and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
*/
|
||||
String condition() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used to veto the cache update.
|
||||
* <p>Unlike {@link #condition()}, this expression is evaluated after the method
|
||||
* has been called and can therefore refer to the {@code result}. Default is "",
|
||||
* meaning that caching is never vetoed.
|
||||
* Spring Expression Language (SpEL) expression used to veto the cache put operation.
|
||||
* <p>Unlike {@link #condition}, this expression is evaluated after the method
|
||||
* has been called and can therefore refer to the {@code result}.
|
||||
* <p>Default is {@code ""}, meaning that caching is never vetoed.
|
||||
* <p>The SpEL expression evaluates again a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #result} for a reference to the result of the method invocation.</li>
|
||||
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
|
||||
* reference to the {@link java.lang.reflect.Method method}, target object and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
* @since 3.2
|
||||
*/
|
||||
String unless() default "";
|
||||
|
||||
}
|
||||
|
||||
+72
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,17 +24,18 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method (or all the methods on a class) can be cached.
|
||||
* Annotation indicating that the result of invoking a method (or all methods
|
||||
* in a class) can be cached.
|
||||
*
|
||||
* <p>Each time a targeted method is invoked, a caching behavior will be applied,
|
||||
* checking whether the method has been already executed for the given arguments. A
|
||||
* sensible default simply uses the method parameters to compute the key but a SpEL
|
||||
* expression can be provided ({@link #key()}) or a custom
|
||||
* {@link org.springframework.cache.interceptor.KeyGenerator KeyGenerator} implementation
|
||||
* can replace the default one ({@link #keyGenerator()}).
|
||||
* <p>Each time an advised method is invoked, caching behavior will be applied,
|
||||
* checking whether the method has been already invoked for the given arguments.
|
||||
* A sensible default simply uses the method parameters to compute the key, but
|
||||
* a SpEL expression can be provided via the {@link #key} attribute, or a custom
|
||||
* {@link org.springframework.cache.interceptor.KeyGenerator} implementation can
|
||||
* replace the default one (see {@link #keyGenerator}).
|
||||
*
|
||||
* <p>If no value is found in the cache for the computed key, the method is executed
|
||||
* and the returned instance is used as the cache value.
|
||||
* <p>If no value is found in the cache for the computed key, the target method
|
||||
* will be invoked and the returned value stored in the associated cache.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Phillip Webb
|
||||
@@ -49,22 +50,37 @@ import java.lang.annotation.Target;
|
||||
public @interface Cacheable {
|
||||
|
||||
/**
|
||||
* Name of the caches in which the update takes place.
|
||||
* <p>May be used to determine the target cache (or caches), matching the
|
||||
* qualifier value (or the bean name(s)) of (a) specific bean definition.
|
||||
* Names of the caches in which method invocation results are stored.
|
||||
* <p>Names may be used to determine the target cache (or caches), matching
|
||||
* the qualifier value or bean name of a specific bean definition.
|
||||
* @see CacheConfig#cacheNames
|
||||
*/
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
|
||||
* <p>Default is "", meaning all method parameters are considered as a key, unless
|
||||
* a custom {@link #keyGenerator()} has been set.
|
||||
* Spring Expression Language (SpEL) expression for computing the key dynamically.
|
||||
* <p>Default is {@code ""}, meaning all method parameters are considered as a key,
|
||||
* unless a custom {@link #keyGenerator} has been configured.
|
||||
* <p>The SpEL expression evaluates again a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
|
||||
* reference to the {@link java.lang.reflect.Method method}, target object and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.KeyGenerator} to use.
|
||||
* <p>Mutually exclusive with the {@link #key()} attribute.
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.KeyGenerator}
|
||||
* to use.
|
||||
* <p>Mutually exclusive with the {@link #key} attribute.
|
||||
* @see CacheConfig#keyGenerator
|
||||
*/
|
||||
String keyGenerator() default "";
|
||||
|
||||
@@ -72,28 +88,58 @@ public @interface Cacheable {
|
||||
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use to
|
||||
* create a default {@link org.springframework.cache.interceptor.CacheResolver} if none
|
||||
* is set already.
|
||||
* <p>Mutually exclusive with the {@link #cacheResolver()} attribute.
|
||||
* <p>Mutually exclusive with the {@link #cacheResolver} attribute.
|
||||
* @see org.springframework.cache.interceptor.SimpleCacheResolver
|
||||
* @see CacheConfig#cacheManager
|
||||
*/
|
||||
String cacheManager() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver} to use.
|
||||
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver}
|
||||
* to use.
|
||||
* @see CacheConfig#cacheResolver
|
||||
*/
|
||||
String cacheResolver() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
|
||||
* <p>Default is "", meaning the method is always cached.
|
||||
* Spring Expression Language (SpEL) expression used for making the method
|
||||
* caching conditional.
|
||||
* <p>Default is {@code ""}, meaning the method result is always cached.
|
||||
* <p>The SpEL expression evaluates again a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
|
||||
* reference to the {@link java.lang.reflect.Method method}, target object and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
*/
|
||||
String condition() default "";
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) attribute used to veto method caching.
|
||||
* <p>Unlike {@link #condition()}, this expression is evaluated after the method
|
||||
* has been called and can therefore refer to the {@code result}. Default is "",
|
||||
* meaning that caching is never vetoed.
|
||||
* Spring Expression Language (SpEL) expression used to veto method caching.
|
||||
* <p>Unlike {@link #condition}, this expression is evaluated after the method
|
||||
* has been called and can therefore refer to the {@code result}.
|
||||
* <p>Default is {@code ""}, meaning that caching is never vetoed.
|
||||
* <p>The SpEL expression evaluates again a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #result} for a reference to the result of the method invocation.</li>
|
||||
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
|
||||
* reference to the {@link java.lang.reflect.Method method}, target object and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
* @since 3.2
|
||||
*/
|
||||
String unless() default "";
|
||||
|
||||
}
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -162,13 +162,12 @@ public @interface EnableCaching {
|
||||
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
|
||||
* to standard Java interface-based proxies. The default is {@code false}. <strong>
|
||||
* Applicable only if {@link #mode()} is set to {@link AdviceMode#PROXY}</strong>.
|
||||
*
|
||||
* <p>Note that setting this attribute to {@code true} will affect <em>all</em>
|
||||
* Spring-managed beans requiring proxying, not just those marked with
|
||||
* {@code @Cacheable}. For example, other beans marked with Spring's
|
||||
* {@code @Transactional} annotation will be upgraded to subclass proxying at the same
|
||||
* time. This approach has no negative impact in practice unless one is explicitly
|
||||
* expecting one type of proxy vs another, e.g. in tests.
|
||||
* Spring-managed beans requiring proxying, not just those marked with {@code @Cacheable}.
|
||||
* For example, other beans marked with Spring's {@code @Transactional} annotation will
|
||||
* be upgraded to subclass proxying at the same time. This approach has no negative
|
||||
* impact in practice unless one is explicitly expecting one type of proxy vs another,
|
||||
* e.g. in tests.
|
||||
*/
|
||||
boolean proxyTargetClass() default false;
|
||||
|
||||
@@ -185,4 +184,5 @@ public @interface EnableCaching {
|
||||
* The default is {@link Ordered#LOWEST_PRECEDENCE}.
|
||||
*/
|
||||
int order() default Ordered.LOWEST_PRECEDENCE;
|
||||
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,7 +35,7 @@ import org.springframework.context.annotation.Role;
|
||||
* @see CachingConfigurationSelector
|
||||
*/
|
||||
@Configuration
|
||||
public class ProxyCachingConfiguration extends AbstractCachingConfiguration<CachingConfigurer> {
|
||||
public class ProxyCachingConfiguration extends AbstractCachingConfiguration {
|
||||
|
||||
@Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
|
||||
Vendored
+1
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -235,11 +235,6 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
|
||||
"default cache resolver if none is set. If a cache resolver is set, the cache manager" +
|
||||
"won't be used.");
|
||||
}
|
||||
if (operation.getCacheNames().isEmpty()) {
|
||||
throw new IllegalStateException("No cache names could be detected on '" +
|
||||
ae.toString() + "'. Make sure to set the value parameter on the annotation or " +
|
||||
"declare a @CacheConfig at the class-level with the default cache name(s) to use.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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.cache.support.SimpleValueWrapper;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple {@link Cache} implementation based on the core JDK
|
||||
* {@code java.util.concurrent} package.
|
||||
* Simple {@link org.springframework.cache.Cache} implementation based on the
|
||||
* core JDK {@code java.util.concurrent} package.
|
||||
*
|
||||
* <p>Useful for testing or simple caching scenarios, typically in combination
|
||||
* with {@link org.springframework.cache.support.SimpleCacheManager} or
|
||||
@@ -124,7 +124,7 @@ public class ConcurrentMapCache implements Cache {
|
||||
|
||||
@Override
|
||||
public ValueWrapper putIfAbsent(Object key, Object value) {
|
||||
Object existing = this.store.putIfAbsent(key, value);
|
||||
Object existing = this.store.putIfAbsent(key, toStoreValue(value));
|
||||
return toWrapper(existing);
|
||||
}
|
||||
|
||||
@@ -169,8 +169,13 @@ public class ConcurrentMapCache implements Cache {
|
||||
return (value != null ? new SimpleValueWrapper(fromStoreValue(value)) : null);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class NullHolder implements Serializable {
|
||||
|
||||
private Object readResolve() {
|
||||
return NULL_HOLDER;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
|
||||
*/
|
||||
private final static Collection<CacheOperation> NULL_CACHING_ATTRIBUTE = Collections.emptyList();
|
||||
|
||||
|
||||
/**
|
||||
* Logger available to subclasses.
|
||||
* <p>As this base class is not marked Serializable, the logger will be recreated
|
||||
@@ -71,9 +72,10 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
|
||||
* <p>As this base class is not marked Serializable, the cache will be recreated
|
||||
* after serialization - provided that the concrete subclass is Serializable.
|
||||
*/
|
||||
final Map<Object, Collection<CacheOperation>> attributeCache =
|
||||
private final Map<Object, Collection<CacheOperation>> attributeCache =
|
||||
new ConcurrentHashMap<Object, Collection<CacheOperation>>(1024);
|
||||
|
||||
|
||||
/**
|
||||
* Determine the caching attribute for this method invocation.
|
||||
* <p>Defaults to the class's caching attribute if no method attribute is found.
|
||||
@@ -84,30 +86,23 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
|
||||
*/
|
||||
@Override
|
||||
public Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) {
|
||||
// First, see if we have a cached value.
|
||||
Object cacheKey = getCacheKey(method, targetClass);
|
||||
Collection<CacheOperation> cached = this.attributeCache.get(cacheKey);
|
||||
|
||||
if (cached != null) {
|
||||
if (cached == NULL_CACHING_ATTRIBUTE) {
|
||||
return null;
|
||||
}
|
||||
// Value will either be canonical value indicating there is no caching attribute,
|
||||
// or an actual caching attribute.
|
||||
return cached;
|
||||
return (cached != NULL_CACHING_ATTRIBUTE ? cached : null);
|
||||
}
|
||||
else {
|
||||
// We need to work it out.
|
||||
Collection<CacheOperation> cacheOps = computeCacheOperations(method, targetClass);
|
||||
// Put it in the cache.
|
||||
if (cacheOps == null) {
|
||||
this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
|
||||
}
|
||||
else {
|
||||
if (cacheOps != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheOps);
|
||||
}
|
||||
this.attributeCache.put(cacheKey, cacheOps);
|
||||
}
|
||||
else {
|
||||
this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
|
||||
}
|
||||
return cacheOps;
|
||||
}
|
||||
}
|
||||
@@ -186,4 +181,5 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
|
||||
protected boolean allowPublicMethodsOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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.springframework.cache.Cache;
|
||||
/**
|
||||
* Determine the {@link Cache} instance(s) to use for an intercepted method invocation.
|
||||
*
|
||||
* <p>Implementations MUST be thread-safe.
|
||||
* <p>Implementations must be thread-safe.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.1
|
||||
@@ -32,9 +32,8 @@ public interface CacheResolver {
|
||||
|
||||
/**
|
||||
* Return the cache(s) to use for the specified invocation.
|
||||
*
|
||||
* @param context the context of the particular invocation
|
||||
* @return the cache(s) to use (never null)
|
||||
* @return the cache(s) to use (never {@code null})
|
||||
*/
|
||||
Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context);
|
||||
|
||||
|
||||
+13
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,7 +40,7 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
|
||||
|
||||
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>(16);
|
||||
|
||||
private Set<String> cacheNames = new LinkedHashSet<String>(16);
|
||||
private final Set<String> cacheNames = new LinkedHashSet<String>(16);
|
||||
|
||||
|
||||
// Early cache initialization on startup
|
||||
@@ -96,6 +96,16 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
|
||||
this.cacheNames.add(cache.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a registered cache of the given name.
|
||||
* In contrast to {@link #getCache(String)}, this method does not trigger
|
||||
* the lazy creation of missing caches via {@link #getMissingCache(String)}.
|
||||
* @param name the cache identifier (must not be {@code null})
|
||||
* @return the associated Cache instance, or {@code null} if none found
|
||||
* @since 4.1
|
||||
* @see #getCache(String)
|
||||
* @see #getMissingCache(String)
|
||||
*/
|
||||
protected final Cache lookupCache(String name) {
|
||||
return this.cacheMap.get(name);
|
||||
}
|
||||
@@ -120,6 +130,7 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
|
||||
* @param name the name of the cache to retrieve
|
||||
* @return the missing cache or {@code null} if no such cache exists or could be
|
||||
* created
|
||||
* @since 4.1
|
||||
* @see #getCache(String)
|
||||
*/
|
||||
protected Cache getMissingCache(String name) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,13 +17,15 @@
|
||||
package org.springframework.context;
|
||||
|
||||
/**
|
||||
* Interface defining methods for start/stop lifecycle control.
|
||||
* A common interface defining methods for start/stop lifecycle control.
|
||||
* The typical use case for this is to control asynchronous processing.
|
||||
* <b>NOTE: This interface does not imply specific auto-startup semantics.
|
||||
* Consider implementing {@link SmartLifecycle} for that purpose.</b>
|
||||
*
|
||||
* <p>Can be implemented by both components (typically a Spring bean defined in
|
||||
* a Spring {@link org.springframework.beans.factory.BeanFactory}) and containers
|
||||
* (typically a Spring {@link ApplicationContext}). Containers will propagate
|
||||
* start/stop signals to all components that apply.
|
||||
* <p>Can be implemented by both components (typically a Spring bean defined in a
|
||||
* Spring context) and containers (typically a Spring {@link ApplicationContext}
|
||||
* itself). Containers will propagate start/stop signals to all components that
|
||||
* apply within each container, e.g. for a stop/restart scenario at runtime.
|
||||
*
|
||||
* <p>Can be used for direct invocations or for management operations via JMX.
|
||||
* In the latter case, the {@link org.springframework.jmx.export.MBeanExporter}
|
||||
@@ -32,10 +34,10 @@ package org.springframework.context;
|
||||
* restricting the visibility of activity-controlled components to the Lifecycle
|
||||
* interface.
|
||||
*
|
||||
* <p>Note that the Lifecycle interface is only supported on <b>top-level singleton beans</b>.
|
||||
* On any other component, the Lifecycle interface will remain undetected and hence ignored.
|
||||
* Also, note that the extended {@link SmartLifecycle} interface provides more sophisticated
|
||||
* integration with the container's startup and shutdown phases.
|
||||
* <p>Note that the Lifecycle interface is only supported on <b>top-level singleton
|
||||
* beans</b>. On any other component, the Lifecycle interface will remain undetected
|
||||
* and hence ignored. Also, note that the extended {@link SmartLifecycle} interface
|
||||
* provides integration with the application context's startup and shutdown phases.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
@@ -51,6 +53,7 @@ public interface Lifecycle {
|
||||
* Should not throw an exception if the component is already running.
|
||||
* <p>In the case of a container, this will propagate the start signal
|
||||
* to all components that apply.
|
||||
* @see SmartLifecycle#isAutoStartup()
|
||||
*/
|
||||
void start();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,8 @@
|
||||
package org.springframework.context;
|
||||
|
||||
/**
|
||||
* An extension of the {@link Lifecycle} interface for those objects that require to be
|
||||
* started upon ApplicationContext refresh and/or shutdown in a particular order.
|
||||
* An extension of the {@link Lifecycle} interface for those objects that require to
|
||||
* be started upon ApplicationContext refresh and/or shutdown in a particular order.
|
||||
* The {@link #isAutoStartup()} return value indicates whether this object should
|
||||
* be started at the time of a context refresh. The callback-accepting
|
||||
* {@link #stop(Runnable)} method is useful for objects that have an asynchronous
|
||||
@@ -55,26 +55,37 @@ package org.springframework.context;
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 3.0
|
||||
* @see LifecycleProcessor
|
||||
* @see ConfigurableApplicationContext
|
||||
*/
|
||||
public interface SmartLifecycle extends Lifecycle, Phased {
|
||||
|
||||
/**
|
||||
* Return whether this Lifecycle component should be started automatically
|
||||
* by the container when the ApplicationContext is refreshed. A value of
|
||||
* "false" indicates that the component is intended to be started manually.
|
||||
* Returns {@code true} if this {@code Lifecycle} component should get
|
||||
* started automatically by the container at the time that the containing
|
||||
* {@link ApplicationContext} gets refreshed.
|
||||
* <p>A value of {@code false} indicates that the component is intended to
|
||||
* be started through an explicit {@link #start()} call instead, analogous
|
||||
* to a plain {@link Lifecycle} implementation.
|
||||
* @see #start()
|
||||
* @see #getPhase()
|
||||
* @see LifecycleProcessor#onRefresh()
|
||||
* @see ConfigurableApplicationContext#refresh()
|
||||
*/
|
||||
boolean isAutoStartup();
|
||||
|
||||
/**
|
||||
* Indicates that a Lifecycle component must stop if it is currently running.
|
||||
* <p>The provided callback is used by the {@link LifecycleProcessor} to support an
|
||||
* ordered, and potentially concurrent, shutdown of all components having a
|
||||
* <p>The provided callback is used by the {@link LifecycleProcessor} to support
|
||||
* an ordered, and potentially concurrent, shutdown of all components having a
|
||||
* common shutdown order value. The callback <b>must</b> be executed after
|
||||
* the SmartLifecycle component does indeed stop.
|
||||
* <p>The {@code LifecycleProcessor} will call <i>only</i> this variant of the
|
||||
* the {@code SmartLifecycle} component does indeed stop.
|
||||
* <p>The {@link LifecycleProcessor} will call <i>only</i> this variant of the
|
||||
* {@code stop} method; i.e. {@link Lifecycle#stop()} will not be called for
|
||||
* {@link SmartLifecycle} implementations unless explicitly delegated to within
|
||||
* this method.
|
||||
* {@code SmartLifecycle} implementations unless explicitly delegated to within
|
||||
* the implementation of this method.
|
||||
* @see #stop()
|
||||
* @see #getPhase()
|
||||
*/
|
||||
void stop(Runnable callback);
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
/*
|
||||
* Copyright 2002-2015 the original author 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,9 +28,9 @@ import org.springframework.util.Assert;
|
||||
* based on an {@link AdviceMode} value from an annotation (such as the {@code @Enable*}
|
||||
* annotations).
|
||||
*
|
||||
* @param <A> Annotation containing {@linkplain #getAdviceModeAttributeName() AdviceMode attribute}
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @param <A> annotation containing {@linkplain #getAdviceModeAttributeName() AdviceMode attribute}
|
||||
*/
|
||||
public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
|
||||
|
||||
|
||||
+9
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,10 +25,10 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link ScopeMetadataResolver} implementation that by default checks for
|
||||
* the presence of Spring's {@link Scope} annotation on the bean class.
|
||||
* the presence of Spring's {@link Scope @Scope} annotation on the bean class.
|
||||
*
|
||||
* <p>The exact type of annotation that is checked for is configurable via the
|
||||
* {@link #setScopeAnnotationType(Class)} property.
|
||||
* <p>The exact type of annotation that is checked for is configurable via
|
||||
* {@link #setScopeAnnotationType(Class)}.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
@@ -43,7 +43,7 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
|
||||
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@code AnnotationScopeMetadataResolver} class.
|
||||
* Construct a new {@code AnnotationScopeMetadataResolver}.
|
||||
* @see #AnnotationScopeMetadataResolver(ScopedProxyMode)
|
||||
* @see ScopedProxyMode#NO
|
||||
*/
|
||||
@@ -52,8 +52,9 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@code AnnotationScopeMetadataResolver} class.
|
||||
* @param defaultProxyMode the desired scoped-proxy mode
|
||||
* Construct a new {@code AnnotationScopeMetadataResolver} using the
|
||||
* supplied default {@link ScopedProxyMode}.
|
||||
* @param defaultProxyMode the default scoped-proxy mode
|
||||
*/
|
||||
public AnnotationScopeMetadataResolver(ScopedProxyMode defaultProxyMode) {
|
||||
Assert.notNull(defaultProxyMode, "'defaultProxyMode' must not be null");
|
||||
@@ -63,7 +64,7 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
|
||||
|
||||
/**
|
||||
* Set the type of annotation that is checked for by this
|
||||
* {@link AnnotationScopeMetadataResolver}.
|
||||
* {@code AnnotationScopeMetadataResolver}.
|
||||
* @param scopeAnnotationType the target annotation type
|
||||
*/
|
||||
public void setScopeAnnotationType(Class<? extends Annotation> scopeAnnotationType) {
|
||||
|
||||
+1
-1
@@ -218,7 +218,7 @@ import org.springframework.stereotype.Component;
|
||||
* {@code <bean>} definitions within Spring XML files. It is also possible to
|
||||
* import Spring XML configuration files into {@code @Configuration} classes using
|
||||
* the {@link ImportResource @ImportResource} annotation. Bean definitions imported from XML can be
|
||||
* injected using {@code @Autowired} or {@code @Import}:
|
||||
* injected using {@code @Autowired} or {@code @Inject}:
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @ImportResource("classpath:/com/acme/database-config.xml")
|
||||
|
||||
+4
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
@@ -63,6 +64,8 @@ final class ConfigurationClass {
|
||||
private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
|
||||
new LinkedHashMap<ImportBeanDefinitionRegistrar, AnnotationMetadata>();
|
||||
|
||||
final Set<String> skippedBeanMethods = new HashSet<String>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@link ConfigurationClass} with the given name.
|
||||
|
||||
+29
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -168,7 +168,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
|
||||
configClass.setBeanName(configBeanName);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Registered bean definition for imported @Configuration class %s", configBeanName));
|
||||
logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -182,33 +182,25 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
* with the BeanDefinitionRegistry based on its contents.
|
||||
*/
|
||||
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
|
||||
if (this.conditionEvaluator.shouldSkip(beanMethod.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigurationClass configClass = beanMethod.getConfigurationClass();
|
||||
MethodMetadata metadata = beanMethod.getMetadata();
|
||||
String methodName = metadata.getMethodName();
|
||||
|
||||
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
|
||||
beanDef.setResource(configClass.getResource());
|
||||
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
|
||||
if (metadata.isStatic()) {
|
||||
// static @Bean method
|
||||
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
|
||||
beanDef.setFactoryMethodName(metadata.getMethodName());
|
||||
// Do we need to mark the bean as skipped by its condition?
|
||||
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
|
||||
configClass.skippedBeanMethods.add(methodName);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// instance @Bean method
|
||||
beanDef.setFactoryBeanName(configClass.getBeanName());
|
||||
beanDef.setUniqueFactoryMethodName(metadata.getMethodName());
|
||||
if (configClass.skippedBeanMethods.contains(methodName)) {
|
||||
return;
|
||||
}
|
||||
beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
|
||||
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
|
||||
|
||||
// Consider name and any aliases
|
||||
AnnotationAttributes bean = AnnotationConfigUtils.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());
|
||||
String beanName = (names.size() > 0 ? names.remove(0) : methodName);
|
||||
|
||||
// Register aliases even when overridden
|
||||
for (String alias : names) {
|
||||
this.registry.registerAlias(beanName, alias);
|
||||
}
|
||||
@@ -218,6 +210,23 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
|
||||
beanDef.setResource(configClass.getResource());
|
||||
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
|
||||
|
||||
if (metadata.isStatic()) {
|
||||
// static @Bean method
|
||||
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
|
||||
beanDef.setFactoryMethodName(methodName);
|
||||
}
|
||||
else {
|
||||
// instance @Bean method
|
||||
beanDef.setFactoryBeanName(configClass.getBeanName());
|
||||
beanDef.setUniqueFactoryMethodName(methodName);
|
||||
}
|
||||
beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
|
||||
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
|
||||
|
||||
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
|
||||
|
||||
Autowire autowire = bean.getEnum("autowire");
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -303,7 +303,7 @@ class ConfigurationClassEnhancer {
|
||||
"result in a failure to process annotations such as @Autowired, " +
|
||||
"@Resource and @PostConstruct within the method's declaring " +
|
||||
"@Configuration class. Add the 'static' modifier to this method to avoid " +
|
||||
"these container lifecycle issues; see @Bean javadoc for complete details",
|
||||
"these container lifecycle issues; see @Bean javadoc for complete details.",
|
||||
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
|
||||
}
|
||||
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
|
||||
|
||||
+35
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -73,6 +73,7 @@ import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -133,7 +134,7 @@ class ConfigurationClassParser {
|
||||
|
||||
private final ImportStack importStack = new ImportStack();
|
||||
|
||||
private final List<DeferredImportSelectorHolder> deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
|
||||
private List<DeferredImportSelectorHolder> deferredImportSelectors;
|
||||
|
||||
|
||||
/**
|
||||
@@ -156,6 +157,8 @@ class ConfigurationClassParser {
|
||||
|
||||
|
||||
public void parse(Set<BeanDefinitionHolder> configCandidates) {
|
||||
this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
|
||||
|
||||
for (BeanDefinitionHolder holder : configCandidates) {
|
||||
BeanDefinition bd = holder.getBeanDefinition();
|
||||
try {
|
||||
@@ -177,6 +180,7 @@ class ConfigurationClassParser {
|
||||
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
processDeferredImportSelectors();
|
||||
}
|
||||
|
||||
@@ -269,7 +273,7 @@ class ConfigurationClassParser {
|
||||
}
|
||||
|
||||
// Process any @Import annotations
|
||||
processImports(configClass, sourceClass, getImports(sourceClass), true, false);
|
||||
processImports(configClass, sourceClass, getImports(sourceClass), true);
|
||||
|
||||
// Process any @ImportResource annotations
|
||||
if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
|
||||
@@ -416,12 +420,15 @@ class ConfigurationClassParser {
|
||||
}
|
||||
|
||||
private void processDeferredImportSelectors() {
|
||||
Collections.sort(this.deferredImportSelectors, DEFERRED_IMPORT_COMPARATOR);
|
||||
for (DeferredImportSelectorHolder deferredImport : this.deferredImportSelectors) {
|
||||
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
|
||||
this.deferredImportSelectors = null;
|
||||
Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
|
||||
|
||||
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
|
||||
ConfigurationClass configClass = deferredImport.getConfigurationClass();
|
||||
try {
|
||||
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
|
||||
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false, true);
|
||||
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
|
||||
}
|
||||
catch (BeanDefinitionStoreException ex) {
|
||||
throw ex;
|
||||
@@ -431,18 +438,17 @@ class ConfigurationClassParser {
|
||||
configClass.getMetadata().getClassName() + "]", ex);
|
||||
}
|
||||
}
|
||||
this.deferredImportSelectors.clear();
|
||||
}
|
||||
|
||||
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
|
||||
Collection<SourceClass> importCandidates, boolean checkForCircularImports, boolean deferred) throws IOException {
|
||||
Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
|
||||
|
||||
if (importCandidates.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkForCircularImports && this.importStack.contains(configClass)) {
|
||||
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata()));
|
||||
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
|
||||
}
|
||||
else {
|
||||
this.importStack.push(configClass);
|
||||
@@ -453,14 +459,14 @@ class ConfigurationClassParser {
|
||||
Class<?> candidateClass = candidate.loadClass();
|
||||
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
|
||||
invokeAwareMethods(selector);
|
||||
if (!deferred && selector instanceof DeferredImportSelector) {
|
||||
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
|
||||
this.deferredImportSelectors.add(
|
||||
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
|
||||
}
|
||||
else {
|
||||
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
|
||||
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
|
||||
processImports(configClass, currentSourceClass, importSourceClasses, false, false);
|
||||
processImports(configClass, currentSourceClass, importSourceClasses, false);
|
||||
}
|
||||
}
|
||||
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
|
||||
@@ -474,7 +480,7 @@ class ConfigurationClassParser {
|
||||
}
|
||||
else {
|
||||
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
|
||||
// process it as a @Configuration class
|
||||
// process it as an @Configuration class
|
||||
this.importStack.registerImport(
|
||||
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
|
||||
processConfigurationClass(candidate.asConfigClass(configClass));
|
||||
@@ -615,7 +621,7 @@ class ConfigurationClassParser {
|
||||
@Override
|
||||
public AnnotationMetadata getImportingClassFor(String importedClass) {
|
||||
List<AnnotationMetadata> list = this.imports.get(importedClass);
|
||||
return (list == null || list.isEmpty() ? null : list.get(list.size() - 1));
|
||||
return (!CollectionUtils.isEmpty(list) ? list.get(list.size() - 1) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -629,7 +635,7 @@ class ConfigurationClassParser {
|
||||
Comparator<ConfigurationClass> comparator = new Comparator<ConfigurationClass>() {
|
||||
@Override
|
||||
public int compare(ConfigurationClass first, ConfigurationClass second) {
|
||||
return first.getMetadata().getClassName().equals(second.getMetadata().getClassName()) ? 0 : 1;
|
||||
return (first.getMetadata().getClassName().equals(second.getMetadata().getClassName()) ? 0 : 1);
|
||||
}
|
||||
};
|
||||
return (Collections.binarySearch(this, configClass, comparator) != -1);
|
||||
@@ -642,11 +648,11 @@ class ConfigurationClassParser {
|
||||
* <li>com.acme.Bar</li>
|
||||
* <li>com.acme.Baz</li>
|
||||
* </ul>
|
||||
* return "ImportStack: [Foo->Bar->Baz]".
|
||||
* return "[Foo->Bar->Baz]".
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder("ImportStack: [");
|
||||
StringBuilder builder = new StringBuilder("[");
|
||||
Iterator<ConfigurationClass> iterator = iterator();
|
||||
while (iterator.hasNext()) {
|
||||
builder.append(iterator.next().getSimpleName());
|
||||
@@ -750,7 +756,16 @@ class ConfigurationClassParser {
|
||||
String[] memberClassNames = sourceReader.getClassMetadata().getMemberClassNames();
|
||||
List<SourceClass> members = new ArrayList<SourceClass>(memberClassNames.length);
|
||||
for (String memberClassName : memberClassNames) {
|
||||
members.add(asSourceClass(memberClassName));
|
||||
try {
|
||||
members.add(asSourceClass(memberClassName));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// Let's skip it if it's not resolvable - we're just looking for candidates
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to resolve member class [" + memberClassName +
|
||||
"] - not considering it as a configuration class candidate");
|
||||
}
|
||||
}
|
||||
}
|
||||
return members;
|
||||
}
|
||||
@@ -829,12 +844,12 @@ class ConfigurationClassParser {
|
||||
*/
|
||||
private static class CircularImportProblem extends Problem {
|
||||
|
||||
public CircularImportProblem(ConfigurationClass attemptedImport, Stack<ConfigurationClass> importStack, AnnotationMetadata metadata) {
|
||||
public CircularImportProblem(ConfigurationClass attemptedImport, Stack<ConfigurationClass> importStack) {
|
||||
super(String.format("A circular @Import has been detected: " +
|
||||
"Illegal attempt by @Configuration class '%s' to import class '%s' as '%s' is " +
|
||||
"already present in the current import stack [%s]", importStack.peek().getSimpleName(),
|
||||
"already present in the current import stack %s", importStack.peek().getSimpleName(),
|
||||
attemptedImport.getSimpleName(), attemptedImport.getSimpleName(), importStack),
|
||||
new Location(importStack.peek().getResource(), metadata));
|
||||
new Location(importStack.peek().getResource(), attemptedImport.getMetadata()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -149,12 +149,24 @@ abstract class ConfigurationClassUtils {
|
||||
if (metadata.isInterface()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Any of the typical annotations found?
|
||||
for (String indicator : candidateIndicators) {
|
||||
if (metadata.isAnnotated(indicator)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return metadata.hasAnnotatedMethods(Bean.class.getName());
|
||||
|
||||
// Finally, let's look for @Bean methods...
|
||||
try {
|
||||
return metadata.hasAnnotatedMethods(Bean.class.getName());
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,16 +30,16 @@ import java.lang.annotation.Target;
|
||||
* one {@link Bean @Bean} method, as well as {@link ImportSelector} and
|
||||
* {@link ImportBeanDefinitionRegistrar} implementations.
|
||||
*
|
||||
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes
|
||||
* should be accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
|
||||
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes should be
|
||||
* accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
|
||||
* injection. Either the bean itself can be autowired, or the configuration class instance
|
||||
* declaring the bean can be autowired. The latter approach allows for explicit,
|
||||
* IDE-friendly navigation between {@code @Configuration} class methods.
|
||||
* declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly
|
||||
* navigation between {@code @Configuration} class methods.
|
||||
*
|
||||
* <p>May be declared at the class level or as a meta-annotation.
|
||||
*
|
||||
* <p>If XML or other non-{@code @Configuration} bean definition resources need to be
|
||||
* imported, use {@link ImportResource @ImportResource}
|
||||
* imported, use the {@link ImportResource @ImportResource} annotation instead.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.0
|
||||
@@ -57,4 +57,5 @@ public @interface Import {
|
||||
* {@link ImportBeanDefinitionRegistrar} classes to import.
|
||||
*/
|
||||
Class<?>[] value();
|
||||
|
||||
}
|
||||
|
||||
+12
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,9 +26,6 @@ import org.springframework.context.weaving.DefaultContextLoadTimeWeaver;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.instrument.classloading.LoadTimeWeaver;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import static org.springframework.context.weaving.AspectJWeavingEnabler.*;
|
||||
|
||||
/**
|
||||
* {@code @Configuration} class that registers a {@link LoadTimeWeaver} bean.
|
||||
@@ -47,7 +44,6 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
|
||||
|
||||
private AnnotationAttributes enableLTW;
|
||||
|
||||
@Autowired(required=false)
|
||||
private LoadTimeWeavingConfigurer ltwConfigurer;
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
@@ -56,8 +52,15 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
|
||||
@Override
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
this.enableLTW = AnnotationConfigUtils.attributesFor(importMetadata, EnableLoadTimeWeaving.class);
|
||||
Assert.notNull(this.enableLTW,
|
||||
"@EnableLoadTimeWeaving is not present on importing class " + importMetadata.getClassName());
|
||||
if (this.enableLTW == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"@EnableLoadTimeWeaving is not present on importing class " + importMetadata.getClassName());
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setLoadTimeWeavingConfigurer(LoadTimeWeavingConfigurer ltwConfigurer) {
|
||||
this.ltwConfigurer = ltwConfigurer;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,7 +69,7 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
|
||||
}
|
||||
|
||||
|
||||
@Bean(name=ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME)
|
||||
@Bean(name = ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public LoadTimeWeaver loadTimeWeaver() {
|
||||
LoadTimeWeaver loadTimeWeaver = null;
|
||||
@@ -87,7 +90,7 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
|
||||
// AJ weaving is disabled -> do nothing
|
||||
break;
|
||||
case AUTODETECT:
|
||||
if (this.beanClassLoader.getResource(ASPECTJ_AOP_XML_RESOURCE) == null) {
|
||||
if (this.beanClassLoader.getResource(AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE) == null) {
|
||||
// No aop.xml present on the classpath -> treat as 'disabled'
|
||||
break;
|
||||
}
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -51,7 +51,7 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
|
||||
|
||||
private static final String MBEAN_EXPORTER_BEAN_NAME = "mbeanExporter";
|
||||
|
||||
private AnnotationAttributes attributes;
|
||||
private AnnotationAttributes enableMBeanExport;
|
||||
|
||||
private Environment environment;
|
||||
|
||||
@@ -61,8 +61,8 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
|
||||
@Override
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
Map<String, Object> map = importMetadata.getAnnotationAttributes(EnableMBeanExport.class.getName());
|
||||
this.attributes = AnnotationAttributes.fromMap(map);
|
||||
if (this.attributes == null) {
|
||||
this.enableMBeanExport = AnnotationAttributes.fromMap(map);
|
||||
if (this.enableMBeanExport == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"@EnableMBeanExport is not present on importing class " + importMetadata.getClassName());
|
||||
}
|
||||
@@ -90,7 +90,7 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
|
||||
}
|
||||
|
||||
private void setupDomain(AnnotationMBeanExporter exporter) {
|
||||
String defaultDomain = this.attributes.getString("defaultDomain");
|
||||
String defaultDomain = this.enableMBeanExport.getString("defaultDomain");
|
||||
if (defaultDomain != null && this.environment != null) {
|
||||
defaultDomain = this.environment.resolvePlaceholders(defaultDomain);
|
||||
}
|
||||
@@ -100,7 +100,7 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
|
||||
}
|
||||
|
||||
private void setupServer(AnnotationMBeanExporter exporter) {
|
||||
String server = this.attributes.getString("server");
|
||||
String server = this.enableMBeanExport.getString("server");
|
||||
if (server != null && this.environment != null) {
|
||||
server = this.environment.resolvePlaceholders(server);
|
||||
}
|
||||
@@ -116,7 +116,7 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
|
||||
}
|
||||
|
||||
private void setupRegistrationPolicy(AnnotationMBeanExporter exporter) {
|
||||
RegistrationPolicy registrationPolicy = this.attributes.getEnum("registration");
|
||||
RegistrationPolicy registrationPolicy = this.enableMBeanExport.getEnum("registration");
|
||||
exporter.setRegistrationPolicy(registrationPolicy);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,16 +28,16 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
* Indicates the 'role' hint for a given bean.
|
||||
*
|
||||
* <p>May be used on any class directly or indirectly annotated with
|
||||
* {@link org.springframework.stereotype.Component} or on methods annotated with
|
||||
* {@link Bean}.
|
||||
* {@link org.springframework.stereotype.Component} or on methods
|
||||
* annotated with {@link Bean}.
|
||||
*
|
||||
* <p>If this annotation is not present on a Component or Bean definition, the
|
||||
* default value of {@link BeanDefinition#ROLE_APPLICATION} will apply.
|
||||
* <p>If this annotation is not present on a Component or Bean definition,
|
||||
* the default value of {@link BeanDefinition#ROLE_APPLICATION} will apply.
|
||||
*
|
||||
* <p>If Role is present on a {@link Configuration @Configuration} class, this
|
||||
* indicates the role of the configuration class bean definition and does not
|
||||
* cascade to all @{@code Bean} methods defined within. This behavior is
|
||||
* different than that of the @{@link Lazy} annotation, for example.
|
||||
* <p>If Role is present on a {@link Configuration @Configuration} class,
|
||||
* this indicates the role of the configuration class bean definition and
|
||||
* does not cascade to all @{@code Bean} methods defined within. This behavior
|
||||
* is different than that of the @{@link Lazy} annotation, for example.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,8 +37,8 @@ class PropertyOverrideBeanDefinitionParser extends AbstractPropertyLoadingBeanDe
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, BeanDefinitionBuilder builder) {
|
||||
|
||||
super.doParse(element, builder);
|
||||
|
||||
builder.addPropertyValue("ignoreInvalidKeys",
|
||||
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
|
||||
|
||||
|
||||
+3
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2015 the original author 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,8 +34,10 @@ import org.springframework.util.StringUtils;
|
||||
class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
|
||||
|
||||
private static final String SYSTEM_PROPERTIES_MODE_ATTRIB = "system-properties-mode";
|
||||
|
||||
private static final String SYSTEM_PROPERTIES_MODE_DEFAULT = "ENVIRONMENT";
|
||||
|
||||
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
// As of Spring 3.1, the default value of system-properties-mode has changed from
|
||||
|
||||
+53
-45
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,6 +28,7 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.support.AbstractBeanFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.core.OrderComparator;
|
||||
@@ -65,47 +66,8 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private Object retrievalMutex = this.defaultRetriever;
|
||||
|
||||
@Override
|
||||
public void addApplicationListener(ApplicationListener<?> listener) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
this.defaultRetriever.applicationListeners.add(listener);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addApplicationListenerBean(String listenerBeanName) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeApplicationListener(ApplicationListener<?> listener) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
this.defaultRetriever.applicationListeners.remove(listener);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeApplicationListenerBean(String listenerBeanName) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllListeners() {
|
||||
synchronized (this.defaultRetriever) {
|
||||
this.defaultRetriever.applicationListeners.clear();
|
||||
this.defaultRetriever.applicationListenerBeans.clear();
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
@@ -118,6 +80,9 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
if (this.beanClassLoader == null && beanFactory instanceof ConfigurableBeanFactory) {
|
||||
this.beanClassLoader = ((ConfigurableBeanFactory) beanFactory).getBeanClassLoader();
|
||||
}
|
||||
if (beanFactory instanceof AbstractBeanFactory) {
|
||||
this.retrievalMutex = ((AbstractBeanFactory) beanFactory).getSingletonMutex();
|
||||
}
|
||||
}
|
||||
|
||||
private BeanFactory getBeanFactory() {
|
||||
@@ -129,13 +94,55 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addApplicationListener(ApplicationListener<?> listener) {
|
||||
synchronized (this.retrievalMutex) {
|
||||
this.defaultRetriever.applicationListeners.add(listener);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addApplicationListenerBean(String listenerBeanName) {
|
||||
synchronized (this.retrievalMutex) {
|
||||
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeApplicationListener(ApplicationListener<?> listener) {
|
||||
synchronized (this.retrievalMutex) {
|
||||
this.defaultRetriever.applicationListeners.remove(listener);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeApplicationListenerBean(String listenerBeanName) {
|
||||
synchronized (this.retrievalMutex) {
|
||||
this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllListeners() {
|
||||
synchronized (this.retrievalMutex) {
|
||||
this.defaultRetriever.applicationListeners.clear();
|
||||
this.defaultRetriever.applicationListenerBeans.clear();
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a Collection containing all ApplicationListeners.
|
||||
* @return a Collection of ApplicationListeners
|
||||
* @see org.springframework.context.ApplicationListener
|
||||
*/
|
||||
protected Collection<ApplicationListener<?>> getApplicationListeners() {
|
||||
synchronized (this.defaultRetriever) {
|
||||
synchronized (this.retrievalMutex) {
|
||||
return this.defaultRetriever.getApplicationListeners();
|
||||
}
|
||||
}
|
||||
@@ -163,13 +170,14 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
|
||||
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
|
||||
// Fully synchronized building and caching of a ListenerRetriever
|
||||
synchronized (this.defaultRetriever) {
|
||||
synchronized (this.retrievalMutex) {
|
||||
retriever = this.retrieverCache.get(cacheKey);
|
||||
if (retriever != null) {
|
||||
return retriever.getApplicationListeners();
|
||||
}
|
||||
retriever = new ListenerRetriever(true);
|
||||
Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(event, sourceType, retriever);
|
||||
Collection<ApplicationListener<?>> listeners =
|
||||
retrieveApplicationListeners(event, sourceType, retriever);
|
||||
this.retrieverCache.put(cacheKey, retriever);
|
||||
return listeners;
|
||||
}
|
||||
@@ -193,7 +201,7 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>();
|
||||
Set<ApplicationListener<?>> listeners;
|
||||
Set<String> listenerBeans;
|
||||
synchronized (this.defaultRetriever) {
|
||||
synchronized (this.retrievalMutex) {
|
||||
listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners);
|
||||
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
|
||||
}
|
||||
|
||||
+18
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -162,6 +162,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
/** Parent context */
|
||||
private ApplicationContext parent;
|
||||
|
||||
/** Environment used by this context */
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
/** BeanFactoryPostProcessors to apply on refresh */
|
||||
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors =
|
||||
new ArrayList<BeanFactoryPostProcessor>();
|
||||
@@ -194,10 +197,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
private ApplicationEventMulticaster applicationEventMulticaster;
|
||||
|
||||
/** Statically specified listeners */
|
||||
private Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
|
||||
|
||||
/** Environment used by this context; initialized by {@link #createEnvironment()} */
|
||||
private ConfigurableEnvironment environment;
|
||||
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -352,7 +352,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
* @return the internal LifecycleProcessor (never {@code null})
|
||||
* @throws IllegalStateException if the context has not been initialized yet
|
||||
*/
|
||||
LifecycleProcessor getLifecycleProcessor() {
|
||||
LifecycleProcessor getLifecycleProcessor() throws IllegalStateException {
|
||||
if (this.lifecycleProcessor == null) {
|
||||
throw new IllegalStateException("LifecycleProcessor not initialized - " +
|
||||
"call 'refresh' before invoking lifecycle methods via the context: " + this);
|
||||
@@ -484,7 +484,10 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
}
|
||||
|
||||
catch (BeansException ex) {
|
||||
logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Exception encountered during context initialization - " +
|
||||
"cancelling refresh attempt: " + ex);
|
||||
}
|
||||
|
||||
// Destroy already created singletons to avoid dangling resources.
|
||||
destroyBeans();
|
||||
@@ -504,6 +507,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
*/
|
||||
protected void prepareRefresh() {
|
||||
this.startupDate = System.currentTimeMillis();
|
||||
this.closed.set(false);
|
||||
this.active.set(true);
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
@@ -721,11 +725,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
for (ApplicationListener<?> listener : getApplicationListeners()) {
|
||||
getApplicationEventMulticaster().addApplicationListener(listener);
|
||||
}
|
||||
|
||||
// Do not initialize FactoryBeans here: We need to leave all regular beans
|
||||
// uninitialized to let post-processors apply to them!
|
||||
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
|
||||
for (String lisName : listenerBeanNames) {
|
||||
getApplicationEventMulticaster().addApplicationListenerBean(lisName);
|
||||
for (String listenerBeanName : listenerBeanNames) {
|
||||
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,7 +806,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
this.shutdownHook = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
doClose();
|
||||
synchronized (startupShutdownMonitor) {
|
||||
doClose();
|
||||
}
|
||||
}
|
||||
};
|
||||
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
|
||||
@@ -1178,7 +1185,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return getLifecycleProcessor().isRunning();
|
||||
return (this.lifecycleProcessor != null && this.lifecycleProcessor.isRunning());
|
||||
}
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user