mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
242 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d85e7f81e | |||
| 940f57d023 | |||
| 29799be474 | |||
| 67979c93c3 | |||
| 4ae3ab14ec | |||
| 81f0d76f3d | |||
| 9f1e822f3e | |||
| b4baa86bfa | |||
| 81be4c22d0 | |||
| a17c2ccb4e | |||
| 64df93168d | |||
| 27c5480c82 | |||
| 594ec8f8a9 | |||
| c09b2513e0 | |||
| 6c22f7ef5e | |||
| 236623f630 | |||
| e18fba1626 | |||
| 070c596a66 | |||
| 7a9bf1578e | |||
| 8a150ee3a4 | |||
| 6051f4ecbd | |||
| 698e74f7cd | |||
| 51079a40ae | |||
| 94ac2e4de7 | |||
| 271a9097ac | |||
| 3c030edbf2 | |||
| 059cff52b7 | |||
| 619a3edae5 | |||
| eb3811e590 | |||
| f011e58f90 | |||
| 7325a863bb | |||
| fe26b7d3fd | |||
| cfdceae70f | |||
| 17647801aa | |||
| 33476a2eae | |||
| a8091b916b | |||
| 396fdf125f | |||
| 085825fbc0 | |||
| b0c6e5e322 | |||
| a7efa9659a | |||
| f7605eaf58 | |||
| ce67b89861 | |||
| 736af46fc0 | |||
| a495bd6679 | |||
| 7c33c70742 | |||
| 81c1b60f19 | |||
| 3703be5aaf | |||
| b929edb221 | |||
| 50803ce142 | |||
| 346445ee7e | |||
| e238c8a87c | |||
| 9e99fd5df2 | |||
| 990c74b1e2 | |||
| 37bda566eb | |||
| 322babc04a | |||
| 4e720e8104 | |||
| fdab75a1d8 | |||
| 240cfb1224 | |||
| db2786264b | |||
| 763fa98bdf | |||
| 25cbc263f0 | |||
| 9949a91048 | |||
| d8b7a593c5 | |||
| d3d8f1a487 | |||
| a637f6a27c | |||
| e9416b369e | |||
| cde95e1446 | |||
| da4e37dc1d | |||
| 010d0947c7 | |||
| 5b06c23a1b | |||
| 7881329cf7 | |||
| 58aa0659cc | |||
| dbbedc6c86 | |||
| 09c1e986b9 | |||
| 10bff054a9 | |||
| e713e0d6d5 | |||
| b4f8fc8177 | |||
| 8c3cdc6118 | |||
| 01827fd8d2 | |||
| af1d721aa3 | |||
| 0acb1e5513 | |||
| a9dec6a4af | |||
| bb4e802af5 | |||
| d91b66a04c | |||
| b6dae6acba | |||
| f50c2caf59 | |||
| d12996a6a8 | |||
| 188a5a086b | |||
| 449377908f | |||
| c840ba9989 | |||
| 9d70d2023c | |||
| 82835b99ec | |||
| 4726663f81 | |||
| 86af93a504 | |||
| fb4363e4e0 | |||
| 6946fe2f74 | |||
| db9e0b0ccb | |||
| f7ec92c647 | |||
| 7bee3d1574 | |||
| db3d537e72 | |||
| a0727191e1 | |||
| 5ab1097b43 | |||
| d77ecb26a9 | |||
| c45b106d95 | |||
| 431ec906c4 | |||
| 1d96f6a266 | |||
| 7b6293fa05 | |||
| cd7e5f61f0 | |||
| 06b6a4be16 | |||
| f3f19504c6 | |||
| 72b2dda17f | |||
| e176c4e799 | |||
| 690e219fe8 | |||
| 66a67ec807 | |||
| 69c330d905 | |||
| ec9de943ee | |||
| eb11c6fa23 | |||
| ca7fb23432 | |||
| f83bb7183e | |||
| 1745a3f25d | |||
| e417318915 | |||
| 2533ba5253 | |||
| e44b08f1fc | |||
| 86f2ebec1b | |||
| 7ad60d385b | |||
| 4b9c3fa739 | |||
| b322cbd625 | |||
| d022fcf32f | |||
| e028ef8170 | |||
| 6e4fcb69f0 | |||
| 392ad09990 | |||
| 21cb9e8bff | |||
| c83f6adc24 | |||
| d9da663f6d | |||
| c04400890f | |||
| bf00db3c6c | |||
| f5d36aa47a | |||
| a532c527dd | |||
| a5a4960859 | |||
| 2342f5f48a | |||
| f5d7161d6b | |||
| 82e64af5a5 | |||
| c1617d3c52 | |||
| 9dfef59af2 | |||
| a6daed1b71 | |||
| 28df426798 | |||
| 845cb715e7 | |||
| f010368a66 | |||
| 3ec4538981 | |||
| 3c84863271 | |||
| c2f6a98c90 | |||
| 49d65d5c41 | |||
| 16d125ce76 | |||
| dccc78146a | |||
| dde79a9b65 | |||
| 49356b2c0f | |||
| 852718ec0e | |||
| 07d2c08f48 | |||
| ed3b7cd10f | |||
| 4d1d60ac42 | |||
| c6cc6705ef | |||
| ae1d15c8f4 | |||
| d616c6632d | |||
| 94c91c9e9c | |||
| b6ff12d2f5 | |||
| b1d84067cd | |||
| c19fc9d53f | |||
| 899761f0a8 | |||
| f88759c3c9 | |||
| 4f0f29880f | |||
| 4b211fb18c | |||
| e797398b10 | |||
| 613b05d814 | |||
| 939c76c4a5 | |||
| 40bf83c9e5 | |||
| c368ce8223 | |||
| 670b9fd60b | |||
| c2363a6ef9 | |||
| cdfdc340d2 | |||
| 7bd6b8d279 | |||
| 141470ff58 | |||
| d62202f464 | |||
| bcdc2503fa | |||
| 3a73533b1c | |||
| d8c420ab75 | |||
| 97d84d9ab8 | |||
| ae4160e131 | |||
| bb9e79daa7 | |||
| 6d9d4157ef | |||
| 387eddcf75 | |||
| 71e70aed14 | |||
| a8b295c516 | |||
| cf2e0c7959 | |||
| 589060d10f | |||
| 60fa704f78 | |||
| f43c39c905 | |||
| 6f0461c569 | |||
| 04df9b8f49 | |||
| 0d4040aa63 | |||
| 148dc95eb1 | |||
| d939016a09 | |||
| a83529c844 | |||
| 32e851617e | |||
| 93e5214d01 | |||
| 9bf5cba3c2 | |||
| 7d56c303a4 | |||
| bd65762582 | |||
| 6a7e58ac82 | |||
| e25e690ad4 | |||
| a614abe17b | |||
| 292f581cdd | |||
| 686f5d4a5e | |||
| 3b9558a269 | |||
| 692c5f292d | |||
| 7fdb33a105 | |||
| 8dd285f877 | |||
| 94eee6a32a | |||
| 96a4e1150e | |||
| 6acbc5093a | |||
| 0501999e43 | |||
| b6842730f7 | |||
| 5cb2cc2466 | |||
| 96da1ff9ea | |||
| 40fc472c70 | |||
| 7a31885ae5 | |||
| 91d1383e93 | |||
| 969aa8ad47 | |||
| 482adb9478 | |||
| 5a12e7b2c5 | |||
| 5576321b04 | |||
| 785ab5798a | |||
| 89bb9cb749 | |||
| 9b0729007f | |||
| 7dbf42e858 | |||
| 83a95832e6 | |||
| b841e8560c | |||
| 2b3fdfabb2 | |||
| 5442d8779a | |||
| 650cbeee14 | |||
| 335c3d5db6 | |||
| ab859fcc96 | |||
| fc6b38a8f6 |
+37
-36
@@ -1,15 +1,16 @@
|
||||
plugins {
|
||||
id 'io.spring.dependency-management' version '1.0.8.RELEASE' apply false
|
||||
id 'io.spring.dependency-management' version '1.0.9.RELEASE' apply false
|
||||
id 'io.spring.ge.conventions' version '0.0.7'
|
||||
id 'io.spring.nohttp' version '0.0.5.RELEASE'
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.3.72' apply false
|
||||
id 'org.jetbrains.dokka' version '0.10.1' apply false
|
||||
id 'org.asciidoctor.jvm.convert' version '2.4.0'
|
||||
id 'io.spring.gradle-enterprise-conventions' version '0.0.2'
|
||||
id 'io.spring.nohttp' version '0.0.5.RELEASE'
|
||||
id 'de.undercouch.download' version '4.0.0'
|
||||
id 'org.asciidoctor.jvm.pdf' version '2.4.0'
|
||||
id 'de.undercouch.download' version '4.1.1'
|
||||
id "io.freefair.aspectj" version '4.1.6' apply false
|
||||
id "com.github.ben-manes.versions" version '0.28.0'
|
||||
id 'com.gradle.build-scan' version '3.2'
|
||||
id "com.jfrog.artifactory" version '4.12.0' apply false
|
||||
id "io.freefair.aspectj" version '4.1.1' apply false
|
||||
id "com.github.ben-manes.versions" version '0.24.0'
|
||||
}
|
||||
|
||||
apply from: "$rootDir/gradle/build-scan-user-data.gradle"
|
||||
@@ -26,31 +27,31 @@ configure(allprojects) { project ->
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.10.4"
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.10.5"
|
||||
mavenBom "io.netty:netty-bom:4.1.51.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:Dysprosium-SR10"
|
||||
mavenBom "io.rsocket:rsocket-bom:1.0.1"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.30.v20200611"
|
||||
mavenBom "io.projectreactor:reactor-bom:Dysprosium-SR17"
|
||||
mavenBom "io.rsocket:rsocket-bom:1.0.3"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.31.v20200723"
|
||||
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.3.72"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.3.5"
|
||||
mavenBom "org.junit:junit-bom:5.6.2"
|
||||
mavenBom "org.junit:junit-bom:5.6.3"
|
||||
}
|
||||
dependencies {
|
||||
dependencySet(group: 'org.apache.logging.log4j', version: '2.13.3') {
|
||||
entry 'log4j-api'
|
||||
entry 'log4j-core'
|
||||
entry 'log4j-slf4j-impl'
|
||||
entry 'log4j-jul'
|
||||
entry 'log4j-slf4j-impl'
|
||||
}
|
||||
dependency "org.slf4j:slf4j-api:1.7.30"
|
||||
dependency "com.google.code.findbugs:jsr305:3.0.2"
|
||||
|
||||
dependencySet(group: 'org.aspectj', version: '1.9.5') {
|
||||
dependencySet(group: 'org.aspectj', version: '1.9.6') {
|
||||
entry 'aspectjrt'
|
||||
entry 'aspectjtools'
|
||||
entry 'aspectjweaver'
|
||||
}
|
||||
dependencySet(group: 'org.codehaus.groovy', version: '2.5.12') {
|
||||
dependencySet(group: 'org.codehaus.groovy', version: '2.5.13') {
|
||||
entry 'groovy'
|
||||
entry 'groovy-jsr223'
|
||||
entry 'groovy-templates'
|
||||
@@ -60,12 +61,12 @@ configure(allprojects) { project ->
|
||||
|
||||
dependency "io.reactivex:rxjava:1.3.8"
|
||||
dependency "io.reactivex:rxjava-reactive-streams:1.2.1"
|
||||
dependency "io.reactivex.rxjava2:rxjava:2.2.19"
|
||||
dependency "io.projectreactor.tools:blockhound:1.0.2.RELEASE"
|
||||
dependency "io.reactivex.rxjava2:rxjava:2.2.21"
|
||||
dependency "io.projectreactor.tools:blockhound:1.0.4.RELEASE"
|
||||
|
||||
dependency "com.caucho:hessian:4.0.63"
|
||||
dependency "com.fasterxml:aalto-xml:1.2.2"
|
||||
dependency("com.fasterxml.woodstox:woodstox-core:6.1.1") {
|
||||
dependency("com.fasterxml.woodstox:woodstox-core:6.2.3") {
|
||||
exclude group: "stax", name: "stax-api"
|
||||
}
|
||||
dependency "com.google.code.gson:gson:2.8.6"
|
||||
@@ -75,7 +76,7 @@ configure(allprojects) { project ->
|
||||
exclude group: "xpp3", name: "xpp3_min"
|
||||
exclude group: "xmlpull", name: "xmlpull"
|
||||
}
|
||||
dependency "org.apache.johnzon:johnzon-jsonb:1.2.8"
|
||||
dependency "org.apache.johnzon:johnzon-jsonb:1.2.10"
|
||||
dependency("org.codehaus.jettison:jettison:1.3.8") {
|
||||
exclude group: "stax", name: "stax-api"
|
||||
}
|
||||
@@ -84,11 +85,11 @@ configure(allprojects) { project ->
|
||||
entry 'jibx-run'
|
||||
}
|
||||
dependency "org.ogce:xpp3:1.1.6"
|
||||
dependency "org.yaml:snakeyaml:1.26"
|
||||
dependency "org.yaml:snakeyaml:1.27"
|
||||
|
||||
dependency "com.h2database:h2:1.4.200"
|
||||
dependency "com.github.ben-manes.caffeine:caffeine:2.8.5"
|
||||
dependency "com.github.librepdf:openpdf:1.3.20"
|
||||
dependency "com.github.ben-manes.caffeine:caffeine:2.8.8"
|
||||
dependency "com.github.librepdf:openpdf:1.3.25"
|
||||
dependency "com.rometools:rome:1.12.2"
|
||||
dependency "commons-io:commons-io:2.5"
|
||||
dependency "io.vavr:vavr:0.10.3"
|
||||
@@ -101,7 +102,7 @@ configure(allprojects) { project ->
|
||||
entry 'activemq-stomp'
|
||||
}
|
||||
dependency "org.apache.bcel:bcel:6.0"
|
||||
dependency "org.apache.commons:commons-pool2:2.8.0"
|
||||
dependency "org.apache.commons:commons-pool2:2.8.1"
|
||||
dependencySet(group: 'org.apache.derby', version: '10.14.2.0') {
|
||||
entry 'derby'
|
||||
entry 'derbyclient'
|
||||
@@ -109,15 +110,15 @@ configure(allprojects) { project ->
|
||||
dependency "org.apache.poi:poi-ooxml:4.1.2"
|
||||
dependency "org.apache-extras.beanshell:bsh:2.0b6"
|
||||
dependency "org.freemarker:freemarker:2.3.30"
|
||||
dependency "org.hsqldb:hsqldb:2.5.0"
|
||||
dependency "org.hsqldb:hsqldb:2.5.1"
|
||||
dependency "org.quartz-scheduler:quartz:2.3.2"
|
||||
dependency "org.codehaus.fabric3.api:commonj:1.1.0"
|
||||
dependency "net.sf.ehcache:ehcache:2.10.6"
|
||||
dependency "org.ehcache:jcache:1.0.1"
|
||||
dependency "org.ehcache:ehcache:3.4.0"
|
||||
dependency "org.hibernate:hibernate-core:5.4.18.Final"
|
||||
dependency "org.hibernate:hibernate-validator:6.1.5.Final"
|
||||
dependency "org.webjars:webjars-locator-core:0.45"
|
||||
dependency "org.hibernate:hibernate-core:5.4.28.Final"
|
||||
dependency "org.hibernate:hibernate-validator:6.1.7.Final"
|
||||
dependency "org.webjars:webjars-locator-core:0.46"
|
||||
dependency "org.webjars:underscorejs:1.8.3"
|
||||
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.37') {
|
||||
@@ -131,7 +132,7 @@ configure(allprojects) { project ->
|
||||
entry 'tomcat-embed-core'
|
||||
entry 'tomcat-embed-websocket'
|
||||
}
|
||||
dependencySet(group: 'io.undertow', version: '2.0.30.Final') {
|
||||
dependencySet(group: 'io.undertow', version: '2.0.32.Final') {
|
||||
entry 'undertow-core'
|
||||
entry('undertow-websockets-jsr') {
|
||||
exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec"
|
||||
@@ -146,7 +147,7 @@ configure(allprojects) { project ->
|
||||
entry 'okhttp'
|
||||
entry 'mockwebserver'
|
||||
}
|
||||
dependency("org.apache.httpcomponents:httpclient:4.5.12") {
|
||||
dependency("org.apache.httpcomponents:httpclient:4.5.13") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.apache.httpcomponents:httpasyncclient:4.1.4") {
|
||||
@@ -179,7 +180,7 @@ configure(allprojects) { project ->
|
||||
dependency "org.testng:testng:6.14.3"
|
||||
dependency "org.hamcrest:hamcrest:2.1"
|
||||
dependency "org.awaitility:awaitility:3.1.6"
|
||||
dependency "org.assertj:assertj-core:3.16.1"
|
||||
dependency "org.assertj:assertj-core:3.18.1"
|
||||
dependencySet(group: 'org.xmlunit', version: '2.6.2') {
|
||||
entry 'xmlunit-assertj'
|
||||
entry('xmlunit-matchers') {
|
||||
@@ -192,12 +193,12 @@ configure(allprojects) { project ->
|
||||
}
|
||||
entry 'mockito-junit-jupiter'
|
||||
}
|
||||
dependency "io.mockk:mockk:1.10.0"
|
||||
dependency "io.mockk:mockk:1.10.2"
|
||||
|
||||
dependency("net.sourceforge.htmlunit:htmlunit:2.42.0") {
|
||||
dependency("net.sourceforge.htmlunit:htmlunit:2.43.0") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.seleniumhq.selenium:htmlunit-driver:2.42.0") {
|
||||
dependency("org.seleniumhq.selenium:htmlunit-driver:2.43.1") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
|
||||
@@ -224,8 +225,8 @@ configure(allprojects) { project ->
|
||||
|
||||
dependency "com.ibm.websphere:uow:6.0.2.17"
|
||||
dependency "com.jamonapi:jamon:2.82"
|
||||
dependency "joda-time:joda-time:2.10.6"
|
||||
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.6"
|
||||
dependency "joda-time:joda-time:2.10.10"
|
||||
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.7"
|
||||
dependency "org.javamoney:moneta:1.3"
|
||||
|
||||
dependency "com.sun.activation:javax.activation:1.2.0"
|
||||
@@ -325,7 +326,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "8.34"
|
||||
toolVersion = "8.38"
|
||||
configDir = rootProject.file("src/checkstyle")
|
||||
}
|
||||
|
||||
@@ -366,7 +367,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/",
|
||||
"https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/",
|
||||
"https://junit.org/junit4/javadoc/4.12/",
|
||||
"https://junit.org/junit5/docs/5.6.2/api/"
|
||||
"https://junit.org/junit5/docs/5.6.3/api/"
|
||||
] as String[]
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=5.2.8.RELEASE
|
||||
version=5.2.13.RELEASE
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
+37
-26
@@ -130,29 +130,6 @@ asciidoctorj {
|
||||
}
|
||||
}
|
||||
fatalWarnings ".*"
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce the Spring Framework Reference documentation
|
||||
* from "src/docs/asciidoc" into "build/asciidoc/html5"
|
||||
*/
|
||||
asciidoctor {
|
||||
baseDirFollowsSourceDir()
|
||||
configurations 'asciidoctorExt'
|
||||
sources {
|
||||
include '*.adoc'
|
||||
}
|
||||
outputDir "$buildDir/docs/ref-docs/"
|
||||
resources {
|
||||
from(sourceDir) {
|
||||
include 'images/*', 'css/**', 'js/**'
|
||||
}
|
||||
from extractDocResources
|
||||
}
|
||||
logDocuments = true
|
||||
outputOptions {
|
||||
backends = ["html5", "pdf"]
|
||||
}
|
||||
options doctype: 'book', eruby: 'erubis'
|
||||
attributes([
|
||||
icons: 'font',
|
||||
@@ -171,10 +148,44 @@ asciidoctor {
|
||||
])
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the Spring Framework Reference documentation from "src/docs/asciidoc"
|
||||
* in "build/docs/ref-docs/html5".
|
||||
*/
|
||||
asciidoctor {
|
||||
baseDirFollowsSourceDir()
|
||||
configurations 'asciidoctorExt'
|
||||
sources {
|
||||
include '*.adoc'
|
||||
}
|
||||
outputDir "$buildDir/docs/ref-docs/html5"
|
||||
logDocuments = true
|
||||
resources {
|
||||
from(sourceDir) {
|
||||
include 'images/*', 'css/**', 'js/**'
|
||||
}
|
||||
from extractDocResources
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the Spring Framework Reference documentation from "src/docs/asciidoc"
|
||||
* in "build/docs/ref-docs/pdf".
|
||||
*/
|
||||
asciidoctorPdf {
|
||||
baseDirFollowsSourceDir()
|
||||
configurations 'asciidoctorExt'
|
||||
sources {
|
||||
include '*.adoc'
|
||||
}
|
||||
outputDir "$buildDir/docs/ref-docs/pdf"
|
||||
logDocuments = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Zip all docs (API and reference) into a single archive
|
||||
*/
|
||||
task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'dokka']) {
|
||||
task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'asciidoctorPdf', 'dokka']) {
|
||||
group = "Distribution"
|
||||
description = "Builds -${archiveClassifier} archive containing api and reference " +
|
||||
"for deployment at https://docs.spring.io/spring-framework/docs."
|
||||
@@ -187,10 +198,10 @@ task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'dokka']) {
|
||||
from (api) {
|
||||
into "javadoc-api"
|
||||
}
|
||||
from ("$asciidoctor.outputDir/html5") {
|
||||
from ("$asciidoctor.outputDir") {
|
||||
into "spring-framework-reference"
|
||||
}
|
||||
from ("$asciidoctor.outputDir/pdf") {
|
||||
from ("$asciidoctorPdf.outputDir") {
|
||||
into "spring-framework-reference/pdf"
|
||||
}
|
||||
from (dokka) {
|
||||
|
||||
+1
-2
@@ -29,12 +29,11 @@ eclipse.classpath.file.whenMerged { classpath ->
|
||||
classpath.entries.removeAll { entry -> (entry.path =~ /(?!.*?repack.*\.jar).*?\/([^\/]+)\/build\/libs\/[^\/]+\.jar/) }
|
||||
}
|
||||
|
||||
|
||||
// Use separate main/test outputs (prevents WTP from packaging test classes)
|
||||
eclipse.classpath.defaultOutputDir = file(project.name+"/bin/eclipse")
|
||||
eclipse.classpath.file.beforeMerged { classpath ->
|
||||
classpath.entries.findAll{ it instanceof SourceFolder }.each {
|
||||
if(it.output.startsWith("bin/")) {
|
||||
if (it.output.startsWith("bin/")) {
|
||||
it.output = null
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -10,8 +10,8 @@ include "spring-aop"
|
||||
include "spring-aspects"
|
||||
include "spring-beans"
|
||||
include "spring-context"
|
||||
include "spring-context-support"
|
||||
include "spring-context-indexer"
|
||||
include "spring-context-support"
|
||||
include "spring-core"
|
||||
include "kotlin-coroutines"
|
||||
project(':kotlin-coroutines').projectDir = file('spring-core/kotlin-coroutines')
|
||||
@@ -26,8 +26,8 @@ include "spring-oxm"
|
||||
include "spring-test"
|
||||
include "spring-tx"
|
||||
include "spring-web"
|
||||
include "spring-webmvc"
|
||||
include "spring-webflux"
|
||||
include "spring-webmvc"
|
||||
include "spring-websocket"
|
||||
include "framework-bom"
|
||||
include "integration-tests"
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -648,7 +648,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
}
|
||||
|
||||
if (tokens[currentIndex].endsWith(")")) {
|
||||
sb.append(tokens[currentIndex].substring(0, tokens[currentIndex].length() - 1));
|
||||
sb.append(tokens[currentIndex], 0, tokens[currentIndex].length() - 1);
|
||||
return new PointcutBody(numTokensConsumed, sb.toString().trim());
|
||||
}
|
||||
|
||||
|
||||
+6
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,10 +219,12 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
|
||||
@Override
|
||||
@Nullable
|
||||
public String[] getParameterNames() {
|
||||
if (this.parameterNames == null) {
|
||||
this.parameterNames = parameterNameDiscoverer.getParameterNames(getMethod());
|
||||
String[] parameterNames = this.parameterNames;
|
||||
if (parameterNames == null) {
|
||||
parameterNames = parameterNameDiscoverer.getParameterNames(getMethod());
|
||||
this.parameterNames = parameterNames;
|
||||
}
|
||||
return this.parameterNames;
|
||||
return parameterNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -97,7 +97,7 @@ public class BeanFactoryAspectJAdvisorsBuilder {
|
||||
}
|
||||
// We must be careful not to instantiate beans eagerly as in this case they
|
||||
// would be cached by the Spring container but would not have been weaved.
|
||||
Class<?> beanType = this.beanFactory.getType(beanName);
|
||||
Class<?> beanType = this.beanFactory.getType(beanName, false);
|
||||
if (beanType == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,13 +30,14 @@ public class AdviceEntry implements ParseState.Entry {
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link AdviceEntry} class.
|
||||
* @param kind the kind of advice represented by this entry (before, after, around, etc.)
|
||||
* Create a new {@code AdviceEntry} instance.
|
||||
* @param kind the kind of advice represented by this entry (before, after, around)
|
||||
*/
|
||||
public AdviceEntry(String kind) {
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Advice (" + this.kind + ")";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,13 +30,14 @@ public class AdvisorEntry implements ParseState.Entry {
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link AdvisorEntry} class.
|
||||
* Create a new {@code AdvisorEntry} instance.
|
||||
* @param name the bean name of the advisor
|
||||
*/
|
||||
public AdvisorEntry(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Advisor '" + this.name + "'";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,7 +34,7 @@ public class AspectEntry implements ParseState.Entry {
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AspectEntry.
|
||||
* Create a new {@code AspectEntry} instance.
|
||||
* @param id the id of the aspect element
|
||||
* @param ref the bean name referenced by this aspect element
|
||||
*/
|
||||
@@ -43,6 +43,7 @@ public class AspectEntry implements ParseState.Entry {
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Aspect: " + (StringUtils.hasLength(this.id) ? "id='" + this.id + "'" : "ref='" + this.ref + "'");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,14 +28,16 @@ public class PointcutEntry implements ParseState.Entry {
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link PointcutEntry} class.
|
||||
* Create a new {@code PointcutEntry} instance.
|
||||
* @param name the bean name of the pointcut
|
||||
*/
|
||||
public PointcutEntry(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Pointcut '" + this.name + "'";
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,7 +59,8 @@ public abstract aspect AbstractTransactionAspect extends TransactionAspectSuppor
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
clearTransactionManagerCache(); // An aspect is basically a singleton
|
||||
// An aspect is basically a singleton -> cleanup on destruction
|
||||
clearTransactionManagerCache();
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
|
||||
@@ -25,6 +25,7 @@ sourceSets {
|
||||
compileGroovy {
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
options.compilerArgs += "-Werror"
|
||||
}
|
||||
|
||||
// This module also builds Kotlin code and the compileKotlin task naturally depends on
|
||||
|
||||
+6
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -422,9 +422,12 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw createNotWritablePropertyException(tokens.canonicalName);
|
||||
if (this.suppressNotWritablePropertyException) {
|
||||
// Optimization for common ignoreUnknown=true scenario since the
|
||||
// exception would be caught and swallowed higher up anyway...
|
||||
return;
|
||||
}
|
||||
throw createNotWritablePropertyException(tokens.canonicalName);
|
||||
}
|
||||
|
||||
Object oldValue = null;
|
||||
@@ -806,7 +809,6 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
* @param propertyPath property path, which may be nested
|
||||
* @return a property accessor for the target bean
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // avoid nested generic
|
||||
protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {
|
||||
int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
|
||||
// Handle nested properties recursively.
|
||||
|
||||
+33
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,6 +40,8 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
|
||||
|
||||
private boolean autoGrowNestedPaths = false;
|
||||
|
||||
boolean suppressNotWritablePropertyException = false;
|
||||
|
||||
|
||||
@Override
|
||||
public void setExtractOldValueForEditor(boolean extractOldValueForEditor) {
|
||||
@@ -89,30 +91,41 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
|
||||
List<PropertyAccessException> propertyAccessExceptions = null;
|
||||
List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
|
||||
((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
|
||||
for (PropertyValue pv : propertyValues) {
|
||||
try {
|
||||
// This method may throw any BeansException, which won't be caught
|
||||
|
||||
if (ignoreUnknown) {
|
||||
this.suppressNotWritablePropertyException = true;
|
||||
}
|
||||
try {
|
||||
for (PropertyValue pv : propertyValues) {
|
||||
// setPropertyValue may throw any BeansException, which won't be caught
|
||||
// here, if there is a critical failure such as no matching field.
|
||||
// We can attempt to deal only with less serious exceptions.
|
||||
setPropertyValue(pv);
|
||||
}
|
||||
catch (NotWritablePropertyException ex) {
|
||||
if (!ignoreUnknown) {
|
||||
throw ex;
|
||||
try {
|
||||
setPropertyValue(pv);
|
||||
}
|
||||
// Otherwise, just ignore it and continue...
|
||||
}
|
||||
catch (NullValueInNestedPathException ex) {
|
||||
if (!ignoreInvalid) {
|
||||
throw ex;
|
||||
catch (NotWritablePropertyException ex) {
|
||||
if (!ignoreUnknown) {
|
||||
throw ex;
|
||||
}
|
||||
// Otherwise, just ignore it and continue...
|
||||
}
|
||||
// Otherwise, just ignore it and continue...
|
||||
}
|
||||
catch (PropertyAccessException ex) {
|
||||
if (propertyAccessExceptions == null) {
|
||||
propertyAccessExceptions = new ArrayList<>();
|
||||
catch (NullValueInNestedPathException ex) {
|
||||
if (!ignoreInvalid) {
|
||||
throw ex;
|
||||
}
|
||||
// Otherwise, just ignore it and continue...
|
||||
}
|
||||
propertyAccessExceptions.add(ex);
|
||||
catch (PropertyAccessException ex) {
|
||||
if (propertyAccessExceptions == null) {
|
||||
propertyAccessExceptions = new ArrayList<>();
|
||||
}
|
||||
propertyAccessExceptions.add(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (ignoreUnknown) {
|
||||
this.suppressNotWritablePropertyException = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +227,6 @@ public abstract class BeanUtils {
|
||||
* @since 5.0
|
||||
* @see <a href="https://kotlinlang.org/docs/reference/classes.html#constructors">Kotlin docs</a>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
@@ -442,8 +441,7 @@ public abstract class BeanUtils {
|
||||
* @throws BeansException if PropertyDescriptor look fails
|
||||
*/
|
||||
public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws BeansException {
|
||||
CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);
|
||||
return cr.getPropertyDescriptors();
|
||||
return CachedIntrospectionResults.forClass(clazz).getPropertyDescriptors();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,11 +452,8 @@ public abstract class BeanUtils {
|
||||
* @throws BeansException if PropertyDescriptor lookup fails
|
||||
*/
|
||||
@Nullable
|
||||
public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName)
|
||||
throws BeansException {
|
||||
|
||||
CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);
|
||||
return cr.getPropertyDescriptor(propertyName);
|
||||
public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName) throws BeansException {
|
||||
return CachedIntrospectionResults.forClass(clazz).getPropertyDescriptor(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -511,6 +506,7 @@ public abstract class BeanUtils {
|
||||
if (targetType == null || targetType.isArray() || unknownEditorTypes.contains(targetType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClassLoader cl = targetType.getClassLoader();
|
||||
if (cl == null) {
|
||||
try {
|
||||
@@ -527,28 +523,34 @@ public abstract class BeanUtils {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String targetTypeName = targetType.getName();
|
||||
String editorName = targetTypeName + "Editor";
|
||||
try {
|
||||
Class<?> editorClass = cl.loadClass(editorName);
|
||||
if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Editor class [" + editorName +
|
||||
"] does not implement [java.beans.PropertyEditor] interface");
|
||||
if (editorClass != null) {
|
||||
if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Editor class [" + editorName +
|
||||
"] does not implement [java.beans.PropertyEditor] interface");
|
||||
}
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
}
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
return (PropertyEditor) instantiateClass(editorClass);
|
||||
}
|
||||
return (PropertyEditor) instantiateClass(editorClass);
|
||||
// Misbehaving ClassLoader returned null instead of ClassNotFoundException
|
||||
// - fall back to unknown editor type registration below
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("No property editor [" + editorName + "] found for type " +
|
||||
targetTypeName + " according to 'Editor' suffix convention");
|
||||
}
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
// Ignore - fall back to unknown editor type registration below
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("No property editor [" + editorName + "] found for type " +
|
||||
targetTypeName + " according to 'Editor' suffix convention");
|
||||
}
|
||||
unknownEditorTypes.add(targetType);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+12
-18
@@ -92,6 +92,8 @@ public final class CachedIntrospectionResults {
|
||||
*/
|
||||
public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";
|
||||
|
||||
private static final PropertyDescriptor[] EMPTY_PROPERTY_DESCRIPTOR_ARRAY = {};
|
||||
|
||||
|
||||
private static final boolean shouldIntrospectorIgnoreBeaninfoClasses =
|
||||
SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME);
|
||||
@@ -253,7 +255,7 @@ public final class CachedIntrospectionResults {
|
||||
private final BeanInfo beanInfo;
|
||||
|
||||
/** PropertyDescriptor objects keyed by property name String. */
|
||||
private final Map<String, PropertyDescriptor> propertyDescriptorCache;
|
||||
private final Map<String, PropertyDescriptor> propertyDescriptors;
|
||||
|
||||
/** TypeDescriptor objects keyed by PropertyDescriptor. */
|
||||
private final ConcurrentMap<PropertyDescriptor, TypeDescriptor> typeDescriptorCache;
|
||||
@@ -274,7 +276,7 @@ public final class CachedIntrospectionResults {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]");
|
||||
}
|
||||
this.propertyDescriptorCache = new LinkedHashMap<>();
|
||||
this.propertyDescriptors = new LinkedHashMap<>();
|
||||
|
||||
// This call is slow so we do it once.
|
||||
PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
|
||||
@@ -291,7 +293,7 @@ public final class CachedIntrospectionResults {
|
||||
"; editor [" + pd.getPropertyEditorClass().getName() + "]" : ""));
|
||||
}
|
||||
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
|
||||
this.propertyDescriptorCache.put(pd.getName(), pd);
|
||||
this.propertyDescriptors.put(pd.getName(), pd);
|
||||
}
|
||||
|
||||
// Explicitly check implemented interfaces for setter/getter methods as well,
|
||||
@@ -313,13 +315,13 @@ public final class CachedIntrospectionResults {
|
||||
for (Class<?> ifc : currClass.getInterfaces()) {
|
||||
if (!ClassUtils.isJavaLanguageInterface(ifc)) {
|
||||
for (PropertyDescriptor pd : getBeanInfo(ifc).getPropertyDescriptors()) {
|
||||
PropertyDescriptor existingPd = this.propertyDescriptorCache.get(pd.getName());
|
||||
PropertyDescriptor existingPd = this.propertyDescriptors.get(pd.getName());
|
||||
if (existingPd == null ||
|
||||
(existingPd.getReadMethod() == null && pd.getReadMethod() != null)) {
|
||||
// GenericTypeAwarePropertyDescriptor leniently resolves a set* write method
|
||||
// against a declared read method, so we prefer read method descriptors here.
|
||||
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
|
||||
this.propertyDescriptorCache.put(pd.getName(), pd);
|
||||
this.propertyDescriptors.put(pd.getName(), pd);
|
||||
}
|
||||
}
|
||||
introspectInterfaces(ifc, ifc);
|
||||
@@ -338,27 +340,19 @@ public final class CachedIntrospectionResults {
|
||||
|
||||
@Nullable
|
||||
PropertyDescriptor getPropertyDescriptor(String name) {
|
||||
PropertyDescriptor pd = this.propertyDescriptorCache.get(name);
|
||||
PropertyDescriptor pd = this.propertyDescriptors.get(name);
|
||||
if (pd == null && StringUtils.hasLength(name)) {
|
||||
// Same lenient fallback checking as in Property...
|
||||
pd = this.propertyDescriptorCache.get(StringUtils.uncapitalize(name));
|
||||
pd = this.propertyDescriptors.get(StringUtils.uncapitalize(name));
|
||||
if (pd == null) {
|
||||
pd = this.propertyDescriptorCache.get(StringUtils.capitalize(name));
|
||||
pd = this.propertyDescriptors.get(StringUtils.capitalize(name));
|
||||
}
|
||||
}
|
||||
return (pd == null || pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
|
||||
buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd));
|
||||
return pd;
|
||||
}
|
||||
|
||||
PropertyDescriptor[] getPropertyDescriptors() {
|
||||
PropertyDescriptor[] pds = new PropertyDescriptor[this.propertyDescriptorCache.size()];
|
||||
int i = 0;
|
||||
for (PropertyDescriptor pd : this.propertyDescriptorCache.values()) {
|
||||
pds[i] = (pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
|
||||
buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd));
|
||||
i++;
|
||||
}
|
||||
return pds;
|
||||
return this.propertyDescriptors.values().toArray(EMPTY_PROPERTY_DESCRIPTOR_ARRAY);
|
||||
}
|
||||
|
||||
private PropertyDescriptor buildGenericTypeAwarePropertyDescriptor(Class<?> beanClass, PropertyDescriptor pd) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -92,8 +92,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
|
||||
@Override
|
||||
protected NotWritablePropertyException createNotWritablePropertyException(String propertyName) {
|
||||
PropertyMatches matches = PropertyMatches.forField(propertyName, getRootClass());
|
||||
throw new NotWritablePropertyException(
|
||||
getRootClass(), getNestedPath() + propertyName,
|
||||
throw new NotWritablePropertyException(getRootClass(), getNestedPath() + propertyName,
|
||||
matches.buildErrorMessage(), matches.getPossibleMatches());
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -60,12 +60,13 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
|
||||
@Nullable
|
||||
private Class<?> propertyType;
|
||||
|
||||
@Nullable
|
||||
private final Class<?> propertyEditorClass;
|
||||
|
||||
|
||||
public GenericTypeAwarePropertyDescriptor(Class<?> beanClass, String propertyName,
|
||||
@Nullable Method readMethod, @Nullable Method writeMethod, Class<?> propertyEditorClass)
|
||||
throws IntrospectionException {
|
||||
@Nullable Method readMethod, @Nullable Method writeMethod,
|
||||
@Nullable Class<?> propertyEditorClass) throws IntrospectionException {
|
||||
|
||||
super(propertyName, null, null);
|
||||
this.beanClass = beanClass;
|
||||
@@ -156,6 +157,7 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Class<?> getPropertyEditorClass() {
|
||||
return this.propertyEditorClass;
|
||||
}
|
||||
|
||||
+1
-1
@@ -501,7 +501,7 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
||||
if (endIndex != -1) {
|
||||
String prefix = propertyPath.substring(0, startIndex);
|
||||
String key = propertyPath.substring(startIndex, endIndex + 1);
|
||||
String suffix = propertyPath.substring(endIndex + 1, propertyPath.length());
|
||||
String suffix = propertyPath.substring(endIndex + 1);
|
||||
// Strip the first key.
|
||||
strippedPaths.add(nestedPath + prefix + suffix);
|
||||
// Search for further keys to strip, with the first key stripped.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,10 +41,10 @@ public class TypeMismatchException extends PropertyAccessException {
|
||||
private String propertyName;
|
||||
|
||||
@Nullable
|
||||
private transient Object value;
|
||||
private final transient Object value;
|
||||
|
||||
@Nullable
|
||||
private Class<?> requiredType;
|
||||
private final Class<?> requiredType;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
+108
-85
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -613,7 +613,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
private final boolean required;
|
||||
|
||||
private volatile boolean cached = false;
|
||||
private volatile boolean cached;
|
||||
|
||||
@Nullable
|
||||
private volatile Object cachedFieldValue;
|
||||
@@ -628,46 +628,58 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
Field field = (Field) this.member;
|
||||
Object value;
|
||||
if (this.cached) {
|
||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
||||
try {
|
||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Unexpected removal of target bean for cached argument -> re-resolve
|
||||
value = resolveFieldValue(field, bean, beanName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
|
||||
desc.setContainingClass(bean.getClass());
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
try {
|
||||
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
if (value != null || this.required) {
|
||||
this.cachedFieldValue = desc;
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == 1) {
|
||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
|
||||
this.cachedFieldValue = new ShortcutDependencyDescriptor(
|
||||
desc, autowiredBeanName, field.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.cachedFieldValue = null;
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
value = resolveFieldValue(field, bean, beanName);
|
||||
}
|
||||
if (value != null) {
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
field.set(bean, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
|
||||
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
|
||||
desc.setContainingClass(bean.getClass());
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
Object value;
|
||||
try {
|
||||
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
Object cachedFieldValue = null;
|
||||
if (value != null || this.required) {
|
||||
cachedFieldValue = desc;
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == 1) {
|
||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
|
||||
cachedFieldValue = new ShortcutDependencyDescriptor(
|
||||
desc, autowiredBeanName, field.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cachedFieldValue = cachedFieldValue;
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -678,7 +690,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
private final boolean required;
|
||||
|
||||
private volatile boolean cached = false;
|
||||
private volatile boolean cached;
|
||||
|
||||
@Nullable
|
||||
private volatile Object[] cachedMethodArguments;
|
||||
@@ -696,58 +708,16 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
Method method = (Method) this.member;
|
||||
Object[] arguments;
|
||||
if (this.cached) {
|
||||
// Shortcut for avoiding synchronization...
|
||||
arguments = resolveCachedArguments(beanName);
|
||||
try {
|
||||
arguments = resolveCachedArguments(beanName);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Unexpected removal of target bean for cached argument -> re-resolve
|
||||
arguments = resolveMethodArguments(method, bean, beanName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int argumentCount = method.getParameterCount();
|
||||
arguments = new Object[argumentCount];
|
||||
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
|
||||
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
|
||||
currDesc.setContainingClass(bean.getClass());
|
||||
descriptors[i] = currDesc;
|
||||
try {
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
|
||||
if (arg == null && !this.required) {
|
||||
arguments = null;
|
||||
break;
|
||||
}
|
||||
arguments[i] = arg;
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
|
||||
}
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
if (arguments != null) {
|
||||
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
|
||||
registerDependentBeans(beanName, autowiredBeans);
|
||||
if (autowiredBeans.size() == argumentCount) {
|
||||
Iterator<String> it = autowiredBeans.iterator();
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
String autowiredBeanName = it.next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
|
||||
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
|
||||
descriptors[i], autowiredBeanName, paramTypes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cachedMethodArguments = cachedMethodArguments;
|
||||
}
|
||||
else {
|
||||
this.cachedMethodArguments = null;
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
arguments = resolveMethodArguments(method, bean, beanName);
|
||||
}
|
||||
if (arguments != null) {
|
||||
try {
|
||||
@@ -772,6 +742,59 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
|
||||
int argumentCount = method.getParameterCount();
|
||||
Object[] arguments = new Object[argumentCount];
|
||||
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
|
||||
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
|
||||
Assert.state(beanFactory != null, "No BeanFactory available");
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
|
||||
currDesc.setContainingClass(bean.getClass());
|
||||
descriptors[i] = currDesc;
|
||||
try {
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
|
||||
if (arg == null && !this.required) {
|
||||
arguments = null;
|
||||
break;
|
||||
}
|
||||
arguments[i] = arg;
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
|
||||
}
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!this.cached) {
|
||||
if (arguments != null) {
|
||||
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
|
||||
registerDependentBeans(beanName, autowiredBeans);
|
||||
if (autowiredBeans.size() == argumentCount) {
|
||||
Iterator<String> it = autowiredBeans.iterator();
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
String autowiredBeanName = it.next();
|
||||
if (beanFactory.containsBean(autowiredBeanName) &&
|
||||
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
|
||||
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
|
||||
descriptors[i], autowiredBeanName, paramTypes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cachedMethodArguments = cachedMethodArguments;
|
||||
}
|
||||
else {
|
||||
this.cachedMethodArguments = null;
|
||||
}
|
||||
this.cached = true;
|
||||
}
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-14
@@ -26,9 +26,6 @@ import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
@@ -69,8 +66,6 @@ public class InjectionMetadata {
|
||||
};
|
||||
|
||||
|
||||
private static final Log logger = LogFactory.getLog(InjectionMetadata.class);
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
private final Collection<InjectedElement> injectedElements;
|
||||
@@ -110,9 +105,6 @@ public class InjectionMetadata {
|
||||
if (!beanDefinition.isExternallyManagedConfigMember(member)) {
|
||||
beanDefinition.registerExternallyManagedConfigMember(member);
|
||||
checkedElements.add(element);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.checkedElements = checkedElements;
|
||||
@@ -124,9 +116,6 @@ public class InjectionMetadata {
|
||||
(checkedElements != null ? checkedElements : this.injectedElements);
|
||||
if (!elementsToIterate.isEmpty()) {
|
||||
for (InjectedElement element : elementsToIterate) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
|
||||
}
|
||||
element.inject(target, beanName, pvs);
|
||||
}
|
||||
}
|
||||
@@ -152,12 +141,12 @@ public class InjectionMetadata {
|
||||
* Return an {@code InjectionMetadata} instance, possibly for empty elements.
|
||||
* @param elements the elements to inject (possibly empty)
|
||||
* @param clazz the target class
|
||||
* @return a new {@link #InjectionMetadata(Class, Collection)} instance,
|
||||
* or {@link #EMPTY} in case of no elements
|
||||
* @return a new {@link #InjectionMetadata(Class, Collection)} instance
|
||||
* @since 5.2
|
||||
*/
|
||||
public static InjectionMetadata forElements(Collection<InjectedElement> elements, Class<?> clazz) {
|
||||
return (elements.isEmpty() ? InjectionMetadata.EMPTY : new InjectionMetadata(clazz, elements));
|
||||
return (elements.isEmpty() ? new InjectionMetadata(clazz, Collections.emptyList()) :
|
||||
new InjectionMetadata(clazz, elements));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+12
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -164,10 +164,10 @@ public class ConstructorArgumentValues {
|
||||
Assert.isTrue(index >= 0, "Index must not be negative");
|
||||
ValueHolder valueHolder = this.indexedArgumentValues.get(index);
|
||||
if (valueHolder != null &&
|
||||
(valueHolder.getType() == null ||
|
||||
(requiredType != null && ClassUtils.matchesTypeName(requiredType, valueHolder.getType()))) &&
|
||||
(valueHolder.getName() == null || "".equals(requiredName) ||
|
||||
(requiredName != null && requiredName.equals(valueHolder.getName())))) {
|
||||
(valueHolder.getType() == null || (requiredType != null &&
|
||||
ClassUtils.matchesTypeName(requiredType, valueHolder.getType()))) &&
|
||||
(valueHolder.getName() == null || (requiredName != null &&
|
||||
(requiredName.isEmpty() || requiredName.equals(valueHolder.getName()))))) {
|
||||
return valueHolder;
|
||||
}
|
||||
return null;
|
||||
@@ -277,17 +277,19 @@ public class ConstructorArgumentValues {
|
||||
* @return the ValueHolder for the argument, or {@code null} if none found
|
||||
*/
|
||||
@Nullable
|
||||
public ValueHolder getGenericArgumentValue(@Nullable Class<?> requiredType, @Nullable String requiredName, @Nullable Set<ValueHolder> usedValueHolders) {
|
||||
public ValueHolder getGenericArgumentValue(@Nullable Class<?> requiredType, @Nullable String requiredName,
|
||||
@Nullable Set<ValueHolder> usedValueHolders) {
|
||||
|
||||
for (ValueHolder valueHolder : this.genericArgumentValues) {
|
||||
if (usedValueHolders != null && usedValueHolders.contains(valueHolder)) {
|
||||
continue;
|
||||
}
|
||||
if (valueHolder.getName() != null && !"".equals(requiredName) &&
|
||||
(requiredName == null || !valueHolder.getName().equals(requiredName))) {
|
||||
if (valueHolder.getName() != null && (requiredName == null ||
|
||||
(!requiredName.isEmpty() && !requiredName.equals(valueHolder.getName())))) {
|
||||
continue;
|
||||
}
|
||||
if (valueHolder.getType() != null &&
|
||||
(requiredType == null || !ClassUtils.matchesTypeName(requiredType, valueHolder.getType()))) {
|
||||
if (valueHolder.getType() != null && (requiredType == null ||
|
||||
!ClassUtils.matchesTypeName(requiredType, valueHolder.getType()))) {
|
||||
continue;
|
||||
}
|
||||
if (requiredType != null && valueHolder.getType() == null && valueHolder.getName() == null &&
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,11 +24,11 @@ package org.springframework.beans.factory.parsing;
|
||||
*/
|
||||
public class BeanEntry implements ParseState.Entry {
|
||||
|
||||
private String beanDefinitionName;
|
||||
private final String beanDefinitionName;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link BeanEntry} class.
|
||||
* Create a new {@code BeanEntry} instance.
|
||||
* @param beanDefinitionName the name of the associated bean definition
|
||||
*/
|
||||
public BeanEntry(String beanDefinitionName) {
|
||||
|
||||
+25
-30
@@ -16,69 +16,63 @@
|
||||
|
||||
package org.springframework.beans.factory.parsing;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Simple {@link LinkedList}-based structure for tracking the logical position during
|
||||
* a parsing process. {@link Entry entries} are added to the LinkedList at
|
||||
* each point during the parse phase in a reader-specific manner.
|
||||
* Simple {@link ArrayDeque}-based structure for tracking the logical position during
|
||||
* a parsing process. {@link Entry entries} are added to the ArrayDeque at each point
|
||||
* during the parse phase in a reader-specific manner.
|
||||
*
|
||||
* <p>Calling {@link #toString()} will render a tree-style view of the current logical
|
||||
* position in the parse phase. This representation is intended for use in
|
||||
* error messages.
|
||||
* position in the parse phase. This representation is intended for use in error messages.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public final class ParseState {
|
||||
|
||||
/**
|
||||
* Tab character used when rendering the tree-style representation.
|
||||
* Internal {@link ArrayDeque} storage.
|
||||
*/
|
||||
private static final char TAB = '\t';
|
||||
|
||||
/**
|
||||
* Internal {@link LinkedList} storage.
|
||||
*/
|
||||
private final LinkedList<Entry> state;
|
||||
private final ArrayDeque<Entry> state;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code ParseState} with an empty {@link LinkedList}.
|
||||
* Create a new {@code ParseState} with an empty {@link ArrayDeque}.
|
||||
*/
|
||||
public ParseState() {
|
||||
this.state = new LinkedList<>();
|
||||
this.state = new ArrayDeque<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code ParseState} whose {@link LinkedList} is a {@link Object#clone clone}
|
||||
* of that of the passed in {@code ParseState}.
|
||||
* Create a new {@code ParseState} whose {@link ArrayDeque} is a clone
|
||||
* of the state in the passed-in {@code ParseState}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private ParseState(ParseState other) {
|
||||
this.state = (LinkedList<Entry>) other.state.clone();
|
||||
this.state = other.state.clone();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a new {@link Entry} to the {@link LinkedList}.
|
||||
* Add a new {@link Entry} to the {@link ArrayDeque}.
|
||||
*/
|
||||
public void push(Entry entry) {
|
||||
this.state.push(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an {@link Entry} from the {@link LinkedList}.
|
||||
* Remove an {@link Entry} from the {@link ArrayDeque}.
|
||||
*/
|
||||
public void pop() {
|
||||
this.state.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link Entry} currently at the top of the {@link LinkedList} or
|
||||
* {@code null} if the {@link LinkedList} is empty.
|
||||
* Return the {@link Entry} currently at the top of the {@link ArrayDeque} or
|
||||
* {@code null} if the {@link ArrayDeque} is empty.
|
||||
*/
|
||||
@Nullable
|
||||
public Entry peek() {
|
||||
@@ -99,16 +93,18 @@ public final class ParseState {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int x = 0; x < this.state.size(); x++) {
|
||||
if (x > 0) {
|
||||
StringBuilder sb = new StringBuilder(64);
|
||||
int i = 0;
|
||||
for (ParseState.Entry entry : this.state) {
|
||||
if (i > 0) {
|
||||
sb.append('\n');
|
||||
for (int y = 0; y < x; y++) {
|
||||
sb.append(TAB);
|
||||
for (int j = 0; j < i; j++) {
|
||||
sb.append('\t');
|
||||
}
|
||||
sb.append("-> ");
|
||||
}
|
||||
sb.append(this.state.get(x));
|
||||
sb.append(entry);
|
||||
i++;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -118,7 +114,6 @@ public final class ParseState {
|
||||
* Marker interface for entries into the {@link ParseState}.
|
||||
*/
|
||||
public interface Entry {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,14 +30,12 @@ public class PropertyEntry implements ParseState.Entry {
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link PropertyEntry} class.
|
||||
* Create a new {@code PropertyEntry} instance.
|
||||
* @param name the name of the JavaBean property represented by this instance
|
||||
* @throws IllegalArgumentException if the supplied {@code name} is {@code null}
|
||||
* or consists wholly of whitespace
|
||||
*/
|
||||
public PropertyEntry(String name) {
|
||||
if (!StringUtils.hasText(name)) {
|
||||
throw new IllegalArgumentException("Invalid property name '" + name + "'.");
|
||||
throw new IllegalArgumentException("Invalid property name '" + name + "'");
|
||||
}
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
+8
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,16 +26,21 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class QualifierEntry implements ParseState.Entry {
|
||||
|
||||
private String typeName;
|
||||
private final String typeName;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code QualifierEntry} instance.
|
||||
* @param typeName the name of the qualifier type
|
||||
*/
|
||||
public QualifierEntry(String typeName) {
|
||||
if (!StringUtils.hasText(typeName)) {
|
||||
throw new IllegalArgumentException("Invalid qualifier type '" + typeName + "'.");
|
||||
throw new IllegalArgumentException("Invalid qualifier type '" + typeName + "'");
|
||||
}
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Qualifier '" + this.typeName + "'";
|
||||
|
||||
+6
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -1013,6 +1013,11 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
throw ex;
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
// Don't swallow a linkage error since it contains a full stacktrace on
|
||||
// first occurrence... and just a plain NoClassDefFoundError afterwards.
|
||||
if (ex.contains(LinkageError.class)) {
|
||||
throw ex;
|
||||
}
|
||||
// Instantiation failure, maybe too early...
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Bean creation exception on singleton FactoryBean type check: " + ex);
|
||||
|
||||
+23
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -1194,8 +1194,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
this.primary == that.primary &&
|
||||
this.nonPublicAccessAllowed == that.nonPublicAccessAllowed &&
|
||||
this.lenientConstructorResolution == that.lenientConstructorResolution &&
|
||||
ObjectUtils.nullSafeEquals(this.constructorArgumentValues, that.constructorArgumentValues) &&
|
||||
ObjectUtils.nullSafeEquals(this.propertyValues, that.propertyValues) &&
|
||||
equalsConstructorArgumentValues(that) &&
|
||||
equalsPropertyValues(that) &&
|
||||
ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides) &&
|
||||
ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName) &&
|
||||
ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName) &&
|
||||
@@ -1208,12 +1208,30 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
super.equals(other));
|
||||
}
|
||||
|
||||
private boolean equalsConstructorArgumentValues(AbstractBeanDefinition other) {
|
||||
if (!hasConstructorArgumentValues()) {
|
||||
return !other.hasConstructorArgumentValues();
|
||||
}
|
||||
return ObjectUtils.nullSafeEquals(this.constructorArgumentValues, other.constructorArgumentValues);
|
||||
}
|
||||
|
||||
private boolean equalsPropertyValues(AbstractBeanDefinition other) {
|
||||
if (!hasPropertyValues()) {
|
||||
return !other.hasPropertyValues();
|
||||
}
|
||||
return ObjectUtils.nullSafeEquals(this.propertyValues, other.propertyValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = ObjectUtils.nullSafeHashCode(getBeanClassName());
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.scope);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.constructorArgumentValues);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.propertyValues);
|
||||
if (hasConstructorArgumentValues()) {
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.constructorArgumentValues);
|
||||
}
|
||||
if (hasPropertyValues()) {
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.propertyValues);
|
||||
}
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryBeanName);
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryMethodName);
|
||||
hashCode = 29 * hashCode + super.hashCode();
|
||||
|
||||
+11
-10
@@ -1621,21 +1621,22 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
/**
|
||||
* Determine the bean type for the given FactoryBean definition, as far as possible.
|
||||
* Only called if there is no singleton instance registered for the target bean
|
||||
* already. Implementations are only allowed to instantiate the factory bean if
|
||||
* {@code allowInit} is {@code true}, otherwise they should try to determine the
|
||||
* result through other means.
|
||||
* already. The implementation is allowed to instantiate the target factory bean if
|
||||
* {@code allowInit} is {@code true} and the type cannot be determined another way;
|
||||
* otherwise it is restricted to introspecting signatures and related metadata.
|
||||
* <p>If no {@link FactoryBean#OBJECT_TYPE_ATTRIBUTE} if set on the bean definition
|
||||
* and {@code allowInit} is {@code true}, the default implementation will create
|
||||
* the FactoryBean via {@code getBean} to call its {@code getObjectType} method.
|
||||
* Subclasses are encouraged to optimize this, typically by inspecting the generic
|
||||
* signature of the factory bean class or the factory method that creates it. If
|
||||
* subclasses do instantiate the FactoryBean, they should consider trying the
|
||||
* {@code getObjectType} method without fully populating the bean. If this fails, a
|
||||
* full FactoryBean creation as performed by this implementation should be used as
|
||||
* fallback.
|
||||
* signature of the factory bean class or the factory method that creates it.
|
||||
* If subclasses do instantiate the FactoryBean, they should consider trying the
|
||||
* {@code getObjectType} method without fully populating the bean. If this fails,
|
||||
* a full FactoryBean creation as performed by this implementation should be used
|
||||
* as fallback.
|
||||
* @param beanName the name of the bean
|
||||
* @param mbd the merged bean definition for the bean
|
||||
* @param allowInit if initialization of the FactoryBean is permitted
|
||||
* @param allowInit if initialization of the FactoryBean is permitted if the type
|
||||
* cannot be determined another way
|
||||
* @return the type for the bean if determinable, otherwise {@code ResolvableType.NONE}
|
||||
* @since 5.2
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
@@ -1651,7 +1652,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
try {
|
||||
FactoryBean<?> factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true);
|
||||
Class<?> objectType = getTypeForFactoryBean(factoryBean);
|
||||
return (objectType != null) ? ResolvableType.forClass(objectType) : ResolvableType.NONE;
|
||||
return (objectType != null ? ResolvableType.forClass(objectType) : ResolvableType.NONE);
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
if (ex.contains(BeanCurrentlyInCreationException.class)) {
|
||||
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -238,8 +238,10 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
Assert.state(lo != null, "LookupOverride not found");
|
||||
Object[] argsToUse = (args.length > 0 ? args : null); // if no-arg, don't insist on args at all
|
||||
if (StringUtils.hasText(lo.getBeanName())) {
|
||||
return (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
|
||||
Object bean = (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
|
||||
this.owner.getBean(lo.getBeanName()));
|
||||
// Detect package-protected NullBean instance through equals(null) check
|
||||
return (bean.equals(null) ? null : bean);
|
||||
}
|
||||
else {
|
||||
return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
|
||||
|
||||
+7
-5
@@ -66,6 +66,7 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Delegate for resolving constructors and factory methods.
|
||||
*
|
||||
* <p>Performs constructor resolution through argument matching.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
@@ -84,7 +85,7 @@ class ConstructorResolver {
|
||||
private static final Object[] EMPTY_ARGS = new Object[0];
|
||||
|
||||
/**
|
||||
* Marker for autowired arguments in a cached argument array, to be later replaced
|
||||
* Marker for autowired arguments in a cached argument array, to be replaced
|
||||
* by a {@linkplain #resolveAutowiredArgument resolved autowired argument}.
|
||||
*/
|
||||
private static final Object autowiredArgumentMarker = new Object();
|
||||
@@ -148,7 +149,7 @@ class ConstructorResolver {
|
||||
}
|
||||
}
|
||||
if (argsToResolve != null) {
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,6 +410,7 @@ class ConstructorResolver {
|
||||
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
|
||||
throw new ImplicitlyAppearedSingletonException();
|
||||
}
|
||||
this.beanFactory.registerDependentBean(factoryBeanName, beanName);
|
||||
factoryClass = factoryBean.getClass();
|
||||
isStatic = false;
|
||||
}
|
||||
@@ -443,7 +445,7 @@ class ConstructorResolver {
|
||||
}
|
||||
}
|
||||
if (argsToResolve != null) {
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
|
||||
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -815,7 +817,7 @@ class ConstructorResolver {
|
||||
* Resolve the prepared arguments stored in the given bean definition.
|
||||
*/
|
||||
private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
|
||||
Executable executable, Object[] argsToResolve, boolean fallback) {
|
||||
Executable executable, Object[] argsToResolve) {
|
||||
|
||||
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
|
||||
TypeConverter converter = (customConverter != null ? customConverter : bw);
|
||||
@@ -828,7 +830,7 @@ class ConstructorResolver {
|
||||
Object argValue = argsToResolve[argIndex];
|
||||
MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex);
|
||||
if (argValue == autowiredArgumentMarker) {
|
||||
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, fallback);
|
||||
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, true);
|
||||
}
|
||||
else if (argValue instanceof BeanMetadataElement) {
|
||||
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
|
||||
|
||||
+8
-8
@@ -96,8 +96,7 @@ import org.springframework.util.StringUtils;
|
||||
* operating on pre-resolved bean definition metadata objects.
|
||||
*
|
||||
* <p>Note that readers for specific bean definition formats are typically
|
||||
* implemented separately rather than as bean factory subclasses:
|
||||
* see for example {@link PropertiesBeanDefinitionReader} and
|
||||
* implemented separately rather than as bean factory subclasses: see for example
|
||||
* {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}.
|
||||
*
|
||||
* <p>For an alternative implementation of the
|
||||
@@ -184,7 +183,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
private volatile String[] frozenBeanDefinitionNames;
|
||||
|
||||
/** Whether bean definition metadata may be cached for all beans. */
|
||||
private volatile boolean configurationFrozen = false;
|
||||
private volatile boolean configurationFrozen;
|
||||
|
||||
|
||||
/**
|
||||
@@ -326,9 +325,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
this.allowBeanDefinitionOverriding = otherListableFactory.allowBeanDefinitionOverriding;
|
||||
this.allowEagerClassLoading = otherListableFactory.allowEagerClassLoading;
|
||||
this.dependencyComparator = otherListableFactory.dependencyComparator;
|
||||
// A clone of the AutowireCandidateResolver since it is potentially BeanFactoryAware...
|
||||
// A clone of the AutowireCandidateResolver since it is potentially BeanFactoryAware
|
||||
setAutowireCandidateResolver(otherListableFactory.getAutowireCandidateResolver().cloneIfNecessary());
|
||||
// Make resolvable dependencies (e.g. ResourceLoader) available here as well...
|
||||
// Make resolvable dependencies (e.g. ResourceLoader) available here as well
|
||||
this.resolvableDependencies.putAll(otherListableFactory.resolvableDependencies);
|
||||
}
|
||||
}
|
||||
@@ -355,12 +354,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType) throws BeansException {
|
||||
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType) {
|
||||
Assert.notNull(requiredType, "Required type must not be null");
|
||||
return getBeanProvider(ResolvableType.forRawClass(requiredType));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {
|
||||
return new BeanObjectProvider<T>() {
|
||||
@@ -390,12 +388,14 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
public T getIfUnique() throws BeansException {
|
||||
return resolveBean(requiredType, null, true);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Stream<T> stream() {
|
||||
return Arrays.stream(getBeanNamesForTypedStream(requiredType))
|
||||
.map(name -> (T) getBean(name))
|
||||
.filter(bean -> !(bean instanceof NullBean));
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Stream<T> orderedStream() {
|
||||
String[] beanNames = getBeanNamesForTypedStream(requiredType);
|
||||
@@ -530,7 +530,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else {
|
||||
if (includeNonSingletons || isNonLazyDecorated ||
|
||||
(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
|
||||
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
|
||||
|
||||
+17
-9
@@ -81,7 +81,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
|
||||
|
||||
/** Cache of early singleton objects: bean name to bean instance. */
|
||||
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
|
||||
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
|
||||
|
||||
/** Set of registered singletons, containing the bean names in registration order. */
|
||||
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
|
||||
@@ -178,16 +178,24 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
*/
|
||||
@Nullable
|
||||
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
|
||||
// Quick check for existing instance without full singleton lock
|
||||
Object singletonObject = this.singletonObjects.get(beanName);
|
||||
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
|
||||
synchronized (this.singletonObjects) {
|
||||
singletonObject = this.earlySingletonObjects.get(beanName);
|
||||
if (singletonObject == null && allowEarlyReference) {
|
||||
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
|
||||
if (singletonFactory != null) {
|
||||
singletonObject = singletonFactory.getObject();
|
||||
this.earlySingletonObjects.put(beanName, singletonObject);
|
||||
this.singletonFactories.remove(beanName);
|
||||
singletonObject = this.earlySingletonObjects.get(beanName);
|
||||
if (singletonObject == null && allowEarlyReference) {
|
||||
synchronized (this.singletonObjects) {
|
||||
// Consistent creation of early reference within full singleton lock
|
||||
singletonObject = this.singletonObjects.get(beanName);
|
||||
if (singletonObject == null) {
|
||||
singletonObject = this.earlySingletonObjects.get(beanName);
|
||||
if (singletonObject == null) {
|
||||
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
|
||||
if (singletonFactory != null) {
|
||||
singletonObject = singletonFactory.getObject();
|
||||
this.earlySingletonObjects.put(beanName, singletonObject);
|
||||
this.singletonFactories.remove(beanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+77
-76
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -87,7 +87,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
private transient Method destroyMethod;
|
||||
|
||||
@Nullable
|
||||
private List<DestructionAwareBeanPostProcessor> beanPostProcessors;
|
||||
private final List<DestructionAwareBeanPostProcessor> beanPostProcessors;
|
||||
|
||||
|
||||
/**
|
||||
@@ -120,14 +120,16 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
}
|
||||
}
|
||||
else {
|
||||
Class<?>[] paramTypes = destroyMethod.getParameterTypes();
|
||||
if (paramTypes.length > 1) {
|
||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||
beanName + "' has more than one parameter - not supported as destroy method");
|
||||
}
|
||||
else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
|
||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||
beanName + "' has a non-boolean parameter - not supported as destroy method");
|
||||
if (destroyMethod.getParameterCount() > 0) {
|
||||
Class<?>[] paramTypes = destroyMethod.getParameterTypes();
|
||||
if (paramTypes.length > 1) {
|
||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||
beanName + "' has more than one parameter - not supported as destroy method");
|
||||
}
|
||||
else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
|
||||
throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
|
||||
beanName + "' has a non-boolean parameter - not supported as destroy method");
|
||||
}
|
||||
}
|
||||
destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);
|
||||
}
|
||||
@@ -169,67 +171,6 @@ 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" 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
|
||||
* used in XML within the {@code <bean destroy-method="">} or {@code
|
||||
* <beans default-destroy-method="">} attributes.
|
||||
* <p>Also processes the {@link java.io.Closeable} and {@link java.lang.AutoCloseable}
|
||||
* interfaces, reflectively calling the "close" method on implementing beans as well.
|
||||
*/
|
||||
@Nullable
|
||||
private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
|
||||
String destroyMethodName = beanDefinition.getDestroyMethodName();
|
||||
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
|
||||
(destroyMethodName == null && bean instanceof AutoCloseable)) {
|
||||
// Only perform destroy method inference or Closeable detection
|
||||
// in case of the bean not explicitly implementing DisposableBean
|
||||
if (!(bean instanceof DisposableBean)) {
|
||||
try {
|
||||
return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
try {
|
||||
return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
|
||||
}
|
||||
catch (NoSuchMethodException ex2) {
|
||||
// no candidate destroy method found
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for all DestructionAwareBeanPostProcessors in the List.
|
||||
* @param processors the List to search
|
||||
* @return the filtered List of DestructionAwareBeanPostProcessors
|
||||
*/
|
||||
@Nullable
|
||||
private List<DestructionAwareBeanPostProcessor> filterPostProcessors(List<BeanPostProcessor> processors, Object bean) {
|
||||
List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
|
||||
if (!CollectionUtils.isEmpty(processors)) {
|
||||
filteredPostProcessors = new ArrayList<>(processors.size());
|
||||
for (BeanPostProcessor processor : processors) {
|
||||
if (processor instanceof DestructionAwareBeanPostProcessor) {
|
||||
DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor;
|
||||
if (dabpp.requiresDestruction(bean)) {
|
||||
filteredPostProcessors.add(dabpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return filteredPostProcessors;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
destroy();
|
||||
@@ -384,12 +325,50 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
|
||||
return true;
|
||||
}
|
||||
String destroyMethodName = beanDefinition.getDestroyMethodName();
|
||||
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) {
|
||||
return (ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME) ||
|
||||
ClassUtils.hasMethod(bean.getClass(), SHUTDOWN_METHOD_NAME));
|
||||
return inferDestroyMethodIfNecessary(bean, beanDefinition) != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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" 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
|
||||
* used in XML within the {@code <bean destroy-method="">} or {@code
|
||||
* <beans default-destroy-method="">} attributes.
|
||||
* <p>Also processes the {@link java.io.Closeable} and {@link java.lang.AutoCloseable}
|
||||
* interfaces, reflectively calling the "close" method on implementing beans as well.
|
||||
*/
|
||||
@Nullable
|
||||
private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
|
||||
String destroyMethodName = beanDefinition.resolvedDestroyMethodName;
|
||||
if (destroyMethodName == null) {
|
||||
destroyMethodName = beanDefinition.getDestroyMethodName();
|
||||
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
|
||||
(destroyMethodName == null && bean instanceof AutoCloseable)) {
|
||||
// Only perform destroy method inference or Closeable detection
|
||||
// in case of the bean not explicitly implementing DisposableBean
|
||||
destroyMethodName = null;
|
||||
if (!(bean instanceof DisposableBean)) {
|
||||
try {
|
||||
destroyMethodName = bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
try {
|
||||
destroyMethodName = bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
|
||||
}
|
||||
catch (NoSuchMethodException ex2) {
|
||||
// no candidate destroy method found
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : "");
|
||||
}
|
||||
return StringUtils.hasLength(destroyMethodName);
|
||||
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -411,4 +390,26 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for all DestructionAwareBeanPostProcessors in the List.
|
||||
* @param processors the List to search
|
||||
* @return the filtered List of DestructionAwareBeanPostProcessors
|
||||
*/
|
||||
@Nullable
|
||||
private List<DestructionAwareBeanPostProcessor> filterPostProcessors(List<BeanPostProcessor> processors, Object bean) {
|
||||
List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
|
||||
if (!CollectionUtils.isEmpty(processors)) {
|
||||
filteredPostProcessors = new ArrayList<>(processors.size());
|
||||
for (BeanPostProcessor processor : processors) {
|
||||
if (processor instanceof DestructionAwareBeanPostProcessor) {
|
||||
DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor;
|
||||
if (dabpp.requiresDestruction(bean)) {
|
||||
filteredPostProcessors.add(dabpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return filteredPostProcessors;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -446,8 +446,8 @@ public class PropertiesBeanDefinitionReader extends AbstractBeanDefinitionReader
|
||||
else if (SINGLETON_KEY.equals(property)) {
|
||||
// Spring 1.2 style
|
||||
String val = StringUtils.trimWhitespace((String) entry.getValue());
|
||||
scope = ("".equals(val) || TRUE_VALUE.equals(val) ? BeanDefinition.SCOPE_SINGLETON :
|
||||
BeanDefinition.SCOPE_PROTOTYPE);
|
||||
scope = (!StringUtils.hasLength(val) || TRUE_VALUE.equals(val) ?
|
||||
BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE);
|
||||
}
|
||||
else if (LAZY_INIT_KEY.equals(property)) {
|
||||
String val = StringUtils.trimWhitespace((String) entry.getValue());
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.LinkedList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -39,7 +39,7 @@ public class ReplaceOverride extends MethodOverride {
|
||||
|
||||
private final String methodReplacerBeanName;
|
||||
|
||||
private List<String> typeIdentifiers = new LinkedList<>();
|
||||
private final List<String> typeIdentifiers = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -49,7 +49,7 @@ public class ReplaceOverride extends MethodOverride {
|
||||
*/
|
||||
public ReplaceOverride(String methodName, String methodReplacerBeanName) {
|
||||
super(methodName);
|
||||
Assert.notNull(methodName, "Method replacer bean name must not be null");
|
||||
Assert.notNull(methodReplacerBeanName, "Method replacer bean name must not be null");
|
||||
this.methodReplacerBeanName = methodReplacerBeanName;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ public class ReplaceOverride extends MethodOverride {
|
||||
this.typeIdentifiers.add(identifier);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean matches(Method method) {
|
||||
if (!method.getName().equals(getMethodName())) {
|
||||
|
||||
+6
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -65,7 +65,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
|
||||
boolean allowCaching = true;
|
||||
|
||||
boolean isFactoryMethodUnique = false;
|
||||
boolean isFactoryMethodUnique;
|
||||
|
||||
@Nullable
|
||||
volatile ResolvableType targetType;
|
||||
@@ -86,6 +86,10 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
||||
@Nullable
|
||||
volatile Method factoryMethodToIntrospect;
|
||||
|
||||
/** Package-visible field for caching a resolved destroy method name (also for inferred). */
|
||||
@Nullable
|
||||
volatile String resolvedDestroyMethodName;
|
||||
|
||||
/** Common lock for the four constructor fields below. */
|
||||
final Object constructorArgumentLock = new Object();
|
||||
|
||||
|
||||
+16
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,7 +37,7 @@ import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.SmartFactoryBean;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -45,20 +45,22 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Static {@link org.springframework.beans.factory.BeanFactory} implementation
|
||||
* which allows to register existing singleton instances programmatically.
|
||||
* Does not have support for prototype beans or aliases.
|
||||
* which allows one to register existing singleton instances programmatically.
|
||||
*
|
||||
* <p>Serves as example for a simple implementation of the
|
||||
* <p>Does not have support for prototype beans or aliases.
|
||||
*
|
||||
* <p>Serves as an example for a simple implementation of the
|
||||
* {@link org.springframework.beans.factory.ListableBeanFactory} interface,
|
||||
* managing existing bean instances rather than creating new ones based on bean
|
||||
* definitions, and not implementing any extended SPI interfaces (such as
|
||||
* {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}).
|
||||
*
|
||||
* <p>For a full-fledged factory based on bean definitions, have a look
|
||||
* at {@link DefaultListableBeanFactory}.
|
||||
* <p>For a full-fledged factory based on bean definitions, have a look at
|
||||
* {@link DefaultListableBeanFactory}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 06.01.2003
|
||||
* @see DefaultListableBeanFactory
|
||||
*/
|
||||
@@ -83,7 +85,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||
* or {@link java.util.Collections#emptyMap()} for a dummy factory which
|
||||
* enforces operating against an empty set of beans.
|
||||
* @param beans a {@code Map} for holding this factory's beans, with the
|
||||
* bean name String as key and the corresponding singleton object as value
|
||||
* bean name as key and the corresponding singleton object as value
|
||||
* @since 4.3
|
||||
*/
|
||||
public StaticListableBeanFactory(Map<String, Object> beans) {
|
||||
@@ -94,7 +96,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||
|
||||
/**
|
||||
* Add a new singleton bean.
|
||||
* Will overwrite any existing instance for the given name.
|
||||
* <p>Will overwrite any existing instance for the given name.
|
||||
* @param name the name of the bean
|
||||
* @param bean the bean instance
|
||||
*/
|
||||
@@ -262,7 +264,10 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
|
||||
Object bean = getBean(name);
|
||||
// In case of FactoryBean, return singleton status of created object.
|
||||
return (bean instanceof FactoryBean && ((FactoryBean<?>) bean).isSingleton());
|
||||
if (bean instanceof FactoryBean) {
|
||||
return ((FactoryBean<?>) bean).isSingleton();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -337,7 +342,6 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||
return getBeanNamesForType(type, true, true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String[] getBeanNamesForType(@Nullable ResolvableType type,
|
||||
boolean includeNonSingletons, boolean allowEagerInit) {
|
||||
@@ -446,7 +450,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||
throws NoSuchBeanDefinitionException {
|
||||
|
||||
Class<?> beanType = getType(beanName);
|
||||
return (beanType != null ? AnnotationUtils.findAnnotation(beanType, annotationType) : null);
|
||||
return (beanType != null ? AnnotatedElementUtils.findMergedAnnotation(beanType, annotationType) : null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -1523,7 +1523,7 @@ public class BeanDefinitionParserDelegate {
|
||||
* Determine whether the given URI indicates the default namespace.
|
||||
*/
|
||||
public boolean isDefaultNamespace(@Nullable String namespaceUri) {
|
||||
return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri));
|
||||
return !StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1534,7 +1534,7 @@ public class BeanDefinitionParserDelegate {
|
||||
}
|
||||
|
||||
private boolean isDefaultValue(String value) {
|
||||
return (DEFAULT_VALUE.equals(value) || "".equals(value));
|
||||
return !StringUtils.hasLength(value) || DEFAULT_VALUE.equals(value);
|
||||
}
|
||||
|
||||
private boolean isCandidateElement(Node node) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -119,7 +119,7 @@ public class URIEditor extends PropertyEditorSupport {
|
||||
setValue(createURI(uri));
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalArgumentException("Invalid URI syntax: " + ex);
|
||||
throw new IllegalArgumentException("Invalid URI syntax: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+178
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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.beans.factory;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -33,6 +35,7 @@ import org.springframework.beans.testfixture.beans.TestAnnotation;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.beans.testfixture.beans.factory.DummyFactory;
|
||||
import org.springframework.cglib.proxy.NoOp;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -43,6 +46,7 @@ import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifie
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Sam Brannen
|
||||
* @since 04.07.2003
|
||||
*/
|
||||
public class BeanFactoryUtilsTests {
|
||||
@@ -59,9 +63,8 @@ public class BeanFactoryUtilsTests {
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
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);
|
||||
@@ -89,7 +92,7 @@ public class BeanFactoryUtilsTests {
|
||||
* Check that override doesn't count as two separate beans.
|
||||
*/
|
||||
@Test
|
||||
public void testHierarchicalCountBeansWithOverride() throws Exception {
|
||||
public void testHierarchicalCountBeansWithOverride() {
|
||||
// Leaf count
|
||||
assertThat(this.listableBeanFactory.getBeanDefinitionCount() == 1).isTrue();
|
||||
// Count minus duplicate
|
||||
@@ -97,14 +100,14 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesWithNoMatch() throws Exception {
|
||||
public void testHierarchicalNamesWithNoMatch() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, NoOp.class));
|
||||
assertThat(names.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesWithMatchOnlyInRoot() throws Exception {
|
||||
public void testHierarchicalNamesWithMatchOnlyInRoot() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, IndexedTestBean.class));
|
||||
assertThat(names.size()).isEqualTo(1);
|
||||
@@ -114,7 +117,7 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanNamesForTypeWithOverride() throws Exception {
|
||||
public void testGetBeanNamesForTypeWithOverride() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class));
|
||||
// includes 2 TestBeans from FactoryBeans (DummyFactory definitions)
|
||||
@@ -232,7 +235,7 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalResolutionWithOverride() throws Exception {
|
||||
public void testHierarchicalResolutionWithOverride() {
|
||||
Object test3 = this.listableBeanFactory.getBean("test3");
|
||||
Object test = this.listableBeanFactory.getBean("test");
|
||||
|
||||
@@ -272,14 +275,14 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesForAnnotationWithNoMatch() throws Exception {
|
||||
public void testHierarchicalNamesForAnnotationWithNoMatch() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, Override.class));
|
||||
assertThat(names.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() throws Exception {
|
||||
public void testHierarchicalNamesForAnnotationWithMatchOnlyInRoot() {
|
||||
List<String> names = Arrays.asList(
|
||||
BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.listableBeanFactory, TestAnnotation.class));
|
||||
assertThat(names.size()).isEqualTo(1);
|
||||
@@ -289,7 +292,7 @@ public class BeanFactoryUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanNamesForAnnotationWithOverride() throws Exception {
|
||||
public void testGetBeanNamesForAnnotationWithOverride() {
|
||||
AnnotatedBean annotatedBean = new AnnotatedBean();
|
||||
this.listableBeanFactory.registerSingleton("anotherAnnotatedBean", annotatedBean);
|
||||
List<String> names = Arrays.asList(
|
||||
@@ -323,4 +326,168 @@ public class BeanFactoryUtilsTests {
|
||||
assertThat(Arrays.equals(new String[] { "buffer" }, deps)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAnnotationOnBean() {
|
||||
this.listableBeanFactory.registerSingleton("controllerAdvice", new ControllerAdviceClass());
|
||||
this.listableBeanFactory.registerSingleton("restControllerAdvice", new RestControllerAdviceClass());
|
||||
testFindAnnotationOnBean(this.listableBeanFactory);
|
||||
}
|
||||
|
||||
@Test // gh-25520
|
||||
public void findAnnotationOnBeanWithStaticFactory() {
|
||||
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
|
||||
lbf.addBean("controllerAdvice", new ControllerAdviceClass());
|
||||
lbf.addBean("restControllerAdvice", new RestControllerAdviceClass());
|
||||
testFindAnnotationOnBean(lbf);
|
||||
}
|
||||
|
||||
private void testFindAnnotationOnBean(ListableBeanFactory lbf) {
|
||||
assertControllerAdvice(lbf, "controllerAdvice");
|
||||
assertControllerAdvice(lbf, "restControllerAdvice");
|
||||
}
|
||||
|
||||
private void assertControllerAdvice(ListableBeanFactory lbf, String beanName) {
|
||||
ControllerAdvice controllerAdvice = lbf.findAnnotationOnBean(beanName, ControllerAdvice.class);
|
||||
assertThat(controllerAdvice).isNotNull();
|
||||
assertThat(controllerAdvice.value()).isEqualTo("com.example");
|
||||
assertThat(controllerAdvice.basePackage()).isEqualTo("com.example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSingletonAndIsPrototypeWithStaticFactory() {
|
||||
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
|
||||
TestBean bean = new TestBean();
|
||||
DummyFactory fb1 = new DummyFactory();
|
||||
DummyFactory fb2 = new DummyFactory();
|
||||
fb2.setSingleton(false);
|
||||
TestBeanSmartFactoryBean sfb1 = new TestBeanSmartFactoryBean(true, true);
|
||||
TestBeanSmartFactoryBean sfb2 = new TestBeanSmartFactoryBean(true, false);
|
||||
TestBeanSmartFactoryBean sfb3 = new TestBeanSmartFactoryBean(false, true);
|
||||
TestBeanSmartFactoryBean sfb4 = new TestBeanSmartFactoryBean(false, false);
|
||||
lbf.addBean("bean", bean);
|
||||
lbf.addBean("fb1", fb1);
|
||||
lbf.addBean("fb2", fb2);
|
||||
lbf.addBean("sfb1", sfb1);
|
||||
lbf.addBean("sfb2", sfb2);
|
||||
lbf.addBean("sfb3", sfb3);
|
||||
lbf.addBean("sfb4", sfb4);
|
||||
|
||||
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, true);
|
||||
assertThat(beans.get("bean")).isSameAs(bean);
|
||||
assertThat(beans.get("fb1")).isSameAs(fb1.getObject());
|
||||
assertThat(beans.get("fb2")).isInstanceOf(TestBean.class);
|
||||
assertThat(beans.get("sfb1")).isInstanceOf(TestBean.class);
|
||||
assertThat(beans.get("sfb2")).isInstanceOf(TestBean.class);
|
||||
assertThat(beans.get("sfb3")).isInstanceOf(TestBean.class);
|
||||
assertThat(beans.get("sfb4")).isInstanceOf(TestBean.class);
|
||||
|
||||
assertThat(lbf.getBeanDefinitionCount()).isEqualTo(7);
|
||||
assertThat(lbf.getBean("bean")).isInstanceOf(TestBean.class);
|
||||
assertThat(lbf.getBean("&fb1")).isInstanceOf(FactoryBean.class);
|
||||
assertThat(lbf.getBean("&fb2")).isInstanceOf(FactoryBean.class);
|
||||
assertThat(lbf.getBean("&sfb1")).isInstanceOf(SmartFactoryBean.class);
|
||||
assertThat(lbf.getBean("&sfb2")).isInstanceOf(SmartFactoryBean.class);
|
||||
assertThat(lbf.getBean("&sfb3")).isInstanceOf(SmartFactoryBean.class);
|
||||
assertThat(lbf.getBean("&sfb4")).isInstanceOf(SmartFactoryBean.class);
|
||||
|
||||
assertThat(lbf.isSingleton("bean")).isTrue();
|
||||
assertThat(lbf.isSingleton("fb1")).isTrue();
|
||||
assertThat(lbf.isSingleton("fb2")).isTrue();
|
||||
assertThat(lbf.isSingleton("sfb1")).isTrue();
|
||||
assertThat(lbf.isSingleton("sfb2")).isTrue();
|
||||
assertThat(lbf.isSingleton("sfb3")).isTrue();
|
||||
assertThat(lbf.isSingleton("sfb4")).isTrue();
|
||||
|
||||
assertThat(lbf.isSingleton("&fb1")).isTrue();
|
||||
assertThat(lbf.isSingleton("&fb2")).isFalse();
|
||||
assertThat(lbf.isSingleton("&sfb1")).isTrue();
|
||||
assertThat(lbf.isSingleton("&sfb2")).isTrue();
|
||||
assertThat(lbf.isSingleton("&sfb3")).isFalse();
|
||||
assertThat(lbf.isSingleton("&sfb4")).isFalse();
|
||||
|
||||
assertThat(lbf.isPrototype("bean")).isFalse();
|
||||
assertThat(lbf.isPrototype("fb1")).isFalse();
|
||||
assertThat(lbf.isPrototype("fb2")).isFalse();
|
||||
assertThat(lbf.isPrototype("sfb1")).isFalse();
|
||||
assertThat(lbf.isPrototype("sfb2")).isFalse();
|
||||
assertThat(lbf.isPrototype("sfb3")).isFalse();
|
||||
assertThat(lbf.isPrototype("sfb4")).isFalse();
|
||||
|
||||
assertThat(lbf.isPrototype("&fb1")).isFalse();
|
||||
assertThat(lbf.isPrototype("&fb2")).isTrue();
|
||||
assertThat(lbf.isPrototype("&sfb1")).isTrue();
|
||||
assertThat(lbf.isPrototype("&sfb2")).isFalse();
|
||||
assertThat(lbf.isPrototype("&sfb3")).isTrue();
|
||||
assertThat(lbf.isPrototype("&sfb4")).isTrue();
|
||||
}
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ControllerAdvice {
|
||||
|
||||
@AliasFor("basePackage")
|
||||
String value() default "";
|
||||
|
||||
@AliasFor("value")
|
||||
String basePackage() default "";
|
||||
}
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@ControllerAdvice
|
||||
@interface RestControllerAdvice {
|
||||
|
||||
@AliasFor(annotation = ControllerAdvice.class)
|
||||
String value() default "";
|
||||
|
||||
@AliasFor(annotation = ControllerAdvice.class)
|
||||
String basePackage() default "";
|
||||
}
|
||||
|
||||
|
||||
@ControllerAdvice("com.example")
|
||||
static class ControllerAdviceClass {
|
||||
}
|
||||
|
||||
|
||||
@RestControllerAdvice("com.example")
|
||||
static class RestControllerAdviceClass {
|
||||
}
|
||||
|
||||
|
||||
static class TestBeanSmartFactoryBean implements SmartFactoryBean<TestBean> {
|
||||
|
||||
private final TestBean testBean = new TestBean("enigma", 42);
|
||||
|
||||
private final boolean singleton;
|
||||
|
||||
private final boolean prototype;
|
||||
|
||||
TestBeanSmartFactoryBean(boolean singleton, boolean prototype) {
|
||||
this.singleton = singleton;
|
||||
this.prototype = prototype;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return this.singleton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrototype() {
|
||||
return this.prototype;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<TestBean> getObjectType() {
|
||||
return TestBean.class;
|
||||
}
|
||||
|
||||
public TestBean getObject() {
|
||||
// We don't really care if the actual instance is a singleton or prototype
|
||||
// for the tests that use this factory.
|
||||
return this.testBean;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-22
@@ -796,12 +796,13 @@ class DefaultListableBeanFactoryTests {
|
||||
factory.registerBeanDefinition("child", childDefinition);
|
||||
factory.registerAlias("parent", "alias");
|
||||
|
||||
TestBean child = (TestBean) factory.getBean("child");
|
||||
TestBean child = factory.getBean("child", TestBean.class);
|
||||
assertThat(child.getName()).isEqualTo(EXPECTED_NAME);
|
||||
assertThat(child.getAge()).isEqualTo(EXPECTED_AGE);
|
||||
Object mergedBeanDefinition2 = factory.getMergedBeanDefinition("child");
|
||||
BeanDefinition mergedBeanDefinition1 = factory.getMergedBeanDefinition("child");
|
||||
BeanDefinition mergedBeanDefinition2 = factory.getMergedBeanDefinition("child");
|
||||
|
||||
assertThat(mergedBeanDefinition2).as("Use cached merged bean definition").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(mergedBeanDefinition1).as("Use cached merged bean definition").isSameAs(mergedBeanDefinition2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1849,8 +1850,7 @@ class DefaultListableBeanFactoryTests {
|
||||
assertThat(factoryBean).as("The FactoryBean should have been registered.").isNotNull();
|
||||
FactoryBeanDependentBean bean = (FactoryBeanDependentBean) lbf.autowire(FactoryBeanDependentBean.class,
|
||||
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
|
||||
Object mergedBeanDefinition2 = bean.getFactoryBean();
|
||||
assertThat(mergedBeanDefinition2).as("The FactoryBeanDependentBean should have been autowired 'by type' with the LazyInitFactory.").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(bean.getFactoryBean()).as("The FactoryBeanDependentBean should have been autowired 'by type' with the LazyInitFactory.").isEqualTo(factoryBean);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2556,8 +2556,7 @@ class DefaultListableBeanFactoryTests {
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount;
|
||||
assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2571,8 +2570,7 @@ class DefaultListableBeanFactoryTests {
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount;
|
||||
assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2587,8 +2585,7 @@ class DefaultListableBeanFactoryTests {
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
Object mergedBeanDefinition2 = BeanWithDestroyMethod.closeCount;
|
||||
assertThat(mergedBeanDefinition2).as("Destroy methods invoked").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(BeanWithDestroyMethod.closeCount).as("Destroy methods invoked").isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2710,14 +2707,15 @@ class DefaultListableBeanFactoryTests {
|
||||
factory.registerBeanDefinition("child", child);
|
||||
|
||||
AbstractBeanDefinition def = (AbstractBeanDefinition) factory.getBeanDefinition("child");
|
||||
Object mergedBeanDefinition2 = def.getScope();
|
||||
assertThat(mergedBeanDefinition2).as("Child 'scope' not overriding parent scope (it must).").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(def.getScope()).as("Child 'scope' not overriding parent scope (it must).").isEqualTo(theChildScope);
|
||||
}
|
||||
|
||||
@Test
|
||||
void scopeInheritanceForChildBeanDefinitions() {
|
||||
String theParentScope = "bonanza!";
|
||||
|
||||
RootBeanDefinition parent = new RootBeanDefinition();
|
||||
parent.setScope("bonanza!");
|
||||
parent.setScope(theParentScope);
|
||||
|
||||
AbstractBeanDefinition child = new ChildBeanDefinition("parent");
|
||||
child.setBeanClass(TestBean.class);
|
||||
@@ -2727,8 +2725,7 @@ class DefaultListableBeanFactoryTests {
|
||||
factory.registerBeanDefinition("child", child);
|
||||
|
||||
BeanDefinition def = factory.getMergedBeanDefinition("child");
|
||||
Object mergedBeanDefinition2 = def.getScope();
|
||||
assertThat(mergedBeanDefinition2).as("Child 'scope' not inherited").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(def.getScope()).as("Child 'scope' not inherited").isEqualTo(theParentScope);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2764,15 +2761,12 @@ class DefaultListableBeanFactoryTests {
|
||||
});
|
||||
lbf.preInstantiateSingletons();
|
||||
TestBean tb = (TestBean) lbf.getBean("test");
|
||||
Object mergedBeanDefinition2 = tb.getName();
|
||||
assertThat(mergedBeanDefinition2).as("Name was set on field by IAPP").isEqualTo(mergedBeanDefinition2);
|
||||
assertThat(tb.getName()).as("Name was set on field by IAPP").isEqualTo(nameSetOnField);
|
||||
if (!skipPropertyPopulation) {
|
||||
Object mergedBeanDefinition21 = tb.getAge();
|
||||
assertThat(mergedBeanDefinition21).as("Property value still set").isEqualTo(mergedBeanDefinition21);
|
||||
assertThat(tb.getAge()).as("Property value still set").isEqualTo(ageSetByPropertyValue);
|
||||
}
|
||||
else {
|
||||
Object mergedBeanDefinition21 = tb.getAge();
|
||||
assertThat(mergedBeanDefinition21).as("Property value was NOT set and still has default value").isEqualTo(mergedBeanDefinition21);
|
||||
assertThat(tb.getAge()).as("Property value was NOT set and still has default value").isEqualTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+193
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -297,6 +297,121 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalResourceInjectionWithSingletonRemoval() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(OptionalResourceInjectionBean.class);
|
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", rbd);
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
IndexedTestBean itb = new IndexedTestBean();
|
||||
bf.registerSingleton("indexedTestBean", itb);
|
||||
NestedTestBean ntb1 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean1", ntb1);
|
||||
NestedTestBean ntb2 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
|
||||
bf.destroySingleton("testBean");
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
assertThat(bean.getTestBean4()).isNull();
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
|
||||
bf.registerSingleton("testBean", tb);
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalResourceInjectionWithBeanDefinitionRemoval() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(OptionalResourceInjectionBean.class);
|
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", rbd);
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
IndexedTestBean itb = new IndexedTestBean();
|
||||
bf.registerSingleton("indexedTestBean", itb);
|
||||
NestedTestBean ntb1 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean1", ntb1);
|
||||
NestedTestBean ntb2 = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean2", ntb2);
|
||||
|
||||
OptionalResourceInjectionBean bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean4()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
|
||||
bf.removeBeanDefinition("testBean");
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isNull();
|
||||
assertThat(bean.getTestBean2()).isNull();
|
||||
assertThat(bean.getTestBean3()).isNull();
|
||||
assertThat(bean.getTestBean4()).isNull();
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
|
||||
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
bean = (OptionalResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean2()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean3()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getTestBean4()).isSameAs(bf.getBean("testBean"));
|
||||
assertThat(bean.getIndexedTestBean()).isSameAs(itb);
|
||||
assertThat(bean.getNestedTestBeans().length).isEqualTo(2);
|
||||
assertThat(bean.getNestedTestBeans()[0]).isSameAs(ntb1);
|
||||
assertThat(bean.getNestedTestBeans()[1]).isSameAs(ntb2);
|
||||
assertThat(bean.nestedTestBeansField.length).isEqualTo(2);
|
||||
assertThat(bean.nestedTestBeansField[0]).isSameAs(ntb1);
|
||||
assertThat(bean.nestedTestBeansField[1]).isSameAs(ntb2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalCollectionResourceInjection() {
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(OptionalCollectionResourceInjectionBean.class);
|
||||
@@ -533,6 +648,83 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorResourceInjectionWithSingletonRemoval() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class);
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
NestedTestBean ntb = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bf.destroySingleton("nestedTestBean");
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isNull();
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(ntb);
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorResourceInjectionWithBeanDefinitionRemoval() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class);
|
||||
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
bf.registerBeanDefinition("annotatedBean", bd);
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NestedTestBean.class));
|
||||
|
||||
ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(bf.getBean("nestedTestBean"));
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bf.removeBeanDefinition("nestedTestBean");
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isNull();
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
|
||||
bf.registerBeanDefinition("nestedTestBean", new RootBeanDefinition(NestedTestBean.class));
|
||||
|
||||
bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bean.getTestBean()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean2()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean3()).isSameAs(tb);
|
||||
assertThat(bean.getTestBean4()).isSameAs(tb);
|
||||
assertThat(bean.getNestedTestBean()).isSameAs(bf.getBean("nestedTestBean"));
|
||||
assertThat(bean.getBeanFactory()).isSameAs(bf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorResourceInjectionWithNullFromFactoryBean() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class);
|
||||
|
||||
+15
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -108,10 +108,23 @@ public class LookupAnnotationTests {
|
||||
assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
|
||||
}
|
||||
|
||||
@Test // gh-25806
|
||||
public void testWithNullBean() {
|
||||
RootBeanDefinition tbd = new RootBeanDefinition(TestBean.class, () -> null);
|
||||
tbd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
beanFactory.registerBeanDefinition("testBean", tbd);
|
||||
|
||||
AbstractBean bean = beanFactory.getBean("beanConsumer", BeanConsumer.class).abstractBean;
|
||||
assertThat(bean).isNotNull();
|
||||
Object expected = bean.get();
|
||||
assertThat(expected).isNull();
|
||||
assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
|
||||
}
|
||||
|
||||
|
||||
public static abstract class AbstractBean {
|
||||
|
||||
@Lookup
|
||||
@Lookup("testBean")
|
||||
public abstract TestBean get();
|
||||
|
||||
@Lookup
|
||||
|
||||
+11
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -133,6 +133,16 @@ public class BeanDefinitionTests {
|
||||
assertThat(bd.equals(otherBd)).isTrue();
|
||||
assertThat(otherBd.equals(bd)).isTrue();
|
||||
assertThat(bd.hashCode() == otherBd.hashCode()).isTrue();
|
||||
|
||||
bd.getPropertyValues();
|
||||
assertThat(bd.equals(otherBd)).isTrue();
|
||||
assertThat(otherBd.equals(bd)).isTrue();
|
||||
assertThat(bd.hashCode() == otherBd.hashCode()).isTrue();
|
||||
|
||||
bd.getConstructorArgumentValues();
|
||||
assertThat(bd.equals(otherBd)).isTrue();
|
||||
assertThat(otherBd.equals(bd)).isTrue();
|
||||
assertThat(bd.hashCode() == otherBd.hashCode()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -126,7 +126,7 @@ public class DefinitionMetadataEqualsHashCodeTests {
|
||||
assertThat(equal.hashCode()).as("Hash code for equal instances should match").isEqualTo(master.hashCode());
|
||||
|
||||
assertThat(notEqual).as("Should not be equal").isNotEqualTo(master);
|
||||
assertThat(notEqual.hashCode()).as("Hash code for non-equal instances should not match").isNotEqualTo((long) master.hashCode());
|
||||
assertThat(notEqual.hashCode()).as("Hash code for non-equal instances should not match").isNotEqualTo(master.hashCode());
|
||||
|
||||
assertThat(subclass).as("Subclass should be equal").isEqualTo(master);
|
||||
assertThat(subclass.hashCode()).as("Hash code for subclass should match").isEqualTo(master.hashCode());
|
||||
|
||||
+37
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -159,8 +159,6 @@ public class MimeMessageHelper {
|
||||
|
||||
private static final String HEADER_PRIORITY = "X-Priority";
|
||||
|
||||
private static final String HEADER_CONTENT_ID = "Content-ID";
|
||||
|
||||
|
||||
private final MimeMessage mimeMessage;
|
||||
|
||||
@@ -175,6 +173,8 @@ public class MimeMessageHelper {
|
||||
|
||||
private FileTypeMap fileTypeMap;
|
||||
|
||||
private boolean encodeFilenames = true;
|
||||
|
||||
private boolean validateAddresses = false;
|
||||
|
||||
|
||||
@@ -464,7 +464,7 @@ public class MimeMessageHelper {
|
||||
* Set the Java Activation Framework {@code FileTypeMap} to use
|
||||
* for determining the content type of inline content and attachments
|
||||
* that get added to the message.
|
||||
* <p>Default is the {@code FileTypeMap} that the underlying
|
||||
* <p>The default is the {@code FileTypeMap} that the underlying
|
||||
* MimeMessage carries, if any, or the Activation Framework's default
|
||||
* {@code FileTypeMap} instance else.
|
||||
* @see #addInline
|
||||
@@ -480,18 +480,40 @@ public class MimeMessageHelper {
|
||||
|
||||
/**
|
||||
* Return the {@code FileTypeMap} used by this MimeMessageHelper.
|
||||
* @see #setFileTypeMap
|
||||
*/
|
||||
public FileTypeMap getFileTypeMap() {
|
||||
return this.fileTypeMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to encode attachment filenames passed to this helper's
|
||||
* {@code #addAttachment} methods.
|
||||
* <p>The default is {@code true} for compatibility with older email clients;
|
||||
* turn this to {@code false} for standard MIME behavior. On a related note,
|
||||
* check out JavaMail's {@code mail.mime.encodefilename} system property.
|
||||
* @since 5.2.9
|
||||
* @see #addAttachment(String, DataSource)
|
||||
* @see MimeBodyPart#setFileName(String)
|
||||
*/
|
||||
public void setEncodeFilenames(boolean encodeFilenames) {
|
||||
this.encodeFilenames = encodeFilenames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to encode attachment filenames passed to this helper's
|
||||
* {@code #addAttachment} methods.
|
||||
* @since 5.2.9
|
||||
* @see #setEncodeFilenames
|
||||
*/
|
||||
public boolean isEncodeFilenames() {
|
||||
return this.encodeFilenames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to validate all addresses which get passed to this helper.
|
||||
* Default is "false".
|
||||
* <p>Note that this is by default just available for JavaMail >= 1.3.
|
||||
* You can override the default {@code validateAddress method} for
|
||||
* validation on older JavaMail versions (or for custom validation).
|
||||
* <p>The default is {@code false}.
|
||||
* @see #validateAddress
|
||||
*/
|
||||
public void setValidateAddresses(boolean validateAddresses) {
|
||||
@@ -500,6 +522,7 @@ public class MimeMessageHelper {
|
||||
|
||||
/**
|
||||
* Return whether this helper will validate all addresses passed to it.
|
||||
* @see #setValidateAddresses
|
||||
*/
|
||||
public boolean isValidateAddresses() {
|
||||
return this.validateAddresses;
|
||||
@@ -508,10 +531,8 @@ public class MimeMessageHelper {
|
||||
/**
|
||||
* Validate the given mail address.
|
||||
* Called by all of MimeMessageHelper's address setters and adders.
|
||||
* <p>Default implementation invokes {@code InternetAddress.validate()},
|
||||
* <p>The default implementation invokes {@link InternetAddress#validate()},
|
||||
* provided that address validation is activated for the helper instance.
|
||||
* <p>Note that this method will just work on JavaMail >= 1.3. You can override
|
||||
* it for validation on older JavaMail versions or for custom validation.
|
||||
* @param address the address to validate
|
||||
* @throws AddressException if validation failed
|
||||
* @see #isValidateAddresses()
|
||||
@@ -525,7 +546,8 @@ public class MimeMessageHelper {
|
||||
|
||||
/**
|
||||
* Validate all given mail addresses.
|
||||
* Default implementation simply delegates to validateAddress for each address.
|
||||
* <p>The default implementation simply delegates to {@link #validateAddress}
|
||||
* for each address.
|
||||
* @param addresses the addresses to validate
|
||||
* @throws AddressException if validation failed
|
||||
* @see #validateAddress(InternetAddress)
|
||||
@@ -885,9 +907,7 @@ public class MimeMessageHelper {
|
||||
Assert.notNull(dataSource, "DataSource must not be null");
|
||||
MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||
mimeBodyPart.setDisposition(MimeBodyPart.INLINE);
|
||||
// We're using setHeader here to remain compatible with JavaMail 1.2,
|
||||
// rather than JavaMail 1.3's setContentID.
|
||||
mimeBodyPart.setHeader(HEADER_CONTENT_ID, "<" + contentId + ">");
|
||||
mimeBodyPart.setContentID("<" + contentId + ">");
|
||||
mimeBodyPart.setDataHandler(new DataHandler(dataSource));
|
||||
getMimeMultipart().addBodyPart(mimeBodyPart);
|
||||
}
|
||||
@@ -997,7 +1017,8 @@ public class MimeMessageHelper {
|
||||
try {
|
||||
MimeBodyPart mimeBodyPart = new MimeBodyPart();
|
||||
mimeBodyPart.setDisposition(MimeBodyPart.ATTACHMENT);
|
||||
mimeBodyPart.setFileName(MimeUtility.encodeText(attachmentFilename));
|
||||
mimeBodyPart.setFileName(isEncodeFilenames() ?
|
||||
MimeUtility.encodeText(attachmentFilename) : attachmentFilename);
|
||||
mimeBodyPart.setDataHandler(new DataHandler(dataSource));
|
||||
getRootMimeMultipart().addBodyPart(mimeBodyPart);
|
||||
}
|
||||
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,6 +17,7 @@
|
||||
package org.springframework.scheduling.quartz;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
@@ -147,7 +148,8 @@ public class LocalDataSourceJobStore extends JobStoreCMT {
|
||||
|
||||
// No, if HSQL is the platform, we really don't want to use locks...
|
||||
try {
|
||||
String productName = JdbcUtils.extractDatabaseMetaData(this.dataSource, "getDatabaseProductName");
|
||||
String productName = JdbcUtils.extractDatabaseMetaData(this.dataSource,
|
||||
DatabaseMetaData::getDatabaseProductName);
|
||||
productName = JdbcUtils.commonDatabaseName(productName);
|
||||
if (productName != null && productName.toLowerCase().contains("hsql")) {
|
||||
setUseDBLocks(false);
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,7 +46,7 @@ public abstract class FreeMarkerTemplateUtils {
|
||||
public static String processTemplateIntoString(Template template, Object model)
|
||||
throws IOException, TemplateException {
|
||||
|
||||
StringWriter result = new StringWriter();
|
||||
StringWriter result = new StringWriter(1024);
|
||||
template.process(model, result);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
+8
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2021 the original author 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,7 +31,8 @@ import org.springframework.core.annotation.AliasFor;
|
||||
*
|
||||
* <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. Note
|
||||
* method to be invoked and its result to be stored in the associated cache if the
|
||||
* {@link #condition()} and {@link #unless()} expressions match accordingly. Note
|
||||
* that Java8's {@code Optional} return types are automatically handled and its
|
||||
* content is stored in the cache if present.
|
||||
*
|
||||
@@ -118,10 +119,15 @@ public @interface CachePut {
|
||||
/**
|
||||
* Spring Expression Language (SpEL) expression used for making the cache
|
||||
* put operation conditional.
|
||||
* <p>This expression is evaluated after the method has been called due to the
|
||||
* nature of the put operation and can therefore refer to the {@code result}.
|
||||
* <p>Default is {@code ""}, meaning the method result is always cached.
|
||||
* <p>The SpEL expression evaluates against a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #result} for a reference to the result of the method invocation. For
|
||||
* supported wrappers such as {@code Optional}, {@code #result} refers to the actual
|
||||
* object, not the wrapper</li>
|
||||
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
|
||||
* references to the {@link java.lang.reflect.Method method}, target object, and
|
||||
* affected cache(s) respectively.</li>
|
||||
@@ -136,8 +142,6 @@ public @interface CachePut {
|
||||
|
||||
/**
|
||||
* 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 against a dedicated context that provides the
|
||||
* following meta-data:
|
||||
|
||||
+26
-1
@@ -379,7 +379,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
|
||||
Cache cache = context.getCaches().iterator().next();
|
||||
try {
|
||||
return wrapCacheValue(method, cache.get(key, () -> unwrapReturnValue(invokeOperation(invoker))));
|
||||
return wrapCacheValue(method, handleSynchronizedGet(invoker, key, cache));
|
||||
}
|
||||
catch (Cache.ValueRetrievalException ex) {
|
||||
// Directly propagate ThrowableWrapper from the invoker,
|
||||
@@ -436,6 +436,22 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object handleSynchronizedGet(CacheOperationInvoker invoker, Object key, Cache cache) {
|
||||
InvocationAwareResult invocationResult = new InvocationAwareResult();
|
||||
Object result = cache.get(key, () -> {
|
||||
invocationResult.invoked = true;
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("No cache entry for key '" + key + "' in cache " + cache.getName());
|
||||
}
|
||||
return unwrapReturnValue(invokeOperation(invoker));
|
||||
});
|
||||
if (!invocationResult.invoked && logger.isTraceEnabled()) {
|
||||
logger.trace("Cache entry for key '" + key + "' found in cache '" + cache.getName() + "'");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object wrapCacheValue(Method method, @Nullable Object cacheValue) {
|
||||
if (method.getReturnType() == Optional.class &&
|
||||
@@ -869,4 +885,13 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal holder class for recording that a cache method was invoked.
|
||||
*/
|
||||
private static class InvocationAwareResult {
|
||||
|
||||
boolean invoked;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vendored
+2
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -55,8 +55,7 @@ public abstract class AbstractValueAdaptingCache implements Cache {
|
||||
@Override
|
||||
@Nullable
|
||||
public ValueWrapper get(Object key) {
|
||||
Object value = lookup(key);
|
||||
return toValueWrapper(value);
|
||||
return toValueWrapper(lookup(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,5 +122,4 @@ public abstract class AbstractValueAdaptingCache implements Cache {
|
||||
return (storeValue != null ? new SimpleValueWrapper(fromStoreValue(storeValue)) : null);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+7
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,6 +24,11 @@ import org.springframework.cache.Cache;
|
||||
/**
|
||||
* Simple cache manager working against a given collection of caches.
|
||||
* Useful for testing or simple caching declarations.
|
||||
* <p>
|
||||
* When using this implementation directly, i.e. not via a regular
|
||||
* bean registration, {@link #initializeCaches()} should be invoked
|
||||
* to initialize its internal state once the
|
||||
* {@linkplain #setCaches(Collection) caches have been provided}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @since 3.1
|
||||
@@ -35,6 +40,7 @@ public class SimpleCacheManager extends AbstractCacheManager {
|
||||
|
||||
/**
|
||||
* Specify the collection of Cache instances to use for this CacheManager.
|
||||
* @see #initializeCaches()
|
||||
*/
|
||||
public void setCaches(Collection<? extends Cache> caches) {
|
||||
this.caches = caches;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -194,7 +194,7 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* declaring {@code @Configuration} class, thus avoiding the above-mentioned lifecycle conflicts.
|
||||
* Note however that {@code static} {@code @Bean} methods will not be enhanced for scoping and AOP
|
||||
* semantics as mentioned above. This works out in {@code BFPP} cases, as they are not typically
|
||||
* referenced by other {@code @Bean} methods. As a reminder, a WARN-level log message will be
|
||||
* referenced by other {@code @Bean} methods. As a reminder, an INFO-level log message will be
|
||||
* issued for any non-static {@code @Bean} methods having a return type assignable to
|
||||
* {@code BeanFactoryPostProcessor}.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,8 +29,8 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
*
|
||||
* <p>Conditions must follow the same restrictions as {@link BeanFactoryPostProcessor}
|
||||
* and take care to never interact with bean instances. For more fine-grained control
|
||||
* of conditions that interact with {@code @Configuration} beans consider the
|
||||
* {@link ConfigurationCondition} interface.
|
||||
* of conditions that interact with {@code @Configuration} beans consider implementing
|
||||
* the {@link ConfigurationCondition} interface.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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.core.io.ResourceLoader;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Context information for use by {@link Condition Conditions}.
|
||||
* Context information for use by {@link Condition} implementations.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Juergen Hoeller
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -62,7 +62,7 @@ import java.lang.annotation.Target;
|
||||
public @interface Conditional {
|
||||
|
||||
/**
|
||||
* All {@link Condition Conditions} that must {@linkplain Condition#matches match}
|
||||
* All {@link Condition} classes that must {@linkplain Condition#matches match}
|
||||
* in order for the component to be registered.
|
||||
*/
|
||||
Class<? extends Condition>[] value();
|
||||
|
||||
+14
-6
@@ -211,7 +211,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
|
||||
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
|
||||
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
|
||||
|
||||
if (metadata.isStatic()) {
|
||||
@@ -276,7 +276,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
new BeanDefinitionHolder(beanDef, beanName), this.registry,
|
||||
proxyMode == ScopedProxyMode.TARGET_CLASS);
|
||||
beanDefToRegister = new ConfigurationClassBeanDefinition(
|
||||
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
|
||||
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, beanName);
|
||||
}
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
@@ -398,24 +398,31 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
|
||||
private final MethodMetadata factoryMethodMetadata;
|
||||
|
||||
public ConfigurationClassBeanDefinition(ConfigurationClass configClass, MethodMetadata beanMethodMetadata) {
|
||||
private final String derivedBeanName;
|
||||
|
||||
public ConfigurationClassBeanDefinition(
|
||||
ConfigurationClass configClass, MethodMetadata beanMethodMetadata, String derivedBeanName) {
|
||||
|
||||
this.annotationMetadata = configClass.getMetadata();
|
||||
this.factoryMethodMetadata = beanMethodMetadata;
|
||||
this.derivedBeanName = derivedBeanName;
|
||||
setResource(configClass.getResource());
|
||||
setLenientConstructorResolution(false);
|
||||
}
|
||||
|
||||
public ConfigurationClassBeanDefinition(
|
||||
RootBeanDefinition original, ConfigurationClass configClass, MethodMetadata beanMethodMetadata) {
|
||||
public ConfigurationClassBeanDefinition(RootBeanDefinition original,
|
||||
ConfigurationClass configClass, MethodMetadata beanMethodMetadata, String derivedBeanName) {
|
||||
super(original);
|
||||
this.annotationMetadata = configClass.getMetadata();
|
||||
this.factoryMethodMetadata = beanMethodMetadata;
|
||||
this.derivedBeanName = derivedBeanName;
|
||||
}
|
||||
|
||||
private ConfigurationClassBeanDefinition(ConfigurationClassBeanDefinition original) {
|
||||
super(original);
|
||||
this.annotationMetadata = original.annotationMetadata;
|
||||
this.factoryMethodMetadata = original.factoryMethodMetadata;
|
||||
this.derivedBeanName = original.derivedBeanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -431,7 +438,8 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
|
||||
@Override
|
||||
public boolean isFactoryMethod(Method candidate) {
|
||||
return (super.isFactoryMethod(candidate) && BeanAnnotationHelper.isBeanAnnotated(candidate));
|
||||
return (super.isFactoryMethod(candidate) && BeanAnnotationHelper.isBeanAnnotated(candidate) &&
|
||||
BeanAnnotationHelper.determineBeanNameFor(candidate).equals(this.derivedBeanName));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -19,6 +19,7 @@ package org.springframework.context.annotation;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
@@ -461,7 +462,7 @@ class ConfigurationClassParser {
|
||||
Resource resource = this.resourceLoader.getResource(resolvedLocation);
|
||||
addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
|
||||
}
|
||||
catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) {
|
||||
catch (IllegalArgumentException | FileNotFoundException | UnknownHostException | SocketException ex) {
|
||||
// Placeholders not resolvable or resource not found when trying to open it
|
||||
if (ignoreResourceNotFound) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
@@ -666,7 +667,7 @@ class ConfigurationClassParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to obtain {@link SourceClass SourceClasss} from class names.
|
||||
* Factory method to obtain a {@link SourceClass} collection from class names.
|
||||
*/
|
||||
private Collection<SourceClass> asSourceClasses(String[] classNames, Predicate<String> filter) throws IOException {
|
||||
List<SourceClass> annotatedClasses = new ArrayList<>(classNames.length);
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,7 @@ package org.springframework.context.annotation;
|
||||
|
||||
/**
|
||||
* A {@link Condition} that offers more fine-grained control when used with
|
||||
* {@code @Configuration}. Allows certain {@link Condition Conditions} to adapt when they match
|
||||
* {@code @Configuration}. Allows certain conditions to adapt when they match
|
||||
* based on the configuration phase. For example, a condition that checks if a bean
|
||||
* has already been registered might choose to only be evaluated during the
|
||||
* {@link ConfigurationPhase#REGISTER_BEAN REGISTER_BEAN} {@link ConfigurationPhase}.
|
||||
@@ -52,8 +52,8 @@ public interface ConfigurationCondition extends Condition {
|
||||
* The {@link Condition} should be evaluated when adding a regular
|
||||
* (non {@code @Configuration}) bean. The condition will not prevent
|
||||
* {@code @Configuration} classes from being added.
|
||||
* <p>At the time that the condition is evaluated, all {@code @Configuration}s
|
||||
* will have been parsed.
|
||||
* <p>At the time that the condition is evaluated, all {@code @Configuration}
|
||||
* classes will have been parsed.
|
||||
*/
|
||||
REGISTER_BEAN
|
||||
}
|
||||
|
||||
+18
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,12 +20,14 @@ import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
@@ -73,9 +75,11 @@ public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotat
|
||||
}
|
||||
|
||||
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
|
||||
Assert.state(getBeanFactory() instanceof DefaultListableBeanFactory,
|
||||
BeanFactory beanFactory = getBeanFactory();
|
||||
Assert.state(beanFactory instanceof DefaultListableBeanFactory,
|
||||
"BeanFactory needs to be a DefaultListableBeanFactory");
|
||||
final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory();
|
||||
final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;
|
||||
|
||||
TargetSource ts = new TargetSource() {
|
||||
@Override
|
||||
public Class<?> getTargetClass() {
|
||||
@@ -87,7 +91,8 @@ public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotat
|
||||
}
|
||||
@Override
|
||||
public Object getTarget() {
|
||||
Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null);
|
||||
Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);
|
||||
Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
|
||||
if (target == null) {
|
||||
Class<?> type = getTargetClass();
|
||||
if (Map.class == type) {
|
||||
@@ -102,19 +107,27 @@ public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotat
|
||||
throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
|
||||
"Optional dependency not present for lazy injection point");
|
||||
}
|
||||
if (autowiredBeanNames != null) {
|
||||
for (String autowiredBeanName : autowiredBeanNames) {
|
||||
if (dlbf.containsBean(autowiredBeanName)) {
|
||||
dlbf.registerDependentBean(autowiredBeanName, beanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
@Override
|
||||
public void releaseTarget(Object target) {
|
||||
}
|
||||
};
|
||||
|
||||
ProxyFactory pf = new ProxyFactory();
|
||||
pf.setTargetSource(ts);
|
||||
Class<?> dependencyType = descriptor.getDependencyType();
|
||||
if (dependencyType.isInterface()) {
|
||||
pf.addInterface(dependencyType);
|
||||
}
|
||||
return pf.getProxy(beanFactory.getBeanClassLoader());
|
||||
return pf.getProxy(dlbf.getBeanClassLoader());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
@@ -43,6 +43,15 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class FullyQualifiedAnnotationBeanNameGenerator extends AnnotationBeanNameGenerator {
|
||||
|
||||
/**
|
||||
* A convenient constant for a default {@code FullyQualifiedAnnotationBeanNameGenerator}
|
||||
* instance, as used for configuration-level import purposes.
|
||||
* @since 5.2.11
|
||||
*/
|
||||
public static final FullyQualifiedAnnotationBeanNameGenerator INSTANCE =
|
||||
new FullyQualifiedAnnotationBeanNameGenerator();
|
||||
|
||||
|
||||
@Override
|
||||
protected String buildDefaultBeanName(BeanDefinition definition) {
|
||||
String beanClassName = definition.getBeanClassName();
|
||||
|
||||
+98
-54
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -63,9 +63,9 @@ import org.springframework.util.ObjectUtils;
|
||||
public abstract class AbstractApplicationEventMulticaster
|
||||
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
|
||||
|
||||
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
|
||||
private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();
|
||||
|
||||
final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
|
||||
final Map<ListenerCacheKey, CachedListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
|
||||
|
||||
@Nullable
|
||||
private ClassLoader beanClassLoader;
|
||||
@@ -73,8 +73,6 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
@Nullable
|
||||
private ConfigurableBeanFactory beanFactory;
|
||||
|
||||
private Object retrievalMutex = this.defaultRetriever;
|
||||
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
@@ -90,7 +88,6 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
if (this.beanClassLoader == null) {
|
||||
this.beanClassLoader = this.beanFactory.getBeanClassLoader();
|
||||
}
|
||||
this.retrievalMutex = this.beanFactory.getSingletonMutex();
|
||||
}
|
||||
|
||||
private ConfigurableBeanFactory getBeanFactory() {
|
||||
@@ -104,7 +101,7 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
|
||||
@Override
|
||||
public void addApplicationListener(ApplicationListener<?> listener) {
|
||||
synchronized (this.retrievalMutex) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
// Explicitly remove target for a proxy, if registered already,
|
||||
// in order to avoid double invocations of the same listener.
|
||||
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
|
||||
@@ -118,7 +115,7 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
|
||||
@Override
|
||||
public void addApplicationListenerBean(String listenerBeanName) {
|
||||
synchronized (this.retrievalMutex) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
@@ -126,7 +123,7 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
|
||||
@Override
|
||||
public void removeApplicationListener(ApplicationListener<?> listener) {
|
||||
synchronized (this.retrievalMutex) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
this.defaultRetriever.applicationListeners.remove(listener);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
@@ -134,7 +131,7 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
|
||||
@Override
|
||||
public void removeApplicationListenerBean(String listenerBeanName) {
|
||||
synchronized (this.retrievalMutex) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName);
|
||||
this.retrieverCache.clear();
|
||||
}
|
||||
@@ -142,7 +139,7 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
|
||||
@Override
|
||||
public void removeAllListeners() {
|
||||
synchronized (this.retrievalMutex) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
this.defaultRetriever.applicationListeners.clear();
|
||||
this.defaultRetriever.applicationListenerBeans.clear();
|
||||
this.retrieverCache.clear();
|
||||
@@ -156,7 +153,7 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
* @see org.springframework.context.ApplicationListener
|
||||
*/
|
||||
protected Collection<ApplicationListener<?>> getApplicationListeners() {
|
||||
synchronized (this.retrievalMutex) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
return this.defaultRetriever.getApplicationListeners();
|
||||
}
|
||||
}
|
||||
@@ -177,32 +174,34 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
Class<?> sourceType = (source != null ? source.getClass() : null);
|
||||
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
|
||||
|
||||
// Quick check for existing entry on ConcurrentHashMap...
|
||||
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
|
||||
if (retriever != null) {
|
||||
return retriever.getApplicationListeners();
|
||||
}
|
||||
// Potential new retriever to populate
|
||||
CachedListenerRetriever newRetriever = null;
|
||||
|
||||
if (this.beanClassLoader == null ||
|
||||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
|
||||
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
|
||||
// Fully synchronized building and caching of a ListenerRetriever
|
||||
synchronized (this.retrievalMutex) {
|
||||
retriever = this.retrieverCache.get(cacheKey);
|
||||
if (retriever != null) {
|
||||
return retriever.getApplicationListeners();
|
||||
// Quick check for existing entry on ConcurrentHashMap
|
||||
CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
|
||||
if (existingRetriever == null) {
|
||||
// Caching a new ListenerRetriever if possible
|
||||
if (this.beanClassLoader == null ||
|
||||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
|
||||
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
|
||||
newRetriever = new CachedListenerRetriever();
|
||||
existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
|
||||
if (existingRetriever != null) {
|
||||
newRetriever = null; // no need to populate it in retrieveApplicationListeners
|
||||
}
|
||||
retriever = new ListenerRetriever(true);
|
||||
Collection<ApplicationListener<?>> listeners =
|
||||
retrieveApplicationListeners(eventType, sourceType, retriever);
|
||||
this.retrieverCache.put(cacheKey, retriever);
|
||||
return listeners;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No ListenerRetriever caching -> no synchronization necessary
|
||||
return retrieveApplicationListeners(eventType, sourceType, null);
|
||||
|
||||
if (existingRetriever != null) {
|
||||
Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
// If result is null, the existing retriever is not fully populated yet by another thread.
|
||||
// Proceed like caching wasn't possible for this current local attempt.
|
||||
}
|
||||
|
||||
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,12 +212,15 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
* @return the pre-filtered list of application listeners for the given event and source type
|
||||
*/
|
||||
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
|
||||
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
|
||||
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {
|
||||
|
||||
List<ApplicationListener<?>> allListeners = new ArrayList<>();
|
||||
Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
|
||||
Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);
|
||||
|
||||
Set<ApplicationListener<?>> listeners;
|
||||
Set<String> listenerBeans;
|
||||
synchronized (this.retrievalMutex) {
|
||||
synchronized (this.defaultRetriever) {
|
||||
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
|
||||
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
|
||||
}
|
||||
@@ -228,7 +230,7 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
for (ApplicationListener<?> listener : listeners) {
|
||||
if (supportsEvent(listener, eventType, sourceType)) {
|
||||
if (retriever != null) {
|
||||
retriever.applicationListeners.add(listener);
|
||||
filteredListeners.add(listener);
|
||||
}
|
||||
allListeners.add(listener);
|
||||
}
|
||||
@@ -246,10 +248,10 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
|
||||
if (retriever != null) {
|
||||
if (beanFactory.isSingleton(listenerBeanName)) {
|
||||
retriever.applicationListeners.add(listener);
|
||||
filteredListeners.add(listener);
|
||||
}
|
||||
else {
|
||||
retriever.applicationListenerBeans.add(listenerBeanName);
|
||||
filteredListenerBeans.add(listenerBeanName);
|
||||
}
|
||||
}
|
||||
allListeners.add(listener);
|
||||
@@ -261,7 +263,7 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
// BeanDefinition metadata (e.g. factory method generics) above.
|
||||
Object listener = beanFactory.getSingleton(listenerBeanName);
|
||||
if (retriever != null) {
|
||||
retriever.applicationListeners.remove(listener);
|
||||
filteredListeners.remove(listener);
|
||||
}
|
||||
allListeners.remove(listener);
|
||||
}
|
||||
@@ -274,9 +276,15 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
}
|
||||
|
||||
AnnotationAwareOrderComparator.sort(allListeners);
|
||||
if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
|
||||
retriever.applicationListeners.clear();
|
||||
retriever.applicationListeners.addAll(allListeners);
|
||||
if (retriever != null) {
|
||||
if (filteredListenerBeans.isEmpty()) {
|
||||
retriever.applicationListeners = new LinkedHashSet<>(allListeners);
|
||||
retriever.applicationListenerBeans = filteredListenerBeans;
|
||||
}
|
||||
else {
|
||||
retriever.applicationListeners = filteredListeners;
|
||||
retriever.applicationListenerBeans = filteredListenerBeans;
|
||||
}
|
||||
}
|
||||
return allListeners;
|
||||
}
|
||||
@@ -415,18 +423,55 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
* allowing for efficient retrieval of pre-filtered listeners.
|
||||
* <p>An instance of this helper gets cached per event type and source type.
|
||||
*/
|
||||
private class ListenerRetriever {
|
||||
private class CachedListenerRetriever {
|
||||
|
||||
@Nullable
|
||||
public volatile Set<ApplicationListener<?>> applicationListeners;
|
||||
|
||||
@Nullable
|
||||
public volatile Set<String> applicationListenerBeans;
|
||||
|
||||
@Nullable
|
||||
public Collection<ApplicationListener<?>> getApplicationListeners() {
|
||||
Set<ApplicationListener<?>> applicationListeners = this.applicationListeners;
|
||||
Set<String> applicationListenerBeans = this.applicationListenerBeans;
|
||||
if (applicationListeners == null || applicationListenerBeans == null) {
|
||||
// Not fully populated yet
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ApplicationListener<?>> allListeners = new ArrayList<>(
|
||||
applicationListeners.size() + applicationListenerBeans.size());
|
||||
allListeners.addAll(applicationListeners);
|
||||
if (!applicationListenerBeans.isEmpty()) {
|
||||
BeanFactory beanFactory = getBeanFactory();
|
||||
for (String listenerBeanName : applicationListenerBeans) {
|
||||
try {
|
||||
allListeners.add(beanFactory.getBean(listenerBeanName, ApplicationListener.class));
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Singleton listener instance (without backing bean definition) disappeared -
|
||||
// probably in the middle of the destruction phase
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!applicationListenerBeans.isEmpty()) {
|
||||
AnnotationAwareOrderComparator.sort(allListeners);
|
||||
}
|
||||
return allListeners;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper class that encapsulates a general set of target listeners.
|
||||
*/
|
||||
private class DefaultListenerRetriever {
|
||||
|
||||
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
|
||||
|
||||
public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
|
||||
|
||||
private final boolean preFiltered;
|
||||
|
||||
public ListenerRetriever(boolean preFiltered) {
|
||||
this.preFiltered = preFiltered;
|
||||
}
|
||||
|
||||
public Collection<ApplicationListener<?>> getApplicationListeners() {
|
||||
List<ApplicationListener<?>> allListeners = new ArrayList<>(
|
||||
this.applicationListeners.size() + this.applicationListenerBeans.size());
|
||||
@@ -435,8 +480,9 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
BeanFactory beanFactory = getBeanFactory();
|
||||
for (String listenerBeanName : this.applicationListenerBeans) {
|
||||
try {
|
||||
ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
|
||||
if (this.preFiltered || !allListeners.contains(listener)) {
|
||||
ApplicationListener<?> listener =
|
||||
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
|
||||
if (!allListeners.contains(listener)) {
|
||||
allListeners.add(listener);
|
||||
}
|
||||
}
|
||||
@@ -446,9 +492,7 @@ public abstract class AbstractApplicationEventMulticaster
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this.preFiltered || !this.applicationListenerBeans.isEmpty()) {
|
||||
AnnotationAwareOrderComparator.sort(allListeners);
|
||||
}
|
||||
AnnotationAwareOrderComparator.sort(allListeners);
|
||||
return allListeners;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -218,7 +218,7 @@ public abstract class AbstractResourceBasedMessageSource extends AbstractMessage
|
||||
* a non-classpath location.
|
||||
*/
|
||||
public void setCacheSeconds(int cacheSeconds) {
|
||||
this.cacheMillis = (cacheSeconds * 1000);
|
||||
this.cacheMillis = cacheSeconds * 1000L;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+9
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -67,7 +67,14 @@ public class SimpleThreadScope implements Scope {
|
||||
@Override
|
||||
public Object get(String name, ObjectFactory<?> objectFactory) {
|
||||
Map<String, Object> scope = this.threadScope.get();
|
||||
return scope.computeIfAbsent(name, k -> objectFactory.getObject());
|
||||
// NOTE: Do NOT modify the following to use Map::computeIfAbsent. For details,
|
||||
// see https://github.com/spring-projects/spring-framework/issues/25801.
|
||||
Object scopedObject = scope.get(name);
|
||||
if (scopedObject == null) {
|
||||
scopedObject = objectFactory.getObject();
|
||||
scope.put(name, scopedObject);
|
||||
}
|
||||
return scopedObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -106,7 +106,6 @@ public @interface DateTimeFormat {
|
||||
/**
|
||||
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSXXX},
|
||||
* e.g. "2000-10-31T01:30:00.000-05:00".
|
||||
* <p>This is the default if no annotation value is specified.
|
||||
*/
|
||||
DATE_TIME,
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,7 +39,7 @@ import org.springframework.util.StringValueResolver;
|
||||
* {@link DefaultConversionService#addDefaultConverters addDefaultConverters} method.
|
||||
*
|
||||
* <p>Automatically registers formatters for JSR-354 Money & Currency, JSR-310 Date-Time
|
||||
* and/or Joda-Time, depending on the presence of the corresponding API on the classpath.
|
||||
* and/or Joda-Time 2.x, depending on the presence of the corresponding API on the classpath.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
@@ -54,7 +54,7 @@ public class DefaultFormattingConversionService extends FormattingConversionServ
|
||||
static {
|
||||
ClassLoader classLoader = DefaultFormattingConversionService.class.getClassLoader();
|
||||
jsr354Present = ClassUtils.isPresent("javax.money.MonetaryAmount", classLoader);
|
||||
jodaTimePresent = ClassUtils.isPresent("org.joda.time.LocalDate", classLoader);
|
||||
jodaTimePresent = ClassUtils.isPresent("org.joda.time.YearMonth", classLoader);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,10 +37,11 @@ import org.springframework.lang.Nullable;
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
* @see javax.enterprise.concurrent.ManagedScheduledExecutorService
|
||||
*/
|
||||
public class DefaultManagedTaskScheduler extends ConcurrentTaskScheduler implements InitializingBean {
|
||||
|
||||
private JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate();
|
||||
private final JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate();
|
||||
|
||||
@Nullable
|
||||
private String jndiName = "java:comp/DefaultManagedScheduledExecutorService";
|
||||
|
||||
+1
-1
@@ -146,7 +146,7 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
|
||||
* @see java.util.concurrent.ExecutorService#awaitTermination
|
||||
*/
|
||||
public void setAwaitTerminationSeconds(int awaitTerminationSeconds) {
|
||||
this.awaitTerminationMillis = awaitTerminationSeconds * 1000;
|
||||
this.awaitTerminationMillis = awaitTerminationSeconds * 1000L;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -107,7 +107,7 @@ public class TaskExecutorFactoryBean implements
|
||||
int separatorIndex = this.poolSize.indexOf('-');
|
||||
if (separatorIndex != -1) {
|
||||
corePoolSize = Integer.parseInt(this.poolSize.substring(0, separatorIndex));
|
||||
maxPoolSize = Integer.parseInt(this.poolSize.substring(separatorIndex + 1, this.poolSize.length()));
|
||||
maxPoolSize = Integer.parseInt(this.poolSize.substring(separatorIndex + 1));
|
||||
if (corePoolSize > maxPoolSize) {
|
||||
throw new IllegalArgumentException(
|
||||
"Lower bound of pool-size range must not exceed the upper bound");
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,11 +18,11 @@ package org.springframework.validation;
|
||||
|
||||
import java.beans.PropertyEditor;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -50,7 +50,7 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi
|
||||
|
||||
private MessageCodesResolver messageCodesResolver = new DefaultMessageCodesResolver();
|
||||
|
||||
private final List<ObjectError> errors = new LinkedList<>();
|
||||
private final List<ObjectError> errors = new ArrayList<>();
|
||||
|
||||
private final Map<String, Class<?>> fieldTypes = new HashMap<>();
|
||||
|
||||
@@ -105,7 +105,7 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi
|
||||
public void rejectValue(@Nullable String field, String errorCode, @Nullable Object[] errorArgs,
|
||||
@Nullable String defaultMessage) {
|
||||
|
||||
if ("".equals(getNestedPath()) && !StringUtils.hasLength(field)) {
|
||||
if (!StringUtils.hasLength(getNestedPath()) && !StringUtils.hasLength(field)) {
|
||||
// We're at the top of the nested object hierarchy,
|
||||
// so the present level is not a field but rather the top object.
|
||||
// The best we can do is register a global error here...
|
||||
@@ -145,7 +145,7 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi
|
||||
|
||||
@Override
|
||||
public List<ObjectError> getGlobalErrors() {
|
||||
List<ObjectError> result = new LinkedList<>();
|
||||
List<ObjectError> result = new ArrayList<>();
|
||||
for (ObjectError objectError : this.errors) {
|
||||
if (!(objectError instanceof FieldError)) {
|
||||
result.add(objectError);
|
||||
@@ -167,7 +167,7 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi
|
||||
|
||||
@Override
|
||||
public List<FieldError> getFieldErrors() {
|
||||
List<FieldError> result = new LinkedList<>();
|
||||
List<FieldError> result = new ArrayList<>();
|
||||
for (ObjectError objectError : this.errors) {
|
||||
if (objectError instanceof FieldError) {
|
||||
result.add((FieldError) objectError);
|
||||
@@ -189,7 +189,7 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi
|
||||
|
||||
@Override
|
||||
public List<FieldError> getFieldErrors(String field) {
|
||||
List<FieldError> result = new LinkedList<>();
|
||||
List<FieldError> result = new ArrayList<>();
|
||||
String fixedField = fixedField(field);
|
||||
for (ObjectError objectError : this.errors) {
|
||||
if (objectError instanceof FieldError && isMatchingFieldError(fixedField, (FieldError) objectError)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,9 +18,9 @@ package org.springframework.validation;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
@@ -146,7 +146,7 @@ public abstract class AbstractErrors implements Errors, Serializable {
|
||||
|
||||
@Override
|
||||
public List<ObjectError> getAllErrors() {
|
||||
List<ObjectError> result = new LinkedList<>();
|
||||
List<ObjectError> result = new ArrayList<>();
|
||||
result.addAll(getGlobalErrors());
|
||||
result.addAll(getFieldErrors());
|
||||
return Collections.unmodifiableList(result);
|
||||
@@ -199,7 +199,7 @@ public abstract class AbstractErrors implements Errors, Serializable {
|
||||
@Override
|
||||
public List<FieldError> getFieldErrors(String field) {
|
||||
List<FieldError> fieldErrors = getFieldErrors();
|
||||
List<FieldError> result = new LinkedList<>();
|
||||
List<FieldError> result = new ArrayList<>();
|
||||
String fixedField = fixedField(field);
|
||||
for (FieldError error : fieldErrors) {
|
||||
if (isMatchingFieldError(fixedField, error)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -70,8 +70,6 @@ public class BindException extends Exception implements BindingResult {
|
||||
|
||||
/**
|
||||
* Return the BindingResult that this BindException wraps.
|
||||
* Will typically be a BeanPropertyBindingResult.
|
||||
* @see BeanPropertyBindingResult
|
||||
*/
|
||||
public final BindingResult getBindingResult() {
|
||||
return this.bindingResult;
|
||||
@@ -231,6 +229,7 @@ public class BindException extends Exception implements BindingResult {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getTarget() {
|
||||
return this.bindingResult.getTarget();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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.validation;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -52,11 +53,15 @@ public class MapBindingResult extends AbstractBindingResult implements Serializa
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the target Map to bind onto.
|
||||
*/
|
||||
public final Map<?, ?> getTargetMap() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public final Object getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
+30
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 the original author 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,10 @@
|
||||
package org.springframework.validation.beanvalidation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -291,12 +293,17 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
configureParameterNameProvider(this.parameterNameDiscoverer, configuration);
|
||||
}
|
||||
|
||||
List<InputStream> mappingStreams = null;
|
||||
if (this.mappingLocations != null) {
|
||||
mappingStreams = new ArrayList<>(this.mappingLocations.length);
|
||||
for (Resource location : this.mappingLocations) {
|
||||
try {
|
||||
configuration.addMapping(location.getInputStream());
|
||||
InputStream stream = location.getInputStream();
|
||||
mappingStreams.add(stream);
|
||||
configuration.addMapping(stream);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
closeMappingStreams(mappingStreams);
|
||||
throw new IllegalStateException("Cannot read mapping resource: " + location);
|
||||
}
|
||||
}
|
||||
@@ -307,8 +314,13 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
// Allow for custom post-processing before we actually build the ValidatorFactory.
|
||||
postProcessConfiguration(configuration);
|
||||
|
||||
this.validatorFactory = configuration.buildValidatorFactory();
|
||||
setTargetValidator(this.validatorFactory.getValidator());
|
||||
try {
|
||||
this.validatorFactory = configuration.buildValidatorFactory();
|
||||
setTargetValidator(this.validatorFactory.getValidator());
|
||||
}
|
||||
finally {
|
||||
closeMappingStreams(mappingStreams);
|
||||
}
|
||||
}
|
||||
|
||||
private void configureParameterNameProvider(ParameterNameDiscoverer discoverer, Configuration<?> configuration) {
|
||||
@@ -329,6 +341,18 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
});
|
||||
}
|
||||
|
||||
private void closeMappingStreams(@Nullable List<InputStream> mappingStreams){
|
||||
if (!CollectionUtils.isEmpty(mappingStreams)) {
|
||||
for (InputStream stream : mappingStreams) {
|
||||
try {
|
||||
stream.close();
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process the given Bean Validation configuration,
|
||||
* adding to or overriding any of its settings.
|
||||
@@ -397,7 +421,7 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
return super.unwrap(type);
|
||||
}
|
||||
catch (ValidationException ex) {
|
||||
// ignore - we'll try ValidatorFactory unwrapping next
|
||||
// Ignore - we'll try ValidatorFactory unwrapping next
|
||||
}
|
||||
}
|
||||
if (this.validatorFactory != null) {
|
||||
@@ -405,7 +429,7 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
return this.validatorFactory.unwrap(type);
|
||||
}
|
||||
catch (ValidationException ex) {
|
||||
// ignore if just being asked for ValidatorFactory
|
||||
// Ignore if just being asked for ValidatorFactory
|
||||
if (ValidatorFactory.class == type) {
|
||||
return (T) this.validatorFactory;
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -179,7 +179,7 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
|
||||
}
|
||||
}
|
||||
else {
|
||||
// got no BindingResult - can only do standard rejectValue call
|
||||
// Got no BindingResult - can only do standard rejectValue call
|
||||
// with automatic extraction of the current field value
|
||||
errors.rejectValue(field, errorCode, errorArgs, violation.getMessage());
|
||||
}
|
||||
@@ -311,7 +311,7 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
|
||||
@Nullable
|
||||
protected Object getRejectedValue(String field, ConstraintViolation<Object> violation, BindingResult bindingResult) {
|
||||
Object invalidValue = violation.getInvalidValue();
|
||||
if (!"".equals(field) && !field.contains("[]") &&
|
||||
if (!field.isEmpty() && !field.contains("[]") &&
|
||||
(invalidValue == violation.getLeafBean() || field.contains("[") || field.contains("."))) {
|
||||
// Possibly a bean constraint with property path: retrieve the actual property value.
|
||||
// However, explicitly avoid this for "address[]" style paths that we can't handle.
|
||||
@@ -386,7 +386,7 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
|
||||
return (type != null ? this.targetValidator.unwrap(type) : (T) this.targetValidator);
|
||||
}
|
||||
catch (ValidationException ex) {
|
||||
// ignore if just being asked for plain Validator
|
||||
// Ignore if just being asked for plain JSR-303 Validator
|
||||
if (javax.validation.Validator.class == type) {
|
||||
return (T) this.targetValidator;
|
||||
}
|
||||
|
||||
+8
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,24 +36,26 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class AtAspectJAfterThrowingTests {
|
||||
|
||||
@Test
|
||||
public void testAccessThrowable() throws Exception {
|
||||
public void testAccessThrowable() {
|
||||
ClassPathXmlApplicationContext ctx =
|
||||
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
|
||||
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
|
||||
|
||||
ITestBean bean = (ITestBean) ctx.getBean("testBean");
|
||||
ExceptionHandlingAspect aspect = (ExceptionHandlingAspect) ctx.getBean("aspect");
|
||||
|
||||
assertThat(AopUtils.isAopProxy(bean)).isTrue();
|
||||
IOException exceptionThrown = null;
|
||||
try {
|
||||
bean.unreliableFileOperation();
|
||||
}
|
||||
catch (IOException e) {
|
||||
//
|
||||
catch (IOException ex) {
|
||||
exceptionThrown = ex;
|
||||
}
|
||||
|
||||
assertThat(aspect.handled).isEqualTo(1);
|
||||
assertThat(aspect.lastException).isNotNull();
|
||||
assertThat(aspect.lastException).isSameAs(exceptionThrown);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class AtAspectJAnnotationBindingTests {
|
||||
|
||||
private AnnotatedTestBean testBean;
|
||||
|
||||
private ClassPathXmlApplicationContext ctx;
|
||||
|
||||
|
||||
@@ -70,8 +71,7 @@ public class AtAspectJAnnotationBindingTests {
|
||||
class AtAspectJAnnotationBindingTestAspect {
|
||||
|
||||
@Around("execution(* *(..)) && @annotation(testAnn)")
|
||||
public Object doWithAnnotation(ProceedingJoinPoint pjp, TestAnnotation testAnn)
|
||||
throws Throwable {
|
||||
public Object doWithAnnotation(ProceedingJoinPoint pjp, TestAnnotation testAnn) throws Throwable {
|
||||
String annValue = testAnn.value();
|
||||
Object result = pjp.proceed();
|
||||
return (result instanceof String ? annValue + " " + result : result);
|
||||
|
||||
+69
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author 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,14 +16,23 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* @author Andy Wilkinson
|
||||
* @author Liu Dongmiao
|
||||
*/
|
||||
public class AggressiveFactoryBeanInstantiationTests {
|
||||
|
||||
@@ -49,17 +58,66 @@ public class AggressiveFactoryBeanInstantiationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkLinkageError() {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
context.register(BeanMethodConfigurationWithExceptionInInitializer.class);
|
||||
context.refresh();
|
||||
fail("Should have thrown BeanCreationException");
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
PrintWriter pw = new PrintWriter(baos);
|
||||
ex.printStackTrace(pw);
|
||||
pw.flush();
|
||||
String stackTrace = baos.toString();
|
||||
assertThat(stackTrace.contains(".<clinit>")).isTrue();
|
||||
assertThat(stackTrace.contains("java.lang.NoClassDefFoundError")).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class BeanMethodConfiguration {
|
||||
|
||||
@Bean
|
||||
public String foo() {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AutowiredBean autowiredBean() {
|
||||
return new AutowiredBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@DependsOn("autowiredBean")
|
||||
public SimpleFactoryBean simpleFactoryBean(ApplicationContext applicationContext) {
|
||||
return new SimpleFactoryBean(applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class BeanMethodConfigurationWithExceptionInInitializer extends BeanMethodConfiguration {
|
||||
|
||||
@Bean
|
||||
@DependsOn("autowiredBean")
|
||||
@Override
|
||||
public SimpleFactoryBean simpleFactoryBean(ApplicationContext applicationContext) {
|
||||
new ExceptionInInitializer();
|
||||
return new SimpleFactoryBean(applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class AutowiredBean {
|
||||
|
||||
@Autowired
|
||||
String foo;
|
||||
}
|
||||
|
||||
|
||||
static class SimpleFactoryBean implements FactoryBean<Object> {
|
||||
|
||||
public SimpleFactoryBean(ApplicationContext applicationContext) {
|
||||
@@ -76,4 +134,14 @@ public class AggressiveFactoryBeanInstantiationTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class ExceptionInInitializer {
|
||||
|
||||
private static final int ERROR = callInClinit();
|
||||
|
||||
private static int callInClinit() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,7 +20,6 @@ import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -105,7 +104,9 @@ public class ConfigurationClassPostProcessorTests {
|
||||
Foo foo = beanFactory.getBean("foo", Foo.class);
|
||||
Bar bar = beanFactory.getBean("bar", Bar.class);
|
||||
assertThat(bar.foo).isSameAs(foo);
|
||||
assertThat(Arrays.asList(beanFactory.getDependentBeans("foo")).contains("bar")).isTrue();
|
||||
assertThat(ObjectUtils.containsElement(beanFactory.getDependentBeans("foo"), "bar")).isTrue();
|
||||
assertThat(ObjectUtils.containsElement(beanFactory.getDependentBeans("config"), "foo")).isTrue();
|
||||
assertThat(ObjectUtils.containsElement(beanFactory.getDependentBeans("config"), "bar")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -117,7 +118,9 @@ public class ConfigurationClassPostProcessorTests {
|
||||
Foo foo = beanFactory.getBean("foo", Foo.class);
|
||||
Bar bar = beanFactory.getBean("bar", Bar.class);
|
||||
assertThat(bar.foo).isSameAs(foo);
|
||||
assertThat(Arrays.asList(beanFactory.getDependentBeans("foo")).contains("bar")).isTrue();
|
||||
assertThat(ObjectUtils.containsElement(beanFactory.getDependentBeans("foo"), "bar")).isTrue();
|
||||
assertThat(ObjectUtils.containsElement(beanFactory.getDependentBeans("config"), "foo")).isTrue();
|
||||
assertThat(ObjectUtils.containsElement(beanFactory.getDependentBeans("config"), "bar")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+7
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author 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 class EnableLoadTimeWeavingTests {
|
||||
@Test
|
||||
public void control() {
|
||||
GenericXmlApplicationContext ctx =
|
||||
new GenericXmlApplicationContext(getClass(), "EnableLoadTimeWeavingTests-context.xml");
|
||||
new GenericXmlApplicationContext(getClass(), "EnableLoadTimeWeavingTests-context.xml");
|
||||
ctx.getBean("loadTimeWeaver", LoadTimeWeaver.class);
|
||||
}
|
||||
|
||||
@@ -73,9 +73,11 @@ public class EnableLoadTimeWeavingTests {
|
||||
verify(loadTimeWeaver).addTransformer(isA(ClassFileTransformer.class));
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.DISABLED)
|
||||
static class EnableLTWConfig_withAjWeavingDisabled implements LoadTimeWeavingConfigurer {
|
||||
|
||||
@Override
|
||||
public LoadTimeWeaver getLoadTimeWeaver() {
|
||||
return mock(LoadTimeWeaver.class);
|
||||
@@ -85,6 +87,7 @@ public class EnableLoadTimeWeavingTests {
|
||||
@Configuration
|
||||
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.AUTODETECT)
|
||||
static class EnableLTWConfig_withAjWeavingAutodetect implements LoadTimeWeavingConfigurer {
|
||||
|
||||
@Override
|
||||
public LoadTimeWeaver getLoadTimeWeaver() {
|
||||
return mock(LoadTimeWeaver.class);
|
||||
@@ -94,9 +97,11 @@ public class EnableLoadTimeWeavingTests {
|
||||
@Configuration
|
||||
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
|
||||
static class EnableLTWConfig_withAjWeavingEnabled implements LoadTimeWeavingConfigurer {
|
||||
|
||||
@Override
|
||||
public LoadTimeWeaver getLoadTimeWeaver() {
|
||||
return mock(LoadTimeWeaver.class);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,11 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -49,14 +51,18 @@ public class LazyAutowiredAnnotationBeanPostProcessorTests {
|
||||
ac.registerBeanDefinition("testBean", tbd);
|
||||
ac.refresh();
|
||||
|
||||
ConfigurableListableBeanFactory bf = ac.getBeanFactory();
|
||||
TestBeanHolder bean = ac.getBean("annotatedBean", TestBeanHolder.class);
|
||||
assertThat(ac.getBeanFactory().containsSingleton("testBean")).isFalse();
|
||||
assertThat(bf.containsSingleton("testBean")).isFalse();
|
||||
assertThat(bean.getTestBean()).isNotNull();
|
||||
assertThat(bean.getTestBean().getName()).isNull();
|
||||
assertThat(ac.getBeanFactory().containsSingleton("testBean")).isTrue();
|
||||
assertThat(bf.containsSingleton("testBean")).isTrue();
|
||||
TestBean tb = (TestBean) ac.getBean("testBean");
|
||||
tb.setName("tb");
|
||||
assertThat(bean.getTestBean().getName()).isSameAs("tb");
|
||||
|
||||
assertThat(ObjectUtils.containsElement(bf.getDependenciesForBean("annotatedBean"), "testBean")).isTrue();
|
||||
assertThat(ObjectUtils.containsElement(bf.getDependentBeans("testBean"), "annotatedBean")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+93
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -280,12 +280,49 @@ public class ConfigurationClassProcessingTests {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithApplicationListener.class);
|
||||
ctx.refresh();
|
||||
|
||||
ConfigWithApplicationListener config = ctx.getBean(ConfigWithApplicationListener.class);
|
||||
assertThat(config.closed).isFalse();
|
||||
ctx.close();
|
||||
assertThat(config.closed).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configurationWithOverloadedBeanMismatch() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.registerBeanDefinition("config", new RootBeanDefinition(OverloadedBeanMismatch.class));
|
||||
ctx.refresh();
|
||||
|
||||
TestBean tb = ctx.getBean(TestBean.class);
|
||||
assertThat(tb.getLawyer()).isEqualTo(ctx.getBean(NestedTestBean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configurationWithOverloadedBeanMismatchWithAsm() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.registerBeanDefinition("config", new RootBeanDefinition(OverloadedBeanMismatch.class.getName()));
|
||||
ctx.refresh();
|
||||
|
||||
TestBean tb = ctx.getBean(TestBean.class);
|
||||
assertThat(tb.getLawyer()).isEqualTo(ctx.getBean(NestedTestBean.class));
|
||||
}
|
||||
|
||||
@Test // gh-26019
|
||||
public void autowiringWithDynamicPrototypeBeanClass() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
|
||||
ConfigWithDynamicPrototype.class, PrototypeDependency.class);
|
||||
|
||||
PrototypeInterface p1 = ctx.getBean(PrototypeInterface.class, 1);
|
||||
assertThat(p1).isInstanceOf(PrototypeOne.class);
|
||||
assertThat(((PrototypeOne) p1).prototypeDependency).isNotNull();
|
||||
|
||||
PrototypeInterface p2 = ctx.getBean(PrototypeInterface.class, 2);
|
||||
assertThat(p2).isInstanceOf(PrototypeTwo.class);
|
||||
|
||||
PrototypeInterface p3 = ctx.getBean(PrototypeInterface.class, 1);
|
||||
assertThat(p3).isInstanceOf(PrototypeOne.class);
|
||||
assertThat(((PrototypeOne) p3).prototypeDependency).isNotNull();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -595,4 +632,59 @@ public class ConfigurationClassProcessingTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
public static class OverloadedBeanMismatch {
|
||||
|
||||
@Bean(name = "other")
|
||||
public NestedTestBean foo() {
|
||||
return new NestedTestBean();
|
||||
}
|
||||
|
||||
@Bean(name = "foo")
|
||||
public TestBean foo(@Qualifier("other") NestedTestBean other) {
|
||||
TestBean tb = new TestBean();
|
||||
tb.setLawyer(other);
|
||||
return tb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class PrototypeDependency {
|
||||
}
|
||||
|
||||
interface PrototypeInterface {
|
||||
}
|
||||
|
||||
static class PrototypeOne extends AbstractPrototype {
|
||||
|
||||
@Autowired
|
||||
PrototypeDependency prototypeDependency;
|
||||
|
||||
}
|
||||
|
||||
static class PrototypeTwo extends AbstractPrototype {
|
||||
|
||||
// no autowired dependency here, in contrast to above
|
||||
}
|
||||
|
||||
static class AbstractPrototype implements PrototypeInterface {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ConfigWithDynamicPrototype {
|
||||
|
||||
@Bean
|
||||
@Scope(value = "prototype")
|
||||
public PrototypeInterface getDemoBean( int i) {
|
||||
switch ( i) {
|
||||
case 1: return new PrototypeOne();
|
||||
case 2:
|
||||
default:
|
||||
return new PrototypeTwo();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+82
-2
@@ -16,8 +16,8 @@
|
||||
|
||||
package org.springframework.context.event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
@@ -35,6 +36,8 @@ import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.PayloadApplicationEvent;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
@@ -374,6 +377,19 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen
|
||||
assertThat(MyNonSingletonListener.seenEvents.contains(event4)).isTrue();
|
||||
MyNonSingletonListener.seenEvents.clear();
|
||||
|
||||
context.publishEvent(event1);
|
||||
context.publishEvent(event2);
|
||||
context.publishEvent(event3);
|
||||
context.publishEvent(event4);
|
||||
assertThat(MyNonSingletonListener.seenEvents.contains(event1)).isTrue();
|
||||
assertThat(MyNonSingletonListener.seenEvents.contains(event2)).isTrue();
|
||||
assertThat(MyNonSingletonListener.seenEvents.contains(event3)).isTrue();
|
||||
assertThat(MyNonSingletonListener.seenEvents.contains(event4)).isTrue();
|
||||
MyNonSingletonListener.seenEvents.clear();
|
||||
|
||||
AbstractApplicationEventMulticaster multicaster = context.getBean(AbstractApplicationEventMulticaster.class);
|
||||
assertThat(multicaster.retrieverCache.size()).isEqualTo(3);
|
||||
|
||||
context.close();
|
||||
}
|
||||
|
||||
@@ -516,6 +532,36 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initMethodPublishesEvent() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition("listener", new RootBeanDefinition(BeanThatListens.class));
|
||||
context.registerBeanDefinition("messageSource", new RootBeanDefinition(StaticMessageSource.class));
|
||||
context.registerBeanDefinition("initMethod", new RootBeanDefinition(EventPublishingInitMethod.class));
|
||||
context.refresh();
|
||||
|
||||
context.publishEvent(new MyEvent(this));
|
||||
BeanThatListens listener = context.getBean(BeanThatListens.class);
|
||||
assertThat(listener.getEventCount()).isEqualTo(3);
|
||||
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initMethodPublishesAsyncEvent() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition("listener", new RootBeanDefinition(BeanThatListens.class));
|
||||
context.registerBeanDefinition("messageSource", new RootBeanDefinition(StaticMessageSource.class));
|
||||
context.registerBeanDefinition("initMethod", new RootBeanDefinition(AsyncEventPublishingInitMethod.class));
|
||||
context.refresh();
|
||||
|
||||
context.publishEvent(new MyEvent(this));
|
||||
BeanThatListens listener = context.getBean(BeanThatListens.class);
|
||||
assertThat(listener.getEventCount()).isEqualTo(3);
|
||||
|
||||
context.close();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class MyEvent extends ApplicationEvent {
|
||||
@@ -537,7 +583,7 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen
|
||||
|
||||
public static class MyOrderedListener1 implements ApplicationListener<ApplicationEvent>, Ordered {
|
||||
|
||||
public final List<ApplicationEvent> seenEvents = new LinkedList<>();
|
||||
public final List<ApplicationEvent> seenEvents = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
@@ -652,4 +698,38 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class EventPublishingInitMethod implements ApplicationEventPublisherAware, InitializingBean {
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
this.publisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.publisher.publishEvent(new MyEvent(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class AsyncEventPublishingInitMethod implements ApplicationEventPublisherAware, InitializingBean {
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
this.publisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Thread thread = new Thread(() -> this.publisher.publishEvent(new MyEvent(this)));
|
||||
thread.start();
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author 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,15 +30,15 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Arjen Poutsma
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class SimpleThreadScopeTests {
|
||||
class SimpleThreadScopeTests {
|
||||
|
||||
private final ApplicationContext applicationContext =
|
||||
new ClassPathXmlApplicationContext("simpleThreadScopeTests.xml", getClass());
|
||||
|
||||
|
||||
@Test
|
||||
public void getFromScope() throws Exception {
|
||||
String name = "threadScopedObject";
|
||||
void getFromScope() throws Exception {
|
||||
String name = "removeNodeStatusScreen";
|
||||
TestBean bean = this.applicationContext.getBean(name, TestBean.class);
|
||||
assertThat(bean).isNotNull();
|
||||
assertThat(this.applicationContext.getBean(name)).isSameAs(bean);
|
||||
@@ -47,11 +47,11 @@ public class SimpleThreadScopeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMultipleInstances() throws Exception {
|
||||
void getMultipleInstances() throws Exception {
|
||||
// Arrange
|
||||
TestBean[] beans = new TestBean[2];
|
||||
Thread thread1 = new Thread(() -> beans[0] = applicationContext.getBean("threadScopedObject", TestBean.class));
|
||||
Thread thread2 = new Thread(() -> beans[1] = applicationContext.getBean("threadScopedObject", TestBean.class));
|
||||
Thread thread1 = new Thread(() -> beans[0] = applicationContext.getBean("removeNodeStatusScreen", TestBean.class));
|
||||
Thread thread2 = new Thread(() -> beans[1] = applicationContext.getBean("removeNodeStatusScreen", TestBean.class));
|
||||
// Act
|
||||
thread1.start();
|
||||
thread2.start();
|
||||
|
||||
+12
-34
@@ -1,51 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
|
||||
<property name="scopes">
|
||||
<map>
|
||||
<entry key="thread">
|
||||
<bean class="org.springframework.context.support.SimpleThreadScope"/>
|
||||
<bean class="org.springframework.context.support.SimpleThreadScope" />
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="threadScopedObject" class="org.springframework.beans.testfixture.beans.TestBean" scope="thread"/>
|
||||
|
||||
<!--
|
||||
<bean id="requestScopedDisposableObject" class="org.springframework.beans.testfixture.beans.DerivedTestBean" scope="request"/>
|
||||
NOTE: The bean names removeNodeStatusScreen and removeNodeStatusPresenter are seemingly
|
||||
quite odd for TestBean instances; however, these have been chosen due to the fact that
|
||||
they end up in the same bucket within a HashMap/ConcurrentHashMap initialized with the
|
||||
default initial capacity.
|
||||
|
||||
<bean id="requestScopedFactoryBean" class="org.springframework.beans.testfixture.beans.factory.DummyFactory" scope="request"/>
|
||||
|
||||
<bean id="requestScopedObjectCircle1" class="org.springframework.beans.testfixture.beans.TestBean" scope="request">
|
||||
<property name="spouse" ref="requestScopedObjectCircle2"/>
|
||||
For details see: https://github.com/spring-projects/spring-framework/issues/25801
|
||||
-->
|
||||
<bean id="removeNodeStatusScreen" class="org.springframework.beans.testfixture.beans.TestBean" scope="thread">
|
||||
<property name="spouse" ref="removeNodeStatusPresenter" />
|
||||
</bean>
|
||||
|
||||
<bean id="requestScopedObjectCircle2" class="org.springframework.beans.testfixture.beans.TestBean" scope="request">
|
||||
<property name="spouse" ref="requestScopedObjectCircle1"/>
|
||||
</bean>
|
||||
<bean id="removeNodeStatusPresenter" class="org.springframework.beans.testfixture.beans.TestBean" scope="thread" />
|
||||
|
||||
<bean id="requestScopedOuterBean" class="org.springframework.beans.testfixture.beans.DerivedTestBean" scope="request">
|
||||
<property name="name" value="outer"/>
|
||||
<property name="spouse">
|
||||
<bean class="org.springframework.beans.testfixture.beans.DerivedTestBean">
|
||||
<property name="name" value="inner"/>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="singletonOuterBean" class="org.springframework.beans.testfixture.beans.DerivedTestBean" lazy-init="true">
|
||||
<property name="name" value="outer"/>
|
||||
<property name="spouse">
|
||||
<bean class="org.springframework.beans.testfixture.beans.DerivedTestBean" scope="request">
|
||||
<property name="name" value="inner"/>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
-->
|
||||
</beans>
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -126,7 +126,7 @@ public class SimpleNamingContext implements Context {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Static JNDI lookup: [" + name + "]");
|
||||
}
|
||||
if ("".equals(name)) {
|
||||
if (name.isEmpty()) {
|
||||
return new SimpleNamingContext(this.root, this.boundObjects, this.environment);
|
||||
}
|
||||
Object found = this.boundObjects.get(name);
|
||||
@@ -303,10 +303,10 @@ public class SimpleNamingContext implements Context {
|
||||
|
||||
private abstract static class AbstractNamingEnumeration<T> implements NamingEnumeration<T> {
|
||||
|
||||
private Iterator<T> iterator;
|
||||
private final Iterator<T> iterator;
|
||||
|
||||
private AbstractNamingEnumeration(SimpleNamingContext context, String proot) throws NamingException {
|
||||
if (!"".equals(proot) && !proot.endsWith("/")) {
|
||||
if (!proot.isEmpty() && !proot.endsWith("/")) {
|
||||
proot = proot + "/";
|
||||
}
|
||||
String root = context.root + proot;
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -66,10 +66,10 @@ internal fun isSuspendingFunction(method: Method) = method.kotlinFunction!!.isSu
|
||||
* @since 5.2
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal fun invokeSuspendingFunction(method: Method, bean: Any, vararg args: Any?): Publisher<*> {
|
||||
internal fun invokeSuspendingFunction(method: Method, target: Any, vararg args: Any?): Publisher<*> {
|
||||
val function = method.kotlinFunction!!
|
||||
val mono = mono(Dispatchers.Unconfined) {
|
||||
function.callSuspend(bean, *args.sliceArray(0..(args.size-2))).let { if (it == Unit) null else it }
|
||||
function.callSuspend(target, *args.sliceArray(0..(args.size-2))).let { if (it == Unit) null else it }
|
||||
}.onErrorMap(InvocationTargetException::class.java) { it.targetException }
|
||||
return if (function.returnType.classifier == Flow::class) {
|
||||
mono.flatMapMany { (it as Flow<Any>).asFlux() }
|
||||
|
||||
@@ -54,20 +54,20 @@ dependencies {
|
||||
optional("io.reactivex.rxjava2:rxjava")
|
||||
optional("io.netty:netty-buffer")
|
||||
testCompile("io.projectreactor:reactor-test")
|
||||
testCompile("javax.annotation:javax.annotation-api")
|
||||
testCompile("com.google.code.findbugs:jsr305")
|
||||
testCompile("org.xmlunit:xmlunit-assertj")
|
||||
testCompile("org.xmlunit:xmlunit-matchers")
|
||||
testCompile("javax.annotation:javax.annotation-api")
|
||||
testCompile("javax.xml.bind:jaxb-api")
|
||||
testCompile("com.fasterxml.woodstox:woodstox-core")
|
||||
testCompile("org.xmlunit:xmlunit-assertj")
|
||||
testCompile("org.xmlunit:xmlunit-matchers")
|
||||
testCompile(project(":kotlin-coroutines"))
|
||||
testCompile("io.projectreactor.tools:blockhound")
|
||||
testFixturesImplementation("com.google.code.findbugs:jsr305")
|
||||
testFixturesImplementation("io.projectreactor:reactor-test")
|
||||
testFixturesImplementation("org.assertj:assertj-core")
|
||||
testFixturesImplementation("com.google.code.findbugs:jsr305")
|
||||
testFixturesImplementation("org.junit.platform:junit-platform-launcher")
|
||||
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api")
|
||||
testFixturesImplementation("org.junit.jupiter:junit-jupiter-params")
|
||||
testFixturesImplementation("org.assertj:assertj-core")
|
||||
testFixturesImplementation("org.xmlunit:xmlunit-assertj")
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ public abstract class AnnotationVisitor {
|
||||
&& api != Opcodes.ASM8_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
// SPRING PATCH: no preview mode check for ASM 8 experimental
|
||||
// SPRING PATCH: no preview mode check for ASM experimental
|
||||
this.api = api;
|
||||
this.av = annotationVisitor;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public abstract class ClassVisitor {
|
||||
&& api != Opcodes.ASM8_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
// SPRING PATCH: no preview mode check for ASM 8 experimental
|
||||
// SPRING PATCH: no preview mode check for ASM experimental
|
||||
this.api = api;
|
||||
this.cv = classVisitor;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public abstract class FieldVisitor {
|
||||
&& api != Opcodes.ASM8_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
// SPRING PATCH: no preview mode check for ASM 8 experimental
|
||||
// SPRING PATCH: no preview mode check for ASM experimental
|
||||
this.api = api;
|
||||
this.fv = fieldVisitor;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public abstract class MethodVisitor {
|
||||
&& api != Opcodes.ASM8_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
// SPRING PATCH: no preview mode check for ASM 8 experimental
|
||||
// SPRING PATCH: no preview mode check for ASM experimental
|
||||
this.api = api;
|
||||
this.mv = methodVisitor;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public abstract class ModuleVisitor {
|
||||
&& api != Opcodes.ASM8_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
// SPRING PATCH: no preview mode check for ASM 8 experimental
|
||||
// SPRING PATCH: no preview mode check for ASM experimental
|
||||
this.api = api;
|
||||
this.mv = moduleVisitor;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public abstract class RecordComponentVisitor {
|
||||
&& api != Opcodes.ASM8_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
// SPRING PATCH: no preview mode check for ASM 8 experimental
|
||||
// SPRING PATCH: no preview mode check for ASM experimental
|
||||
this.api = api;
|
||||
this.delegate = recordComponentVisitor;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Spring's repackaging of
|
||||
* <a href="https://gitlab.ow2.org/asm/asm">ASM 7.0</a>
|
||||
* <a href="https://gitlab.ow2.org/asm/asm">ASM 7.x</a>
|
||||
* (with Spring-specific patches; for internal use only).
|
||||
*
|
||||
* <p>This repackaging technique avoids any potential conflicts with
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -101,8 +101,7 @@ public class OrderComparator implements Comparator<Object> {
|
||||
Object orderSource = sourceProvider.getOrderSource(obj);
|
||||
if (orderSource != null) {
|
||||
if (orderSource.getClass().isArray()) {
|
||||
Object[] sources = ObjectUtils.toObjectArray(orderSource);
|
||||
for (Object source : sources) {
|
||||
for (Object source : ObjectUtils.toObjectArray(orderSource)) {
|
||||
order = findOrder(source);
|
||||
if (order != null) {
|
||||
break;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user