mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
289 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f9b6e94e00 | |||
| bb816c123c | |||
| 33f3aa9b8a | |||
| e1f51cbce7 | |||
| 6ec7cffc93 | |||
| 4bc6f40ce8 | |||
| bf2790498b | |||
| 95d7f883ae | |||
| 25131ebf6f | |||
| 0267b00a65 | |||
| c6e644e5c3 | |||
| 62e916534f | |||
| e1c0f3b067 | |||
| 1ff8da3635 | |||
| ed27ea7aa0 | |||
| 128689e79b | |||
| 475396b516 | |||
| f3f0bd22c5 | |||
| 6d01d49b76 | |||
| a90ed957be | |||
| 171b283e49 | |||
| 71202d62ed | |||
| ded9c4eb50 | |||
| 925edf28fc | |||
| 75d4465908 | |||
| 98685e8be7 | |||
| e719bc2cda | |||
| f9167c3df5 | |||
| fbf4724d78 | |||
| 39442143b7 | |||
| d3b1c4f62b | |||
| 531174258c | |||
| 564c6f7f86 | |||
| a07c7865a5 | |||
| 8680fdb8bc | |||
| 4fe3ca1b82 | |||
| c45c46dad7 | |||
| 74f91339e2 | |||
| acb2aec3dd | |||
| 297880d93e | |||
| 9cbb5af622 | |||
| fed1a426b6 | |||
| cf78895ba0 | |||
| b9d65eef61 | |||
| 8d747298de | |||
| 76b1c0f1fc | |||
| 94f56a2684 | |||
| cb251347c3 | |||
| 048954dc1d | |||
| 403e1f2505 | |||
| f39c6d36c7 | |||
| 83bcd409fc | |||
| 411745f4cb | |||
| 01df63b9cd | |||
| bde622880d | |||
| 6427a4b5c0 | |||
| 66848cfd59 | |||
| 4863b5d4a8 | |||
| d6df4a6577 | |||
| dee0108e79 | |||
| 3ccbf1edeb | |||
| 7f6f184acb | |||
| b0f724a597 | |||
| 9add04f800 | |||
| 5d919dc094 | |||
| a2ef6badc4 | |||
| ddbb7c1b5b | |||
| 2bc7a3aa0a | |||
| 882004fc9b | |||
| 1bc236785c | |||
| 300fed97c1 | |||
| 4f770ca860 | |||
| d469f6215d | |||
| 3214786757 | |||
| f69152c14e | |||
| 4bb88f3b1d | |||
| edf0343cfe | |||
| eb964542b4 | |||
| 4e8828dc10 | |||
| a8102e6a41 | |||
| 782d7169e4 | |||
| 71995a9087 | |||
| f9bcb99040 | |||
| 791134c53c | |||
| df588e030f | |||
| b677206159 | |||
| e04ca3d671 | |||
| 2fc47d8752 | |||
| 3676084472 | |||
| bcb0580492 | |||
| 3c8074b669 | |||
| 4a13928a27 | |||
| 20d9a1e844 | |||
| 8b1302bbe2 | |||
| c7c35aff42 | |||
| 000b6a7e95 | |||
| f3db6b996d | |||
| a42540e64a | |||
| cc2b980e5c | |||
| aa2bfd4b62 | |||
| 29fa9c1728 | |||
| 39660710f6 | |||
| e35fe33b72 | |||
| 23f396a231 | |||
| 090e394fb5 | |||
| 708e61a7ef | |||
| e24b2e6b5d | |||
| aff0d8efe7 | |||
| e3e4e49319 | |||
| 5420d7113b | |||
| 6251222a23 | |||
| 05eca05671 | |||
| 3fa4e4168d | |||
| f0f450a18d | |||
| f854803e18 | |||
| d29d4d45aa | |||
| 432fdad7d0 | |||
| 345d8186d4 | |||
| ad63a534cb | |||
| c9d341e9c0 | |||
| 950b183715 | |||
| 821ecb4cfd | |||
| 1c17305d7b | |||
| 491d1c4c78 | |||
| 7dbbf364f7 | |||
| 5204d736f3 | |||
| e0690335fc | |||
| 5cbbbed377 | |||
| 6f2fe5ddcb | |||
| da9ee06e05 | |||
| 4c28266eb6 | |||
| b3dcb64ff1 | |||
| b18f8771c8 | |||
| 93244e9f9d | |||
| f45a852aca | |||
| 4203e90655 | |||
| 1e2e114e3c | |||
| 0e73213144 | |||
| 1e1045ba42 | |||
| 8d17bcea5b | |||
| 597b31b1fc | |||
| 4049951c03 | |||
| 89441ea006 | |||
| de1ba79c55 | |||
| ffbc537835 | |||
| 9295bcc4a4 | |||
| 746b1b2fe1 | |||
| ab2c78a9d5 | |||
| ac0e71745b | |||
| f65cbe0992 | |||
| a2e5d9a14f | |||
| 360f555e77 | |||
| 7c756027a0 | |||
| 4c642ccdcd | |||
| fab7b1cebe | |||
| 101ed17b6f | |||
| 66588bae92 | |||
| d33545bdce | |||
| e8e157ebf8 | |||
| 7f5904c68b | |||
| 66e488850b | |||
| 3dba3691a7 | |||
| c80c4e001a | |||
| 8da049b613 | |||
| 1acd832759 | |||
| 261927b72a | |||
| 24aa7f546b | |||
| 4cfad25468 | |||
| 569ce840cf | |||
| fae484855b | |||
| cab20d1202 | |||
| e2bf513563 | |||
| 84e56bb5d9 | |||
| 6f5e66f00c | |||
| cda72e4a70 | |||
| e31a4c4c77 | |||
| 4809632f44 | |||
| 0d0d75e253 | |||
| cce60c479c | |||
| 1469bdbc70 | |||
| be52ec8bd5 | |||
| cd9cad31f9 | |||
| 60c551a95b | |||
| 4164fc63b1 | |||
| 0865abef83 | |||
| 90af2d5794 | |||
| 5f5cd8a7c4 | |||
| 46b7cd54a1 | |||
| 7f670bbe68 | |||
| 6aaf7596c0 | |||
| 4f2c589fe6 | |||
| aa51ed1940 | |||
| dc4e053d59 | |||
| 07ba95739b | |||
| 0468ef46ac | |||
| eb03144e9d | |||
| 29790d5bb1 | |||
| 355d394d7f | |||
| 9ddab9e69b | |||
| c20a43f72b | |||
| e0fa58aa0f | |||
| 65797d04f2 | |||
| 5811212a9f | |||
| d79e33b5a0 | |||
| dddcc5e9ad | |||
| 582b94d50e | |||
| 443c34cc90 | |||
| 959e6d1745 | |||
| 38b592444d | |||
| 2c2464b1e7 | |||
| 3b247a9c19 | |||
| d30432b6c0 | |||
| c70aed58bf | |||
| 2de7bf6e2b | |||
| a28511cdbd | |||
| 668b938832 | |||
| 091e7bb891 | |||
| b76e0c4826 | |||
| 55faf6e320 | |||
| a522ed0788 | |||
| 4152ebc2f3 | |||
| 21c90829df | |||
| 5b96c9b87e | |||
| 08855fee51 | |||
| 66cd979ce4 | |||
| 5667d459a7 | |||
| 85eb589c2e | |||
| b18cf3c873 | |||
| 399e7ebf22 | |||
| b5d6e53e50 | |||
| 865969400b | |||
| 6f4fb08bf8 | |||
| 4c7cc705de | |||
| f7fc36250e | |||
| ae7d5200e5 | |||
| ff9b68c1b6 | |||
| 36c829386b | |||
| 7316dc726a | |||
| 118c7f969b | |||
| 26ed6d8bce | |||
| 98770b15e7 | |||
| 697108cc42 | |||
| 607d918340 | |||
| 8456eaca8e | |||
| 59015344a7 | |||
| c03162e616 | |||
| 1dde30a7fd | |||
| 35196d3c62 | |||
| d7f67b3dc3 | |||
| 719e7394d6 | |||
| e4a5d2aaa5 | |||
| ab64607420 | |||
| b595dc1dfa | |||
| 86123de883 | |||
| 7c3a18490b | |||
| 01e50fb60a | |||
| 6c3a0a9026 | |||
| 3bded7659a | |||
| 7f1062159e | |||
| e4c0ff569b | |||
| e7cbe23771 | |||
| d275a4e28d | |||
| 42a23098de | |||
| d25ae4b02c | |||
| 5740eaf33e | |||
| 80d46ba80e | |||
| db9a10bf35 | |||
| 27bfcbbc82 | |||
| b153b5e53b | |||
| 1f477a5c1c | |||
| ceac2a5c3c | |||
| e03fdeaf8b | |||
| 0286549466 | |||
| 71158f4d96 | |||
| 7303680369 | |||
| 906a1f561a | |||
| e489706f13 | |||
| 69bbdce826 | |||
| 0f31830ae2 | |||
| 5d297c6387 | |||
| 320f5836b4 | |||
| af06b80bdf | |||
| 5b1ab31559 | |||
| bf05da1f8c | |||
| 63217e44f1 | |||
| 5226a67161 | |||
| 1694274e32 | |||
| 27c4e74e24 | |||
| b73eb51cb1 |
+1
-1
@@ -72,7 +72,7 @@ to start a discussion first or have already created an issue, once a pull reques
|
||||
created, we will close the issue as superseded by the pull request, and the discussion
|
||||
about the issue will continue under the pull request.
|
||||
|
||||
1. Always check out the `master` branch and submit pull requests against it
|
||||
1. Always check out the `main` branch and submit pull requests against it
|
||||
(for target version see [settings.gradle](settings.gradle)).
|
||||
Backports to prior versions will be considered on a case-by-case basis and reflected as
|
||||
the fix version in the issue tracker.
|
||||
|
||||
+46
-48
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'io.spring.dependency-management' version '1.0.9.RELEASE' apply false
|
||||
id 'io.spring.nohttp' version '0.0.5.RELEASE'
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.4.32' apply false
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.5.21' apply false
|
||||
id 'org.jetbrains.dokka' version '0.10.1' apply false
|
||||
id 'org.asciidoctor.jvm.convert' version '3.1.0'
|
||||
id 'org.asciidoctor.jvm.pdf' version '3.1.0'
|
||||
@@ -9,8 +9,9 @@ plugins {
|
||||
id "io.freefair.aspectj" version '5.1.1' apply false
|
||||
id "com.github.ben-manes.versions" version '0.28.0'
|
||||
id "com.github.johnrengelman.shadow" version "6.1.0" apply false
|
||||
id "me.champeau.gradle.jmh" version "0.5.2" apply false
|
||||
id "org.jetbrains.kotlin.plugin.serialization" version "1.4.32" apply false
|
||||
id "me.champeau.jmh" version "0.6.4" apply false
|
||||
id "org.jetbrains.kotlin.plugin.serialization" version "1.5.21" apply false
|
||||
id "org.unbroken-dome.xjc" version '2.0.0' apply false
|
||||
}
|
||||
|
||||
ext {
|
||||
@@ -26,15 +27,16 @@ configure(allprojects) { project ->
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.2"
|
||||
mavenBom "io.netty:netty-bom:4.1.63.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.6"
|
||||
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR9"
|
||||
mavenBom "io.rsocket:rsocket-bom:1.1.0"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.39.v20210325"
|
||||
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.4.32"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.4.3"
|
||||
mavenBom "org.junit:junit-bom:5.7.1"
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.4"
|
||||
mavenBom "io.netty:netty-bom:4.1.65.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.9"
|
||||
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR10"
|
||||
mavenBom "io.rsocket:rsocket-bom:1.1.1"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.43.v20210629"
|
||||
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.5.21"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.5.1"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-serialization-bom:1.2.1"
|
||||
mavenBom "org.junit:junit-bom:5.7.2"
|
||||
}
|
||||
dependencies {
|
||||
dependencySet(group: 'org.apache.logging.log4j', version: '2.14.1') {
|
||||
@@ -49,12 +51,12 @@ configure(allprojects) { project ->
|
||||
}
|
||||
dependency "com.google.code.findbugs:jsr305:3.0.2"
|
||||
|
||||
dependencySet(group: 'org.aspectj', version: '1.9.6') {
|
||||
dependencySet(group: 'org.aspectj', version: '1.9.7') {
|
||||
entry 'aspectjrt'
|
||||
entry 'aspectjtools'
|
||||
entry 'aspectjweaver'
|
||||
}
|
||||
dependencySet(group: 'org.codehaus.groovy', version: '3.0.7') {
|
||||
dependencySet(group: 'org.codehaus.groovy', version: '3.0.8') {
|
||||
entry 'groovy'
|
||||
entry 'groovy-jsr223'
|
||||
entry 'groovy-templates' // requires findbugs for warning-free compilation
|
||||
@@ -65,18 +67,18 @@ 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.21"
|
||||
dependency "io.reactivex.rxjava3:rxjava:3.0.12"
|
||||
dependency "io.reactivex.rxjava3:rxjava:3.0.13"
|
||||
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.2.4") {
|
||||
dependency "com.fasterxml:aalto-xml:1.3.0"
|
||||
dependency("com.fasterxml.woodstox:woodstox-core:6.2.6") {
|
||||
exclude group: "stax", name: "stax-api"
|
||||
}
|
||||
dependency "com.google.code.gson:gson:2.8.6"
|
||||
dependency "com.google.protobuf:protobuf-java-util:3.15.5"
|
||||
dependency "com.google.code.gson:gson:2.8.7"
|
||||
dependency "com.google.protobuf:protobuf-java-util:3.17.3"
|
||||
dependency "com.googlecode.protobuf-java-format:protobuf-java-format:1.4"
|
||||
dependency("com.thoughtworks.xstream:xstream:1.4.15") {
|
||||
dependency("com.thoughtworks.xstream:xstream:1.4.17") {
|
||||
exclude group: "xpp3", name: "xpp3_min"
|
||||
exclude group: "xmlpull", name: "xmlpull"
|
||||
}
|
||||
@@ -89,20 +91,16 @@ configure(allprojects) { project ->
|
||||
entry 'jibx-run'
|
||||
}
|
||||
dependency "org.ogce:xpp3:1.1.6"
|
||||
dependency "org.yaml:snakeyaml:1.28"
|
||||
dependencySet(group: 'org.jetbrains.kotlinx', version: '1.0.1') {
|
||||
entry 'kotlinx-serialization-core'
|
||||
entry 'kotlinx-serialization-json'
|
||||
}
|
||||
dependency "org.yaml:snakeyaml:1.29"
|
||||
|
||||
dependency "com.h2database:h2:1.4.200"
|
||||
dependency "com.github.ben-manes.caffeine:caffeine:2.9.0"
|
||||
dependency "com.github.librepdf:openpdf:1.3.25"
|
||||
dependency "com.github.ben-manes.caffeine:caffeine:2.9.1"
|
||||
dependency "com.github.librepdf:openpdf:1.3.26"
|
||||
dependency "com.rometools:rome:1.15.0"
|
||||
dependency "commons-io:commons-io:2.5"
|
||||
dependency "io.vavr:vavr:0.10.3"
|
||||
dependency "net.sf.jopt-simple:jopt-simple:5.0.4"
|
||||
dependencySet(group: 'org.apache.activemq', version: '5.16.1') {
|
||||
dependencySet(group: 'org.apache.activemq', version: '5.16.2') {
|
||||
entry 'activemq-broker'
|
||||
entry('activemq-kahadb-store') {
|
||||
exclude group: "org.springframework", name: "spring-context"
|
||||
@@ -118,29 +116,29 @@ 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.31"
|
||||
dependency "org.hsqldb:hsqldb:2.5.1"
|
||||
dependency "org.hsqldb:hsqldb:2.5.2"
|
||||
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.30.Final"
|
||||
dependency "org.hibernate:hibernate-core:5.4.32.Final"
|
||||
dependency "org.hibernate:hibernate-validator:6.2.0.Final"
|
||||
dependency "org.webjars:webjars-locator-core:0.46"
|
||||
dependency "org.webjars:webjars-locator-core:0.47"
|
||||
dependency "org.webjars:underscorejs:1.8.3"
|
||||
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.45') {
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.50') {
|
||||
entry 'tomcat-util'
|
||||
entry('tomcat-websocket') {
|
||||
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
|
||||
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
|
||||
}
|
||||
}
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.45') {
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.50') {
|
||||
entry 'tomcat-embed-core'
|
||||
entry 'tomcat-embed-websocket'
|
||||
}
|
||||
dependencySet(group: 'io.undertow', version: '2.2.7.Final') {
|
||||
dependencySet(group: 'io.undertow', version: '2.2.8.Final') {
|
||||
entry 'undertow-core'
|
||||
entry('undertow-websockets-jsr') {
|
||||
exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec"
|
||||
@@ -161,11 +159,11 @@ configure(allprojects) { project ->
|
||||
dependency("org.apache.httpcomponents:httpasyncclient:4.1.4") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency 'org.apache.httpcomponents.client5:httpclient5:5.0.3'
|
||||
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.0.3'
|
||||
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.6"
|
||||
dependency 'org.apache.httpcomponents.client5:httpclient5:5.1'
|
||||
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.1.1'
|
||||
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.9"
|
||||
|
||||
dependency "org.jruby:jruby:9.2.16.0"
|
||||
dependency "org.jruby:jruby:9.2.19.0"
|
||||
dependency "org.python:jython-standalone:2.7.1"
|
||||
dependency "org.mozilla:rhino:1.7.11"
|
||||
|
||||
@@ -191,25 +189,25 @@ configure(allprojects) { project ->
|
||||
dependency "org.testng:testng:7.4.0"
|
||||
dependency "org.hamcrest:hamcrest:2.1"
|
||||
dependency "org.awaitility:awaitility:3.1.6"
|
||||
dependency "org.assertj:assertj-core:3.19.0"
|
||||
dependency "org.assertj:assertj-core:3.20.2"
|
||||
dependencySet(group: 'org.xmlunit', version: '2.8.2') {
|
||||
entry 'xmlunit-assertj'
|
||||
entry('xmlunit-matchers') {
|
||||
exclude group: "org.hamcrest", name: "hamcrest-core"
|
||||
}
|
||||
}
|
||||
dependencySet(group: 'org.mockito', version: '3.8.0') {
|
||||
dependencySet(group: 'org.mockito', version: '3.11.0') {
|
||||
entry('mockito-core') {
|
||||
exclude group: "org.hamcrest", name: "hamcrest-core"
|
||||
}
|
||||
entry 'mockito-junit-jupiter'
|
||||
}
|
||||
dependency "io.mockk:mockk:1.10.2"
|
||||
dependency "io.mockk:mockk:1.11.0"
|
||||
|
||||
dependency("net.sourceforge.htmlunit:htmlunit:2.48.0") {
|
||||
dependency("net.sourceforge.htmlunit:htmlunit:2.51.0") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.seleniumhq.selenium:htmlunit-driver:2.48.0") {
|
||||
dependency("org.seleniumhq.selenium:htmlunit-driver:2.51.0") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
|
||||
@@ -238,7 +236,7 @@ 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.10"
|
||||
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.8"
|
||||
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.9"
|
||||
dependency "org.javamoney:moneta:1.3"
|
||||
|
||||
dependency "com.sun.activation:javax.activation:1.2.0"
|
||||
@@ -318,7 +316,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
kotlinOptions {
|
||||
languageVersion = "1.3"
|
||||
apiVersion = "1.3"
|
||||
freeCompilerArgs = ["-Xjsr305=strict"]
|
||||
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings", "-Xopt-in=kotlin.RequiresOptIn"]
|
||||
allWarningsAsErrors = true
|
||||
}
|
||||
}
|
||||
@@ -338,7 +336,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "8.41"
|
||||
toolVersion = "8.44"
|
||||
configDirectory.set(rootProject.file("src/checkstyle"))
|
||||
}
|
||||
|
||||
@@ -377,10 +375,10 @@ configure([rootProject] + javaProjects) { project ->
|
||||
"https://fasterxml.github.io/jackson-core/javadoc/2.10/",
|
||||
"https://fasterxml.github.io/jackson-databind/javadoc/2.10/",
|
||||
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/",
|
||||
"https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/",
|
||||
"https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/",
|
||||
"https://projectreactor.io/docs/test/release/api/",
|
||||
"https://junit.org/junit4/javadoc/4.13.2/",
|
||||
"https://junit.org/junit5/docs/5.7.1/api/"
|
||||
"https://junit.org/junit5/docs/5.7.2/api/"
|
||||
] as String[]
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ github-repo: "https://github.com/spring-projects/spring-framework.git"
|
||||
github-repo-name: "spring-projects/spring-framework"
|
||||
docker-hub-organization: "springci"
|
||||
artifactory-server: "https://repo.spring.io"
|
||||
branch: "master"
|
||||
branch: "main"
|
||||
milestone: "5.3.x"
|
||||
build-name: "spring-framework"
|
||||
pipeline-name: "spring-framework"
|
||||
|
||||
+56
-8
@@ -18,9 +18,6 @@ anchors:
|
||||
ARTIFACTORY_USERNAME: ((artifactory-username))
|
||||
ARTIFACTORY_PASSWORD: ((artifactory-password))
|
||||
build-project-task-params: &build-project-task-params
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
params:
|
||||
BRANCH: ((branch))
|
||||
<<: *gradle-enterprise-task-params
|
||||
docker-resource-source: &docker-resource-source
|
||||
@@ -54,6 +51,11 @@ resource_types:
|
||||
source:
|
||||
repository: dpb587/github-status-resource
|
||||
tag: master
|
||||
- name: pull-request
|
||||
type: registry-image
|
||||
source:
|
||||
repository: teliaoss/github-pr-resource
|
||||
tag: v0.23.0
|
||||
- name: slack-notification
|
||||
type: registry-image
|
||||
source:
|
||||
@@ -93,6 +95,14 @@ resources:
|
||||
username: ((artifactory-username))
|
||||
password: ((artifactory-password))
|
||||
build_name: ((build-name))
|
||||
- name: git-pull-request
|
||||
type: pull-request
|
||||
icon: source-pull
|
||||
source:
|
||||
access_token: ((github-ci-pull-request-token))
|
||||
repository: ((github-repo-name))
|
||||
base_branch: ((branch))
|
||||
ignore_paths: ["ci/*"]
|
||||
- name: repo-status-build
|
||||
type: github-status-resource
|
||||
icon: eye-check-outline
|
||||
@@ -162,7 +172,10 @@ jobs:
|
||||
- task: build-project
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/build-project.yml
|
||||
<<: *build-project-task-params
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
params:
|
||||
<<: *build-project-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-build
|
||||
@@ -217,10 +230,11 @@ jobs:
|
||||
- task: check-project
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/check-project.yml
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
params:
|
||||
MAIN_TOOLCHAIN: 8
|
||||
TEST_TOOLCHAIN: 11
|
||||
<<: *build-project-task-params
|
||||
<<: *build-project-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-jdk11-build
|
||||
@@ -244,10 +258,11 @@ jobs:
|
||||
- task: check-project
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/check-project.yml
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
params:
|
||||
MAIN_TOOLCHAIN: 8
|
||||
TEST_TOOLCHAIN: 15
|
||||
<<: *build-project-task-params
|
||||
<<: *build-project-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-jdk15-build
|
||||
@@ -257,6 +272,37 @@ jobs:
|
||||
<<: *slack-fail-params
|
||||
- put: repo-status-jdk15-build
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- name: build-pull-requests
|
||||
serial: true
|
||||
public: true
|
||||
plan:
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
resource: git-pull-request
|
||||
trigger: true
|
||||
version: every
|
||||
- do:
|
||||
- put: git-pull-request
|
||||
params:
|
||||
path: git-repo
|
||||
status: pending
|
||||
- task: build-pr
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/build-pr.yml
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
params:
|
||||
<<: *build-project-task-params
|
||||
on_success:
|
||||
put: git-pull-request
|
||||
params:
|
||||
path: git-repo
|
||||
status: success
|
||||
on_failure:
|
||||
put: git-pull-request
|
||||
params:
|
||||
path: git-repo
|
||||
status: failure
|
||||
- name: stage-milestone
|
||||
serial: true
|
||||
plan:
|
||||
@@ -412,3 +458,5 @@ groups:
|
||||
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
|
||||
- name: "ci-images"
|
||||
jobs: ["build-ci-images"]
|
||||
- name: "pull-requests"
|
||||
jobs: [ "build-pull-requests" ]
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
source $(dirname $0)/common.sh
|
||||
|
||||
pushd git-repo > /dev/null
|
||||
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 check
|
||||
popd > /dev/null
|
||||
@@ -4,6 +4,6 @@ set -e
|
||||
source $(dirname $0)/common.sh
|
||||
|
||||
pushd git-repo > /dev/null
|
||||
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Dorg.gradle.java.installations.fromEnv=JDK11,JDK15 \
|
||||
-PmainToolchain=$MAIN_TOOLCHAIN -PtestToolchain=$TEST_TOOLCHAIN --no-daemon --max-workers=4 check
|
||||
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK11,JDK15 \
|
||||
-PmainToolchain=${MAIN_TOOLCHAIN} -PtestToolchain=${TEST_TOOLCHAIN} --no-daemon --max-workers=4 check
|
||||
popd > /dev/null
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
platform: linux
|
||||
inputs:
|
||||
- name: git-repo
|
||||
caches:
|
||||
- path: gradle
|
||||
params:
|
||||
BRANCH:
|
||||
CI: true
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY:
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME:
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD:
|
||||
GRADLE_ENTERPRISE_URL: https://ge.spring.io
|
||||
run:
|
||||
path: bash
|
||||
args:
|
||||
- -ec
|
||||
- |
|
||||
${PWD}/git-repo/ci/scripts/build-pr.sh
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=5.3.6-SNAPSHOT
|
||||
version=5.3.9
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
+13
-1
@@ -103,9 +103,12 @@ dokka {
|
||||
externalDocumentationLink {
|
||||
url = new URL("https://www.reactive-streams.org/reactive-streams-1.0.1-javadoc/")
|
||||
}
|
||||
/*
|
||||
This link causes errors, removing to fix the build.
|
||||
externalDocumentationLink {
|
||||
url = new URL("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/")
|
||||
}
|
||||
*/
|
||||
externalDocumentationLink {
|
||||
url = new URL("https://r2dbc.io/spec/0.8.3.RELEASE/api/")
|
||||
}
|
||||
@@ -127,6 +130,8 @@ task extractDocResources(type: Copy, dependsOn: downloadResources) {
|
||||
}
|
||||
|
||||
asciidoctorj {
|
||||
def docRoot = 'https://docs.spring.io'
|
||||
def docsSpringFramework = "${docRoot}/spring-framework/docs/${project.version}"
|
||||
version = '2.4.1'
|
||||
fatalWarnings ".*"
|
||||
options doctype: 'book', eruby: 'erubis'
|
||||
@@ -143,7 +148,11 @@ asciidoctorj {
|
||||
'highlightjs-theme': 'googlecode',
|
||||
stylesdir: 'css/',
|
||||
stylesheet: 'stylesheet.css',
|
||||
'spring-version': project.version
|
||||
'spring-version': project.version,
|
||||
'spring-framework-main-code': 'https://github.com/spring-projects/spring-framework/tree/main',
|
||||
'doc-root': docRoot,
|
||||
'docs-spring-framework': docsSpringFramework,
|
||||
'api-spring-framework': "${docsSpringFramework}/javadoc-api/org/springframework"
|
||||
])
|
||||
}
|
||||
|
||||
@@ -154,6 +163,9 @@ asciidoctorj {
|
||||
asciidoctor {
|
||||
baseDirFollowsSourceDir()
|
||||
configurations 'asciidoctorExt'
|
||||
attributes([
|
||||
noheader: '' // custom header in docinfo-header.html
|
||||
])
|
||||
sources {
|
||||
include '*.adoc'
|
||||
}
|
||||
|
||||
@@ -108,21 +108,3 @@ task eclipseBuildship(type: Copy) {
|
||||
tasks["eclipseJdt"].dependsOn(eclipseJdtPrepare)
|
||||
tasks["cleanEclipse"].dependsOn(cleanEclipseJdtUi)
|
||||
tasks["eclipse"].dependsOn(eclipseSettings, eclipseWstComponent)
|
||||
|
||||
|
||||
// Filter 'build' folder
|
||||
eclipse.project.file.withXml {
|
||||
def node = it.asNode()
|
||||
|
||||
def filteredResources = node.get("filteredResources")
|
||||
if(filteredResources) {
|
||||
node.remove(filteredResources)
|
||||
}
|
||||
def filterNode = node.appendNode("filteredResources").appendNode("filter")
|
||||
filterNode.appendNode("id", "1359048889071")
|
||||
filterNode.appendNode("name", "")
|
||||
filterNode.appendNode("type", "30")
|
||||
def matcherNode = filterNode.appendNode("matcher")
|
||||
matcherNode.appendNode("id", "org.eclipse.ui.ide.multiFilter")
|
||||
matcherNode.appendNode("arguments", "1.0-projectRelativePath-matches-false-false-build")
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@ apply plugin: 'org.springframework.build.optional-dependencies'
|
||||
// Uncomment the following for Shadow support in the jmhJar block.
|
||||
// Currently commented out due to ZipException: archive is not a ZIP archive
|
||||
// apply plugin: 'com.github.johnrengelman.shadow'
|
||||
apply plugin: 'me.champeau.gradle.jmh'
|
||||
apply plugin: 'me.champeau.jmh'
|
||||
apply from: "$rootDir/gradle/publications.gradle"
|
||||
|
||||
dependencies {
|
||||
jmh 'org.openjdk.jmh:jmh-core:1.25'
|
||||
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.25'
|
||||
jmh 'org.openjdk.jmh:jmh-core:1.28'
|
||||
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.28'
|
||||
jmh 'net.sf.jopt-simple:jopt-simple:4.6'
|
||||
}
|
||||
|
||||
|
||||
+73
-15
@@ -11,6 +11,8 @@
|
||||
* <li>a JDK11 toolchain for compiling and running the test SourceSet
|
||||
* </ul>
|
||||
*
|
||||
* By default, the build will fall back to using the current JDK and 1.8 language level for all sourceSets.
|
||||
*
|
||||
* Gradle will automatically detect JDK distributions in well-known locations.
|
||||
* The following command will list the detected JDKs on the host.
|
||||
* {@code
|
||||
@@ -23,19 +25,41 @@
|
||||
* /opt/openjdk/java11
|
||||
* $ echo JDK15
|
||||
* /opt/openjdk/java15
|
||||
* $ ./gradlew -Dorg.gradle.java.installations.fromEnv=JDK11,JDK15 check
|
||||
* $ ./gradlew -Porg.gradle.java.installations.fromEnv=JDK11,JDK15 check
|
||||
* }
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
|
||||
def mainToolchainConfigured() {
|
||||
return project.hasProperty('mainToolchain') && project.mainToolchain
|
||||
}
|
||||
|
||||
def testToolchainConfigured() {
|
||||
return project.hasProperty('testToolchain') && project.testToolchain
|
||||
}
|
||||
|
||||
def mainToolchainLanguageVersion() {
|
||||
if (mainToolchainConfigured()) {
|
||||
return JavaLanguageVersion.of(project.mainToolchain.toString())
|
||||
}
|
||||
return JavaLanguageVersion.of(8)
|
||||
}
|
||||
|
||||
def testToolchainLanguageVersion() {
|
||||
if (testToolchainConfigured()) {
|
||||
return JavaLanguageVersion.of(project.testToolchain.toString())
|
||||
}
|
||||
return mainToolchainLanguageVersion()
|
||||
}
|
||||
|
||||
plugins.withType(JavaPlugin) {
|
||||
// Configure the Java Toolchain if the 'mainToolchain' property is defined
|
||||
if (project.hasProperty('mainToolchain') && project.mainToolchain) {
|
||||
def mainLanguageVersion = JavaLanguageVersion.of(project.mainToolchain.toString())
|
||||
// Configure the Java Toolchain if the 'mainToolchain' is configured
|
||||
if (mainToolchainConfigured()) {
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = mainLanguageVersion
|
||||
languageVersion = mainToolchainLanguageVersion()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,8 +70,8 @@ plugins.withType(JavaPlugin) {
|
||||
}
|
||||
}
|
||||
// Configure a specific Java Toolchain for compiling and running tests if the 'testToolchain' property is defined
|
||||
if (project.hasProperty('testToolchain') && project.testToolchain) {
|
||||
def testLanguageVersion = JavaLanguageVersion.of(project.testToolchain.toString());
|
||||
if (testToolchainConfigured()) {
|
||||
def testLanguageVersion = testToolchainLanguageVersion()
|
||||
tasks.withType(JavaCompile).matching { it.name.contains("Test") }.configureEach {
|
||||
javaCompiler = javaToolchains.compilerFor {
|
||||
languageVersion = testLanguageVersion
|
||||
@@ -63,17 +87,17 @@ plugins.withType(JavaPlugin) {
|
||||
|
||||
plugins.withType(GroovyPlugin) {
|
||||
// Fallback to JDK8
|
||||
if (!project.hasProperty('mainToolchain')) {
|
||||
if (!mainToolchainConfigured()) {
|
||||
compileGroovy {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the Kotlin compiler if the 'mainToolchain' property is defined
|
||||
pluginManager.withPlugin("kotlin") {
|
||||
if (project.hasProperty('mainToolchain') && project.mainToolchain) {
|
||||
def mainLanguageVersion = JavaLanguageVersion.of(project.mainToolchain.toString());
|
||||
// Configure the Kotlin compiler if the 'mainToolchain' property is defined
|
||||
if (mainToolchainConfigured()) {
|
||||
def mainLanguageVersion = mainToolchainLanguageVersion()
|
||||
def compiler = javaToolchains.compilerFor {
|
||||
languageVersion = mainLanguageVersion
|
||||
}
|
||||
@@ -106,9 +130,9 @@ pluginManager.withPlugin("kotlin") {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (project.hasProperty('testToolchain') && project.testToolchain) {
|
||||
def testLanguageVersion = JavaLanguageVersion.of(project.testToolchain.toString());
|
||||
|
||||
if (testToolchainConfigured()) {
|
||||
def testLanguageVersion = testToolchainLanguageVersion()
|
||||
def compiler = javaToolchains.compilerFor {
|
||||
languageVersion = testLanguageVersion
|
||||
}
|
||||
@@ -121,4 +145,38 @@ pluginManager.withPlugin("kotlin") {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the JMH plugin to use the toolchain for generating and running JMH bytecode
|
||||
pluginManager.withPlugin("me.champeau.jmh") {
|
||||
if (mainToolchainConfigured() || testToolchainConfigured()) {
|
||||
tasks.matching { it.name.contains('jmh') && it.hasProperty('javaLauncher') }.configureEach {
|
||||
javaLauncher.set(javaToolchains.launcherFor {
|
||||
languageVersion.set(testToolchainLanguageVersion())
|
||||
})
|
||||
}
|
||||
tasks.withType(JavaCompile).matching { it.name.contains("Jmh") }.configureEach {
|
||||
javaCompiler = javaToolchains.compilerFor {
|
||||
languageVersion = testToolchainLanguageVersion()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store resolved Toolchain JVM information as custom values in the build scan.
|
||||
rootProject.ext {
|
||||
resolvedMainToolchain = false
|
||||
resolvedTestToolchain = false
|
||||
}
|
||||
gradle.taskGraph.afterTask { Task task, TaskState state ->
|
||||
if (mainToolchainConfigured() && !resolvedMainToolchain && task instanceof JavaCompile && task.javaCompiler.isPresent()) {
|
||||
def metadata = task.javaCompiler.get().metadata
|
||||
task.project.buildScan.value('Main toolchain', "$metadata.vendor $metadata.languageVersion ($metadata.installationPath)")
|
||||
resolvedMainToolchain = true
|
||||
}
|
||||
if (testToolchainConfigured() && !resolvedTestToolchain && task instanceof Test && task.javaLauncher.isPresent()) {
|
||||
def metadata = task.javaLauncher.get().metadata
|
||||
task.project.buildScan.value('Test toolchain', "$metadata.vendor $metadata.languageVersion ($metadata.installationPath)")
|
||||
resolvedTestToolchain = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,12 +45,6 @@ rootProject.children.each {project ->
|
||||
settings.gradle.projectsLoaded {
|
||||
gradleEnterprise {
|
||||
buildScan {
|
||||
if (settings.gradle.rootProject.hasProperty('mainToolchain')) {
|
||||
value("Main toolchain", 'JDK' + settings.gradle.rootProject.getProperty('mainToolchain'))
|
||||
}
|
||||
if (settings.gradle.rootProject.hasProperty('testToolchain')) {
|
||||
value("Test toolchain", 'JDK' + settings.gradle.rootProject.getProperty('testToolchain'))
|
||||
}
|
||||
File buildDir = settings.gradle.rootProject.getBuildDir()
|
||||
buildDir.mkdirs()
|
||||
new File(buildDir, "build-scan-uri.txt").text = "(build scan not generated)"
|
||||
|
||||
+3
-3
@@ -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.
|
||||
@@ -625,7 +625,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (bodyStart >= 0 && bodyStart != (currentToken.length() - 1)) {
|
||||
sb.append(currentToken.substring(bodyStart + 1));
|
||||
sb.append(" ");
|
||||
sb.append(' ');
|
||||
}
|
||||
numTokensConsumed++;
|
||||
int currentIndex = startIndex + numTokensConsumed;
|
||||
@@ -645,7 +645,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
toAppend = toAppend.substring(1);
|
||||
}
|
||||
sb.append(toAppend);
|
||||
sb.append(" ");
|
||||
sb.append(' ');
|
||||
currentIndex++;
|
||||
numTokensConsumed++;
|
||||
}
|
||||
|
||||
+2
-2
@@ -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.
|
||||
@@ -547,7 +547,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
StringBuilder sb = new StringBuilder("AspectJExpressionPointcut: (");
|
||||
for (int i = 0; i < this.pointcutParameterTypes.length; i++) {
|
||||
sb.append(this.pointcutParameterTypes[i].getName());
|
||||
sb.append(" ");
|
||||
sb.append(' ');
|
||||
sb.append(this.pointcutParameterNames[i]);
|
||||
if ((i+1) < this.pointcutParameterTypes.length) {
|
||||
sb.append(", ");
|
||||
|
||||
+7
-7
@@ -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.
|
||||
@@ -255,19 +255,19 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (includeModifier) {
|
||||
sb.append(Modifier.toString(getModifiers()));
|
||||
sb.append(" ");
|
||||
sb.append(' ');
|
||||
}
|
||||
if (includeReturnTypeAndArgs) {
|
||||
appendType(sb, getReturnType(), useLongReturnAndArgumentTypeName);
|
||||
sb.append(" ");
|
||||
sb.append(' ');
|
||||
}
|
||||
appendType(sb, getDeclaringType(), useLongTypeName);
|
||||
sb.append(".");
|
||||
sb.append('.');
|
||||
sb.append(getMethod().getName());
|
||||
sb.append("(");
|
||||
sb.append('(');
|
||||
Class<?>[] parametersTypes = getParameterTypes();
|
||||
appendTypes(sb, parametersTypes, includeReturnTypeAndArgs, useLongReturnAndArgumentTypeName);
|
||||
sb.append(")");
|
||||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
|
||||
for (int size = types.length, i = 0; i < size; i++) {
|
||||
appendType(sb, types[i], useLongReturnAndArgumentTypeName);
|
||||
if (i < size - 1) {
|
||||
sb.append(",");
|
||||
sb.append(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -19,7 +19,9 @@ package org.springframework.aop.framework;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.aop.SpringProxy;
|
||||
import org.springframework.aop.TargetClassAware;
|
||||
@@ -29,7 +31,9 @@ import org.springframework.aop.target.SingletonTargetSource;
|
||||
import org.springframework.core.DecoratingProxy;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Utility methods for AOP proxy factories.
|
||||
@@ -44,6 +48,11 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
public abstract class AopProxyUtils {
|
||||
|
||||
// JDK 17 Class.isSealed() method available?
|
||||
@Nullable
|
||||
private static final Method isSealedMethod = ClassUtils.getMethodIfAvailable(Class.class, "isSealed");
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the singleton target object behind the given proxy, if any.
|
||||
* @param candidate the (potential) proxy to check
|
||||
@@ -130,34 +139,23 @@ public abstract class AopProxyUtils {
|
||||
specifiedInterfaces = advised.getProxiedInterfaces();
|
||||
}
|
||||
}
|
||||
boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
|
||||
boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
|
||||
boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
|
||||
int nonUserIfcCount = 0;
|
||||
if (addSpringProxy) {
|
||||
nonUserIfcCount++;
|
||||
List<Class<?>> proxiedInterfaces = new ArrayList<>(specifiedInterfaces.length + 3);
|
||||
for (Class<?> ifc : specifiedInterfaces) {
|
||||
// Only non-sealed interfaces are actually eligible for JDK proxying (on JDK 17)
|
||||
if (isSealedMethod == null || Boolean.FALSE.equals(ReflectionUtils.invokeMethod(isSealedMethod, ifc))) {
|
||||
proxiedInterfaces.add(ifc);
|
||||
}
|
||||
}
|
||||
if (addAdvised) {
|
||||
nonUserIfcCount++;
|
||||
if (!advised.isInterfaceProxied(SpringProxy.class)) {
|
||||
proxiedInterfaces.add(SpringProxy.class);
|
||||
}
|
||||
if (addDecoratingProxy) {
|
||||
nonUserIfcCount++;
|
||||
if (!advised.isOpaque() && !advised.isInterfaceProxied(Advised.class)) {
|
||||
proxiedInterfaces.add(Advised.class);
|
||||
}
|
||||
Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
|
||||
System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
|
||||
int index = specifiedInterfaces.length;
|
||||
if (addSpringProxy) {
|
||||
proxiedInterfaces[index] = SpringProxy.class;
|
||||
index++;
|
||||
if (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class)) {
|
||||
proxiedInterfaces.add(DecoratingProxy.class);
|
||||
}
|
||||
if (addAdvised) {
|
||||
proxiedInterfaces[index] = Advised.class;
|
||||
index++;
|
||||
}
|
||||
if (addDecoratingProxy) {
|
||||
proxiedInterfaces[index] = DecoratingProxy.class;
|
||||
}
|
||||
return proxiedInterfaces;
|
||||
return ClassUtils.toClassArray(proxiedInterfaces);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+13
-2
@@ -17,6 +17,7 @@
|
||||
package org.springframework.aop.framework.autoproxy;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -440,7 +441,17 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
ProxyFactory proxyFactory = new ProxyFactory();
|
||||
proxyFactory.copyFrom(this);
|
||||
|
||||
if (!proxyFactory.isProxyTargetClass()) {
|
||||
if (proxyFactory.isProxyTargetClass()) {
|
||||
// Explicit handling of JDK proxy targets (for introduction advice scenarios)
|
||||
if (Proxy.isProxyClass(beanClass)) {
|
||||
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
|
||||
for (Class<?> ifc : beanClass.getInterfaces()) {
|
||||
proxyFactory.addInterface(ifc);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No proxyTargetClass flag enforced, let's apply our default checks...
|
||||
if (shouldProxyTargetClass(beanClass, beanName)) {
|
||||
proxyFactory.setProxyTargetClass(true);
|
||||
}
|
||||
@@ -510,7 +521,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
List<Object> allInterceptors = new ArrayList<>();
|
||||
if (specificInterceptors != null) {
|
||||
if (specificInterceptors.length > 0) {
|
||||
// specificInterceptors may equals PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
|
||||
// specificInterceptors may equal PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
|
||||
allInterceptors.addAll(Arrays.asList(specificInterceptors));
|
||||
}
|
||||
if (commonInterceptors.length > 0) {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -137,7 +137,7 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
|
||||
StringBuilder sb = new StringBuilder(getClass().getName());
|
||||
sb.append(": advice ");
|
||||
if (this.adviceBeanName != null) {
|
||||
sb.append("bean '").append(this.adviceBeanName).append("'");
|
||||
sb.append("bean '").append(this.adviceBeanName).append('\'');
|
||||
}
|
||||
else {
|
||||
sb.append(this.advice);
|
||||
|
||||
+3
-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.
|
||||
@@ -71,7 +71,8 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil
|
||||
if (introductionInfo != null) {
|
||||
Class<?>[] introducedInterfaces = introductionInfo.getInterfaces();
|
||||
if (introducedInterfaces.length == 0) {
|
||||
throw new IllegalArgumentException("IntroductionAdviceSupport implements no interfaces");
|
||||
throw new IllegalArgumentException(
|
||||
"IntroductionInfo defines no interfaces to introduce: " + introductionInfo);
|
||||
}
|
||||
for (Class<?> ifc : introducedInterfaces) {
|
||||
addInterface(ifc);
|
||||
|
||||
+2
-2
@@ -191,9 +191,9 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(getClass().getSimpleName());
|
||||
sb.append(" for target bean '").append(this.targetBeanName).append("'");
|
||||
sb.append(" for target bean '").append(this.targetBeanName).append('\'');
|
||||
if (this.targetClass != null) {
|
||||
sb.append(" of type [").append(this.targetClass.getName()).append("]");
|
||||
sb.append(" of type [").append(this.targetClass.getName()).append(']');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
+3
-3
@@ -276,14 +276,14 @@ public class AspectJAdviceParameterNameDiscovererTests {
|
||||
|
||||
private static String format(String[] names) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
sb.append('(');
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
sb.append(names[i]);
|
||||
if ((i + 1) < names.length) {
|
||||
sb.append(",");
|
||||
sb.append(',');
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -183,7 +183,7 @@ public class ProxyFactoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetsAllInterfaces() throws Exception {
|
||||
public void testGetsAllInterfaces() {
|
||||
// Extend to get new interface
|
||||
class TestBeanSubclass extends TestBean implements Comparable<Object> {
|
||||
@Override
|
||||
@@ -240,6 +240,16 @@ public class ProxyFactoryTests {
|
||||
assertThat(factory.countAdvicesOfType(NopInterceptor.class) == 2).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSealedInterfaceExclusion() {
|
||||
// String implements ConstantDesc on JDK 12+, sealed as of JDK 17
|
||||
ProxyFactory factory = new ProxyFactory(new String());
|
||||
NopInterceptor di = new NopInterceptor();
|
||||
factory.addAdvice(0, di);
|
||||
Object proxy = factory.getProxy();
|
||||
assertThat(proxy).isInstanceOf(CharSequence.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should see effect immediately on behavior.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
@@ -41,8 +41,6 @@ import kotlin.reflect.KParameter;
|
||||
import kotlin.reflect.full.KClasses;
|
||||
import kotlin.reflect.jvm.KCallablesJvm;
|
||||
import kotlin.reflect.jvm.ReflectJvmMapping;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.KotlinDetector;
|
||||
@@ -75,8 +73,6 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class BeanUtils {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(BeanUtils.class);
|
||||
|
||||
private static final ParameterNameDiscoverer parameterNameDiscoverer =
|
||||
new DefaultParameterNameDiscoverer();
|
||||
|
||||
@@ -551,9 +547,6 @@ public abstract class BeanUtils {
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// e.g. AccessControlException on Google App Engine
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not access system ClassLoader: " + ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -564,10 +557,6 @@ public abstract class BeanUtils {
|
||||
Class<?> editorClass = cl.loadClass(editorName);
|
||||
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;
|
||||
}
|
||||
@@ -579,10 +568,6 @@ public abstract class BeanUtils {
|
||||
catch (ClassNotFoundException ex) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -247,14 +247,14 @@ class TypeConverterDelegate {
|
||||
// Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Cannot convert value of type '").append(ClassUtils.getDescriptiveType(newValue));
|
||||
msg.append("' to required type '").append(ClassUtils.getQualifiedName(requiredType)).append("'");
|
||||
msg.append("' to required type '").append(ClassUtils.getQualifiedName(requiredType)).append('\'');
|
||||
if (propertyName != null) {
|
||||
msg.append(" for property '").append(propertyName).append("'");
|
||||
msg.append(" for property '").append(propertyName).append('\'');
|
||||
}
|
||||
if (editor != null) {
|
||||
msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
|
||||
"] returned inappropriate value of type '").append(
|
||||
ClassUtils.getDescriptiveType(convertedValue)).append("'");
|
||||
ClassUtils.getDescriptiveType(convertedValue)).append('\'');
|
||||
throw new IllegalArgumentException(msg.toString());
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -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.
|
||||
@@ -84,7 +84,7 @@ import org.springframework.lang.Nullable;
|
||||
* (only applicable when running in a web application context)
|
||||
* <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
|
||||
* <li>InitializingBean's {@code afterPropertiesSet}
|
||||
* <li>a custom init-method definition
|
||||
* <li>a custom {@code init-method} definition
|
||||
* <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
|
||||
* </ol>
|
||||
*
|
||||
@@ -92,7 +92,7 @@ import org.springframework.lang.Nullable;
|
||||
* <ol>
|
||||
* <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
|
||||
* <li>DisposableBean's {@code destroy}
|
||||
* <li>a custom destroy-method definition
|
||||
* <li>a custom {@code destroy-method} definition
|
||||
* </ol>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
@@ -102,6 +102,8 @@ import org.springframework.lang.Nullable;
|
||||
* @see BeanNameAware#setBeanName
|
||||
* @see BeanClassLoaderAware#setBeanClassLoader
|
||||
* @see BeanFactoryAware#setBeanFactory
|
||||
* @see org.springframework.context.EnvironmentAware#setEnvironment
|
||||
* @see org.springframework.context.EmbeddedValueResolverAware#setEmbeddedValueResolver
|
||||
* @see org.springframework.context.ResourceLoaderAware#setResourceLoader
|
||||
* @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher
|
||||
* @see org.springframework.context.MessageSourceAware#setMessageSource
|
||||
@@ -111,6 +113,7 @@ import org.springframework.lang.Nullable;
|
||||
* @see InitializingBean#afterPropertiesSet
|
||||
* @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
|
||||
* @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
|
||||
* @see DisposableBean#destroy
|
||||
* @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
|
||||
*/
|
||||
|
||||
+4
-4
@@ -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.
|
||||
@@ -217,13 +217,13 @@ public class RequiredAnnotationBeanPostProcessor implements SmartInstantiationAw
|
||||
sb.append(" and");
|
||||
}
|
||||
else {
|
||||
sb.append(",");
|
||||
sb.append(',');
|
||||
}
|
||||
}
|
||||
sb.append(" '").append(propertyName).append("'");
|
||||
sb.append(" '").append(propertyName).append('\'');
|
||||
}
|
||||
sb.append(size == 1 ? " is" : " are");
|
||||
sb.append(" required for bean '").append(beanName).append("'");
|
||||
sb.append(" required for bean '").append(beanName).append('\'');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -489,9 +489,9 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length);
|
||||
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class<?>) args[1], constructorArgs);
|
||||
Map<?, ?> namedArgs = (Map<?, ?>) args[0];
|
||||
for (Object key : namedArgs.keySet()) {
|
||||
String propName = (String) key;
|
||||
setProperty(propName, namedArgs.get(propName));
|
||||
for (Map.Entry<?, ?> entity : namedArgs.entrySet()) {
|
||||
String propName = (String) entity.getKey();
|
||||
setProperty(propName, entity.getValue());
|
||||
}
|
||||
}
|
||||
// factory method syntax
|
||||
|
||||
+1
-1
@@ -1241,7 +1241,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("class [");
|
||||
sb.append(getBeanClassName()).append("]");
|
||||
sb.append(getBeanClassName()).append(']');
|
||||
sb.append("; scope=").append(this.scope);
|
||||
sb.append("; abstract=").append(this.abstractFlag);
|
||||
sb.append("; lazyInit=").append(this.lazyInit);
|
||||
|
||||
+37
-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.
|
||||
@@ -21,6 +21,7 @@ import java.util.function.Supplier;
|
||||
import org.springframework.beans.factory.config.AutowiredPropertyMarker;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -102,7 +103,7 @@ public final class BeanDefinitionBuilder {
|
||||
* @param beanClass the {@code Class} of the bean that the definition is being created for
|
||||
*/
|
||||
public static BeanDefinitionBuilder rootBeanDefinition(Class<?> beanClass) {
|
||||
return rootBeanDefinition(beanClass, null);
|
||||
return rootBeanDefinition(beanClass, (String) null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,6 +118,30 @@ public final class BeanDefinitionBuilder {
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code BeanDefinitionBuilder} used to construct a {@link RootBeanDefinition}.
|
||||
* @param beanType the {@link ResolvableType type} of the bean that the definition is being created for
|
||||
* @param instanceSupplier a callback for creating an instance of the bean
|
||||
* @since 5.3.9
|
||||
*/
|
||||
public static <T> BeanDefinitionBuilder rootBeanDefinition(ResolvableType beanType, Supplier<T> instanceSupplier) {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition();
|
||||
beanDefinition.setTargetType(beanType);
|
||||
beanDefinition.setInstanceSupplier(instanceSupplier);
|
||||
return new BeanDefinitionBuilder(beanDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code BeanDefinitionBuilder} used to construct a {@link RootBeanDefinition}.
|
||||
* @param beanClass the {@code Class} of the bean that the definition is being created for
|
||||
* @param instanceSupplier a callback for creating an instance of the bean
|
||||
* @since 5.3.9
|
||||
* @see #rootBeanDefinition(ResolvableType, Supplier)
|
||||
*/
|
||||
public static <T> BeanDefinitionBuilder rootBeanDefinition(Class<T> beanClass, Supplier<T> instanceSupplier) {
|
||||
return rootBeanDefinition(ResolvableType.forClass(beanClass), instanceSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code BeanDefinitionBuilder} used to construct a {@link ChildBeanDefinition}.
|
||||
* @param parentName the name of the parent bean
|
||||
@@ -331,6 +356,16 @@ public final class BeanDefinitionBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this bean is 'synthetic', that is, not defined by
|
||||
* the application itself.
|
||||
* @since 5.3.9
|
||||
*/
|
||||
public BeanDefinitionBuilder setSynthetic(boolean synthetic) {
|
||||
this.beanDefinition.setSynthetic(synthetic);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given customizers to the underlying bean definition.
|
||||
* @since 5.0
|
||||
|
||||
+6
-3
@@ -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.
|
||||
@@ -35,6 +35,7 @@ import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodInterceptor;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.cglib.proxy.NoOp;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -244,8 +245,10 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
||||
return (bean.equals(null) ? null : bean);
|
||||
}
|
||||
else {
|
||||
return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
|
||||
this.owner.getBean(method.getReturnType()));
|
||||
// Find target bean matching the (potentially generic) method return type
|
||||
ResolvableType genericReturnType = ResolvableType.forMethodReturnType(method);
|
||||
return (argsToUse != null ? this.owner.getBeanProvider(genericReturnType).getObject(argsToUse) :
|
||||
this.owner.getBeanProvider(genericReturnType).getObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -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.
|
||||
@@ -277,12 +277,12 @@ class ConstructorResolver {
|
||||
throw ex;
|
||||
}
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Could not resolve matching constructor " +
|
||||
"Could not resolve matching constructor on bean class [" + mbd.getBeanClassName() + "] " +
|
||||
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
|
||||
}
|
||||
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Ambiguous constructor matches found in bean '" + beanName + "' " +
|
||||
"Ambiguous constructor matches found on bean class [" + mbd.getBeanClassName() + "] " +
|
||||
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
|
||||
ambiguousConstructors);
|
||||
}
|
||||
@@ -608,7 +608,7 @@ class ConstructorResolver {
|
||||
}
|
||||
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"No matching factory method found: " +
|
||||
"No matching factory method found on class [" + factoryClass.getName() + "]: " +
|
||||
(mbd.getFactoryBeanName() != null ?
|
||||
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
|
||||
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
|
||||
@@ -619,12 +619,12 @@ class ConstructorResolver {
|
||||
}
|
||||
else if (void.class == factoryMethodToUse.getReturnType()) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Invalid factory method '" + mbd.getFactoryMethodName() +
|
||||
"': needs to have a non-void return type!");
|
||||
"Invalid factory method '" + mbd.getFactoryMethodName() + "' on class [" +
|
||||
factoryClass.getName() + "]: needs to have a non-void return type!");
|
||||
}
|
||||
else if (ambiguousFactoryMethods != null) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Ambiguous factory method matches found in bean '" + beanName + "' " +
|
||||
"Ambiguous factory method matches found on class [" + factoryClass.getName() + "] " +
|
||||
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
|
||||
ambiguousFactoryMethods);
|
||||
}
|
||||
|
||||
+16
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -19,17 +19,25 @@ package org.springframework.beans.factory.support;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Represents an override of a method that looks up an object in the same IoC context.
|
||||
* Represents an override of a method that looks up an object in the same IoC context,
|
||||
* either by bean name or by bean type (based on the declared method return type).
|
||||
*
|
||||
* <p>Methods eligible for lookup override must not have arguments.
|
||||
* <p>Methods eligible for lookup override may declare arguments in which case the
|
||||
* given arguments are passed to the bean retrieval operation.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean(String)
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean(Class)
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean(String, Object...)
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean(Class, Object...)
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBeanProvider(ResolvableType)
|
||||
*/
|
||||
public class LookupOverride extends MethodOverride {
|
||||
|
||||
@@ -43,8 +51,8 @@ public class LookupOverride extends MethodOverride {
|
||||
/**
|
||||
* Construct a new LookupOverride.
|
||||
* @param methodName the name of the method to override
|
||||
* @param beanName the name of the bean in the current {@code BeanFactory}
|
||||
* that the overridden method should return (may be {@code null})
|
||||
* @param beanName the name of the bean in the current {@code BeanFactory} that the
|
||||
* overridden method should return (may be {@code null} for type-based bean retrieval)
|
||||
*/
|
||||
public LookupOverride(String methodName, @Nullable String beanName) {
|
||||
super(methodName);
|
||||
@@ -53,9 +61,9 @@ public class LookupOverride extends MethodOverride {
|
||||
|
||||
/**
|
||||
* Construct a new LookupOverride.
|
||||
* @param method the method to override
|
||||
* @param beanName the name of the bean in the current {@code BeanFactory}
|
||||
* that the overridden method should return (may be {@code null})
|
||||
* @param method the method declaration to override
|
||||
* @param beanName the name of the bean in the current {@code BeanFactory} that the
|
||||
* overridden method should return (may be {@code null} for type-based bean retrieval)
|
||||
*/
|
||||
public LookupOverride(Method method, @Nullable String beanName) {
|
||||
super(method.getName());
|
||||
|
||||
+3
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -19,9 +19,8 @@ package org.springframework.beans.factory.support;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by classes that can reimplement any method
|
||||
* on an IoC-managed object: the <b>Method Injection</b> form of
|
||||
* Dependency Injection.
|
||||
* Interface to be implemented by classes that can reimplement any method on an
|
||||
* IoC-managed object: the <b>Method Injection</b> form of Dependency Injection.
|
||||
*
|
||||
* <p>Such methods may be (but need not be) abstract, in which case the
|
||||
* container will create a concrete subclass to instantiate.
|
||||
|
||||
+3
-3
@@ -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.
|
||||
@@ -25,7 +25,7 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Extension of MethodOverride that represents an arbitrary
|
||||
* Extension of {@link MethodOverride} that represents an arbitrary
|
||||
* override of a method by the IoC container.
|
||||
*
|
||||
* <p>Any non-final method can be overridden, irrespective of its
|
||||
@@ -45,7 +45,7 @@ public class ReplaceOverride extends MethodOverride {
|
||||
/**
|
||||
* Construct a new ReplaceOverride.
|
||||
* @param methodName the name of the method to override
|
||||
* @param methodReplacerBeanName the bean name of the MethodReplacer
|
||||
* @param methodReplacerBeanName the bean name of the {@link MethodReplacer}
|
||||
*/
|
||||
public ReplaceOverride(String methodName, String methodReplacerBeanName) {
|
||||
super(methodName);
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -23,9 +23,9 @@ import org.springframework.util.StringUtils;
|
||||
/**
|
||||
* Editor for {@code java.util.Locale}, to directly populate a Locale property.
|
||||
*
|
||||
* <p>Expects the same syntax as Locale's {@code toString}, i.e. language +
|
||||
* <p>Expects the same syntax as Locale's {@code toString()}, i.e. language +
|
||||
* optionally country + optionally variant, separated by "_" (e.g. "en", "en_US").
|
||||
* Also accepts spaces as separators, as alternative to underscores.
|
||||
* Also accepts spaces as separators, as an alternative to underscores.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 26.05.2003
|
||||
|
||||
+4
-5
@@ -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.
|
||||
@@ -44,8 +44,6 @@ public class PropertyComparator<T> implements Comparator<T> {
|
||||
|
||||
private final SortDefinition sortDefinition;
|
||||
|
||||
private final BeanWrapperImpl beanWrapper = new BeanWrapperImpl(false);
|
||||
|
||||
|
||||
/**
|
||||
* Create a new PropertyComparator for the given SortDefinition.
|
||||
@@ -115,8 +113,9 @@ public class PropertyComparator<T> implements Comparator<T> {
|
||||
// (similar to JSTL EL). If the property doesn't exist in the
|
||||
// first place, let the exception through.
|
||||
try {
|
||||
this.beanWrapper.setWrappedInstance(obj);
|
||||
return this.beanWrapper.getPropertyValue(this.sortDefinition.getProperty());
|
||||
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(false);
|
||||
beanWrapper.setWrappedInstance(obj);
|
||||
return beanWrapper.getPropertyValue(this.sortDefinition.getProperty());
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
logger.debug("PropertyComparator could not access property - treating as null for sorting", ex);
|
||||
|
||||
+11
-13
@@ -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.
|
||||
@@ -18,14 +18,14 @@ package org.springframework.beans;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.RepeatedTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -36,23 +36,21 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Chris Beams
|
||||
* @since 08.03.2004
|
||||
*/
|
||||
public class ConcurrentBeanWrapperTests {
|
||||
class ConcurrentBeanWrapperTests {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private Set<TestRun> set = Collections.synchronizedSet(new HashSet<TestRun>());
|
||||
private final Set<TestRun> set = ConcurrentHashMap.newKeySet();
|
||||
|
||||
private Throwable ex = null;
|
||||
|
||||
@Test
|
||||
public void testSingleThread() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
performSet();
|
||||
}
|
||||
@RepeatedTest(100)
|
||||
void testSingleThread() {
|
||||
performSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcurrent() {
|
||||
void testConcurrent() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
TestRun run = new TestRun(this);
|
||||
set.add(run);
|
||||
@@ -82,7 +80,7 @@ public class ConcurrentBeanWrapperTests {
|
||||
|
||||
Properties p = (Properties) System.getProperties().clone();
|
||||
|
||||
assertThat(p.size() != 0).as("The System properties must not be empty").isTrue();
|
||||
assertThat(p).as("The System properties must not be empty").isNotEmpty();
|
||||
|
||||
for (Iterator<?> i = p.entrySet().iterator(); i.hasNext();) {
|
||||
i.next();
|
||||
@@ -111,7 +109,7 @@ public class ConcurrentBeanWrapperTests {
|
||||
|
||||
private ConcurrentBeanWrapperTests test;
|
||||
|
||||
public TestRun(ConcurrentBeanWrapperTests test) {
|
||||
TestRun(ConcurrentBeanWrapperTests test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -31,6 +31,7 @@ import static org.springframework.beans.factory.support.BeanDefinitionBuilder.ro
|
||||
* invoking a factory method is not instructive to the user and rather misleading.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class Spr5475Tests {
|
||||
|
||||
@@ -40,7 +41,8 @@ public class Spr5475Tests {
|
||||
rootBeanDefinition(Foo.class)
|
||||
.setFactoryMethod("noArgFactory")
|
||||
.addConstructorArgValue("bogusArg").getBeanDefinition(),
|
||||
"Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(String)'. " +
|
||||
"Error creating bean with name 'foo': No matching factory method found on class " +
|
||||
"[org.springframework.beans.factory.Spr5475Tests$Foo]: factory method 'noArgFactory(String)'. " +
|
||||
"Check that a method with the specified name and arguments exists and that it is static.");
|
||||
}
|
||||
|
||||
@@ -51,7 +53,8 @@ public class Spr5475Tests {
|
||||
.setFactoryMethod("noArgFactory")
|
||||
.addConstructorArgValue("bogusArg1")
|
||||
.addConstructorArgValue("bogusArg2".getBytes()).getBeanDefinition(),
|
||||
"Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(String,byte[])'. " +
|
||||
"Error creating bean with name 'foo': No matching factory method found on class " +
|
||||
"[org.springframework.beans.factory.Spr5475Tests$Foo]: factory method 'noArgFactory(String,byte[])'. " +
|
||||
"Check that a method with the specified name and arguments exists and that it is static.");
|
||||
}
|
||||
|
||||
@@ -65,7 +68,8 @@ public class Spr5475Tests {
|
||||
def.setConstructorArgumentValues(cav);
|
||||
|
||||
assertExceptionMessageForMisconfiguredFactoryMethod(def,
|
||||
"Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(CharSequence,byte[])'. " +
|
||||
"Error creating bean with name 'foo': No matching factory method found on class " +
|
||||
"[org.springframework.beans.factory.Spr5475Tests$Foo]: factory method 'noArgFactory(CharSequence,byte[])'. " +
|
||||
"Check that a method with the specified name and arguments exists and that it is static.");
|
||||
}
|
||||
|
||||
|
||||
+35
-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.
|
||||
@@ -121,6 +121,18 @@ public class LookupAnnotationTests {
|
||||
assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithGenericBean() {
|
||||
beanFactory.registerBeanDefinition("numberBean", new RootBeanDefinition(NumberBean.class));
|
||||
beanFactory.registerBeanDefinition("doubleStore", new RootBeanDefinition(DoubleStore.class));
|
||||
beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
|
||||
|
||||
NumberBean bean = (NumberBean) beanFactory.getBean("numberBean");
|
||||
assertThat(bean).isNotNull();
|
||||
assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
|
||||
assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
|
||||
}
|
||||
|
||||
|
||||
public static abstract class AbstractBean {
|
||||
|
||||
@@ -147,4 +159,26 @@ public class LookupAnnotationTests {
|
||||
AbstractBean abstractBean;
|
||||
}
|
||||
|
||||
|
||||
public static class NumberStore<T extends Number> {
|
||||
}
|
||||
|
||||
|
||||
public static class DoubleStore extends NumberStore<Double> {
|
||||
}
|
||||
|
||||
|
||||
public static class FloatStore extends NumberStore<Float> {
|
||||
}
|
||||
|
||||
|
||||
public static abstract class NumberBean {
|
||||
|
||||
@Lookup
|
||||
public abstract NumberStore<Double> getDoubleStore();
|
||||
|
||||
@Lookup
|
||||
public abstract NumberStore<Float> getFloatStore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -141,6 +141,7 @@ class YamlProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void standardTypesSupportedByDefault() throws Exception {
|
||||
setYaml("value: !!set\n ? first\n ? second");
|
||||
this.processor.process((properties, map) -> {
|
||||
|
||||
+82
-5
@@ -17,22 +17,25 @@
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class BeanDefinitionBuilderTests {
|
||||
class BeanDefinitionBuilderTests {
|
||||
|
||||
@Test
|
||||
public void beanClassWithSimpleProperty() {
|
||||
void builderWithBeanClassWithSimpleProperty() {
|
||||
String[] dependsOn = new String[] { "A", "B", "C" };
|
||||
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class);
|
||||
bdb.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
@@ -49,7 +52,7 @@ public class BeanDefinitionBuilderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanClassWithFactoryMethod() {
|
||||
void builderWithBeanClassAndFactoryMethod() {
|
||||
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class, "create");
|
||||
RootBeanDefinition rbd = (RootBeanDefinition) bdb.getBeanDefinition();
|
||||
assertThat(rbd.hasBeanClass()).isTrue();
|
||||
@@ -58,7 +61,7 @@ public class BeanDefinitionBuilderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanClassName() {
|
||||
void builderWithBeanClassName() {
|
||||
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class.getName());
|
||||
RootBeanDefinition rbd = (RootBeanDefinition) bdb.getBeanDefinition();
|
||||
assertThat(rbd.hasBeanClass()).isFalse();
|
||||
@@ -66,7 +69,7 @@ public class BeanDefinitionBuilderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanClassNameWithFactoryMethod() {
|
||||
void builderWithBeanClassNameAndFactoryMethod() {
|
||||
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class.getName(), "create");
|
||||
RootBeanDefinition rbd = (RootBeanDefinition) bdb.getBeanDefinition();
|
||||
assertThat(rbd.hasBeanClass()).isFalse();
|
||||
@@ -74,4 +77,78 @@ public class BeanDefinitionBuilderTests {
|
||||
assertThat(rbd.getFactoryMethodName()).isEqualTo("create");
|
||||
}
|
||||
|
||||
@Test
|
||||
void builderWithResolvableTypeAndInstanceSupplier() {
|
||||
ResolvableType type = ResolvableType.forClassWithGenerics(Function.class, Integer.class, String.class);
|
||||
Function<Integer, String> function = i -> "value " + i;
|
||||
RootBeanDefinition rbd = (RootBeanDefinition) BeanDefinitionBuilder
|
||||
.rootBeanDefinition(type, () -> function).getBeanDefinition();
|
||||
assertThat(rbd.getResolvableType()).isEqualTo(type);
|
||||
assertThat(rbd.getInstanceSupplier()).isNotNull();
|
||||
assertThat(rbd.getInstanceSupplier().get()).isInstanceOf(Function.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void builderWithBeanClassAndInstanceSupplier() {
|
||||
RootBeanDefinition rbd = (RootBeanDefinition) BeanDefinitionBuilder
|
||||
.rootBeanDefinition(String.class, () -> "test").getBeanDefinition();
|
||||
assertThat(rbd.getResolvableType().resolve()).isEqualTo(String.class);
|
||||
assertThat(rbd.getInstanceSupplier()).isNotNull();
|
||||
assertThat(rbd.getInstanceSupplier().get()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void builderWithAutowireMode() {
|
||||
assertThat(BeanDefinitionBuilder.rootBeanDefinition(TestBean.class)
|
||||
.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE).getBeanDefinition().getAutowireMode())
|
||||
.isEqualTo(RootBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void builderWithDependencyCheck() {
|
||||
assertThat(BeanDefinitionBuilder.rootBeanDefinition(TestBean.class)
|
||||
.setDependencyCheck(RootBeanDefinition.DEPENDENCY_CHECK_ALL)
|
||||
.getBeanDefinition().getDependencyCheck())
|
||||
.isEqualTo(RootBeanDefinition.DEPENDENCY_CHECK_ALL);
|
||||
}
|
||||
|
||||
@Test
|
||||
void builderWithDependsOn() {
|
||||
assertThat(BeanDefinitionBuilder.rootBeanDefinition(TestBean.class).addDependsOn("test")
|
||||
.addDependsOn("test2").getBeanDefinition().getDependsOn())
|
||||
.containsExactly("test", "test2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void builderWithPrimary() {
|
||||
assertThat(BeanDefinitionBuilder.rootBeanDefinition(TestBean.class)
|
||||
.setPrimary(true).getBeanDefinition().isPrimary()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void builderWithRole() {
|
||||
assertThat(BeanDefinitionBuilder.rootBeanDefinition(TestBean.class)
|
||||
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition().getRole())
|
||||
.isEqualTo(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void builderWithSynthetic() {
|
||||
assertThat(BeanDefinitionBuilder.rootBeanDefinition(TestBean.class)
|
||||
.setSynthetic(true).getBeanDefinition().isSynthetic()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void builderWithCustomizers() {
|
||||
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class)
|
||||
.applyCustomizers(builder -> {
|
||||
builder.setFactoryMethodName("create");
|
||||
builder.setRole(BeanDefinition.ROLE_SUPPORT);
|
||||
})
|
||||
.applyCustomizers(builder -> builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE))
|
||||
.getBeanDefinition();
|
||||
assertThat(beanDefinition.getFactoryMethodName()).isEqualTo("create");
|
||||
assertThat(beanDefinition.getRole()).isEqualTo(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+39
-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.
|
||||
@@ -36,7 +36,7 @@ public class LookupMethodTests {
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
public void setup() {
|
||||
beanFactory = new DefaultListableBeanFactory();
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
|
||||
reader.loadBeanDefinitions(new ClassPathResource("lookupMethodTests.xml", getClass()));
|
||||
@@ -83,8 +83,8 @@ public class LookupMethodTests {
|
||||
public void testWithThreeArgsShouldFail() {
|
||||
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
|
||||
assertThat(bean).isNotNull();
|
||||
assertThatExceptionOfType(AbstractMethodError.class).as("does not have a three arg constructor").isThrownBy(() ->
|
||||
bean.getThreeArguments("name", 1, 2));
|
||||
assertThatExceptionOfType(AbstractMethodError.class).as("does not have a three arg constructor")
|
||||
.isThrownBy(() -> bean.getThreeArguments("name", 1, 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -97,6 +97,21 @@ public class LookupMethodTests {
|
||||
assertThat(expected.isJedi()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithGenericBean() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(NumberBean.class);
|
||||
bd.getMethodOverrides().addOverride(new LookupOverride("getDoubleStore", null));
|
||||
bd.getMethodOverrides().addOverride(new LookupOverride("getFloatStore", null));
|
||||
beanFactory.registerBeanDefinition("numberBean", bd);
|
||||
beanFactory.registerBeanDefinition("doubleStore", new RootBeanDefinition(DoubleStore.class));
|
||||
beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
|
||||
|
||||
NumberBean bean = (NumberBean) beanFactory.getBean("numberBean");
|
||||
assertThat(bean).isNotNull();
|
||||
assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
|
||||
assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
|
||||
}
|
||||
|
||||
|
||||
public static abstract class AbstractBean {
|
||||
|
||||
@@ -111,4 +126,24 @@ public class LookupMethodTests {
|
||||
public abstract TestBean getThreeArguments(String name, int age, int anotherArg);
|
||||
}
|
||||
|
||||
|
||||
public static class NumberStore<T extends Number> {
|
||||
}
|
||||
|
||||
|
||||
public static class DoubleStore extends NumberStore<Double> {
|
||||
}
|
||||
|
||||
|
||||
public static class FloatStore extends NumberStore<Float> {
|
||||
}
|
||||
|
||||
|
||||
public static abstract class NumberBean {
|
||||
|
||||
public abstract NumberStore<Double> getDoubleStore();
|
||||
|
||||
public abstract NumberStore<Float> getFloatStore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-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.
|
||||
@@ -244,7 +244,7 @@ public class QualifierAnnotationAutowireBeanFactoryTests {
|
||||
@Target({ElementType.FIELD, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Qualifier
|
||||
private static @interface TestQualifier {
|
||||
private @interface TestQualifier {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-7
@@ -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.
|
||||
@@ -19,7 +19,6 @@ package org.springframework.context.index.processor;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -37,7 +36,7 @@ import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
|
||||
/**
|
||||
* Annotation {@link Processor} that writes {@link CandidateComponentsMetadata}
|
||||
* Annotation {@link Processor} that writes a {@link CandidateComponentsMetadata}
|
||||
* file for spring components.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
@@ -46,9 +45,6 @@ import javax.lang.model.element.TypeElement;
|
||||
*/
|
||||
public class CandidateComponentsIndexer implements Processor {
|
||||
|
||||
private static final Set<ElementKind> TYPE_KINDS =
|
||||
Collections.unmodifiableSet(EnumSet.of(ElementKind.CLASS, ElementKind.INTERFACE));
|
||||
|
||||
private MetadataStore metadataStore;
|
||||
|
||||
private MetadataCollector metadataCollector;
|
||||
@@ -136,7 +132,8 @@ public class CandidateComponentsIndexer implements Processor {
|
||||
private static List<TypeElement> staticTypesIn(Iterable<? extends Element> elements) {
|
||||
List<TypeElement> list = new ArrayList<>();
|
||||
for (Element element : elements) {
|
||||
if (TYPE_KINDS.contains(element.getKind()) && element.getModifiers().contains(Modifier.STATIC)) {
|
||||
if ((element.getKind().isClass() || element.getKind() == ElementKind.INTERFACE) &&
|
||||
element.getModifiers().contains(Modifier.STATIC) && element instanceof TypeElement) {
|
||||
list.add((TypeElement) element);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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.
|
||||
@@ -26,7 +26,7 @@ import javax.lang.model.element.ElementKind;
|
||||
|
||||
/**
|
||||
* A {@link StereotypesProvider} implementation that extracts the stereotypes
|
||||
* flagged by the {@value INDEXED_ANNOTATION} annotation. This implementation
|
||||
* flagged by the {@value #INDEXED_ANNOTATION} annotation. This implementation
|
||||
* honors stereotypes defined this way on meta-annotations.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
@@ -48,7 +48,7 @@ class IndexedStereotypesProvider implements StereotypesProvider {
|
||||
public Set<String> getStereotypes(Element element) {
|
||||
Set<String> stereotypes = new LinkedHashSet<>();
|
||||
ElementKind kind = element.getKind();
|
||||
if (kind != ElementKind.CLASS && kind != ElementKind.INTERFACE) {
|
||||
if (!kind.isClass() && kind != ElementKind.INTERFACE) {
|
||||
return stereotypes;
|
||||
}
|
||||
Set<Element> seen = new HashSet<>();
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import javax.lang.model.element.ElementKind;
|
||||
|
||||
/**
|
||||
* A {@link StereotypesProvider} implementation that provides the
|
||||
* {@value STEREOTYPE} stereotype for each package-info.
|
||||
* {@value #STEREOTYPE} stereotype for each package-info.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 5.0
|
||||
|
||||
+3
-3
@@ -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.
|
||||
@@ -24,8 +24,8 @@ import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
|
||||
/**
|
||||
* A {@link StereotypesProvider} that extract a stereotype for each
|
||||
* {@code javax.*} annotation placed on a class or interface.
|
||||
* A {@link StereotypesProvider} that extracts a stereotype for each
|
||||
* {@code javax.*} annotation <i>present</i> on a class or interface.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 5.0
|
||||
|
||||
+2
-2
@@ -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.
|
||||
@@ -22,7 +22,7 @@ import javax.lang.model.element.Element;
|
||||
|
||||
/**
|
||||
* Provide the list of stereotypes that match an {@link Element}.
|
||||
* If an element has one more stereotypes, it is referenced in the index
|
||||
* <p>If an element has one or more stereotypes, it is referenced in the index
|
||||
* of candidate components and each stereotype can be queried individually.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -130,8 +130,8 @@ public class EhCacheManagerFactoryBean implements FactoryBean<CacheManager>, Ini
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws CacheException {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Initializing EhCache CacheManager" +
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Initializing EhCache CacheManager" +
|
||||
(this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : ""));
|
||||
}
|
||||
|
||||
@@ -188,8 +188,8 @@ public class EhCacheManagerFactoryBean implements FactoryBean<CacheManager>, Ini
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (this.cacheManager != null && this.locallyManaged) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Shutting down EhCache CacheManager" +
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Shutting down EhCache CacheManager" +
|
||||
(this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : ""));
|
||||
}
|
||||
this.cacheManager.shutdown();
|
||||
|
||||
+3
-3
@@ -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.
|
||||
@@ -138,7 +138,7 @@ abstract class AbstractJCacheOperation<A extends Annotation> implements JCacheOp
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getOperationDescription().append("]").toString();
|
||||
return getOperationDescription().append(']').toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,7 +148,7 @@ abstract class AbstractJCacheOperation<A extends Annotation> implements JCacheOp
|
||||
protected StringBuilder getOperationDescription() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append(getClass().getSimpleName());
|
||||
result.append("[");
|
||||
result.append('[');
|
||||
result.append(this.methodDetails);
|
||||
return result;
|
||||
}
|
||||
|
||||
+3
-3
@@ -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.
|
||||
@@ -221,11 +221,11 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
}
|
||||
catch (NoUniqueBeanDefinitionException ex) {
|
||||
throw new IllegalStateException("No CacheResolver specified, and no unique bean of type " +
|
||||
"CacheManager found. Mark one as primary or declare a specific CacheManager to use.");
|
||||
"CacheManager found. Mark one as primary or declare a specific CacheManager to use.", ex);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
throw new IllegalStateException("No CacheResolver specified, and no bean of type CacheManager found. " +
|
||||
"Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.");
|
||||
"Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.", ex);
|
||||
}
|
||||
}
|
||||
this.initialized = true;
|
||||
|
||||
Vendored
+3
-3
@@ -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.
|
||||
@@ -71,9 +71,9 @@ public class CacheEvictOperation extends CacheOperation {
|
||||
@Override
|
||||
protected StringBuilder getOperationDescription() {
|
||||
StringBuilder sb = super.getOperationDescription();
|
||||
sb.append(",");
|
||||
sb.append(',');
|
||||
sb.append(this.cacheWide);
|
||||
sb.append(",");
|
||||
sb.append(',');
|
||||
sb.append(this.beforeInvocation);
|
||||
return sb;
|
||||
}
|
||||
|
||||
+3
-3
@@ -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.
|
||||
@@ -216,13 +216,13 @@ public abstract class CacheOperation implements BasicOperation {
|
||||
*/
|
||||
protected StringBuilder getOperationDescription() {
|
||||
StringBuilder result = new StringBuilder(getClass().getSimpleName());
|
||||
result.append("[").append(this.name);
|
||||
result.append('[').append(this.name);
|
||||
result.append("] caches=").append(this.cacheNames);
|
||||
result.append(" | key='").append(this.key);
|
||||
result.append("' | keyGenerator='").append(this.keyGenerator);
|
||||
result.append("' | cacheManager='").append(this.cacheManager);
|
||||
result.append("' | cacheResolver='").append(this.cacheResolver);
|
||||
result.append("' | condition='").append(this.condition).append("'");
|
||||
result.append("' | condition='").append(this.condition).append('\'');
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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.
|
||||
@@ -66,7 +66,7 @@ public class CachePutOperation extends CacheOperation {
|
||||
StringBuilder sb = super.getOperationDescription();
|
||||
sb.append(" | unless='");
|
||||
sb.append(this.unless);
|
||||
sb.append("'");
|
||||
sb.append('\'');
|
||||
return sb;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -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.
|
||||
@@ -79,10 +79,10 @@ public class CacheableOperation extends CacheOperation {
|
||||
StringBuilder sb = super.getOperationDescription();
|
||||
sb.append(" | unless='");
|
||||
sb.append(this.unless);
|
||||
sb.append("'");
|
||||
sb.append('\'');
|
||||
sb.append(" | sync='");
|
||||
sb.append(this.sync);
|
||||
sb.append("'");
|
||||
sb.append('\'');
|
||||
return sb;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,6 +16,7 @@
|
||||
|
||||
package org.springframework.context;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
@@ -37,18 +38,37 @@ public abstract class ApplicationEvent extends EventObject {
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code ApplicationEvent}.
|
||||
* Create a new {@code ApplicationEvent} with its {@link #getTimestamp() timestamp}
|
||||
* set to {@link System#currentTimeMillis()}.
|
||||
* @param source the object on which the event initially occurred or with
|
||||
* which the event is associated (never {@code null})
|
||||
* @see #ApplicationEvent(Object, Clock)
|
||||
*/
|
||||
public ApplicationEvent(Object source) {
|
||||
super(source);
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code ApplicationEvent} with its {@link #getTimestamp() timestamp}
|
||||
* set to the value returned by {@link Clock#millis()} in the provided {@link Clock}.
|
||||
* <p>This constructor is typically used in testing scenarios.
|
||||
* @param source the object on which the event initially occurred or with
|
||||
* which the event is associated (never {@code null})
|
||||
* @param clock a clock which will provide the timestamp
|
||||
* @since 5.3.8
|
||||
* @see #ApplicationEvent(Object)
|
||||
*/
|
||||
public ApplicationEvent(Object source, Clock clock) {
|
||||
super(source);
|
||||
this.timestamp = clock.millis();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the system time in milliseconds when the event occurred.
|
||||
* Return the time in milliseconds when the event occurred.
|
||||
* @see #ApplicationEvent(Object)
|
||||
* @see #ApplicationEvent(Object, Clock)
|
||||
*/
|
||||
public final long getTimestamp() {
|
||||
return this.timestamp;
|
||||
|
||||
+23
-5
@@ -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.
|
||||
@@ -19,13 +19,15 @@ package org.springframework.context.annotation;
|
||||
import org.springframework.beans.factory.parsing.Problem;
|
||||
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a {@link Configuration @Configuration} class method marked with the
|
||||
* {@link Bean @Bean} annotation.
|
||||
* Represents a {@link Configuration @Configuration} class method annotated with
|
||||
* {@link Bean @Bean}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
* @see ConfigurationClass
|
||||
* @see ConfigurationClassParser
|
||||
@@ -33,7 +35,7 @@ import org.springframework.core.type.MethodMetadata;
|
||||
*/
|
||||
final class BeanMethod extends ConfigurationMethod {
|
||||
|
||||
public BeanMethod(MethodMetadata metadata, ConfigurationClass configurationClass) {
|
||||
BeanMethod(MethodMetadata metadata, ConfigurationClass configurationClass) {
|
||||
super(metadata, configurationClass);
|
||||
}
|
||||
|
||||
@@ -52,12 +54,28 @@ final class BeanMethod extends ConfigurationMethod {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return ((this == obj) || ((obj instanceof BeanMethod) &&
|
||||
this.metadata.equals(((BeanMethod) obj).metadata)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.metadata.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BeanMethod: " + this.metadata;
|
||||
}
|
||||
|
||||
private class NonOverridableMethodError extends Problem {
|
||||
|
||||
public NonOverridableMethodError() {
|
||||
NonOverridableMethodError() {
|
||||
super(String.format("@Bean method '%s' must not be private or final; change the method's modifiers to continue",
|
||||
getMetadata().getMethodName()), getResourceLocation());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
-21
@@ -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.
|
||||
@@ -36,7 +36,7 @@ import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Represents a user-defined {@link Configuration @Configuration} class.
|
||||
* Includes a set of {@link Bean} methods, including all such methods
|
||||
* <p>Includes a set of {@link Bean} methods, including all such methods
|
||||
* defined in the ancestry of the class, in a 'flattened-out' manner.
|
||||
*
|
||||
* @author Chris Beams
|
||||
@@ -74,7 +74,7 @@ final class ConfigurationClass {
|
||||
* @param beanName must not be {@code null}
|
||||
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
|
||||
*/
|
||||
public ConfigurationClass(MetadataReader metadataReader, String beanName) {
|
||||
ConfigurationClass(MetadataReader metadataReader, String beanName) {
|
||||
Assert.notNull(beanName, "Bean name must not be null");
|
||||
this.metadata = metadataReader.getAnnotationMetadata();
|
||||
this.resource = metadataReader.getResource();
|
||||
@@ -89,7 +89,7 @@ final class ConfigurationClass {
|
||||
* @param importedBy the configuration class importing this one or {@code null}
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public ConfigurationClass(MetadataReader metadataReader, @Nullable ConfigurationClass importedBy) {
|
||||
ConfigurationClass(MetadataReader metadataReader, @Nullable ConfigurationClass importedBy) {
|
||||
this.metadata = metadataReader.getAnnotationMetadata();
|
||||
this.resource = metadataReader.getResource();
|
||||
this.importedBy.add(importedBy);
|
||||
@@ -101,7 +101,7 @@ final class ConfigurationClass {
|
||||
* @param beanName name of the {@code @Configuration} class bean
|
||||
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
|
||||
*/
|
||||
public ConfigurationClass(Class<?> clazz, String beanName) {
|
||||
ConfigurationClass(Class<?> clazz, String beanName) {
|
||||
Assert.notNull(beanName, "Bean name must not be null");
|
||||
this.metadata = AnnotationMetadata.introspect(clazz);
|
||||
this.resource = new DescriptiveResource(clazz.getName());
|
||||
@@ -116,7 +116,7 @@ final class ConfigurationClass {
|
||||
* @param importedBy the configuration class importing this one (or {@code null})
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public ConfigurationClass(Class<?> clazz, @Nullable ConfigurationClass importedBy) {
|
||||
ConfigurationClass(Class<?> clazz, @Nullable ConfigurationClass importedBy) {
|
||||
this.metadata = AnnotationMetadata.introspect(clazz);
|
||||
this.resource = new DescriptiveResource(clazz.getName());
|
||||
this.importedBy.add(importedBy);
|
||||
@@ -128,7 +128,7 @@ final class ConfigurationClass {
|
||||
* @param beanName name of the {@code @Configuration} class bean
|
||||
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
|
||||
*/
|
||||
public ConfigurationClass(AnnotationMetadata metadata, String beanName) {
|
||||
ConfigurationClass(AnnotationMetadata metadata, String beanName) {
|
||||
Assert.notNull(beanName, "Bean name must not be null");
|
||||
this.metadata = metadata;
|
||||
this.resource = new DescriptiveResource(metadata.getClassName());
|
||||
@@ -136,19 +136,19 @@ final class ConfigurationClass {
|
||||
}
|
||||
|
||||
|
||||
public AnnotationMetadata getMetadata() {
|
||||
AnnotationMetadata getMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
public Resource getResource() {
|
||||
Resource getResource() {
|
||||
return this.resource;
|
||||
}
|
||||
|
||||
public String getSimpleName() {
|
||||
String getSimpleName() {
|
||||
return ClassUtils.getShortName(getMetadata().getClassName());
|
||||
}
|
||||
|
||||
public void setBeanName(String beanName) {
|
||||
void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ final class ConfigurationClass {
|
||||
* Merge the imported-by declarations from the given configuration class into this one.
|
||||
* @since 4.0.5
|
||||
*/
|
||||
public void mergeImportedBy(ConfigurationClass otherConfigClass) {
|
||||
void mergeImportedBy(ConfigurationClass otherConfigClass) {
|
||||
this.importedBy.addAll(otherConfigClass.importedBy);
|
||||
}
|
||||
|
||||
@@ -181,35 +181,35 @@ final class ConfigurationClass {
|
||||
* @since 4.0.5
|
||||
* @see #isImported()
|
||||
*/
|
||||
public Set<ConfigurationClass> getImportedBy() {
|
||||
Set<ConfigurationClass> getImportedBy() {
|
||||
return this.importedBy;
|
||||
}
|
||||
|
||||
public void addBeanMethod(BeanMethod method) {
|
||||
void addBeanMethod(BeanMethod method) {
|
||||
this.beanMethods.add(method);
|
||||
}
|
||||
|
||||
public Set<BeanMethod> getBeanMethods() {
|
||||
Set<BeanMethod> getBeanMethods() {
|
||||
return this.beanMethods;
|
||||
}
|
||||
|
||||
public void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
|
||||
void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
|
||||
this.importedResources.put(importedResource, readerClass);
|
||||
}
|
||||
|
||||
public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
|
||||
void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
|
||||
this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
|
||||
}
|
||||
|
||||
public Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> getImportBeanDefinitionRegistrars() {
|
||||
Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> getImportBeanDefinitionRegistrars() {
|
||||
return this.importBeanDefinitionRegistrars;
|
||||
}
|
||||
|
||||
public Map<String, Class<? extends BeanDefinitionReader>> getImportedResources() {
|
||||
Map<String, Class<? extends BeanDefinitionReader>> getImportedResources() {
|
||||
return this.importedResources;
|
||||
}
|
||||
|
||||
public void validate(ProblemReporter problemReporter) {
|
||||
void validate(ProblemReporter problemReporter) {
|
||||
// A configuration class may not be final (CGLIB limitation) unless it declares proxyBeanMethods=false
|
||||
Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
|
||||
if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) {
|
||||
@@ -244,7 +244,7 @@ final class ConfigurationClass {
|
||||
*/
|
||||
private class FinalConfigurationProblem extends Problem {
|
||||
|
||||
public FinalConfigurationProblem() {
|
||||
FinalConfigurationProblem() {
|
||||
super(String.format("@Configuration class '%s' may not be final. Remove the final modifier to continue.",
|
||||
getSimpleName()), new Location(getResource(), getMetadata()));
|
||||
}
|
||||
|
||||
+2
-11
@@ -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.
|
||||
@@ -51,18 +51,9 @@ abstract class ConfigurationMethod {
|
||||
return new Location(this.configurationClass.getResource(), this.metadata);
|
||||
}
|
||||
|
||||
String getFullyQualifiedMethodName() {
|
||||
return this.metadata.getDeclaringClassName() + "#" + this.metadata.getMethodName();
|
||||
void validate(ProblemReporter problemReporter) {
|
||||
}
|
||||
|
||||
static String getShortMethodName(String fullyQualifiedMethodName) {
|
||||
return fullyQualifiedMethodName.substring(fullyQualifiedMethodName.indexOf('#') + 1);
|
||||
}
|
||||
|
||||
public void validate(ProblemReporter problemReporter) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[%s:name=%s,declaringClass=%s]",
|
||||
|
||||
+2
-2
@@ -396,7 +396,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
||||
* @param message error message to append the HandlerMethod details to
|
||||
*/
|
||||
protected String getDetailedErrorMessage(Object bean, String message) {
|
||||
StringBuilder sb = new StringBuilder(message).append("\n");
|
||||
StringBuilder sb = new StringBuilder(message).append('\n');
|
||||
sb.append("HandlerMethod details: \n");
|
||||
sb.append("Bean [").append(bean.getClass().getName()).append("]\n");
|
||||
sb.append("Method [").append(this.method.toGenericString()).append("]\n");
|
||||
@@ -426,7 +426,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
||||
StringBuilder sb = new StringBuilder(getDetailedErrorMessage(bean, message));
|
||||
sb.append("Resolved arguments: \n");
|
||||
for (int i = 0; i < resolvedArgs.length; i++) {
|
||||
sb.append("[").append(i).append("] ");
|
||||
sb.append('[').append(i).append("] ");
|
||||
if (resolvedArgs[i] == null) {
|
||||
sb.append("[null] \n");
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* @author Sam Brannen
|
||||
* @since 4.2
|
||||
* @see EventListenerMethodProcessor
|
||||
* @see org.springframework.transaction.event.TransactionalEventListener
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -133,7 +134,7 @@ public @interface EventListener {
|
||||
* An optional identifier for the listener, defaulting to the fully-qualified
|
||||
* signature of the declaring method (e.g. "mypackage.MyClass.myMethod()").
|
||||
* @since 5.3.5
|
||||
* @see org.springframework.context.ApplicationListener#getListenerId()
|
||||
* @see SmartApplicationListener#getListenerId()
|
||||
* @see ApplicationEventMulticaster#removeApplicationListeners(Predicate)
|
||||
*/
|
||||
String id() default "";
|
||||
|
||||
@@ -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.
|
||||
@@ -205,12 +205,12 @@ public class LiveBeansView implements LiveBeansViewMBean, ApplicationContextAwar
|
||||
}
|
||||
}
|
||||
result.append("]\n");
|
||||
result.append("}");
|
||||
result.append('}');
|
||||
if (it.hasNext()) {
|
||||
result.append(",\n");
|
||||
}
|
||||
}
|
||||
result.append("]");
|
||||
result.append(']');
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
+18
-17
@@ -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.
|
||||
@@ -57,17 +57,18 @@ public abstract class MessageSourceSupport {
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to always apply the {@code MessageFormat} rules,
|
||||
* parsing even messages without arguments.
|
||||
* <p>Default is "false": Messages without arguments are by default
|
||||
* returned as-is, without parsing them through MessageFormat.
|
||||
* Set this to "true" to enforce MessageFormat for all messages,
|
||||
* expecting all message texts to be written with MessageFormat escaping.
|
||||
* <p>For example, MessageFormat expects a single quote to be escaped
|
||||
* as "''". If your message texts are all written with such escaping,
|
||||
* even when not defining argument placeholders, you need to set this
|
||||
* flag to "true". Else, only message texts with actual arguments
|
||||
* are supposed to be written with MessageFormat escaping.
|
||||
* Set whether to always apply the {@code MessageFormat} rules, parsing even
|
||||
* messages without arguments.
|
||||
* <p>Default is {@code false}: Messages without arguments are by default
|
||||
* returned as-is, without parsing them through {@code MessageFormat}.
|
||||
* Set this to {@code true} to enforce {@code MessageFormat} for all messages,
|
||||
* expecting all message texts to be written with {@code MessageFormat} escaping.
|
||||
* <p>For example, {@code MessageFormat} expects a single quote to be escaped
|
||||
* as two adjacent single quotes ({@code "''"}). If your message texts are all
|
||||
* written with such escaping, even when not defining argument placeholders,
|
||||
* you need to set this flag to {@code true}. Otherwise, only message texts
|
||||
* with actual arguments are supposed to be written with {@code MessageFormat}
|
||||
* escaping.
|
||||
* @see java.text.MessageFormat
|
||||
*/
|
||||
public void setAlwaysUseMessageFormat(boolean alwaysUseMessageFormat) {
|
||||
@@ -75,7 +76,7 @@ public abstract class MessageSourceSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to always apply the MessageFormat rules, parsing even
|
||||
* Return whether to always apply the {@code MessageFormat} rules, parsing even
|
||||
* messages without arguments.
|
||||
*/
|
||||
protected boolean isAlwaysUseMessageFormat() {
|
||||
@@ -150,10 +151,10 @@ public abstract class MessageSourceSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a MessageFormat for the given message and Locale.
|
||||
* @param msg the message to create a MessageFormat for
|
||||
* @param locale the Locale to create a MessageFormat for
|
||||
* @return the MessageFormat instance
|
||||
* Create a {@code MessageFormat} for the given message and Locale.
|
||||
* @param msg the message to create a {@code MessageFormat} for
|
||||
* @param locale the Locale to create a {@code MessageFormat} for
|
||||
* @return the {@code MessageFormat} instance
|
||||
*/
|
||||
protected MessageFormat createMessageFormat(String msg, Locale locale) {
|
||||
return new MessageFormat(msg, locale);
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* <p>Supports formatting by style pattern, ISO date time pattern, or custom format pattern string.
|
||||
* Can be applied to {@link java.util.Date}, {@link java.util.Calendar}, {@link Long} (for
|
||||
* millisecond timestamps) as well as JSR-310 {@code java.time} and Joda-Time value types.
|
||||
* millisecond timestamps) as well as JSR-310 {@code java.time} value types.
|
||||
*
|
||||
* <p>For style-based formatting, set the {@link #style} attribute to the desired style pattern code.
|
||||
* The first character of the code is the date style, and the second character is the time style.
|
||||
|
||||
@@ -219,9 +219,11 @@ public class DateFormatter implements Formatter<Date> {
|
||||
}
|
||||
}
|
||||
if (this.source != null) {
|
||||
throw new ParseException(
|
||||
ParseException parseException = new ParseException(
|
||||
String.format("Unable to parse date time value \"%s\" using configuration from %s", text, this.source),
|
||||
ex.getErrorOffset());
|
||||
parseException.initCause(ex);
|
||||
throw parseException;
|
||||
}
|
||||
// else rethrow original exception
|
||||
throw ex;
|
||||
|
||||
+5
-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.
|
||||
@@ -177,8 +177,8 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
|
||||
* Set up the ExecutorService.
|
||||
*/
|
||||
public void initialize() {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Initializing ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Initializing ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
|
||||
}
|
||||
if (!this.threadNamePrefixSet && this.beanName != null) {
|
||||
setThreadNamePrefix(this.beanName + "-");
|
||||
@@ -214,8 +214,8 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
|
||||
* @see java.util.concurrent.ExecutorService#shutdownNow()
|
||||
*/
|
||||
public void shutdown() {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Shutting down ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Shutting down ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
|
||||
}
|
||||
if (this.executor != null) {
|
||||
if (this.waitForTasksToCompleteOnShutdown) {
|
||||
|
||||
+3
-3
@@ -112,10 +112,10 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
|
||||
*/
|
||||
public void setCorePoolSize(int corePoolSize) {
|
||||
synchronized (this.poolSizeMonitor) {
|
||||
this.corePoolSize = corePoolSize;
|
||||
if (this.threadPoolExecutor != null) {
|
||||
this.threadPoolExecutor.setCorePoolSize(corePoolSize);
|
||||
}
|
||||
this.corePoolSize = corePoolSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,10 +135,10 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
|
||||
*/
|
||||
public void setMaxPoolSize(int maxPoolSize) {
|
||||
synchronized (this.poolSizeMonitor) {
|
||||
this.maxPoolSize = maxPoolSize;
|
||||
if (this.threadPoolExecutor != null) {
|
||||
this.threadPoolExecutor.setMaximumPoolSize(maxPoolSize);
|
||||
}
|
||||
this.maxPoolSize = maxPoolSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,10 +158,10 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
|
||||
*/
|
||||
public void setKeepAliveSeconds(int keepAliveSeconds) {
|
||||
synchronized (this.poolSizeMonitor) {
|
||||
this.keepAliveSeconds = keepAliveSeconds;
|
||||
if (this.threadPoolExecutor != null) {
|
||||
this.threadPoolExecutor.setKeepAliveTime(keepAliveSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
this.keepAliveSeconds = keepAliveSeconds;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+66
-25
@@ -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.
|
||||
@@ -53,6 +53,8 @@ import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
* @since 3.0
|
||||
* @see #setPoolSize
|
||||
* @see #setRemoveOnCancelPolicy
|
||||
* @see #setContinueExistingPeriodicTasksAfterShutdownPolicy
|
||||
* @see #setExecuteExistingDelayedTasksAfterShutdownPolicy
|
||||
* @see #setThreadFactory
|
||||
* @see #setErrorHandler
|
||||
*/
|
||||
@@ -64,6 +66,10 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
|
||||
|
||||
private volatile boolean removeOnCancelPolicy;
|
||||
|
||||
private volatile boolean continueExistingPeriodicTasksAfterShutdownPolicy;
|
||||
|
||||
private volatile boolean executeExistingDelayedTasksAfterShutdownPolicy = true;
|
||||
|
||||
@Nullable
|
||||
private volatile ErrorHandler errorHandler;
|
||||
|
||||
@@ -84,26 +90,54 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
|
||||
*/
|
||||
public void setPoolSize(int poolSize) {
|
||||
Assert.isTrue(poolSize > 0, "'poolSize' must be 1 or higher");
|
||||
this.poolSize = poolSize;
|
||||
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
|
||||
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setCorePoolSize(poolSize);
|
||||
}
|
||||
this.poolSize = poolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the remove-on-cancel mode on {@link ScheduledThreadPoolExecutor}.
|
||||
* <p>Default is {@code false}. If set to {@code true}, the target executor will be
|
||||
* switched into remove-on-cancel mode (if possible, with a soft fallback otherwise).
|
||||
* switched into remove-on-cancel mode (if possible).
|
||||
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
|
||||
* @see ScheduledThreadPoolExecutor#setRemoveOnCancelPolicy
|
||||
*/
|
||||
public void setRemoveOnCancelPolicy(boolean removeOnCancelPolicy) {
|
||||
this.removeOnCancelPolicy = removeOnCancelPolicy;
|
||||
public void setRemoveOnCancelPolicy(boolean flag) {
|
||||
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
|
||||
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(removeOnCancelPolicy);
|
||||
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(flag);
|
||||
}
|
||||
else if (removeOnCancelPolicy && this.scheduledExecutor != null) {
|
||||
logger.debug("Could not apply remove-on-cancel policy - not a ScheduledThreadPoolExecutor");
|
||||
this.removeOnCancelPolicy = flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to continue existing periodic tasks even when this executor has been shutdown.
|
||||
* <p>Default is {@code false}. If set to {@code true}, the target executor will be
|
||||
* switched into continuing periodic tasks (if possible).
|
||||
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
|
||||
* @since 5.3.9
|
||||
* @see ScheduledThreadPoolExecutor#setContinueExistingPeriodicTasksAfterShutdownPolicy
|
||||
*/
|
||||
public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean flag) {
|
||||
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
|
||||
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setContinueExistingPeriodicTasksAfterShutdownPolicy(flag);
|
||||
}
|
||||
this.continueExistingPeriodicTasksAfterShutdownPolicy = flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to execute existing delayed tasks even when this executor has been shutdown.
|
||||
* <p>Default is {@code true}. If set to {@code false}, the target executor will be
|
||||
* switched into dropping remaining tasks (if possible).
|
||||
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
|
||||
* @since 5.3.9
|
||||
* @see ScheduledThreadPoolExecutor#setExecuteExistingDelayedTasksAfterShutdownPolicy
|
||||
*/
|
||||
public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean flag) {
|
||||
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
|
||||
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setExecuteExistingDelayedTasksAfterShutdownPolicy(flag);
|
||||
}
|
||||
this.executeExistingDelayedTasksAfterShutdownPolicy = flag;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,12 +169,16 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
|
||||
|
||||
this.scheduledExecutor = createExecutor(this.poolSize, threadFactory, rejectedExecutionHandler);
|
||||
|
||||
if (this.removeOnCancelPolicy) {
|
||||
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
|
||||
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(true);
|
||||
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
|
||||
ScheduledThreadPoolExecutor scheduledPoolExecutor = (ScheduledThreadPoolExecutor) this.scheduledExecutor;
|
||||
if (this.removeOnCancelPolicy) {
|
||||
scheduledPoolExecutor.setRemoveOnCancelPolicy(true);
|
||||
}
|
||||
else {
|
||||
logger.debug("Could not apply remove-on-cancel policy - not a ScheduledThreadPoolExecutor");
|
||||
if (this.continueExistingPeriodicTasksAfterShutdownPolicy) {
|
||||
scheduledPoolExecutor.setContinueExistingPeriodicTasksAfterShutdownPolicy(true);
|
||||
}
|
||||
if (!this.executeExistingDelayedTasksAfterShutdownPolicy) {
|
||||
scheduledPoolExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,18 +239,6 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
|
||||
return getScheduledThreadPoolExecutor().getPoolSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current setting for the remove-on-cancel mode.
|
||||
* <p>Requires an underlying {@link ScheduledThreadPoolExecutor}.
|
||||
*/
|
||||
public boolean isRemoveOnCancelPolicy() {
|
||||
if (this.scheduledExecutor == null) {
|
||||
// Not initialized yet: return our setting for the time being.
|
||||
return this.removeOnCancelPolicy;
|
||||
}
|
||||
return getScheduledThreadPoolExecutor().getRemoveOnCancelPolicy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of currently active threads.
|
||||
* <p>Requires an underlying {@link ScheduledThreadPoolExecutor}.
|
||||
@@ -227,6 +253,21 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
|
||||
return getScheduledThreadPoolExecutor().getActiveCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current setting for the remove-on-cancel mode.
|
||||
* <p>Requires an underlying {@link ScheduledThreadPoolExecutor}.
|
||||
* @deprecated as of 5.3.9, in favor of direct
|
||||
* {@link #getScheduledThreadPoolExecutor()} access
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isRemoveOnCancelPolicy() {
|
||||
if (this.scheduledExecutor == null) {
|
||||
// Not initialized yet: return our setting for the time being.
|
||||
return this.removeOnCancelPolicy;
|
||||
}
|
||||
return getScheduledThreadPoolExecutor().getRemoveOnCancelPolicy();
|
||||
}
|
||||
|
||||
|
||||
// SchedulingTaskExecutor implementation
|
||||
|
||||
|
||||
+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.
|
||||
@@ -192,6 +192,11 @@ final class BitsCronField extends CronField {
|
||||
while (current != next && count++ < CronExpression.MAX_ATTEMPTS) {
|
||||
temporal = type().elapseUntil(temporal, next);
|
||||
current = type().get(temporal);
|
||||
next = nextSetBit(current);
|
||||
if (next == -1) {
|
||||
temporal = type().rollForward(temporal);
|
||||
next = nextSetBit(0);
|
||||
}
|
||||
}
|
||||
if (count >= CronExpression.MAX_ATTEMPTS) {
|
||||
return null;
|
||||
|
||||
+22
-2
@@ -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.
|
||||
@@ -66,8 +66,9 @@ public final class CronExpression {
|
||||
CronField daysOfWeek,
|
||||
String expression) {
|
||||
|
||||
// reverse order, to make big changes first
|
||||
// to make sure we end up at 0 nanos, we add an extra field
|
||||
this.fields = new CronField[]{CronField.zeroNanos(), seconds, minutes, hours, daysOfMonth, months, daysOfWeek};
|
||||
this.fields = new CronField[]{daysOfWeek, months, daysOfMonth, hours, minutes, seconds, CronField.zeroNanos()};
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@@ -202,6 +203,25 @@ public final class CronExpression {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given string represents a valid cron expression.
|
||||
* @param expression the expression to evaluate
|
||||
* @return {@code true} if the given expression is a valid cron expression
|
||||
* @since 5.3.8
|
||||
*/
|
||||
public static boolean isValidExpression(@Nullable String expression) {
|
||||
if (expression == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
parse(expression);
|
||||
return true;
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static String resolveMacros(String expression) {
|
||||
expression = expression.trim();
|
||||
|
||||
@@ -157,6 +157,11 @@ abstract class CronField {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static <T extends Temporal & Comparable<? super T>> T cast(Temporal temporal) {
|
||||
return (T) temporal;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents the type of cron field, i.e. seconds, minutes, hours,
|
||||
@@ -225,9 +230,7 @@ abstract class CronField {
|
||||
* Elapse the given temporal for the difference between the current
|
||||
* value of this field and the goal value. Typically, the returned
|
||||
* temporal will have the given goal as the current value for this type,
|
||||
* but this is not the case for {@link #DAY_OF_MONTH}. For instance,
|
||||
* if {@code goal} is 31, and {@code temporal} is April 16th,
|
||||
* this method returns May 1st, because April 31st does not exist.
|
||||
* but this is not the case for {@link #DAY_OF_MONTH}.
|
||||
* @param temporal the temporal to elapse
|
||||
* @param goal the goal value
|
||||
* @param <T> the type of temporal
|
||||
@@ -236,16 +239,18 @@ abstract class CronField {
|
||||
*/
|
||||
public <T extends Temporal & Comparable<? super T>> T elapseUntil(T temporal, int goal) {
|
||||
int current = get(temporal);
|
||||
ValueRange range = temporal.range(this.field);
|
||||
if (current < goal) {
|
||||
T result = this.field.getBaseUnit().addTo(temporal, goal - current);
|
||||
current = get(result);
|
||||
if (current > goal) { // can occur due to daylight saving, see gh-26744
|
||||
result = this.field.getBaseUnit().addTo(result, goal - current);
|
||||
if (range.isValidIntValue(goal)) {
|
||||
return cast(temporal.with(this.field, goal));
|
||||
}
|
||||
else {
|
||||
// goal is invalid, eg. 29th Feb, so roll forward
|
||||
long amount = range.getMaximum() - current + 1;
|
||||
return this.field.getBaseUnit().addTo(temporal, amount);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
ValueRange range = temporal.range(this.field);
|
||||
long amount = goal + range.getMaximum() - current + 1 - range.getMinimum();
|
||||
return this.field.getBaseUnit().addTo(temporal, amount);
|
||||
}
|
||||
|
||||
+4
-7
@@ -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.
|
||||
@@ -326,12 +326,6 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends Temporal & Comparable<? super T>> T cast(Temporal temporal) {
|
||||
return (T) temporal;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T extends Temporal & Comparable<? super T>> T nextOrSame(T temporal) {
|
||||
T result = adjust(temporal);
|
||||
@@ -340,6 +334,9 @@ final class QuartzCronField extends CronField {
|
||||
// We ended up before the start, roll forward and try again
|
||||
temporal = this.rollForwardType.rollForward(temporal);
|
||||
result = adjust(temporal);
|
||||
if (result != null) {
|
||||
result = type().reset(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -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.
|
||||
@@ -66,7 +66,8 @@ public class ConcurrentModel extends ConcurrentHashMap<String, Object> implement
|
||||
|
||||
|
||||
@Override
|
||||
public Object put(String key, Object value) {
|
||||
@Nullable
|
||||
public Object put(String key, @Nullable Object value) {
|
||||
if (value != null) {
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.validation.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Utility class for handling validation annotations.
|
||||
* Mainly for internal use within the framework.
|
||||
*
|
||||
* @author Christoph Dreis
|
||||
* @since 5.3.7
|
||||
*/
|
||||
public abstract class ValidationAnnotationUtils {
|
||||
|
||||
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
|
||||
|
||||
/**
|
||||
* Determine any validation hints by the given annotation.
|
||||
* <p>This implementation checks for {@code @javax.validation.Valid},
|
||||
* Spring's {@link org.springframework.validation.annotation.Validated},
|
||||
* and custom annotations whose name starts with "Valid".
|
||||
* @param ann the annotation (potentially a validation annotation)
|
||||
* @return the validation hints to apply (possibly an empty array),
|
||||
* or {@code null} if this annotation does not trigger any validation
|
||||
*/
|
||||
@Nullable
|
||||
public static Object[] determineValidationHints(Annotation ann) {
|
||||
Class<? extends Annotation> annotationType = ann.annotationType();
|
||||
String annotationName = annotationType.getName();
|
||||
if ("javax.validation.Valid".equals(annotationName)) {
|
||||
return EMPTY_OBJECT_ARRAY;
|
||||
}
|
||||
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
|
||||
if (validatedAnn != null) {
|
||||
Object hints = validatedAnn.value();
|
||||
return convertValidationHints(hints);
|
||||
}
|
||||
if (annotationType.getSimpleName().startsWith("Valid")) {
|
||||
Object hints = AnnotationUtils.getValue(ann);
|
||||
return convertValidationHints(hints);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Object[] convertValidationHints(@Nullable Object hints) {
|
||||
if (hints == null) {
|
||||
return EMPTY_OBJECT_ARRAY;
|
||||
}
|
||||
return (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints});
|
||||
}
|
||||
|
||||
}
|
||||
+6
-3
@@ -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.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.validation.support;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.ui.ConcurrentModel;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
||||
@@ -36,17 +37,19 @@ import org.springframework.validation.BindingResult;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
* @see BindingResult
|
||||
* @see BindingAwareModelMap
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class BindingAwareConcurrentModel extends ConcurrentModel {
|
||||
|
||||
@Override
|
||||
public Object put(String key, Object value) {
|
||||
@Nullable
|
||||
public Object put(String key, @Nullable Object value) {
|
||||
removeBindingResultIfNecessary(key, value);
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
private void removeBindingResultIfNecessary(String key, Object value) {
|
||||
private void removeBindingResultIfNecessary(String key, @Nullable Object value) {
|
||||
if (!key.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
|
||||
String resultKey = BindingResult.MODEL_KEY_PREFIX + key;
|
||||
BindingResult result = (BindingResult) get(resultKey);
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.validation.support;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
||||
@@ -39,7 +40,7 @@ import org.springframework.validation.BindingResult;
|
||||
public class BindingAwareModelMap extends ExtendedModelMap {
|
||||
|
||||
@Override
|
||||
public Object put(String key, Object value) {
|
||||
public Object put(String key, @Nullable Object value) {
|
||||
removeBindingResultIfNecessary(key, value);
|
||||
return super.put(key, value);
|
||||
}
|
||||
@@ -50,7 +51,7 @@ public class BindingAwareModelMap extends ExtendedModelMap {
|
||||
super.putAll(map);
|
||||
}
|
||||
|
||||
private void removeBindingResultIfNecessary(Object key, Object value) {
|
||||
private void removeBindingResultIfNecessary(Object key, @Nullable Object value) {
|
||||
if (key instanceof String) {
|
||||
String attributeName = (String) key;
|
||||
if (!attributeName.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
|
||||
|
||||
+2
-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.
|
||||
@@ -1110,7 +1110,7 @@ open class BeanDefinitionDsl internal constructor (private val init: BeanDefinit
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an provider for the specified bean, allowing for lazy on-demand retrieval
|
||||
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
|
||||
* of instances, including availability and uniqueness options.
|
||||
* @see org.springframework.beans.factory.BeanFactory.getBeanProvider
|
||||
*/
|
||||
|
||||
+21
-5
@@ -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.
|
||||
@@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.aop.support.DefaultIntroductionAdvisor;
|
||||
import org.springframework.aop.target.SingletonTargetSource;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
@@ -219,7 +220,7 @@ public class AutoProxyCreatorTests {
|
||||
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.add("proxyFactoryBean", "false");
|
||||
sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class, pvs);
|
||||
sac.registerSingleton("testAutoProxyCreator", IntroductionTestAutoProxyCreator.class, pvs);
|
||||
|
||||
sac.registerSingleton("noInterfaces", NoInterfaces.class);
|
||||
sac.registerSingleton("containerCallbackInterfacesOnly", ContainerCallbackInterfacesOnly.class);
|
||||
@@ -248,9 +249,9 @@ public class AutoProxyCreatorTests {
|
||||
singletonNoInterceptor.getName();
|
||||
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(0);
|
||||
singletonToBeProxied.getAge();
|
||||
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(1);
|
||||
prototypeToBeProxied.getSpouse();
|
||||
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(2);
|
||||
prototypeToBeProxied.getSpouse();
|
||||
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -404,7 +405,7 @@ public class AutoProxyCreatorTests {
|
||||
else if (name.endsWith("ToBeProxied")) {
|
||||
boolean isFactoryBean = FactoryBean.class.isAssignableFrom(beanClass);
|
||||
if ((this.proxyFactoryBean && isFactoryBean) || (this.proxyObject && !isFactoryBean)) {
|
||||
return new Object[] {this.testInterceptor};
|
||||
return getAdvicesAndAdvisors();
|
||||
}
|
||||
else {
|
||||
return DO_NOT_PROXY;
|
||||
@@ -414,6 +415,10 @@ public class AutoProxyCreatorTests {
|
||||
return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
|
||||
}
|
||||
}
|
||||
|
||||
protected Object[] getAdvicesAndAdvisors() {
|
||||
return new Object[] {this.testInterceptor};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -426,6 +431,17 @@ public class AutoProxyCreatorTests {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class IntroductionTestAutoProxyCreator extends TestAutoProxyCreator {
|
||||
|
||||
protected Object[] getAdvicesAndAdvisors() {
|
||||
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(this.testInterceptor);
|
||||
advisor.addInterface(Serializable.class);
|
||||
return new Object[] {this.testInterceptor, advisor};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interceptor that counts the number of non-finalize method calls.
|
||||
*/
|
||||
|
||||
+3
-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.
|
||||
@@ -47,8 +47,9 @@ import static org.springframework.util.ClassUtils.convertClassNameToResourcePath
|
||||
public class QualifierAnnotationTests {
|
||||
|
||||
private static final String CLASSNAME = QualifierAnnotationTests.class.getName();
|
||||
|
||||
private static final String CONFIG_LOCATION =
|
||||
format("classpath:%s-context.xml", convertClassNameToResourcePath(CLASSNAME));
|
||||
format("classpath:%s-context.xml", convertClassNameToResourcePath(CLASSNAME));
|
||||
|
||||
|
||||
@Test
|
||||
|
||||
+1
-1
@@ -146,7 +146,7 @@ class XmlBeanFactoryTests {
|
||||
assertThat(emmasJenks != georgiasJenks).as("Emma and georgia think they have a different boyfriend").isTrue();
|
||||
assertThat(emmasJenks.getName().equals("Andrew")).as("Emmas jenks has right name").isTrue();
|
||||
assertThat(emmasJenks != xbf.getBean("jenks")).as("Emmas doesn't equal new ref").isTrue();
|
||||
assertThat(emmasJenks.getName().equals("Andrew")).as("Georgias jenks has right name").isTrue();
|
||||
assertThat(georgiasJenks.getName().equals("Andrew")).as("Georgias jenks has right name").isTrue();
|
||||
assertThat(emmasJenks.equals(georgiasJenks)).as("They are object equal").isTrue();
|
||||
assertThat(emmasJenks.equals(xbf.getBean("jenks"))).as("They object equal direct ref").isTrue();
|
||||
}
|
||||
|
||||
+5
-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.
|
||||
@@ -19,6 +19,8 @@ package org.springframework.cache.config;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
@@ -87,6 +89,7 @@ public class EnableCachingTests extends AbstractCacheAnnotationTests {
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertThat(ex.getMessage().contains("no unique bean of type CacheManager")).isTrue();
|
||||
assertThat(ex).hasCauseInstanceOf(NoUniqueBeanDefinitionException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +124,7 @@ public class EnableCachingTests extends AbstractCacheAnnotationTests {
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertThat(ex.getMessage().contains("no bean of type CacheManager")).isTrue();
|
||||
assertThat(ex).hasCauseInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -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.
|
||||
@@ -29,7 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests regarding overloading and overriding of bean methods.
|
||||
* Related to SPR-6618.
|
||||
* <p>Related to SPR-6618.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
@@ -41,7 +41,7 @@ public class BeanMethodPolymorphismTests {
|
||||
@Test
|
||||
public void beanMethodDetectedOnSuperClass() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
|
||||
ctx.getBean("testBean", TestBean.class);
|
||||
assertThat(ctx.getBean("testBean", TestBean.class)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.parsing.FailFastProblemReporter;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link ConfigurationClassParser}, {@link ConfigurationClass},
|
||||
* and {@link BeanMethod}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 5.3.9
|
||||
*/
|
||||
class ConfigurationClassAndBeanMethodTests {
|
||||
|
||||
@Test
|
||||
void verifyEquals() throws Exception {
|
||||
ConfigurationClass configurationClass1 = newConfigurationClass(Config1.class);
|
||||
ConfigurationClass configurationClass2 = newConfigurationClass(Config1.class);
|
||||
ConfigurationClass configurationClass3 = newConfigurationClass(Config2.class);
|
||||
|
||||
assertThat(configurationClass1.equals(null)).isFalse();
|
||||
assertThat(configurationClass1).isNotSameAs(configurationClass2);
|
||||
|
||||
assertThat(configurationClass1.equals(configurationClass1)).isTrue();
|
||||
assertThat(configurationClass2.equals(configurationClass2)).isTrue();
|
||||
assertThat(configurationClass1.equals(configurationClass2)).isTrue();
|
||||
assertThat(configurationClass2.equals(configurationClass1)).isTrue();
|
||||
|
||||
assertThat(configurationClass1.equals(configurationClass3)).isFalse();
|
||||
assertThat(configurationClass3.equals(configurationClass2)).isFalse();
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
List<BeanMethod> beanMethods1 = getBeanMethods(configurationClass1);
|
||||
BeanMethod beanMethod_1_0 = beanMethods1.get(0);
|
||||
BeanMethod beanMethod_1_1 = beanMethods1.get(1);
|
||||
BeanMethod beanMethod_1_2 = beanMethods1.get(2);
|
||||
|
||||
List<BeanMethod> beanMethods2 = getBeanMethods(configurationClass2);
|
||||
BeanMethod beanMethod_2_0 = beanMethods2.get(0);
|
||||
BeanMethod beanMethod_2_1 = beanMethods2.get(1);
|
||||
BeanMethod beanMethod_2_2 = beanMethods2.get(2);
|
||||
|
||||
List<BeanMethod> beanMethods3 = getBeanMethods(configurationClass3);
|
||||
BeanMethod beanMethod_3_0 = beanMethods3.get(0);
|
||||
BeanMethod beanMethod_3_1 = beanMethods3.get(1);
|
||||
BeanMethod beanMethod_3_2 = beanMethods3.get(2);
|
||||
|
||||
assertThat(beanMethod_1_0.equals(null)).isFalse();
|
||||
assertThat(beanMethod_1_0).isNotSameAs(beanMethod_2_0);
|
||||
|
||||
assertThat(beanMethod_1_0.equals(beanMethod_1_0)).isTrue();
|
||||
assertThat(beanMethod_1_0.equals(beanMethod_2_0)).isTrue();
|
||||
assertThat(beanMethod_1_1.equals(beanMethod_2_1)).isTrue();
|
||||
assertThat(beanMethod_1_2.equals(beanMethod_2_2)).isTrue();
|
||||
|
||||
assertThat(beanMethod_1_0.getMetadata().getMethodName()).isEqualTo(beanMethod_3_0.getMetadata().getMethodName());
|
||||
assertThat(beanMethod_1_0.equals(beanMethod_3_0)).isFalse();
|
||||
assertThat(beanMethod_1_1.equals(beanMethod_3_1)).isFalse();
|
||||
assertThat(beanMethod_1_2.equals(beanMethod_3_2)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyHashCode() throws Exception {
|
||||
ConfigurationClass configurationClass1 = newConfigurationClass(Config1.class);
|
||||
ConfigurationClass configurationClass2 = newConfigurationClass(Config1.class);
|
||||
ConfigurationClass configurationClass3 = newConfigurationClass(Config2.class);
|
||||
|
||||
assertThat(configurationClass1).hasSameHashCodeAs(configurationClass2);
|
||||
assertThat(configurationClass1).doesNotHaveSameHashCodeAs(configurationClass3);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
List<BeanMethod> beanMethods1 = getBeanMethods(configurationClass1);
|
||||
BeanMethod beanMethod_1_0 = beanMethods1.get(0);
|
||||
BeanMethod beanMethod_1_1 = beanMethods1.get(1);
|
||||
BeanMethod beanMethod_1_2 = beanMethods1.get(2);
|
||||
|
||||
List<BeanMethod> beanMethods2 = getBeanMethods(configurationClass2);
|
||||
BeanMethod beanMethod_2_0 = beanMethods2.get(0);
|
||||
BeanMethod beanMethod_2_1 = beanMethods2.get(1);
|
||||
BeanMethod beanMethod_2_2 = beanMethods2.get(2);
|
||||
|
||||
List<BeanMethod> beanMethods3 = getBeanMethods(configurationClass3);
|
||||
BeanMethod beanMethod_3_0 = beanMethods3.get(0);
|
||||
BeanMethod beanMethod_3_1 = beanMethods3.get(1);
|
||||
BeanMethod beanMethod_3_2 = beanMethods3.get(2);
|
||||
|
||||
assertThat(beanMethod_1_0).hasSameHashCodeAs(beanMethod_2_0);
|
||||
assertThat(beanMethod_1_1).hasSameHashCodeAs(beanMethod_2_1);
|
||||
assertThat(beanMethod_1_2).hasSameHashCodeAs(beanMethod_2_2);
|
||||
|
||||
assertThat(beanMethod_1_0).doesNotHaveSameHashCodeAs(beanMethod_3_0);
|
||||
assertThat(beanMethod_1_1).doesNotHaveSameHashCodeAs(beanMethod_3_1);
|
||||
assertThat(beanMethod_1_2).doesNotHaveSameHashCodeAs(beanMethod_3_2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyToString() throws Exception {
|
||||
ConfigurationClass configurationClass = newConfigurationClass(Config1.class);
|
||||
assertThat(configurationClass.toString())
|
||||
.startsWith("ConfigurationClass: beanName 'Config1', class path resource");
|
||||
|
||||
List<BeanMethod> beanMethods = getBeanMethods(configurationClass);
|
||||
String prefix = "BeanMethod: " + Config1.class.getName();
|
||||
assertThat(beanMethods.get(0).toString()).isEqualTo(prefix + ".bean0()");
|
||||
assertThat(beanMethods.get(1).toString()).isEqualTo(prefix + ".bean1(java.lang.String)");
|
||||
assertThat(beanMethods.get(2).toString()).isEqualTo(prefix + ".bean2(java.lang.String,java.lang.Integer)");
|
||||
}
|
||||
|
||||
|
||||
private static ConfigurationClass newConfigurationClass(Class<?> clazz) throws Exception {
|
||||
ConfigurationClassParser parser = newParser();
|
||||
parser.parse(clazz.getName(), clazz.getSimpleName());
|
||||
assertThat(parser.getConfigurationClasses()).hasSize(1);
|
||||
return parser.getConfigurationClasses().iterator().next();
|
||||
}
|
||||
|
||||
private static ConfigurationClassParser newParser() {
|
||||
return new ConfigurationClassParser(
|
||||
new CachingMetadataReaderFactory(),
|
||||
new FailFastProblemReporter(),
|
||||
new StandardEnvironment(),
|
||||
new DefaultResourceLoader(),
|
||||
new AnnotationBeanNameGenerator(),
|
||||
new DefaultListableBeanFactory());
|
||||
}
|
||||
|
||||
private static List<BeanMethod> getBeanMethods(ConfigurationClass configurationClass) {
|
||||
List<BeanMethod> beanMethods = configurationClass.getBeanMethods().stream()
|
||||
.sorted(Comparator.comparing(beanMethod -> beanMethod.getMetadata().getMethodName()))
|
||||
.collect(Collectors.toList());
|
||||
assertThat(beanMethods).hasSize(3);
|
||||
return beanMethods;
|
||||
}
|
||||
|
||||
static class Config1 {
|
||||
|
||||
@Bean
|
||||
String bean0() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Bean
|
||||
String bean1(String text) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Bean
|
||||
String bean2(String text, Integer num) {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Config2 {
|
||||
|
||||
@Bean
|
||||
String bean0() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Bean
|
||||
String bean1(String text) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Bean
|
||||
String bean2(String text, Integer num) {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+37
-1
@@ -119,6 +119,39 @@ public class DateFormattingTests {
|
||||
assertThat(binder.getBindingResult().getFieldValue("styleDate")).isEqualTo("10/31/09");
|
||||
}
|
||||
|
||||
@Test
|
||||
void styleDateWithInvalidFormat() {
|
||||
String propertyName = "styleDate";
|
||||
String propertyValue = "99/01/01";
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add(propertyName, propertyValue);
|
||||
binder.bind(propertyValues);
|
||||
BindingResult bindingResult = binder.getBindingResult();
|
||||
assertThat(bindingResult.getErrorCount()).isEqualTo(1);
|
||||
FieldError fieldError = bindingResult.getFieldError(propertyName);
|
||||
TypeMismatchException exception = fieldError.unwrap(TypeMismatchException.class);
|
||||
assertThat(exception)
|
||||
.hasMessageContaining("for property 'styleDate'")
|
||||
.hasCauseInstanceOf(ConversionFailedException.class).getCause()
|
||||
.hasMessageContaining("for value '99/01/01'")
|
||||
.hasCauseInstanceOf(IllegalArgumentException.class).getCause()
|
||||
.hasMessageContaining("Parse attempt failed for value [99/01/01]")
|
||||
.hasCauseInstanceOf(ParseException.class).getCause()
|
||||
// Unable to parse date time value "99/01/01" using configuration from
|
||||
// @org.springframework.format.annotation.DateTimeFormat(pattern=, style=S-, iso=NONE, fallbackPatterns=[])
|
||||
// We do not check "fallbackPatterns=[]", since the array representation in the toString()
|
||||
// implementation for annotations changed from [] to {} in Java 9. In addition, strings
|
||||
// are enclosed in double quotes beginning with Java 9. Thus, we cannot check directly
|
||||
// for the presence of "style=S-".
|
||||
.hasMessageContainingAll(
|
||||
"Unable to parse date time value \"99/01/01\" using configuration from",
|
||||
"@org.springframework.format.annotation.DateTimeFormat",
|
||||
"style=", "S-", "iso=NONE")
|
||||
.hasCauseInstanceOf(ParseException.class).getCause()
|
||||
.hasMessageStartingWith("Unparseable date: \"99/01/01\"")
|
||||
.hasNoCause();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindDateArray() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
@@ -330,7 +363,10 @@ public class DateFormattingTests {
|
||||
.hasMessageContainingAll(
|
||||
"Unable to parse date time value \"210302\" using configuration from",
|
||||
"@org.springframework.format.annotation.DateTimeFormat",
|
||||
"yyyy-MM-dd", "M/d/yy", "yyyyMMdd", "yyyy.MM.dd");
|
||||
"yyyy-MM-dd", "M/d/yy", "yyyyMMdd", "yyyy.MM.dd")
|
||||
.hasCauseInstanceOf(ParseException.class).getCause()
|
||||
.hasMessageStartingWith("Unparseable date: \"210302\"")
|
||||
.hasNoCause();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -339,10 +339,11 @@ class DateTimeFormattingTests {
|
||||
.hasCauseInstanceOf(DateTimeParseException.class).getCause()
|
||||
// Unable to parse date time value "2009-31-10" using configuration from
|
||||
// @org.springframework.format.annotation.DateTimeFormat(pattern=, style=SS, iso=DATE, fallbackPatterns=[])
|
||||
// We do not check "fallbackPatterns=[]", since the array representation in the toString()
|
||||
// implementation for annotations changed from [] to {} in Java 9.
|
||||
.hasMessageContainingAll(
|
||||
"Unable to parse date time value \"2009-31-10\" using configuration from",
|
||||
"@org.springframework.format.annotation.DateTimeFormat",
|
||||
"iso=DATE", "fallbackPatterns=[]")
|
||||
"@org.springframework.format.annotation.DateTimeFormat", "iso=DATE")
|
||||
.hasCauseInstanceOf(DateTimeParseException.class).getCause()
|
||||
.hasMessageStartingWith("Text '2009-31-10'")
|
||||
.hasCauseInstanceOf(DateTimeException.class).getCause()
|
||||
|
||||
+81
-2
@@ -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.
|
||||
@@ -16,21 +16,100 @@
|
||||
|
||||
package org.springframework.scheduling.concurrent;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @since 5.0.5
|
||||
*/
|
||||
class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
|
||||
|
||||
private final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
|
||||
|
||||
@Override
|
||||
protected AsyncListenableTaskExecutor buildExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setThreadNamePrefix(this.threadNamePrefix);
|
||||
executor.setMaxPoolSize(1);
|
||||
executor.afterPropertiesSet();
|
||||
return executor;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void modifyCorePoolSizeWhileRunning() {
|
||||
assertThat(executor.getCorePoolSize()).isEqualTo(1);
|
||||
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(1);
|
||||
|
||||
executor.setCorePoolSize(0);
|
||||
|
||||
assertThat(executor.getCorePoolSize()).isEqualTo(0);
|
||||
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void modifyCorePoolSizeWithInvalidValueWhileRunning() {
|
||||
assertThat(executor.getCorePoolSize()).isEqualTo(1);
|
||||
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(1);
|
||||
|
||||
assertThatThrownBy(() -> executor.setCorePoolSize(-1))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
|
||||
assertThat(executor.getCorePoolSize()).isEqualTo(1);
|
||||
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void modifyMaxPoolSizeWhileRunning() {
|
||||
assertThat(executor.getMaxPoolSize()).isEqualTo(1);
|
||||
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(1);
|
||||
|
||||
executor.setMaxPoolSize(5);
|
||||
|
||||
assertThat(executor.getMaxPoolSize()).isEqualTo(5);
|
||||
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
void modifyMaxPoolSizeWithInvalidValueWhileRunning() {
|
||||
assertThat(executor.getMaxPoolSize()).isEqualTo(1);
|
||||
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(1);
|
||||
|
||||
assertThatThrownBy(() -> executor.setMaxPoolSize(0))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
|
||||
assertThat(executor.getMaxPoolSize()).isEqualTo(1);
|
||||
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void modifyKeepAliveSecondsWhileRunning() {
|
||||
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
|
||||
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
|
||||
|
||||
executor.setKeepAliveSeconds(10);
|
||||
|
||||
assertThat(executor.getKeepAliveSeconds()).isEqualTo(10);
|
||||
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
void modifyKeepAliveSecondsWithInvalidValueWhileRunning() {
|
||||
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
|
||||
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
|
||||
|
||||
assertThatThrownBy(() -> executor.setKeepAliveSeconds(-10))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
|
||||
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
|
||||
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+56
@@ -51,6 +51,16 @@ class CronExpressionTests {
|
||||
}
|
||||
};
|
||||
|
||||
@Test
|
||||
public void isValidExpression() {
|
||||
assertThat(CronExpression.isValidExpression(null)).isFalse();
|
||||
assertThat(CronExpression.isValidExpression("")).isFalse();
|
||||
assertThat(CronExpression.isValidExpression("*")).isFalse();
|
||||
assertThat(CronExpression.isValidExpression("* * * * *")).isFalse();
|
||||
assertThat(CronExpression.isValidExpression("* * * * * * *")).isFalse();
|
||||
|
||||
assertThat(CronExpression.isValidExpression("* * * * * *")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchAll() {
|
||||
@@ -497,6 +507,29 @@ class CronExpressionTests {
|
||||
assertThat(actual.getDayOfMonth()).isEqualTo(13);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void everyTenDays() {
|
||||
CronExpression cronExpression = CronExpression.parse("0 15 12 */10 1-8 5");
|
||||
|
||||
LocalDateTime last = LocalDateTime.parse("2021-04-30T12:14:59");
|
||||
LocalDateTime expected = LocalDateTime.parse("2021-05-21T12:15");
|
||||
LocalDateTime actual = cronExpression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
expected = LocalDateTime.parse("2021-06-11T12:15");
|
||||
actual = cronExpression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
last = actual;
|
||||
expected = LocalDateTime.parse("2022-01-21T12:15");
|
||||
actual = cronExpression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void yearly() {
|
||||
CronExpression expression = CronExpression.parse("@yearly");
|
||||
@@ -1276,8 +1309,31 @@ class CronExpressionTests {
|
||||
actual = cronExpression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
cronExpression = CronExpression.parse("0 10 2 * * *");
|
||||
|
||||
last = ZonedDateTime.parse("2013-03-31T01:09:00+01:00[Europe/Amsterdam]");
|
||||
expected = ZonedDateTime.parse("2013-04-01T02:10:00+02:00[Europe/Amsterdam]");
|
||||
actual = cronExpression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void various() {
|
||||
CronExpression cronExpression = CronExpression.parse("3-57 13-28 17,18 1,15 3-12 6#1");
|
||||
LocalDateTime last = LocalDateTime.of(2022, 9, 15, 17, 44, 11);
|
||||
LocalDateTime expected = LocalDateTime.of(2022, 10, 1, 17, 13, 3);
|
||||
LocalDateTime actual = cronExpression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
|
||||
cronExpression = CronExpression.parse("*/28 56 22 */6 * *");
|
||||
last = LocalDateTime.of(2022, 2, 27, 8, 0, 42);
|
||||
expected = LocalDateTime.of(2022, 3, 1, 22, 56, 0);
|
||||
actual = cronExpression.next(last);
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+83
-71
@@ -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.
|
||||
@@ -57,7 +57,7 @@ class CronTriggerTests {
|
||||
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMatchAll(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void matchAll(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("* * * * * *", timeZone);
|
||||
@@ -66,7 +66,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMatchLastSecond(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void matchLastSecond(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("* * * * * *", timeZone);
|
||||
@@ -76,7 +76,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMatchSpecificSecond(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void matchSpecificSecond(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("10 * * * * *", timeZone);
|
||||
@@ -86,7 +86,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementSecondByOne(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementSecondByOne(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("11 * * * * *", timeZone);
|
||||
@@ -98,7 +98,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementSecondWithPreviousExecutionTooEarly(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementSecondWithPreviousExecutionTooEarly(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("11 * * * * *", timeZone);
|
||||
@@ -111,7 +111,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementSecondAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementSecondAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("10 * * * * *", timeZone);
|
||||
@@ -123,7 +123,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testSecondRange(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void secondRange(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("10-15 * * * * *", timeZone);
|
||||
@@ -134,7 +134,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementMinute(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementMinute(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 * * * * *", timeZone);
|
||||
@@ -152,7 +152,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementMinuteByOne(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementMinuteByOne(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 11 * * * *", timeZone);
|
||||
@@ -164,7 +164,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementMinuteAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementMinuteAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 10 * * * *", timeZone);
|
||||
@@ -177,7 +177,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementHour(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementHour(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 0 * * * *", timeZone);
|
||||
@@ -198,7 +198,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementHourAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementHourAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 0 * * * *", timeZone);
|
||||
@@ -220,7 +220,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementDayOfMonth(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementDayOfMonth(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 0 0 * * *", timeZone);
|
||||
@@ -236,13 +236,13 @@ class CronTriggerTests {
|
||||
assertThat(this.calendar.get(Calendar.DAY_OF_MONTH)).isEqualTo(2);
|
||||
this.calendar.add(Calendar.DAY_OF_MONTH, 1);
|
||||
TriggerContext context2 = getTriggerContext(localDate);
|
||||
Object actual = localDate = trigger.nextExecutionTime(context2);
|
||||
Object actual = trigger.nextExecutionTime(context2);
|
||||
assertThat(actual).isEqualTo(this.calendar.getTime());
|
||||
assertThat(this.calendar.get(Calendar.DAY_OF_MONTH)).isEqualTo(3);
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementDayOfMonthByOne(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementDayOfMonthByOne(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("* * * 10 * *", timeZone);
|
||||
@@ -257,7 +257,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementDayOfMonthAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementDayOfMonthAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("* * * 10 * *", timeZone);
|
||||
@@ -273,7 +273,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testDailyTriggerInShortMonth(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void dailyTriggerInShortMonth(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 0 0 * * *", timeZone);
|
||||
@@ -294,7 +294,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testDailyTriggerInLongMonth(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void dailyTriggerInLongMonth(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 0 0 * * *", timeZone);
|
||||
@@ -315,7 +315,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testDailyTriggerOnDaylightSavingBoundary(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void dailyTriggerOnDaylightSavingBoundary(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 0 0 * * *", timeZone);
|
||||
@@ -336,7 +336,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementMonth(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementMonth(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 0 0 1 * *", timeZone);
|
||||
@@ -357,7 +357,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementMonthAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementMonthAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 0 0 1 * *", timeZone);
|
||||
@@ -380,7 +380,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMonthlyTriggerInLongMonth(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void monthlyTriggerInLongMonth(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 0 0 31 * *", timeZone);
|
||||
@@ -396,7 +396,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMonthlyTriggerInShortMonth(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void monthlyTriggerInShortMonth(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 0 0 1 * *", timeZone);
|
||||
@@ -413,7 +413,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementDayOfWeekByOne(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementDayOfWeekByOne(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("* * * * * 2", timeZone);
|
||||
@@ -429,7 +429,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testIncrementDayOfWeekAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void incrementDayOfWeekAndRollover(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("* * * * * 2", timeZone);
|
||||
@@ -445,7 +445,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testSpecificMinuteSecond(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void specificMinuteSecond(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("55 5 * * * *", timeZone);
|
||||
@@ -459,12 +459,12 @@ class CronTriggerTests {
|
||||
assertThat(actual1).isEqualTo(this.calendar.getTime());
|
||||
this.calendar.add(Calendar.HOUR, 1);
|
||||
TriggerContext context2 = getTriggerContext(localDate);
|
||||
Object actual = localDate = trigger.nextExecutionTime(context2);
|
||||
Object actual = trigger.nextExecutionTime(context2);
|
||||
assertThat(actual).isEqualTo(this.calendar.getTime());
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testSpecificHourSecond(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void specificHourSecond(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("55 * 10 * * *", timeZone);
|
||||
@@ -479,12 +479,12 @@ class CronTriggerTests {
|
||||
assertThat(actual1).isEqualTo(this.calendar.getTime());
|
||||
this.calendar.add(Calendar.MINUTE, 1);
|
||||
TriggerContext context2 = getTriggerContext(localDate);
|
||||
Object actual = localDate = trigger.nextExecutionTime(context2);
|
||||
Object actual = trigger.nextExecutionTime(context2);
|
||||
assertThat(actual).isEqualTo(this.calendar.getTime());
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testSpecificMinuteHour(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void specificMinuteHour(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("* 5 10 * * *", timeZone);
|
||||
@@ -500,12 +500,12 @@ class CronTriggerTests {
|
||||
// next trigger is in one second because second is wildcard
|
||||
this.calendar.add(Calendar.SECOND, 1);
|
||||
TriggerContext context2 = getTriggerContext(localDate);
|
||||
Object actual = localDate = trigger.nextExecutionTime(context2);
|
||||
Object actual = trigger.nextExecutionTime(context2);
|
||||
assertThat(actual).isEqualTo(this.calendar.getTime());
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testSpecificDayOfMonthSecond(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void specificDayOfMonthSecond(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("55 * * 3 * *", timeZone);
|
||||
@@ -521,12 +521,12 @@ class CronTriggerTests {
|
||||
assertThat(actual1).isEqualTo(this.calendar.getTime());
|
||||
this.calendar.add(Calendar.MINUTE, 1);
|
||||
TriggerContext context2 = getTriggerContext(localDate);
|
||||
Object actual = localDate = trigger.nextExecutionTime(context2);
|
||||
Object actual = trigger.nextExecutionTime(context2);
|
||||
assertThat(actual).isEqualTo(this.calendar.getTime());
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testSpecificDate(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void specificDate(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("* * * 3 11 *", timeZone);
|
||||
@@ -543,12 +543,12 @@ class CronTriggerTests {
|
||||
assertThat(actual1).isEqualTo(this.calendar.getTime());
|
||||
this.calendar.add(Calendar.SECOND, 1);
|
||||
TriggerContext context2 = getTriggerContext(localDate);
|
||||
Object actual = localDate = trigger.nextExecutionTime(context2);
|
||||
Object actual = trigger.nextExecutionTime(context2);
|
||||
assertThat(actual).isEqualTo(this.calendar.getTime());
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testNonExistentSpecificDate(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void nonExistentSpecificDate(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
// TODO: maybe try and detect this as a special case in parser?
|
||||
@@ -561,7 +561,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testLeapYearSpecificDate(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void leapYearSpecificDate(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 0 0 29 2 *", timeZone);
|
||||
@@ -579,12 +579,12 @@ class CronTriggerTests {
|
||||
assertThat(actual1).isEqualTo(this.calendar.getTime());
|
||||
this.calendar.add(Calendar.YEAR, 4);
|
||||
TriggerContext context2 = getTriggerContext(localDate);
|
||||
Object actual = localDate = trigger.nextExecutionTime(context2);
|
||||
Object actual = trigger.nextExecutionTime(context2);
|
||||
assertThat(actual).isEqualTo(this.calendar.getTime());
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testWeekDaySequence(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void weekDaySequence(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 0 7 ? * MON-FRI", timeZone);
|
||||
@@ -607,12 +607,12 @@ class CronTriggerTests {
|
||||
assertThat(actual1).isEqualTo(this.calendar.getTime());
|
||||
this.calendar.add(Calendar.DAY_OF_MONTH, 1);
|
||||
TriggerContext context3 = getTriggerContext(localDate);
|
||||
Object actual = localDate = trigger.nextExecutionTime(context3);
|
||||
Object actual = trigger.nextExecutionTime(context3);
|
||||
assertThat(actual).isEqualTo(this.calendar.getTime());
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testDayOfWeekIndifferent(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void dayOfWeekIndifferent(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger1 = new CronTrigger("* * * 2 * *", timeZone);
|
||||
@@ -621,7 +621,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testSecondIncrementer(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void secondIncrementer(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger1 = new CronTrigger("57,59 * * * * *", timeZone);
|
||||
@@ -630,7 +630,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testSecondIncrementerWithRange(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void secondIncrementerWithRange(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger1 = new CronTrigger("1,3,5 * * * * *", timeZone);
|
||||
@@ -639,7 +639,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testHourIncrementer(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void hourIncrementer(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger1 = new CronTrigger("* * 4,8,12,16,20 * * *", timeZone);
|
||||
@@ -648,7 +648,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testDayNames(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void dayNames(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger1 = new CronTrigger("* * * * * 0-6", timeZone);
|
||||
@@ -657,7 +657,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testSundayIsZero(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void sundayIsZero(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger1 = new CronTrigger("* * * * * 0", timeZone);
|
||||
@@ -666,7 +666,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testSundaySynonym(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void sundaySynonym(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger1 = new CronTrigger("* * * * * 0", timeZone);
|
||||
@@ -675,7 +675,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMonthNames(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void monthNames(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger1 = new CronTrigger("* * * * 1-12 *", timeZone);
|
||||
@@ -684,7 +684,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMonthNamesMixedCase(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void monthNamesMixedCase(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger1 = new CronTrigger("* * * * 2 *", timeZone);
|
||||
@@ -693,91 +693,91 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testSecondInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void secondInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("77 * * * * *", timeZone));
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testSecondRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void secondRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("44-77 * * * * *", timeZone));
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMinuteInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void minuteInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* 77 * * * *", timeZone));
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMinuteRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void minuteRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* 44-77 * * * *", timeZone));
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testHourInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void hourInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* * 27 * * *", timeZone));
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testHourRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void hourRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* * 23-28 * * *", timeZone));
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testDayInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void dayInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* * * 45 * *", timeZone));
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testDayRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void dayRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* * * 28-45 * *", timeZone));
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMonthInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void monthInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("0 0 0 25 13 ?", timeZone));
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMonthInvalidTooSmall(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void monthInvalidTooSmall(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("0 0 0 25 0 ?", timeZone));
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testDayOfMonthInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void dayOfMonthInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("0 0 0 32 12 ?", timeZone));
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMonthRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void monthRangeInvalid(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new CronTrigger("* * * * 11-13 *", timeZone));
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testWhitespace(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void whitespace(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger1 = new CronTrigger("* * * * 1 *", timeZone);
|
||||
@@ -786,7 +786,7 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testMonthSequence(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void monthSequence(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
CronTrigger trigger = new CronTrigger("0 30 23 30 1/3 ?", timeZone);
|
||||
@@ -808,23 +808,33 @@ class CronTriggerTests {
|
||||
// Next trigger is 3 months latter
|
||||
this.calendar.add(Calendar.MONTH, 3);
|
||||
TriggerContext context3 = getTriggerContext(localDate);
|
||||
Object actual = localDate = trigger.nextExecutionTime(context3);
|
||||
Object actual = trigger.nextExecutionTime(context3);
|
||||
assertThat(actual).isEqualTo(this.calendar.getTime());
|
||||
}
|
||||
|
||||
@ParameterizedCronTriggerTest
|
||||
void testDaylightSavingMissingHour(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
void daylightSavingMissingHour(LocalDateTime localDateTime, TimeZone timeZone) {
|
||||
setUp(localDateTime, timeZone);
|
||||
|
||||
// This trigger has to be somewhere in between 2am and 3am
|
||||
// This trigger has to be somewhere between 2:00 AM and 3:00 AM, so we
|
||||
// use a cron expression for 2:10 AM every day.
|
||||
CronTrigger trigger = new CronTrigger("0 10 2 * * *", timeZone);
|
||||
|
||||
// 2:00 AM on March 31, 2013: start of Daylight Saving Time for CET in 2013.
|
||||
// Setting up last completion:
|
||||
// - PST: Sun Mar 31 10:09:54 CEST 2013
|
||||
// - CET: Sun Mar 31 01:09:54 CET 2013
|
||||
this.calendar.set(Calendar.DAY_OF_MONTH, 31);
|
||||
this.calendar.set(Calendar.MONTH, Calendar.MARCH);
|
||||
this.calendar.set(Calendar.YEAR, 2013);
|
||||
this.calendar.set(Calendar.HOUR_OF_DAY, 1);
|
||||
this.calendar.set(Calendar.MINUTE, 9);
|
||||
this.calendar.set(Calendar.SECOND, 54);
|
||||
Date localDate = this.calendar.getTime();
|
||||
TriggerContext context1 = getTriggerContext(localDate);
|
||||
Date lastCompletionTime = this.calendar.getTime();
|
||||
|
||||
// Setting up expected next execution time:
|
||||
// - PST: Sun Mar 31 11:10:00 CEST 2013
|
||||
// - CET: Mon Apr 01 02:10:00 CEST 2013
|
||||
if (timeZone.equals(TimeZone.getTimeZone("CET"))) {
|
||||
// Clocks go forward an hour so 2am doesn't exist in CET for this localDateTime
|
||||
this.calendar.add(Calendar.DAY_OF_MONTH, 1);
|
||||
@@ -832,8 +842,10 @@ class CronTriggerTests {
|
||||
this.calendar.add(Calendar.HOUR_OF_DAY, 1);
|
||||
this.calendar.set(Calendar.MINUTE, 10);
|
||||
this.calendar.set(Calendar.SECOND, 0);
|
||||
Object actual = localDate = trigger.nextExecutionTime(context1);
|
||||
assertThat(actual).isEqualTo(this.calendar.getTime());
|
||||
|
||||
TriggerContext context = getTriggerContext(lastCompletionTime);
|
||||
Object nextExecutionTime = trigger.nextExecutionTime(context);
|
||||
assertThat(nextExecutionTime).isEqualTo(this.calendar.getTime());
|
||||
}
|
||||
|
||||
private static void roundup(Calendar calendar) {
|
||||
|
||||
+4
-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.
|
||||
@@ -17,10 +17,7 @@
|
||||
@file:JvmName("CoroutinesUtils")
|
||||
package org.springframework.core
|
||||
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.reactive.awaitSingleOrNull
|
||||
import kotlinx.coroutines.reactor.asFlux
|
||||
@@ -48,6 +45,8 @@ internal fun <T: Any> deferredToMono(source: Deferred<T>) =
|
||||
* @author Sebastien Deleuze
|
||||
* @since 5.2
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
internal fun <T: Any> monoToDeferred(source: Mono<T>) =
|
||||
GlobalScope.async(Dispatchers.Unconfined) { source.awaitSingleOrNull() }
|
||||
|
||||
|
||||
@@ -88,6 +88,9 @@ public class ClassReader {
|
||||
*/
|
||||
static final int EXPAND_ASM_INSNS = 256;
|
||||
|
||||
/** The maximum size of array to allocate. */
|
||||
private static final int MAX_BUFFER_SIZE = 1024 * 1024;
|
||||
|
||||
/** The size of the temporary byte array used to read class input streams chunk by chunk. */
|
||||
private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096;
|
||||
|
||||
@@ -191,7 +194,7 @@ public class ClassReader {
|
||||
this.b = classFileBuffer;
|
||||
// Check the class' major_version. This field is after the magic and minor_version fields, which
|
||||
// use 4 and 2 bytes respectively.
|
||||
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V17) {
|
||||
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V18) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported class file major version " + readShort(classFileOffset + 6));
|
||||
}
|
||||
@@ -310,13 +313,19 @@ public class ClassReader {
|
||||
if (inputStream == null) {
|
||||
throw new IOException("Class not found");
|
||||
}
|
||||
int bufferSize = calculateBufferSize(inputStream);
|
||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE];
|
||||
byte[] data = new byte[bufferSize];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
|
||||
int readCount = 0;
|
||||
while ((bytesRead = inputStream.read(data, 0, bufferSize)) != -1) {
|
||||
outputStream.write(data, 0, bytesRead);
|
||||
readCount++;
|
||||
}
|
||||
outputStream.flush();
|
||||
if (readCount == 1) {
|
||||
return data;
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
} finally {
|
||||
if (close) {
|
||||
@@ -325,6 +334,20 @@ public class ClassReader {
|
||||
}
|
||||
}
|
||||
|
||||
private static int calculateBufferSize(final InputStream inputStream) throws IOException {
|
||||
int expectedLength = inputStream.available();
|
||||
/*
|
||||
* Some implementations can return 0 while holding available data
|
||||
* (e.g. new FileInputStream("/proc/a_file"))
|
||||
* Also in some pathological cases a very small number might be returned,
|
||||
* and in this case we use default size
|
||||
*/
|
||||
if (expectedLength < 256) {
|
||||
return INPUT_STREAM_DATA_CHUNK_SIZE;
|
||||
}
|
||||
return Math.min(expectedLength, MAX_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Accessors
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@@ -3456,7 +3479,6 @@ public class ClassReader {
|
||||
private int[] readBootstrapMethodsAttribute(final int maxStringLength) {
|
||||
char[] charBuffer = new char[maxStringLength];
|
||||
int currentAttributeOffset = getFirstAttributeOffset();
|
||||
int[] currentBootstrapMethodOffsets = null;
|
||||
for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
|
||||
// Read the attribute_info's attribute_name and attribute_length fields.
|
||||
String attributeName = readUTF8(currentAttributeOffset, charBuffer);
|
||||
@@ -3464,17 +3486,17 @@ public class ClassReader {
|
||||
currentAttributeOffset += 6;
|
||||
if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
|
||||
// Read the num_bootstrap_methods field and create an array of this size.
|
||||
currentBootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)];
|
||||
int[] result = new int[readUnsignedShort(currentAttributeOffset)];
|
||||
// Compute and store the offset of each 'bootstrap_methods' array field entry.
|
||||
int currentBootstrapMethodOffset = currentAttributeOffset + 2;
|
||||
for (int j = 0; j < currentBootstrapMethodOffsets.length; ++j) {
|
||||
currentBootstrapMethodOffsets[j] = currentBootstrapMethodOffset;
|
||||
for (int j = 0; j < result.length; ++j) {
|
||||
result[j] = currentBootstrapMethodOffset;
|
||||
// Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each),
|
||||
// as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2).
|
||||
currentBootstrapMethodOffset +=
|
||||
4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2;
|
||||
}
|
||||
return currentBootstrapMethodOffsets;
|
||||
return result;
|
||||
}
|
||||
currentAttributeOffset += attributeLength;
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ package org.springframework.asm;
|
||||
/**
|
||||
* A visitor to visit a Java class. The methods of this class must be called in the following order:
|
||||
* {@code visit} [ {@code visitSource} ] [ {@code visitModule} ][ {@code visitNestHost} ][ {@code
|
||||
* visitPermittedSubclass} ][ {@code visitOuterClass} ] ( {@code visitAnnotation} | {@code
|
||||
* visitTypeAnnotation} | {@code visitAttribute} )* ( {@code visitNestMember} | {@code
|
||||
* visitOuterClass} ] ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code
|
||||
* visitAttribute} )* ( {@code visitNestMember} | [ {@code * visitPermittedSubclass} ] | {@code
|
||||
* visitInnerClass} | {@code visitRecordComponent} | {@code visitField} | {@code visitMethod} )*
|
||||
* {@code visitEnd}.
|
||||
*
|
||||
|
||||
@@ -79,7 +79,7 @@ public class ClassWriter extends ClassVisitor {
|
||||
|
||||
/**
|
||||
* The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific
|
||||
* access flags, such as {@link Opcodes#ACC_DEPRECATED} or {}@link Opcodes#ACC_RECORD}, which are
|
||||
* access flags, such as {@link Opcodes#ACC_DEPRECATED} or {@link Opcodes#ACC_RECORD}, which are
|
||||
* removed when generating the ClassFile structure.
|
||||
*/
|
||||
private int accessFlags;
|
||||
|
||||
@@ -282,6 +282,7 @@ public interface Opcodes {
|
||||
int V15 = 0 << 16 | 59;
|
||||
int V16 = 0 << 16 | 60;
|
||||
int V17 = 0 << 16 | 61;
|
||||
int V18 = 0 << 16 | 62;
|
||||
|
||||
/**
|
||||
* Version flag indicating that the class is using 'preview' features.
|
||||
|
||||
@@ -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.
|
||||
@@ -324,7 +324,7 @@ public class Constants {
|
||||
for (int i = 0; i < propertyName.length(); i++) {
|
||||
char c = propertyName.charAt(i);
|
||||
if (Character.isUpperCase(c)) {
|
||||
parsedPrefix.append("_");
|
||||
parsedPrefix.append('_');
|
||||
parsedPrefix.append(c);
|
||||
}
|
||||
else {
|
||||
|
||||
+5
-3
@@ -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.
|
||||
@@ -394,9 +394,11 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
|
||||
sb.append(entry.getKey());
|
||||
sb.append('=');
|
||||
sb.append(valueToString(entry.getValue()));
|
||||
sb.append(entries.hasNext() ? ", " : "");
|
||||
if (entries.hasNext()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append("}");
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -177,17 +177,17 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i
|
||||
private String annotationToString() {
|
||||
String string = this.string;
|
||||
if (string == null) {
|
||||
StringBuilder builder = new StringBuilder("@").append(this.type.getName()).append("(");
|
||||
StringBuilder builder = new StringBuilder("@").append(this.type.getName()).append('(');
|
||||
for (int i = 0; i < this.attributes.size(); i++) {
|
||||
Method attribute = this.attributes.get(i);
|
||||
if (i > 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append(attribute.getName());
|
||||
builder.append("=");
|
||||
builder.append('=');
|
||||
builder.append(toString(getAttributeValue(attribute)));
|
||||
}
|
||||
builder.append(")");
|
||||
builder.append(')');
|
||||
string = builder.toString();
|
||||
this.string = string;
|
||||
}
|
||||
@@ -206,7 +206,7 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i
|
||||
}
|
||||
builder.append(toString(Array.get(value, i)));
|
||||
}
|
||||
builder.append("]");
|
||||
builder.append(']');
|
||||
return builder.toString();
|
||||
}
|
||||
return String.valueOf(value);
|
||||
|
||||
@@ -513,7 +513,7 @@ public class TypeDescriptor implements Serializable {
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Annotation ann : getAnnotations()) {
|
||||
builder.append("@").append(ann.annotationType().getName()).append(' ');
|
||||
builder.append('@').append(ann.annotationType().getName()).append(' ');
|
||||
}
|
||||
builder.append(getResolvableType());
|
||||
return builder.toString();
|
||||
|
||||
@@ -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.
|
||||
@@ -71,7 +71,7 @@ public abstract class DataBufferUtils {
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Obtain a {@link InputStream} from the given supplier, and read it into a
|
||||
* Obtain an {@link InputStream} from the given supplier, and read it into a
|
||||
* {@code Flux} of {@code DataBuffer}s. Closes the input stream when the
|
||||
* Flux is terminated.
|
||||
* @param inputStreamSupplier the supplier for the input stream to read from
|
||||
@@ -125,7 +125,7 @@ public abstract class DataBufferUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a {@code AsynchronousFileChannel} from the given supplier, and
|
||||
* Obtain an {@code AsynchronousFileChannel} from the given supplier, and
|
||||
* read it into a {@code Flux} of {@code DataBuffer}s, starting at the given
|
||||
* position. Closes the channel when the Flux is terminated.
|
||||
* @param channelSupplier the supplier for the channel to read from
|
||||
|
||||
+5
-11
@@ -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.
|
||||
@@ -29,16 +29,16 @@ import java.util.function.Supplier;
|
||||
*/
|
||||
class DefaultApplicationStartup implements ApplicationStartup {
|
||||
|
||||
private static final DefaultStartupStep DEFAULT_STARTUP_STEP = new DefaultStartupStep();
|
||||
|
||||
@Override
|
||||
public DefaultStartupStep start(String name) {
|
||||
return new DefaultStartupStep();
|
||||
return DEFAULT_STARTUP_STEP;
|
||||
}
|
||||
|
||||
|
||||
static class DefaultStartupStep implements StartupStep {
|
||||
|
||||
boolean recorded = false;
|
||||
|
||||
private final DefaultTags TAGS = new DefaultTags();
|
||||
|
||||
@Override
|
||||
@@ -63,23 +63,17 @@ class DefaultApplicationStartup implements ApplicationStartup {
|
||||
|
||||
@Override
|
||||
public StartupStep tag(String key, String value) {
|
||||
if (this.recorded) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StartupStep tag(String key, Supplier<String> value) {
|
||||
if (this.recorded) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
this.recorded = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user