mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
133 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fcfb16839f | |||
| c75da7ba10 | |||
| eeac150030 | |||
| 0ce9516aef | |||
| e47cc44947 | |||
| 57db73dcb8 | |||
| d7be1e0dab | |||
| 30c873b4b5 | |||
| e72b0a04cd | |||
| f8b41c1ad2 | |||
| 8c777111fa | |||
| d28d603081 | |||
| 52d0681ca1 | |||
| 97854d9fec | |||
| 73f3860bb7 | |||
| 452f1b877c | |||
| c278d8c656 | |||
| e3b288716d | |||
| 27738cc20f | |||
| babff8e635 | |||
| 290cc73d3d | |||
| 8a30bc2993 | |||
| aa8be28a01 | |||
| f43b28e7ba | |||
| 1476867ee7 | |||
| 4d9dc61f5d | |||
| 7eebc48a6e | |||
| 8478e8e70a | |||
| e386bdb82c | |||
| 4912c3c455 | |||
| 8fcc7ab9d1 | |||
| 7c47b470ff | |||
| 479ef3f3fd | |||
| be1b7da12f | |||
| 89360b18f4 | |||
| 209fe5f452 | |||
| e18a118f8b | |||
| 77aac7768d | |||
| e2767371b5 | |||
| aab9da0366 | |||
| cda1e5507c | |||
| 1d5ffaf30a | |||
| c55606ed08 | |||
| aa8802a81d | |||
| 1beb7068f6 | |||
| 9d324e59a0 | |||
| 8547f8601d | |||
| 40cb81470b | |||
| 6e3b3c5419 | |||
| a221835558 | |||
| aa06a09dee | |||
| bde0931e51 | |||
| 7b95c928d1 | |||
| 53f88d455f | |||
| 53a506f6bb | |||
| f95bf96ec9 | |||
| 66a5742df3 | |||
| 59c7bb1f86 | |||
| a1c3efbb5f | |||
| 6efe3aee34 | |||
| f2fe7f335c | |||
| 48c797e429 | |||
| be782a2197 | |||
| 8098e45bad | |||
| 06679a5583 | |||
| 745eb1a881 | |||
| 10c55ff912 | |||
| 83186b689f | |||
| dc2947c52d | |||
| e4ec376075 | |||
| c81e11d537 | |||
| de6180b093 | |||
| 1c10cdd1e8 | |||
| 941b92cbed | |||
| e26d8839b3 | |||
| a1c7380398 | |||
| 7dd622bdb2 | |||
| 64c96c579d | |||
| 39e3876301 | |||
| f771603789 | |||
| e441832e99 | |||
| f963fc5f98 | |||
| b55eee1b0d | |||
| 28742171fd | |||
| 7a75b94556 | |||
| ab71ff93bb | |||
| cf30327740 | |||
| e22a038725 | |||
| 7aedb9ee33 | |||
| 5b1719cd77 | |||
| c056b81753 | |||
| dbdd67ec62 | |||
| 4fcfa5b991 | |||
| ed06a6de26 | |||
| afa799b4f0 | |||
| f0d149b330 | |||
| caaf83b8e6 | |||
| b30f4d7bb7 | |||
| b6b03f38d7 | |||
| 46b0d7dc03 | |||
| fcf64798b5 | |||
| 94ed07d9cb | |||
| b81c62d064 | |||
| ca1a11acac | |||
| c261d40610 | |||
| 3017955eff | |||
| 22c82ff206 | |||
| f54952481b | |||
| 9e733b09e2 | |||
| a7cf19cec5 | |||
| 0cf7f7bd89 | |||
| 949c3d450c | |||
| 3b4ae7b028 | |||
| 8b39698553 | |||
| 6fad00ed22 | |||
| 5f6d8df34b | |||
| 35de7e19ee | |||
| 10e979e58b | |||
| 4143b445d6 | |||
| eefdd2c768 | |||
| 9f91168396 | |||
| 7aed6279a2 | |||
| c3fe112fd7 | |||
| 90103b0ae9 | |||
| 0cf15c0fdd | |||
| 4e9af3e277 | |||
| 01fd489b47 | |||
| 270b167e08 | |||
| b158110801 | |||
| 17f7a24118 | |||
| d518a7d8c8 | |||
| 24cd3c1f4c | |||
| 2a8c369cff |
@@ -1,23 +1,33 @@
|
||||
Juergen Hoeller <jhoeller@pivotal.io> jhoeller <jhoeller@vmware.com>
|
||||
<jhoeller@pivotal.io> <jhoeller@vmware.com>
|
||||
<jhoeller@pivotal.io> <jhoeller@gopivotal.com>
|
||||
<rstoyanchev@pivotal.io> <rstoyanchev@vmware.com>
|
||||
<rstoyanchev@pivotal.io> <rstoyanchev@gopivotal.com>
|
||||
<pwebb@pivotal.io> <pwebb@vmware.com>
|
||||
<pwebb@pivotal.io> <pwebb@gopivotal.com>
|
||||
<cbeams@pivotal.io> <cbeams@vmware.com>
|
||||
<cbeams@pivotal.io> <cbeams@gopivotal.com>
|
||||
<cbeams@pivotal.io> <cbeams@gmail.com>
|
||||
<apoutsma@pivotal.io> <apoutsma@vmware.com>
|
||||
<apoutsma@pivotal.io> <apoutsma@gopivotal.com>
|
||||
<apoutsma@pivotal.io> <poutsma@mac.com>
|
||||
<ogierke@pivotal.io> <ogierke@vmware.com>
|
||||
<ogierke@pivotal.io> <ogierke@gopivotal.com>
|
||||
<dsyer@pivotal.io> <dsyer@vmware.com>
|
||||
<dsyer@pivotal.io> <dsyer@gopivotal.com>
|
||||
<dsyer@pivotal.io> <david_syer@hotmail.com>
|
||||
<aclement@pivotal.io> <aclement@vmware.com>
|
||||
<aclement@pivotal.io> <aclement@gopivotal.com>
|
||||
<aclement@pivotal.io> <andrew.clement@gmail.com>
|
||||
Juergen Hoeller <jhoeller@vmware.com>
|
||||
Juergen Hoeller <jhoeller@vmware.com> <jhoeller@pivotal.io>
|
||||
Juergen Hoeller <jhoeller@vmware.com> <jhoeller@gopivotal.com>
|
||||
Rossen Stoyanchev <rstoyanchev@vmware.com>
|
||||
Rossen Stoyanchev <rstoyanchev@vmware.com> <rstoyanchev@pivotal.io>
|
||||
Rossen Stoyanchev <rstoyanchev@vmware.com> <rstoyanchev@gopivotal.com>
|
||||
Phillip Webb <pwebb@vmware.com>
|
||||
Phillip Webb <pwebb@vmware.com> <pwebb@pivotal.io>
|
||||
Phillip Webb <pwebb@vmware.com> <pwebb@gopivotal.com>
|
||||
Chris Beams <cbeams@vmware.com>
|
||||
Chris Beams <cbeams@vmware.com> <cbeams@pivotal.io>
|
||||
Chris Beams <cbeams@vmware.com> <cbeams@gopivotal.com>
|
||||
Arjen Poutsma <apoutsma@vmware.com>
|
||||
Arjen Poutsma <apoutsma@vmware.com> <apoutsma@pivotal.io>
|
||||
Arjen Poutsma <apoutsma@vmware.com> <apoutsma@gopivotal.com>
|
||||
Arjen Poutsma <apoutsma@vmware.com> <poutsma@mac.com>
|
||||
Oliver Drotbohm <odrotbohm@vmware.com>
|
||||
Oliver Drotbohm <odrotbohm@vmware.com> <ogierke@vmware.com>
|
||||
Oliver Drotbohm <odrotbohm@vmware.com> <ogierke@pivotal.io>
|
||||
Oliver Drotbohm <odrotbohm@vmware.com> <ogierke@gopivotal.com>
|
||||
Dave Syer <dsyer@vmware.com>
|
||||
Dave Syer <dsyer@vmware.com> <dsyer@pivotal.io>
|
||||
Dave Syer <dsyer@vmware.com> <dsyer@gopivotal.com>
|
||||
Dave Syer <dsyer@vmware.com> <david_syer@hotmail.com>
|
||||
Andy Clement <aclement@vmware.com>
|
||||
Andy Clement <aclement@vmware.com> <aclement@pivotal.io>
|
||||
Andy Clement <aclement@vmware.com> <aclement@gopivotal.com>
|
||||
Andy Clement <aclement@vmware.com> <andrew.clement@gmail.com>
|
||||
Sam Brannen <sbrannen@vmware.com>
|
||||
Sam Brannen <sbrannen@vmware.com> <sbrannen@pivotal.io>
|
||||
Sam Brannen <sbrannen@vmware.com> <sam@sambrannen.com>
|
||||
<dmitry.katsubo@gmail.com> <dmitry.katsubo@gmai.com>
|
||||
Nick Williams <nicholas@nicholaswilliams.net> Nicholas Williams <nicholas@nicholaswilliams.net>
|
||||
Nick Williams <nicholas@nicholaswilliams.net>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Enable auto-env through the sdkman_auto_env config
|
||||
# Add key=value pairs of SDKs to use below
|
||||
java=8.0.322-librca
|
||||
java=8.0.333-librca
|
||||
|
||||
+19
-19
@@ -27,12 +27,12 @@ configure(allprojects) { project ->
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.6"
|
||||
mavenBom "io.netty:netty-bom:4.1.75.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.17"
|
||||
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR12"
|
||||
mavenBom "io.rsocket:rsocket-bom:1.1.1"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.45.v20220203"
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.7"
|
||||
mavenBom "io.netty:netty-bom:4.1.77.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.20"
|
||||
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR13"
|
||||
mavenBom "io.rsocket:rsocket-bom:1.1.2"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.46.v20220331"
|
||||
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.5.32"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.5.2"
|
||||
mavenBom "org.jetbrains.kotlinx:kotlinx-serialization-bom:1.2.2"
|
||||
@@ -67,7 +67,7 @@ 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.1.3"
|
||||
dependency "io.reactivex.rxjava3:rxjava:3.1.4"
|
||||
dependency "io.smallrye.reactive:mutiny:1.4.0"
|
||||
dependency "io.projectreactor.tools:blockhound:1.0.6.RELEASE"
|
||||
|
||||
@@ -83,7 +83,7 @@ configure(allprojects) { project ->
|
||||
exclude group: "xpp3", name: "xpp3_min"
|
||||
exclude group: "xmlpull", name: "xmlpull"
|
||||
}
|
||||
dependency "org.apache.johnzon:johnzon-jsonb:1.2.16"
|
||||
dependency "org.apache.johnzon:johnzon-jsonb:1.2.18"
|
||||
dependency("org.codehaus.jettison:jettison:1.3.8") {
|
||||
exclude group: "stax", name: "stax-api"
|
||||
}
|
||||
@@ -94,9 +94,9 @@ configure(allprojects) { project ->
|
||||
dependency "org.ogce:xpp3:1.1.6"
|
||||
dependency "org.yaml:snakeyaml:1.30"
|
||||
|
||||
dependency "com.h2database:h2:2.1.210"
|
||||
dependency "com.h2database:h2:2.1.212"
|
||||
dependency "com.github.ben-manes.caffeine:caffeine:2.9.3"
|
||||
dependency "com.github.librepdf:openpdf:1.3.26"
|
||||
dependency "com.github.librepdf:openpdf:1.3.28"
|
||||
dependency "com.rometools:rome:1.18.0"
|
||||
dependency "commons-io:commons-io:2.5"
|
||||
dependency "io.vavr:vavr:0.10.4"
|
||||
@@ -128,18 +128,18 @@ configure(allprojects) { project ->
|
||||
dependency "org.webjars:webjars-locator-core:0.48"
|
||||
dependency "org.webjars:underscorejs:1.8.3"
|
||||
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.60') {
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.64') {
|
||||
entry 'tomcat-util'
|
||||
entry('tomcat-websocket') {
|
||||
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
|
||||
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
|
||||
}
|
||||
}
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.60') {
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.64') {
|
||||
entry 'tomcat-embed-core'
|
||||
entry 'tomcat-embed-websocket'
|
||||
}
|
||||
dependencySet(group: 'io.undertow', version: '2.2.16.Final') {
|
||||
dependencySet(group: 'io.undertow', version: '2.2.17.Final') {
|
||||
entry 'undertow-core'
|
||||
entry('undertow-servlet') {
|
||||
exclude group: "org.jboss.spec.javax.servlet", name: "jboss-servlet-api_4.0_spec"
|
||||
@@ -150,7 +150,7 @@ configure(allprojects) { project ->
|
||||
}
|
||||
}
|
||||
|
||||
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.10"
|
||||
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.11"
|
||||
dependency 'org.apache.httpcomponents.client5:httpclient5:5.1.3'
|
||||
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.1.3'
|
||||
dependency("org.apache.httpcomponents:httpclient:4.5.13") {
|
||||
@@ -191,14 +191,14 @@ configure(allprojects) { project ->
|
||||
dependency "org.junit.support:testng-engine:1.0.1"
|
||||
dependency "org.hamcrest:hamcrest:2.1"
|
||||
dependency "org.awaitility:awaitility:3.1.6"
|
||||
dependency "org.assertj:assertj-core:3.22.0"
|
||||
dependency "org.assertj:assertj-core:3.23.0"
|
||||
dependencySet(group: 'org.xmlunit', version: '2.9.0') {
|
||||
entry 'xmlunit-assertj'
|
||||
entry('xmlunit-matchers') {
|
||||
exclude group: "org.hamcrest", name: "hamcrest-core"
|
||||
}
|
||||
}
|
||||
dependencySet(group: 'org.mockito', version: '4.4.0') {
|
||||
dependencySet(group: 'org.mockito', version: '4.6.1') {
|
||||
entry('mockito-core') {
|
||||
exclude group: "org.hamcrest", name: "hamcrest-core"
|
||||
}
|
||||
@@ -206,10 +206,10 @@ configure(allprojects) { project ->
|
||||
}
|
||||
dependency "io.mockk:mockk:1.12.1"
|
||||
|
||||
dependency("net.sourceforge.htmlunit:htmlunit:2.59.0") {
|
||||
dependency("net.sourceforge.htmlunit:htmlunit:2.62.0") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.seleniumhq.selenium:htmlunit-driver:2.59.0") {
|
||||
dependency("org.seleniumhq.selenium:htmlunit-driver:2.62.0") {
|
||||
exclude group: "commons-logging", name: "commons-logging"
|
||||
}
|
||||
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
|
||||
@@ -340,7 +340,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "9.3"
|
||||
toolVersion = "10.3"
|
||||
configDirectory.set(rootProject.file("src/checkstyle"))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:focal-20220302
|
||||
FROM ubuntu:focal-20220531
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
|
||||
@@ -3,18 +3,18 @@ set -e
|
||||
|
||||
case "$1" in
|
||||
java8)
|
||||
echo "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u322-b06/OpenJDK8U-jdk_x64_linux_hotspot_8u322b06.tar.gz"
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/8u333+2/bellsoft-jdk8u333+2-linux-amd64.tar.gz"
|
||||
;;
|
||||
java11)
|
||||
echo "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.14.1%2B1/OpenJDK11U-jdk_x64_linux_hotspot_11.0.14.1_1.tar.gz"
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/11.0.15.1+2/bellsoft-jdk11.0.15.1+2-linux-amd64.tar.gz"
|
||||
;;
|
||||
java17)
|
||||
echo "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.2%2B8/OpenJDK17U-jdk_x64_linux_hotspot_17.0.2_8.tar.gz"
|
||||
;;
|
||||
java18)
|
||||
echo "https://github.com/adoptium/temurin18-binaries/releases/download/jdk18-2022-02-12-08-06-beta/OpenJDK18-jdk_x64_linux_hotspot_2022-02-12-08-06.tar.gz"
|
||||
;;
|
||||
*)
|
||||
java17)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.3.1+2/bellsoft-jdk17.0.3.1+2-linux-amd64.tar.gz"
|
||||
;;
|
||||
java18)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/18.0.1.1+2/bellsoft-jdk18.0.1.1+2-linux-amd64.tar.gz"
|
||||
;;
|
||||
*)
|
||||
echo $"Unknown java version"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
@@ -14,8 +14,6 @@ rm -rf /var/lib/apt/lists/*
|
||||
|
||||
curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/concourse-java.sh > /opt/concourse-java.sh
|
||||
|
||||
curl --output /opt/concourse-release-scripts.jar https://repo.spring.io/release/io/spring/concourse/releasescripts/concourse-release-scripts/0.3.2/concourse-release-scripts-0.3.2.jar
|
||||
|
||||
###########################################################
|
||||
# JAVA
|
||||
###########################################################
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
github-repo: "https://github.com/spring-projects/spring-framework.git"
|
||||
github-repo-name: "spring-projects/spring-framework"
|
||||
sonatype-staging-profile: "org.springframework"
|
||||
docker-hub-organization: "springci"
|
||||
artifactory-server: "https://repo.spring.io"
|
||||
branch: "5.3.x"
|
||||
@@ -7,4 +8,7 @@ milestone: "5.3.x"
|
||||
build-name: "spring-framework"
|
||||
pipeline-name: "spring-framework"
|
||||
concourse-url: "https://ci.spring.io"
|
||||
registry-mirror-host: docker.repo.spring.io
|
||||
registry-mirror-username: ((artifactory-username))
|
||||
registry-mirror-password: ((artifactory-password))
|
||||
task-timeout: 1h00m
|
||||
|
||||
+23
-10
@@ -12,7 +12,7 @@ anchors:
|
||||
SONATYPE_USERNAME: ((sonatype-username))
|
||||
SONATYPE_PASSWORD: ((sonatype-password))
|
||||
SONATYPE_URL: ((sonatype-url))
|
||||
SONATYPE_STAGING_PROFILE_ID: ((sonatype-staging-profile-id))
|
||||
SONATYPE_STAGING_PROFILE: ((sonatype-staging-profile))
|
||||
artifactory-task-params: &artifactory-task-params
|
||||
ARTIFACTORY_SERVER: ((artifactory-server))
|
||||
ARTIFACTORY_USERNAME: ((artifactory-username))
|
||||
@@ -24,6 +24,10 @@ anchors:
|
||||
username: ((docker-hub-username))
|
||||
password: ((docker-hub-password))
|
||||
tag: ((milestone))
|
||||
registry-mirror-vars: ®istry-mirror-vars
|
||||
registry-mirror-host: ((registry-mirror-host))
|
||||
registry-mirror-username: ((registry-mirror-username))
|
||||
registry-mirror-password: ((registry-mirror-password))
|
||||
slack-fail-params: &slack-fail-params
|
||||
text: >
|
||||
:concourse-failed: <https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!>
|
||||
@@ -41,6 +45,11 @@ anchors:
|
||||
GITHUB_TOKEN: ((github-ci-release-token))
|
||||
|
||||
resource_types:
|
||||
- name: registry-image
|
||||
type: registry-image
|
||||
source:
|
||||
repository: concourse/registry-image-resource
|
||||
tag: 1.5.0
|
||||
- name: artifactory-resource
|
||||
type: registry-image
|
||||
source:
|
||||
@@ -87,7 +96,7 @@ resources:
|
||||
branch: ((branch))
|
||||
paths: ["ci/images/*"]
|
||||
- name: ci-image
|
||||
type: docker-image
|
||||
type: registry-image
|
||||
icon: docker
|
||||
source:
|
||||
<<: *docker-resource-source
|
||||
@@ -157,13 +166,20 @@ resources:
|
||||
jobs:
|
||||
- name: build-ci-images
|
||||
plan:
|
||||
- get: ci-images-git-repo
|
||||
trigger: true
|
||||
- in_parallel:
|
||||
- get: git-repo
|
||||
- get: ci-images-git-repo
|
||||
trigger: true
|
||||
- task: build-ci-image
|
||||
privileged: true
|
||||
file: git-repo/ci/tasks/build-ci-image.yml
|
||||
output_mapping:
|
||||
image: ci-image
|
||||
vars:
|
||||
ci-image-name: ci-image
|
||||
<<: *registry-mirror-vars
|
||||
- put: ci-image
|
||||
params:
|
||||
build: ci-images-git-repo/ci/images
|
||||
dockerfile: ci-images-git-repo/ci/images/ci-image/Dockerfile
|
||||
image: ci-image/image.tar
|
||||
- name: build
|
||||
serial: true
|
||||
public: true
|
||||
@@ -340,7 +356,6 @@ jobs:
|
||||
download_artifacts: false
|
||||
save_build_info: true
|
||||
- task: promote
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/promote-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: M
|
||||
@@ -385,7 +400,6 @@ jobs:
|
||||
download_artifacts: false
|
||||
save_build_info: true
|
||||
- task: promote
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/promote-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: RC
|
||||
@@ -430,7 +444,6 @@ jobs:
|
||||
download_artifacts: true
|
||||
save_build_info: true
|
||||
- task: promote
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/promote-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: RELEASE
|
||||
|
||||
@@ -6,11 +6,11 @@ CONFIG_DIR=git-repo/ci/config
|
||||
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
|
||||
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
|
||||
|
||||
java -jar /opt/concourse-release-scripts.jar \
|
||||
java -jar /concourse-release-scripts.jar \
|
||||
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
|
||||
publishToCentral $RELEASE_TYPE $BUILD_INFO_LOCATION artifactory-repo || { exit 1; }
|
||||
|
||||
java -jar /opt/concourse-release-scripts.jar \
|
||||
java -jar /concourse-release-scripts.jar \
|
||||
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
|
||||
promote $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; }
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
|
||||
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
|
||||
java -jar /opt/concourse-release-scripts.jar syncToCentral "RELEASE" $BUILD_INFO_LOCATION || { exit 1; }
|
||||
|
||||
echo "Sync complete"
|
||||
echo $version > version/version
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
platform: linux
|
||||
image_resource:
|
||||
type: registry-image
|
||||
source:
|
||||
repository: concourse/oci-build-task
|
||||
tag: 0.9.1
|
||||
registry_mirror:
|
||||
host: ((registry-mirror-host))
|
||||
username: ((registry-mirror-username))
|
||||
password: ((registry-mirror-password))
|
||||
inputs:
|
||||
- name: ci-images-git-repo
|
||||
outputs:
|
||||
- name: image
|
||||
caches:
|
||||
- path: ci-image-cache
|
||||
params:
|
||||
CONTEXT: ci-images-git-repo/ci/images
|
||||
DOCKERFILE: ci-images-git-repo/ci/images/ci-image/Dockerfile
|
||||
DOCKER_HUB_AUTH: ((docker-hub-auth))
|
||||
run:
|
||||
path: /bin/sh
|
||||
args:
|
||||
- "-c"
|
||||
- |
|
||||
mkdir -p /root/.docker
|
||||
cat > /root/.docker/config.json <<EOF
|
||||
{ "auths": { "https://index.docker.io/v1/": { "auth": "$DOCKER_HUB_AUTH" }}}
|
||||
EOF
|
||||
build
|
||||
@@ -1,5 +1,10 @@
|
||||
---
|
||||
platform: linux
|
||||
image_resource:
|
||||
type: registry-image
|
||||
source:
|
||||
repository: springio/concourse-release-scripts
|
||||
tag: '0.3.4'
|
||||
inputs:
|
||||
- name: git-repo
|
||||
- name: artifactory-repo
|
||||
@@ -13,6 +18,6 @@ params:
|
||||
SONATYPE_USER:
|
||||
SONATYPE_PASSWORD:
|
||||
SONATYPE_URL:
|
||||
SONATYPE_STAGING_PROFILE_ID:
|
||||
SONATYPE_STAGING_PROFILE:
|
||||
run:
|
||||
path: git-repo/ci/scripts/promote-version.sh
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
version=5.3.18-SNAPSHOT
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
version=5.3.21
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
kotlin.stdlib.default.dependency=false
|
||||
kotlin.stdlib.default.dependency=false
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,7 +28,7 @@ import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
|
||||
/**
|
||||
* Integration tests for advice invocation order for advice configured via the
|
||||
@@ -52,7 +52,7 @@ class AopNamespaceHandlerAdviceOrderIntegrationTests {
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after", "after returning");
|
||||
|
||||
aspect.invocations.clear();
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() -> echo.echo(new Exception()));
|
||||
assertThatException().isThrownBy(() -> echo.echo(new Exception()));
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after", "after throwing");
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ class AopNamespaceHandlerAdviceOrderIntegrationTests {
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after returning", "after");
|
||||
|
||||
aspect.invocations.clear();
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() -> echo.echo(new Exception()));
|
||||
assertThatException().isThrownBy(() -> echo.echo(new Exception()));
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after throwing", "after");
|
||||
}
|
||||
}
|
||||
|
||||
+4
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,7 +38,7 @@ import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
|
||||
/**
|
||||
* Integration tests for advice invocation order for advice configured via
|
||||
@@ -65,8 +65,7 @@ class AspectJAutoProxyAdviceOrderIntegrationTests {
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "after returning", "after", "around - end");
|
||||
|
||||
aspect.invocations.clear();
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(
|
||||
() -> echo.echo(new Exception()));
|
||||
assertThatException().isThrownBy(() -> echo.echo(new Exception()));
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "after throwing", "after", "around - end");
|
||||
}
|
||||
}
|
||||
@@ -95,8 +94,7 @@ class AspectJAutoProxyAdviceOrderIntegrationTests {
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "after returning", "after", "around - end");
|
||||
|
||||
aspect.invocations.clear();
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(
|
||||
() -> echo.echo(new Exception()));
|
||||
assertThatException().isThrownBy(() -> echo.echo(new Exception()));
|
||||
assertThat(aspect.invocations).containsExactly("around - start", "before", "after throwing", "after", "around - end");
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,7 +34,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
|
||||
/**
|
||||
* Integration tests for the @EnableCaching annotation.
|
||||
@@ -62,8 +62,7 @@ class EnableCachingIntegrationTests {
|
||||
// this test is a bit fragile, but gets the job done, proving that an
|
||||
// attempt was made to look up the AJ aspect. It's due to classpath issues
|
||||
// in .integration-tests that it's not found.
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(
|
||||
ctx::refresh)
|
||||
assertThatException().isThrownBy(ctx::refresh)
|
||||
.withMessageContaining("AspectJCachingConfiguration");
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -45,7 +45,7 @@ import org.springframework.transaction.interceptor.BeanFactoryTransactionAttribu
|
||||
import org.springframework.transaction.testfixture.CallCountingTransactionManager;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
|
||||
/**
|
||||
* Integration tests for the @EnableTransactionManagement annotation.
|
||||
@@ -98,7 +98,7 @@ class EnableTransactionManagementIntegrationTests {
|
||||
// this test is a bit fragile, but gets the job done, proving that an
|
||||
// attempt was made to look up the AJ aspect. It's due to classpath issues
|
||||
// in .integration-tests that it's not found.
|
||||
assertThatExceptionOfType(Exception.class)
|
||||
assertThatException()
|
||||
.isThrownBy(ctx::refresh)
|
||||
.withMessageContaining("AspectJJtaTransactionManagementConfiguration");
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "com.gradle.enterprise" version "3.8.1"
|
||||
id "com.gradle.enterprise" version "3.9"
|
||||
id "io.spring.ge.conventions" version "0.0.9"
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -378,7 +378,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) +
|
||||
logger.debug("Failed to evaluate join point for arguments " + Arrays.toString(args) +
|
||||
" - falling back to non-match", ex);
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -134,7 +134,7 @@ public abstract class AopProxyUtils {
|
||||
if (targetClass.isInterface()) {
|
||||
advised.setInterfaces(targetClass);
|
||||
}
|
||||
else if (Proxy.isProxyClass(targetClass) || isLambda(targetClass)) {
|
||||
else if (Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
|
||||
advised.setInterfaces(targetClass.getInterfaces());
|
||||
}
|
||||
specifiedInterfaces = advised.getProxiedInterfaces();
|
||||
@@ -245,18 +245,4 @@ public abstract class AopProxyUtils {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the supplied {@link Class} is a JVM-generated implementation
|
||||
* class for a lambda expression or method reference.
|
||||
* <p>This method makes a best-effort attempt at determining this, based on
|
||||
* checks that work on modern, main stream JVMs.
|
||||
* @param clazz the class to check
|
||||
* @return {@code true} if the class is a lambda implementation class
|
||||
* @since 5.3.16
|
||||
*/
|
||||
static boolean isLambda(Class<?> clazz) {
|
||||
return (clazz.isSynthetic() && (clazz.getSuperclass() == Object.class) &&
|
||||
(clazz.getInterfaces().length > 0) && clazz.getName().contains("$$Lambda"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -375,6 +375,22 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the given method with a CGLIB MethodProxy if possible, falling back
|
||||
* to a plain reflection invocation in case of a fast-class generation failure.
|
||||
*/
|
||||
@Nullable
|
||||
private static Object invokeMethod(@Nullable Object target, Method method, Object[] args, MethodProxy methodProxy)
|
||||
throws Throwable {
|
||||
try {
|
||||
return methodProxy.invoke(target, args);
|
||||
}
|
||||
catch (CodeGenerationException ex) {
|
||||
CglibMethodInvocation.logFastClassGenerationFailure(method);
|
||||
return AopUtils.invokeJoinpointUsingReflection(target, method, args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a return value. Wraps a return of {@code this} if necessary to be the
|
||||
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
|
||||
@@ -425,7 +441,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
@Override
|
||||
@Nullable
|
||||
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
|
||||
Object retVal = methodProxy.invoke(this.target, args);
|
||||
Object retVal = invokeMethod(this.target, method, args, methodProxy);
|
||||
return processReturnType(proxy, this.target, method, retVal);
|
||||
}
|
||||
}
|
||||
@@ -450,7 +466,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
Object oldProxy = null;
|
||||
try {
|
||||
oldProxy = AopContext.setCurrentProxy(proxy);
|
||||
Object retVal = methodProxy.invoke(this.target, args);
|
||||
Object retVal = invokeMethod(this.target, method, args, methodProxy);
|
||||
return processReturnType(proxy, this.target, method, retVal);
|
||||
}
|
||||
finally {
|
||||
@@ -478,7 +494,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
|
||||
Object target = this.targetSource.getTarget();
|
||||
try {
|
||||
Object retVal = methodProxy.invoke(target, args);
|
||||
Object retVal = invokeMethod(target, method, args, methodProxy);
|
||||
return processReturnType(proxy, target, method, retVal);
|
||||
}
|
||||
finally {
|
||||
@@ -508,7 +524,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
Object target = this.targetSource.getTarget();
|
||||
try {
|
||||
oldProxy = AopContext.setCurrentProxy(proxy);
|
||||
Object retVal = methodProxy.invoke(target, args);
|
||||
Object retVal = invokeMethod(target, method, args, methodProxy);
|
||||
return processReturnType(proxy, target, method, retVal);
|
||||
}
|
||||
finally {
|
||||
@@ -685,13 +701,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||
// it does nothing but a reflective operation on the target, and no hot
|
||||
// swapping or fancy proxying.
|
||||
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
|
||||
try {
|
||||
retVal = methodProxy.invoke(target, argsToUse);
|
||||
}
|
||||
catch (CodeGenerationException ex) {
|
||||
CglibMethodInvocation.logFastClassGenerationFailure(method);
|
||||
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
|
||||
}
|
||||
retVal = invokeMethod(target, method, argsToUse, methodProxy);
|
||||
}
|
||||
else {
|
||||
// We need to create a method invocation...
|
||||
|
||||
+2
-1
@@ -21,6 +21,7 @@ import java.lang.reflect.Proxy;
|
||||
|
||||
import org.springframework.aop.SpringProxy;
|
||||
import org.springframework.core.NativeDetector;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy
|
||||
@@ -60,7 +61,7 @@ public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
|
||||
throw new AopConfigException("TargetSource cannot determine target class: " +
|
||||
"Either an interface or a target is required for proxy creation.");
|
||||
}
|
||||
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || AopProxyUtils.isLambda(targetClass)) {
|
||||
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
|
||||
return new JdkDynamicAopProxy(config);
|
||||
}
|
||||
return new ObjenesisCglibAopProxy(config);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -424,7 +424,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
|
||||
if (!this.advisorChainInitialized && !ObjectUtils.isEmpty(this.interceptorNames)) {
|
||||
if (this.beanFactory == null) {
|
||||
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
|
||||
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
|
||||
"- cannot resolve interceptor names " + Arrays.toString(this.interceptorNames));
|
||||
}
|
||||
|
||||
// Globals can't be last unless we specified a targetSource using the property...
|
||||
|
||||
+5
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,6 +50,7 @@ import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostP
|
||||
import org.springframework.core.SmartClassLoader;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -85,6 +86,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Juergen Hoeller
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
* @author Sam Brannen
|
||||
* @since 13.10.2003
|
||||
* @see #setInterceptorNames
|
||||
* @see #getAdvicesAndAdvisorsForBean
|
||||
@@ -442,8 +444,8 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
|
||||
proxyFactory.copyFrom(this);
|
||||
|
||||
if (proxyFactory.isProxyTargetClass()) {
|
||||
// Explicit handling of JDK proxy targets (for introduction advice scenarios)
|
||||
if (Proxy.isProxyClass(beanClass)) {
|
||||
// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
|
||||
if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
|
||||
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
|
||||
for (Class<?> ifc : beanClass.getInterfaces()) {
|
||||
proxyFactory.addInterface(ifc);
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.springframework.aop.framework;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -134,61 +133,4 @@ public class AopProxyUtilsTests {
|
||||
AopProxyUtils.proxiedUserInterfaces(proxy));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isLambda() {
|
||||
assertIsLambda(AopProxyUtilsTests.staticLambdaExpression);
|
||||
assertIsLambda(AopProxyUtilsTests::staticStringFactory);
|
||||
|
||||
assertIsLambda(this.instanceLambdaExpression);
|
||||
assertIsLambda(this::instanceStringFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
void isNotLambda() {
|
||||
assertIsNotLambda(new EnigmaSupplier());
|
||||
|
||||
assertIsNotLambda(new Supplier<String>() {
|
||||
@Override
|
||||
public String get() {
|
||||
return "anonymous inner class";
|
||||
}
|
||||
});
|
||||
|
||||
assertIsNotLambda(new Fake$$LambdaSupplier());
|
||||
}
|
||||
|
||||
private static void assertIsLambda(Supplier<String> supplier) {
|
||||
assertThat(AopProxyUtils.isLambda(supplier.getClass())).isTrue();
|
||||
}
|
||||
|
||||
private static void assertIsNotLambda(Supplier<String> supplier) {
|
||||
assertThat(AopProxyUtils.isLambda(supplier.getClass())).isFalse();
|
||||
}
|
||||
|
||||
private static final Supplier<String> staticLambdaExpression = () -> "static lambda expression";
|
||||
|
||||
private final Supplier<String> instanceLambdaExpression = () -> "instance lambda expressions";
|
||||
|
||||
private static String staticStringFactory() {
|
||||
return "static string factory";
|
||||
}
|
||||
|
||||
private String instanceStringFactory() {
|
||||
return "instance string factory";
|
||||
}
|
||||
|
||||
private static class EnigmaSupplier implements Supplier<String> {
|
||||
@Override
|
||||
public String get() {
|
||||
return "enigma";
|
||||
}
|
||||
}
|
||||
|
||||
private static class Fake$$LambdaSupplier implements Supplier<String> {
|
||||
@Override
|
||||
public String get() {
|
||||
return "fake lambda";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,7 +44,7 @@ import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.testfixture.TimeStamped;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
|
||||
|
||||
/**
|
||||
* Also tests AdvisedSupport and ProxyCreatorSupport superclasses.
|
||||
@@ -277,7 +277,7 @@ public class ProxyFactoryTests {
|
||||
|
||||
assertThat(config.getAdvisors().length == oldCount).isTrue();
|
||||
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
assertThatRuntimeException()
|
||||
.as("Existing object won't implement this interface any more")
|
||||
.isThrownBy(ts::getTimeStamp); // Existing reference will fail
|
||||
|
||||
|
||||
+3
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author 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,6 +26,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.aop.testfixture.advice.MyThrowsHandler;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
@@ -63,9 +64,7 @@ public class ThrowsAdviceInterceptorTests {
|
||||
Exception ex = new Exception();
|
||||
MethodInvocation mi = mock(MethodInvocation.class);
|
||||
given(mi.proceed()).willThrow(ex);
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
|
||||
ti.invoke(mi))
|
||||
.isSameAs(ex);
|
||||
assertThatException().isThrownBy(() -> ti.invoke(mi)).isSameAs(ex);
|
||||
assertThat(th.getCalls()).isEqualTo(0);
|
||||
}
|
||||
|
||||
|
||||
+16
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author 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,9 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.transaction.testfixture.CallCountingTransactionManager;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
@@ -104,44 +106,44 @@ public class TransactionAspectTests {
|
||||
@Test
|
||||
public void defaultCommitOnAnnotatedClass() throws Throwable {
|
||||
Exception ex = new Exception();
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
|
||||
testRollback(() -> annotationOnlyOnClassWithNoInterface.echo(ex), false))
|
||||
assertThatException()
|
||||
.isThrownBy(() -> testRollback(() -> annotationOnlyOnClassWithNoInterface.echo(ex), false))
|
||||
.isSameAs(ex);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultRollbackOnAnnotatedClass() throws Throwable {
|
||||
RuntimeException ex = new RuntimeException();
|
||||
assertThatExceptionOfType(RuntimeException.class).isThrownBy(() ->
|
||||
testRollback(() -> annotationOnlyOnClassWithNoInterface.echo(ex), true))
|
||||
assertThatRuntimeException()
|
||||
.isThrownBy(() -> testRollback(() -> annotationOnlyOnClassWithNoInterface.echo(ex), true))
|
||||
.isSameAs(ex);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultCommitOnSubclassOfAnnotatedClass() throws Throwable {
|
||||
Exception ex = new Exception();
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
|
||||
testRollback(() -> new SubclassOfClassWithTransactionalAnnotation().echo(ex), false))
|
||||
assertThatException()
|
||||
.isThrownBy(() -> testRollback(() -> new SubclassOfClassWithTransactionalAnnotation().echo(ex), false))
|
||||
.isSameAs(ex);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable {
|
||||
Exception ex = new Exception();
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
|
||||
testRollback(() -> new SubclassOfClassWithTransactionalMethodAnnotation().echo(ex), false))
|
||||
assertThatException()
|
||||
.isThrownBy(() -> testRollback(() -> new SubclassOfClassWithTransactionalMethodAnnotation().echo(ex), false))
|
||||
.isSameAs(ex);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noCommitOnImplementationOfAnnotatedInterface() throws Throwable {
|
||||
final Exception ex = new Exception();
|
||||
Exception ex = new Exception();
|
||||
testNotTransactional(() -> new ImplementsAnnotatedInterface().echo(ex), ex);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noRollbackOnImplementationOfAnnotatedInterface() throws Throwable {
|
||||
final Exception rollbackProvokingException = new RuntimeException();
|
||||
Exception rollbackProvokingException = new RuntimeException();
|
||||
testNotTransactional(() -> new ImplementsAnnotatedInterface().echo(rollbackProvokingException),
|
||||
rollbackProvokingException);
|
||||
}
|
||||
@@ -165,8 +167,9 @@ public class TransactionAspectTests {
|
||||
protected void testNotTransactional(TransactionOperationCallback toc, Throwable expected) throws Throwable {
|
||||
txManager.clear();
|
||||
assertThat(txManager.begun).isEqualTo(0);
|
||||
assertThatExceptionOfType(Throwable.class).isThrownBy(
|
||||
toc::performTransactionalOperation).isSameAs(expected);
|
||||
assertThatExceptionOfType(Throwable.class)
|
||||
.isThrownBy(toc::performTransactionalOperation)
|
||||
.isSameAs(expected);
|
||||
assertThat(txManager.begun).isEqualTo(0);
|
||||
}
|
||||
|
||||
|
||||
+22
-10
@@ -22,6 +22,7 @@ import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@@ -287,13 +288,17 @@ public final class CachedIntrospectionResults {
|
||||
// This call is slow so we do it once.
|
||||
PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
|
||||
for (PropertyDescriptor pd : pds) {
|
||||
if (Class.class == beanClass && (!"name".equals(pd.getName()) && !pd.getName().endsWith("Name"))) {
|
||||
if (Class.class == beanClass && !("name".equals(pd.getName()) ||
|
||||
(pd.getName().endsWith("Name") && String.class == pd.getPropertyType()))) {
|
||||
// Only allow all name variants of Class properties
|
||||
continue;
|
||||
}
|
||||
if (pd.getPropertyType() != null && (ClassLoader.class.isAssignableFrom(pd.getPropertyType())
|
||||
|| ProtectionDomain.class.isAssignableFrom(pd.getPropertyType()))) {
|
||||
// Ignore ClassLoader and ProtectionDomain types - nobody needs to bind to those
|
||||
if (URL.class == beanClass && "content".equals(pd.getName())) {
|
||||
// Only allow URL attribute introspection, not content resolution
|
||||
continue;
|
||||
}
|
||||
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
|
||||
// Ignore read-only properties such as ClassLoader - no need to bind to those
|
||||
continue;
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
@@ -342,9 +347,8 @@ public final class CachedIntrospectionResults {
|
||||
// GenericTypeAwarePropertyDescriptor leniently resolves a set* write method
|
||||
// against a declared read method, so we prefer read method descriptors here.
|
||||
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
|
||||
if (pd.getPropertyType() != null && (ClassLoader.class.isAssignableFrom(pd.getPropertyType())
|
||||
|| ProtectionDomain.class.isAssignableFrom(pd.getPropertyType()))) {
|
||||
// Ignore ClassLoader and ProtectionDomain types - nobody needs to bind to those
|
||||
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
|
||||
// Ignore read-only properties such as ClassLoader - no need to bind to those
|
||||
continue;
|
||||
}
|
||||
this.propertyDescriptors.put(pd.getName(), pd);
|
||||
@@ -364,7 +368,7 @@ public final class CachedIntrospectionResults {
|
||||
|
||||
for (Method method : beanClass.getMethods()) {
|
||||
if (!this.propertyDescriptors.containsKey(method.getName()) &&
|
||||
!readMethodNames.contains((method.getName())) && isPlainAccessor(method)) {
|
||||
!readMethodNames.contains(method.getName()) && isPlainAccessor(method)) {
|
||||
this.propertyDescriptors.put(method.getName(),
|
||||
new GenericTypeAwarePropertyDescriptor(beanClass, method.getName(), method, null, null));
|
||||
readMethodNames.add(method.getName());
|
||||
@@ -373,8 +377,10 @@ public final class CachedIntrospectionResults {
|
||||
}
|
||||
|
||||
private boolean isPlainAccessor(Method method) {
|
||||
if (method.getParameterCount() > 0 || method.getReturnType() == void.class ||
|
||||
method.getDeclaringClass() == Object.class || Modifier.isStatic(method.getModifiers())) {
|
||||
if (Modifier.isStatic(method.getModifiers()) ||
|
||||
method.getDeclaringClass() == Object.class || method.getDeclaringClass() == Class.class ||
|
||||
method.getParameterCount() > 0 || method.getReturnType() == void.class ||
|
||||
isInvalidReadOnlyPropertyType(method.getReturnType())) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
@@ -387,6 +393,12 @@ public final class CachedIntrospectionResults {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInvalidReadOnlyPropertyType(@Nullable Class<?> returnType) {
|
||||
return (returnType != null && (AutoCloseable.class.isAssignableFrom(returnType) ||
|
||||
ClassLoader.class.isAssignableFrom(returnType) ||
|
||||
ProtectionDomain.class.isAssignableFrom(returnType)));
|
||||
}
|
||||
|
||||
|
||||
BeanInfo getBeanInfo() {
|
||||
return this.beanInfo;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,8 +23,9 @@ import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Common interface for classes that can access named properties
|
||||
* (such as bean properties of an object or fields in an object)
|
||||
* Serves as base interface for {@link BeanWrapper}.
|
||||
* (such as bean properties of an object or fields in an object).
|
||||
*
|
||||
* <p>Serves as base interface for {@link BeanWrapper}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Support package for the Java 6 ServiceLoader facility.
|
||||
* Support package for the Java {@link java.util.ServiceLoader} facility.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -985,7 +985,7 @@ class ConstructorResolver {
|
||||
|
||||
|
||||
/**
|
||||
* Delegate for checking Java 6's {@link ConstructorProperties} annotation.
|
||||
* Delegate for checking Java's {@link ConstructorProperties} annotation.
|
||||
*/
|
||||
private static class ConstructorPropertiesChecker {
|
||||
|
||||
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -585,7 +585,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (!matchFound) {
|
||||
// In case of FactoryBean, try to match FactoryBean instance itself next.
|
||||
beanName = FACTORY_BEAN_PREFIX + beanName;
|
||||
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
|
||||
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
|
||||
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matchFound) {
|
||||
|
||||
+7
-5
@@ -17,7 +17,7 @@
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
@@ -31,6 +31,8 @@ import org.springframework.lang.Nullable;
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @author Sam Brannen
|
||||
* @since 27.05.2003
|
||||
* @param <E> the element type
|
||||
*/
|
||||
@@ -55,16 +57,16 @@ public class ManagedList<E> extends ArrayList<E> implements Mergeable, BeanMetad
|
||||
|
||||
|
||||
/**
|
||||
* Return a new instance containing an arbitrary number of elements.
|
||||
* Create a new instance containing an arbitrary number of elements.
|
||||
* @param elements the elements to be contained in the list
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @return a {@code List} containing the specified elements
|
||||
* @return a {@code ManagedList} containing the specified elements
|
||||
* @since 5.3.16
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@SafeVarargs
|
||||
public static <E> ManagedList<E> of(E... elements) {
|
||||
ManagedList<E> list = new ManagedList<>();
|
||||
list.addAll(Arrays.asList(elements));
|
||||
Collections.addAll(list, elements);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
+7
-5
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -30,6 +30,8 @@ import org.springframework.lang.Nullable;
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Stephane Nicoll
|
||||
* @author Sam Brannen
|
||||
* @since 21.01.2004
|
||||
* @param <E> the element type
|
||||
*/
|
||||
@@ -54,16 +56,16 @@ public class ManagedSet<E> extends LinkedHashSet<E> implements Mergeable, BeanMe
|
||||
|
||||
|
||||
/**
|
||||
* Return a new instance containing an arbitrary number of elements.
|
||||
* Create a new instance containing an arbitrary number of elements.
|
||||
* @param elements the elements to be contained in the set
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @return a {@code Set} containing the specified elements
|
||||
* @return a {@code ManagedSet} containing the specified elements
|
||||
* @since 5.3.16
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@SafeVarargs
|
||||
public static <E> ManagedSet<E> of(E... elements) {
|
||||
ManagedSet<E> set = new ManagedSet<>();
|
||||
set.addAll(Arrays.asList(elements));
|
||||
Collections.addAll(set, elements);
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,6 +43,7 @@ import org.springframework.core.io.ContextResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceEditor;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.WritableResource;
|
||||
import org.springframework.core.io.support.ResourceArrayPropertyEditor;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
|
||||
@@ -102,6 +103,7 @@ public class ResourceEditorRegistrar implements PropertyEditorRegistrar {
|
||||
ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
|
||||
doRegisterEditor(registry, Resource.class, baseEditor);
|
||||
doRegisterEditor(registry, ContextResource.class, baseEditor);
|
||||
doRegisterEditor(registry, WritableResource.class, baseEditor);
|
||||
doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
|
||||
doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
|
||||
doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,7 +39,7 @@ inline fun <reified T : Any> ListableBeanFactory.getBeansOfType(includeNonSingle
|
||||
|
||||
/**
|
||||
* Extension for [ListableBeanFactory.getBeanNamesForAnnotation] providing a
|
||||
* `getBeansOfType<Foo>()` variant.
|
||||
* `getBeanNamesForAnnotation<Foo>()` variant.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 5.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author 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,6 +23,9 @@ import java.util.Optional;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.core.OverridingClassLoader;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -105,7 +108,7 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
|
||||
.satisfies(ex -> assertThat(ex.getPossibleMatches()).containsExactly("age"));
|
||||
}
|
||||
|
||||
@Test // Can't be shared; there is no such thing as a read-only field
|
||||
@Test // Can't be shared; there is no such thing as a read-only field
|
||||
void setReadOnlyMapProperty() {
|
||||
TypedReadOnlyMap map = new TypedReadOnlyMap(Collections.singletonMap("key", new TestBean()));
|
||||
TypedReadOnlyMapClient target = new TypedReadOnlyMapClient();
|
||||
@@ -151,18 +154,58 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void propertyDescriptors() {
|
||||
void propertyDescriptors() throws Exception {
|
||||
TestBean target = new TestBean();
|
||||
target.setSpouse(new TestBean());
|
||||
BeanWrapper accessor = createAccessor(target);
|
||||
accessor.setPropertyValue("name", "a");
|
||||
accessor.setPropertyValue("spouse.name", "b");
|
||||
|
||||
assertThat(target.getName()).isEqualTo("a");
|
||||
assertThat(target.getSpouse().getName()).isEqualTo("b");
|
||||
assertThat(accessor.getPropertyValue("name")).isEqualTo("a");
|
||||
assertThat(accessor.getPropertyValue("spouse.name")).isEqualTo("b");
|
||||
assertThat(accessor.getPropertyDescriptor("name").getPropertyType()).isEqualTo(String.class);
|
||||
assertThat(accessor.getPropertyDescriptor("spouse.name").getPropertyType()).isEqualTo(String.class);
|
||||
|
||||
assertThat(accessor.isReadableProperty("class.package")).isFalse();
|
||||
assertThat(accessor.isReadableProperty("class.module")).isFalse();
|
||||
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
|
||||
assertThat(accessor.isReadableProperty("class.name")).isTrue();
|
||||
assertThat(accessor.isReadableProperty("class.simpleName")).isTrue();
|
||||
assertThat(accessor.getPropertyValue("class.name")).isEqualTo(TestBean.class.getName());
|
||||
assertThat(accessor.getPropertyValue("class.simpleName")).isEqualTo(TestBean.class.getSimpleName());
|
||||
assertThat(accessor.getPropertyDescriptor("class.name").getPropertyType()).isEqualTo(String.class);
|
||||
assertThat(accessor.getPropertyDescriptor("class.simpleName").getPropertyType()).isEqualTo(String.class);
|
||||
|
||||
accessor = createAccessor(new DefaultResourceLoader());
|
||||
|
||||
assertThat(accessor.isReadableProperty("class.package")).isFalse();
|
||||
assertThat(accessor.isReadableProperty("class.module")).isFalse();
|
||||
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
|
||||
assertThat(accessor.isReadableProperty("class.name")).isTrue();
|
||||
assertThat(accessor.isReadableProperty("class.simpleName")).isTrue();
|
||||
assertThat(accessor.isReadableProperty("classLoader")).isTrue();
|
||||
assertThat(accessor.isWritableProperty("classLoader")).isTrue();
|
||||
OverridingClassLoader ocl = new OverridingClassLoader(getClass().getClassLoader());
|
||||
accessor.setPropertyValue("classLoader", ocl);
|
||||
assertThat(accessor.getPropertyValue("classLoader")).isSameAs(ocl);
|
||||
|
||||
accessor = createAccessor(new UrlResource("https://spring.io"));
|
||||
|
||||
assertThat(accessor.isReadableProperty("class.package")).isFalse();
|
||||
assertThat(accessor.isReadableProperty("class.module")).isFalse();
|
||||
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
|
||||
assertThat(accessor.isReadableProperty("class.name")).isTrue();
|
||||
assertThat(accessor.isReadableProperty("class.simpleName")).isTrue();
|
||||
assertThat(accessor.isReadableProperty("URL.protocol")).isTrue();
|
||||
assertThat(accessor.isReadableProperty("URL.host")).isTrue();
|
||||
assertThat(accessor.isReadableProperty("URL.port")).isTrue();
|
||||
assertThat(accessor.isReadableProperty("URL.file")).isTrue();
|
||||
assertThat(accessor.isReadableProperty("URL.content")).isFalse();
|
||||
assertThat(accessor.isReadableProperty("inputStream")).isFalse();
|
||||
assertThat(accessor.isReadableProperty("filename")).isTrue();
|
||||
assertThat(accessor.isReadableProperty("description")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+90
-107
@@ -26,7 +26,6 @@ import java.security.Principal;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -95,6 +94,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
@@ -178,10 +178,8 @@ class DefaultListableBeanFactoryTests {
|
||||
registerBeanDefinitions(p);
|
||||
|
||||
assertThat(!DummyFactory.wasPrototypeCreated()).as("prototype not instantiated").isTrue();
|
||||
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
|
||||
assertThat(beanNames).hasSize(0);
|
||||
beanNames = lbf.getBeanNamesForAnnotation(SuppressWarnings.class);
|
||||
assertThat(beanNames).hasSize(0);
|
||||
assertBeanNamesForType(TestBean.class, false, false);
|
||||
assertThat(lbf.getBeanNamesForAnnotation(SuppressWarnings.class)).isEmpty();
|
||||
|
||||
assertThat(lbf.containsSingleton("x1")).isFalse();
|
||||
assertThat(lbf.containsBean("x1")).isTrue();
|
||||
@@ -212,10 +210,8 @@ class DefaultListableBeanFactoryTests {
|
||||
registerBeanDefinitions(p);
|
||||
|
||||
assertThat(!DummyFactory.wasPrototypeCreated()).as("prototype not instantiated").isTrue();
|
||||
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
|
||||
assertThat(beanNames).hasSize(0);
|
||||
beanNames = lbf.getBeanNamesForAnnotation(SuppressWarnings.class);
|
||||
assertThat(beanNames).hasSize(0);
|
||||
assertBeanNamesForType(TestBean.class, false, false);
|
||||
assertThat(lbf.getBeanNamesForAnnotation(SuppressWarnings.class)).isEmpty();
|
||||
|
||||
assertThat(lbf.containsSingleton("x1")).isFalse();
|
||||
assertThat(lbf.containsBean("x1")).isTrue();
|
||||
@@ -245,10 +241,8 @@ class DefaultListableBeanFactoryTests {
|
||||
registerBeanDefinitions(p);
|
||||
|
||||
assertThat(!DummyFactory.wasPrototypeCreated()).as("prototype not instantiated").isTrue();
|
||||
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
|
||||
assertThat(beanNames).hasSize(0);
|
||||
beanNames = lbf.getBeanNamesForAnnotation(SuppressWarnings.class);
|
||||
assertThat(beanNames).hasSize(0);
|
||||
assertBeanNamesForType(TestBean.class, false, false);
|
||||
assertThat(lbf.getBeanNamesForAnnotation(SuppressWarnings.class)).isEmpty();
|
||||
|
||||
assertThat(lbf.containsSingleton("x1")).isFalse();
|
||||
assertThat(lbf.containsBean("x1")).isTrue();
|
||||
@@ -278,10 +272,8 @@ class DefaultListableBeanFactoryTests {
|
||||
registerBeanDefinitions(p);
|
||||
lbf.preInstantiateSingletons();
|
||||
|
||||
assertThat(!DummyFactory.wasPrototypeCreated()).as("prototype not instantiated").isTrue();
|
||||
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
|
||||
assertThat(beanNames).hasSize(1);
|
||||
assertThat(beanNames[0]).isEqualTo("x1");
|
||||
assertThat(DummyFactory.wasPrototypeCreated()).as("prototype not instantiated").isFalse();
|
||||
assertBeanNamesForType(TestBean.class, true, false, "x1");
|
||||
assertThat(lbf.containsSingleton("x1")).isTrue();
|
||||
assertThat(lbf.containsBean("x1")).isTrue();
|
||||
assertThat(lbf.containsBean("&x1")).isTrue();
|
||||
@@ -316,14 +308,10 @@ class DefaultListableBeanFactoryTests {
|
||||
assertThat(lbf.isTypeMatch("&x2", Object.class)).isTrue();
|
||||
assertThat(lbf.getType("x2")).isEqualTo(TestBean.class);
|
||||
assertThat(lbf.getType("&x2")).isEqualTo(DummyFactory.class);
|
||||
assertThat(lbf.getAliases("x1").length).isEqualTo(1);
|
||||
assertThat(lbf.getAliases("x1")[0]).isEqualTo("x2");
|
||||
assertThat(lbf.getAliases("&x1").length).isEqualTo(1);
|
||||
assertThat(lbf.getAliases("&x1")[0]).isEqualTo("&x2");
|
||||
assertThat(lbf.getAliases("x2").length).isEqualTo(1);
|
||||
assertThat(lbf.getAliases("x2")[0]).isEqualTo("x1");
|
||||
assertThat(lbf.getAliases("&x2").length).isEqualTo(1);
|
||||
assertThat(lbf.getAliases("&x2")[0]).isEqualTo("&x1");
|
||||
assertThat(lbf.getAliases("x1")).containsExactly("x2");
|
||||
assertThat(lbf.getAliases("&x1")).containsExactly("&x2");
|
||||
assertThat(lbf.getAliases("x2")).containsExactly("x1");
|
||||
assertThat(lbf.getAliases("&x2")).containsExactly("&x1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -333,9 +321,7 @@ class DefaultListableBeanFactoryTests {
|
||||
lbf.registerBeanDefinition("x1", rbd);
|
||||
|
||||
TestBeanFactory.initialized = false;
|
||||
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
|
||||
assertThat(beanNames).hasSize(1);
|
||||
assertThat(beanNames[0]).isEqualTo("x1");
|
||||
assertBeanNamesForType(TestBean.class, true, false, "x1");
|
||||
assertThat(lbf.containsSingleton("x1")).isFalse();
|
||||
assertThat(lbf.containsBean("x1")).isTrue();
|
||||
assertThat(lbf.containsBean("&x1")).isFalse();
|
||||
@@ -358,9 +344,7 @@ class DefaultListableBeanFactoryTests {
|
||||
lbf.registerBeanDefinition("x1", rbd);
|
||||
|
||||
TestBeanFactory.initialized = false;
|
||||
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
|
||||
assertThat(beanNames).hasSize(1);
|
||||
assertThat(beanNames[0]).isEqualTo("x1");
|
||||
assertBeanNamesForType(TestBean.class, true, false, "x1");
|
||||
assertThat(lbf.containsSingleton("x1")).isFalse();
|
||||
assertThat(lbf.containsBean("x1")).isTrue();
|
||||
assertThat(lbf.containsBean("&x1")).isFalse();
|
||||
@@ -385,9 +369,7 @@ class DefaultListableBeanFactoryTests {
|
||||
lbf.registerBeanDefinition("x1", rbd);
|
||||
|
||||
TestBeanFactory.initialized = false;
|
||||
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
|
||||
assertThat(beanNames).hasSize(1);
|
||||
assertThat(beanNames[0]).isEqualTo("x1");
|
||||
assertBeanNamesForType(TestBean.class, true, false, "x1");
|
||||
assertThat(lbf.containsSingleton("x1")).isFalse();
|
||||
assertThat(lbf.containsBean("x1")).isTrue();
|
||||
assertThat(lbf.containsBean("&x1")).isFalse();
|
||||
@@ -413,9 +395,7 @@ class DefaultListableBeanFactoryTests {
|
||||
lbf.registerBeanDefinition("x1", rbd);
|
||||
|
||||
TestBeanFactory.initialized = false;
|
||||
String[] beanNames = lbf.getBeanNamesForType(TestBean.class, true, false);
|
||||
assertThat(beanNames).hasSize(1);
|
||||
assertThat(beanNames[0]).isEqualTo("x1");
|
||||
assertBeanNamesForType(TestBean.class, true, false, "x1");
|
||||
assertThat(lbf.containsSingleton("x1")).isFalse();
|
||||
assertThat(lbf.containsBean("x1")).isTrue();
|
||||
assertThat(lbf.containsBean("&x1")).isFalse();
|
||||
@@ -448,14 +428,10 @@ class DefaultListableBeanFactoryTests {
|
||||
assertThat(lbf.isTypeMatch("&x2", Object.class)).isFalse();
|
||||
assertThat(lbf.getType("x2")).isEqualTo(TestBean.class);
|
||||
assertThat(lbf.getType("&x2")).isNull();
|
||||
assertThat(lbf.getAliases("x1").length).isEqualTo(1);
|
||||
assertThat(lbf.getAliases("x1")[0]).isEqualTo("x2");
|
||||
assertThat(lbf.getAliases("&x1").length).isEqualTo(1);
|
||||
assertThat(lbf.getAliases("&x1")[0]).isEqualTo("&x2");
|
||||
assertThat(lbf.getAliases("x2").length).isEqualTo(1);
|
||||
assertThat(lbf.getAliases("x2")[0]).isEqualTo("x1");
|
||||
assertThat(lbf.getAliases("&x2").length).isEqualTo(1);
|
||||
assertThat(lbf.getAliases("&x2")[0]).isEqualTo("&x1");
|
||||
assertThat(lbf.getAliases("x1")).containsExactly("x2");
|
||||
assertThat(lbf.getAliases("&x1")).containsExactly("&x2");
|
||||
assertThat(lbf.getAliases("x2")).containsExactly("x1");
|
||||
assertThat(lbf.getAliases("&x2")).containsExactly("&x1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -619,8 +595,7 @@ class DefaultListableBeanFactoryTests {
|
||||
lbf.registerSingleton("string", "A");
|
||||
|
||||
TestBean self = (TestBean) lbf.getBean("self");
|
||||
assertThat(self.getStringArray()).hasSize(1);
|
||||
assertThat(self.getStringArray()).contains("A");
|
||||
assertThat(self.getStringArray()).containsExactly("A");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -633,8 +608,7 @@ class DefaultListableBeanFactoryTests {
|
||||
lbf.registerSingleton("string", "A");
|
||||
|
||||
TestBean self = (TestBean) lbf.getBean("self");
|
||||
assertThat(self.getStringArray()).hasSize(1);
|
||||
assertThat(self.getStringArray()).contains("A");
|
||||
assertThat(self.getStringArray()).containsExactly("A");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -666,8 +640,7 @@ class DefaultListableBeanFactoryTests {
|
||||
.withCauseInstanceOf(NotWritablePropertyException.class)
|
||||
.satisfies(ex -> {
|
||||
NotWritablePropertyException cause = (NotWritablePropertyException) ex.getCause();
|
||||
assertThat(cause.getPossibleMatches()).hasSize(1);
|
||||
assertThat(cause.getPossibleMatches()[0]).isEqualTo("age");
|
||||
assertThat(cause.getPossibleMatches()).containsExactly("age");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -685,7 +658,7 @@ class DefaultListableBeanFactoryTests {
|
||||
lbf = new DefaultListableBeanFactory();
|
||||
p = new Properties();
|
||||
p.setProperty("kerry.(class)", TestBean.class.getName());
|
||||
p.setProperty("kerry.(scope)", "prototype");
|
||||
p.setProperty("kerry.(scope)", BeanDefinition.SCOPE_PROTOTYPE);
|
||||
p.setProperty("kerry.age", "35");
|
||||
registerBeanDefinitions(p);
|
||||
kerry1 = (TestBean) lbf.getBean("kerry");
|
||||
@@ -1145,7 +1118,7 @@ class DefaultListableBeanFactoryTests {
|
||||
assertThat(lbf.containsBean("singletonObject")).isTrue();
|
||||
assertThat(lbf.isSingleton("singletonObject")).isTrue();
|
||||
assertThat(lbf.getType("singletonObject")).isEqualTo(TestBean.class);
|
||||
assertThat(lbf.getAliases("singletonObject").length).isEqualTo(0);
|
||||
assertThat(lbf.getAliases("singletonObject")).isEmpty();
|
||||
DependenciesBean test = (DependenciesBean) lbf.getBean("test");
|
||||
assertThat(lbf.getBean("singletonObject")).isEqualTo(singletonObject);
|
||||
assertThat(test.getSpouse()).isEqualTo(singletonObject);
|
||||
@@ -1791,12 +1764,12 @@ class DefaultListableBeanFactoryTests {
|
||||
assertThat(bean.beanName).isEqualTo("bd1");
|
||||
assertThat(bean.spouseAge).isEqualTo(42);
|
||||
|
||||
assertThat(lbf.getBeanNamesForType(ConstructorDependency.class).length).isEqualTo(1);
|
||||
assertThat(lbf.getBeanNamesForType(ConstructorDependencyFactoryBean.class).length).isEqualTo(1);
|
||||
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class)).length).isEqualTo(1);
|
||||
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class)).length).isEqualTo(0);
|
||||
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class), true, true).length).isEqualTo(1);
|
||||
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class), true, true).length).isEqualTo(0);
|
||||
assertThat(lbf.getBeanNamesForType(ConstructorDependency.class)).hasSize(1);
|
||||
assertThat(lbf.getBeanNamesForType(ConstructorDependencyFactoryBean.class)).hasSize(1);
|
||||
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class))).hasSize(1);
|
||||
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class))).isEmpty();
|
||||
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class), true, true)).hasSize(1);
|
||||
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class), true, true)).isEmpty();
|
||||
}
|
||||
|
||||
private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) {
|
||||
@@ -1861,46 +1834,45 @@ class DefaultListableBeanFactoryTests {
|
||||
|
||||
@Test
|
||||
void getBeanNamesForTypeBeforeFactoryBeanCreation() {
|
||||
FactoryBeanThatShouldntBeCalled.instantiated = false;
|
||||
lbf.registerBeanDefinition("factoryBean", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class));
|
||||
assertThat(lbf.containsSingleton("factoryBean")).isFalse();
|
||||
assertThat(FactoryBeanThatShouldntBeCalled.instantiated).isFalse();
|
||||
|
||||
String[] beanNames = lbf.getBeanNamesForType(Runnable.class, false, false);
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
assertThat(beanNames[0]).isEqualTo("&factoryBean");
|
||||
|
||||
beanNames = lbf.getBeanNamesForType(Callable.class, false, false);
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
assertThat(beanNames[0]).isEqualTo("&factoryBean");
|
||||
|
||||
beanNames = lbf.getBeanNamesForType(RepositoryFactoryInformation.class, false, false);
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
assertThat(beanNames[0]).isEqualTo("&factoryBean");
|
||||
|
||||
beanNames = lbf.getBeanNamesForType(FactoryBean.class, false, false);
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
assertThat(beanNames[0]).isEqualTo("&factoryBean");
|
||||
assertBeanNamesForType(Runnable.class, false, false, "&factoryBean");
|
||||
assertBeanNamesForType(Callable.class, false, false, "&factoryBean");
|
||||
assertBeanNamesForType(RepositoryFactoryInformation.class, false, false, "&factoryBean");
|
||||
assertBeanNamesForType(FactoryBean.class, false, false, "&factoryBean");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanNamesForTypeAfterFactoryBeanCreation() {
|
||||
FactoryBeanThatShouldntBeCalled.instantiated = false;
|
||||
lbf.registerBeanDefinition("factoryBean", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class));
|
||||
lbf.getBean("&factoryBean");
|
||||
assertThat(FactoryBeanThatShouldntBeCalled.instantiated).isTrue();
|
||||
assertThat(lbf.containsSingleton("factoryBean")).isTrue();
|
||||
|
||||
String[] beanNames = lbf.getBeanNamesForType(Runnable.class, false, false);
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
assertThat(beanNames[0]).isEqualTo("&factoryBean");
|
||||
assertBeanNamesForType(Runnable.class, false, false, "&factoryBean");
|
||||
assertBeanNamesForType(Callable.class, false, false, "&factoryBean");
|
||||
assertBeanNamesForType(RepositoryFactoryInformation.class, false, false, "&factoryBean");
|
||||
assertBeanNamesForType(FactoryBean.class, false, false, "&factoryBean");
|
||||
}
|
||||
|
||||
beanNames = lbf.getBeanNamesForType(Callable.class, false, false);
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
assertThat(beanNames[0]).isEqualTo("&factoryBean");
|
||||
@Test // gh-28616
|
||||
void getBeanNamesForTypeWithPrototypeScopedFactoryBean() {
|
||||
FactoryBeanThatShouldntBeCalled.instantiated = false;
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class);
|
||||
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
lbf.registerBeanDefinition("factoryBean", beanDefinition);
|
||||
assertThat(FactoryBeanThatShouldntBeCalled.instantiated).isFalse();
|
||||
assertThat(lbf.containsSingleton("factoryBean")).isFalse();
|
||||
|
||||
beanNames = lbf.getBeanNamesForType(RepositoryFactoryInformation.class, false, false);
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
assertThat(beanNames[0]).isEqualTo("&factoryBean");
|
||||
|
||||
beanNames = lbf.getBeanNamesForType(FactoryBean.class, false, false);
|
||||
assertThat(beanNames.length).isEqualTo(1);
|
||||
assertThat(beanNames[0]).isEqualTo("&factoryBean");
|
||||
// We should not find any beans of the following types if the FactoryBean itself is prototype-scoped.
|
||||
assertBeanNamesForType(Runnable.class, false, false);
|
||||
assertBeanNamesForType(Callable.class, false, false);
|
||||
assertBeanNamesForType(RepositoryFactoryInformation.class, false, false);
|
||||
assertBeanNamesForType(FactoryBean.class, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2165,8 +2137,7 @@ class DefaultListableBeanFactoryTests {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyBean.class);
|
||||
bd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
|
||||
lbf.registerBeanDefinition("test", bd);
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
|
||||
lbf::preInstantiateSingletons);
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(lbf::preInstantiateSingletons);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2174,8 +2145,7 @@ class DefaultListableBeanFactoryTests {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyFactoryBean.class);
|
||||
bd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
|
||||
lbf.registerBeanDefinition("test", bd);
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
|
||||
lbf::preInstantiateSingletons);
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(lbf::preInstantiateSingletons);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2183,8 +2153,7 @@ class DefaultListableBeanFactoryTests {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyFactoryBean.class);
|
||||
bd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
|
||||
lbf.registerBeanDefinition("test", bd);
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() ->
|
||||
lbf.getBeansOfType(String.class));
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() -> lbf.getBeansOfType(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2211,8 +2180,7 @@ class DefaultListableBeanFactoryTests {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependencyWithClassResolution.class);
|
||||
bd.getConstructorArgumentValues().addGenericArgumentValue("java.lang.Strin");
|
||||
lbf.registerBeanDefinition("test", bd);
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
|
||||
lbf::preInstantiateSingletons);
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(lbf::preInstantiateSingletons);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2236,7 +2204,13 @@ class DefaultListableBeanFactoryTests {
|
||||
@Test
|
||||
void prototypeFactoryBeanNotEagerlyCalled() {
|
||||
lbf.registerBeanDefinition("test", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class));
|
||||
lbf.preInstantiateSingletons();
|
||||
assertThatNoException().isThrownBy(lbf::preInstantiateSingletons);
|
||||
}
|
||||
|
||||
@Test
|
||||
void prototypeFactoryBeanNotEagerlyCalledInCaseOfBeanClassName() {
|
||||
lbf.registerBeanDefinition("test", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class.getName(), null, null));
|
||||
assertThatNoException().isThrownBy(lbf::preInstantiateSingletons);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2276,13 +2250,6 @@ class DefaultListableBeanFactoryTests {
|
||||
assertThat(factory.initialized).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void prototypeFactoryBeanNotEagerlyCalledInCaseOfBeanClassName() {
|
||||
lbf.registerBeanDefinition("test",
|
||||
new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class.getName(), null, null));
|
||||
lbf.preInstantiateSingletons();
|
||||
}
|
||||
|
||||
@Test
|
||||
void prototypeStringCreatedRepeatedly() {
|
||||
RootBeanDefinition stringDef = new RootBeanDefinition(String.class);
|
||||
@@ -2462,10 +2429,7 @@ class DefaultListableBeanFactoryTests {
|
||||
lbf.registerBeanDefinition("fmWithArgs", factoryMethodDefinitionWithArgs);
|
||||
|
||||
assertThat(lbf.getBeanDefinitionCount()).isEqualTo(4);
|
||||
List<String> tbNames = Arrays.asList(lbf.getBeanNamesForType(TestBean.class));
|
||||
assertThat(tbNames.contains("fmWithProperties")).isTrue();
|
||||
assertThat(tbNames.contains("fmWithArgs")).isTrue();
|
||||
assertThat(tbNames.size()).isEqualTo(2);
|
||||
assertBeanNamesForType(TestBean.class, true, true, "fmWithProperties", "fmWithArgs");
|
||||
|
||||
TestBean tb = (TestBean) lbf.getBean("fmWithProperties");
|
||||
TestBean second = (TestBean) lbf.getBean("fmWithProperties");
|
||||
@@ -2669,6 +2633,19 @@ class DefaultListableBeanFactoryTests {
|
||||
return (new org.springframework.beans.factory.support.PropertiesBeanDefinitionReader(lbf)).registerBeanDefinitions(p, prefix);
|
||||
}
|
||||
|
||||
private void assertBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit, String... names) {
|
||||
if (names.length == 0) {
|
||||
assertThat(lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit))
|
||||
.as("bean names for type " + type.getName())
|
||||
.isEmpty();
|
||||
}
|
||||
else {
|
||||
assertThat(lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit))
|
||||
.as("bean names for type " + type.getName())
|
||||
.containsExactly(names);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class NoDependencies {
|
||||
|
||||
@@ -2859,6 +2836,12 @@ class DefaultListableBeanFactoryTests {
|
||||
public static class FactoryBeanThatShouldntBeCalled<T extends Repository<S, ID>, S, ID extends Serializable>
|
||||
extends RepositoryFactoryBeanSupport<T, S, ID> implements Runnable, Callable<T> {
|
||||
|
||||
static boolean instantiated = false;
|
||||
|
||||
{
|
||||
instantiated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getObject() {
|
||||
throw new IllegalStateException();
|
||||
|
||||
+14
-14
@@ -25,61 +25,61 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ManagedList}.
|
||||
*
|
||||
* @author Rick Evans
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public class ManagedListTests {
|
||||
class ManagedListTests {
|
||||
|
||||
@Test
|
||||
public void mergeSunnyDay() {
|
||||
void mergeSunnyDay() {
|
||||
ManagedList parent = ManagedList.of("one", "two");
|
||||
ManagedList child = ManagedList.of("three");
|
||||
child.setMergeEnabled(true);
|
||||
List mergedList = child.merge(parent);
|
||||
assertThat(mergedList.size()).as("merge() obviously did not work.").isEqualTo(3);
|
||||
assertThat(mergedList).as("merge() obviously did not work.").containsExactly("one", "two", "three");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeWithNullParent() {
|
||||
void mergeWithNullParent() {
|
||||
ManagedList child = ManagedList.of("one");
|
||||
child.setMergeEnabled(true);
|
||||
assertThat(child.merge(null)).isSameAs(child);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeNotAllowedWhenMergeNotEnabled() {
|
||||
void mergeNotAllowedWhenMergeNotEnabled() {
|
||||
ManagedList child = new ManagedList();
|
||||
assertThatIllegalStateException().isThrownBy(() ->
|
||||
child.merge(null));
|
||||
assertThatIllegalStateException().isThrownBy(() -> child.merge(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeWithNonCompatibleParentType() {
|
||||
void mergeWithIncompatibleParentType() {
|
||||
ManagedList child = ManagedList.of("one");
|
||||
child.setMergeEnabled(true);
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
child.merge("hello"));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> child.merge("hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeEmptyChild() {
|
||||
void mergeEmptyChild() {
|
||||
ManagedList parent = ManagedList.of("one", "two");
|
||||
ManagedList child = new ManagedList();
|
||||
child.setMergeEnabled(true);
|
||||
List mergedList = child.merge(parent);
|
||||
assertThat(mergedList.size()).as("merge() obviously did not work.").isEqualTo(2);
|
||||
assertThat(mergedList).as("merge() obviously did not work.").containsExactly("one", "two");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeChildValuesOverrideTheParents() {
|
||||
void mergedChildValuesDoNotOverrideTheParents() {
|
||||
// doesn't make much sense in the context of a list...
|
||||
ManagedList parent = ManagedList.of("one", "two");
|
||||
ManagedList child = ManagedList.of("one");
|
||||
child.setMergeEnabled(true);
|
||||
List mergedList = child.merge(parent);
|
||||
assertThat(mergedList.size()).as("merge() obviously did not work.").isEqualTo(3);
|
||||
assertThat(mergedList).as("merge() obviously did not work.").containsExactly("one", "two", "one");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-14
@@ -25,61 +25,62 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ManagedSet}.
|
||||
*
|
||||
* @author Rick Evans
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public class ManagedSetTests {
|
||||
class ManagedSetTests {
|
||||
|
||||
@Test
|
||||
public void mergeSunnyDay() {
|
||||
void mergeSunnyDay() {
|
||||
ManagedSet parent = ManagedSet.of("one", "two");
|
||||
ManagedSet child = ManagedSet.of("three");
|
||||
child.add("three");
|
||||
child.add("four");
|
||||
child.setMergeEnabled(true);
|
||||
Set mergedSet = child.merge(parent);
|
||||
assertThat(mergedSet.size()).as("merge() obviously did not work.").isEqualTo(3);
|
||||
assertThat(mergedSet).as("merge() obviously did not work.").containsExactly("one", "two", "three", "four");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeWithNullParent() {
|
||||
void mergeWithNullParent() {
|
||||
ManagedSet child = ManagedSet.of("one");
|
||||
child.setMergeEnabled(true);
|
||||
assertThat(child.merge(null)).isSameAs(child);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeNotAllowedWhenMergeNotEnabled() {
|
||||
assertThatIllegalStateException().isThrownBy(() ->
|
||||
new ManagedSet().merge(null));
|
||||
void mergeNotAllowedWhenMergeNotEnabled() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> new ManagedSet().merge(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeWithNonCompatibleParentType() {
|
||||
void mergeWithNonCompatibleParentType() {
|
||||
ManagedSet child = ManagedSet.of("one");
|
||||
child.setMergeEnabled(true);
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
child.merge("hello"));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> child.merge("hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeEmptyChild() {
|
||||
void mergeEmptyChild() {
|
||||
ManagedSet parent = ManagedSet.of("one", "two");
|
||||
ManagedSet child = new ManagedSet();
|
||||
child.setMergeEnabled(true);
|
||||
Set mergedSet = child.merge(parent);
|
||||
assertThat(mergedSet.size()).as("merge() obviously did not work.").isEqualTo(2);
|
||||
assertThat(mergedSet).as("merge() obviously did not work.").containsExactly("one", "two");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeChildValuesOverrideTheParents() {
|
||||
void mergeChildValuesOverrideTheParents() {
|
||||
// asserts that the set contract is not violated during a merge() operation...
|
||||
ManagedSet parent = ManagedSet.of("one", "two");
|
||||
ManagedSet child = ManagedSet.of("one");
|
||||
child.setMergeEnabled(true);
|
||||
Set mergedSet = child.merge(parent);
|
||||
assertThat(mergedSet.size()).as("merge() obviously did not work.").isEqualTo(2);
|
||||
assertThat(mergedSet).as("merge() obviously did not work.").containsExactly("one", "two");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-2
@@ -58,6 +58,7 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.testfixture.security.TestPrincipal;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
@@ -303,14 +304,14 @@ public class CallbacksSecurityTests {
|
||||
Method method = bean.getClass().getMethod("destroy");
|
||||
method.setAccessible(true);
|
||||
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
|
||||
assertThatException().isThrownBy(() ->
|
||||
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
|
||||
method.invoke(bean);
|
||||
return null;
|
||||
}, acc));
|
||||
|
||||
Class<ConstructorBean> cl = ConstructorBean.class;
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
|
||||
assertThatException().isThrownBy(() ->
|
||||
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
|
||||
cl.newInstance(), acc));
|
||||
}
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,8 +23,7 @@ import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
|
||||
/**
|
||||
* With Spring 3.1, bean id attributes (and all other id attributes across the
|
||||
@@ -40,22 +39,23 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanFactoryTests#withDuplicateName
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanFactoryTests#withDuplicateNameInAlias
|
||||
*/
|
||||
public class DuplicateBeanIdTests {
|
||||
class DuplicateBeanIdTests {
|
||||
|
||||
@Test
|
||||
public void duplicateBeanIdsWithinSameNestingLevelRaisesError() {
|
||||
void duplicateBeanIdsWithinSameNestingLevelRaisesError() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf);
|
||||
assertThatExceptionOfType(Exception.class).as("duplicate ids in same nesting level").isThrownBy(() ->
|
||||
assertThatException().as("duplicate ids in same nesting level").isThrownBy(() ->
|
||||
reader.loadBeanDefinitions(new ClassPathResource("DuplicateBeanIdTests-sameLevel-context.xml", this.getClass())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void duplicateBeanIdsAcrossNestingLevels() {
|
||||
void duplicateBeanIdsAcrossNestingLevels() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf);
|
||||
reader.loadBeanDefinitions(new ClassPathResource("DuplicateBeanIdTests-multiLevel-context.xml", this.getClass()));
|
||||
TestBean testBean = bf.getBean(TestBean.class); // there should be only one
|
||||
assertThat(testBean.getName()).isEqualTo("nested");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,7 @@ import javax.lang.model.element.Element;
|
||||
|
||||
/**
|
||||
* Provide the list of stereotypes that match an {@link Element}.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,7 +40,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.contextsupport.testfixture.jcache.JCacheableService;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
|
||||
|
||||
/**
|
||||
* @author Stephane Nicoll
|
||||
@@ -86,8 +86,8 @@ public class JCacheCustomInterceptorTests {
|
||||
|
||||
@Test
|
||||
public void customInterceptorAppliesWithCheckedException() {
|
||||
assertThatExceptionOfType(RuntimeException.class).isThrownBy(() ->
|
||||
cs.cacheWithCheckedException("id", true))
|
||||
assertThatRuntimeException()
|
||||
.isThrownBy(() -> cs.cacheWithCheckedException("id", true))
|
||||
.withCauseExactlyInstanceOf(IOException.class);
|
||||
}
|
||||
|
||||
|
||||
+90
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author 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 java.util.Set;
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import javax.validation.ConstraintValidatorFactory;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Payload;
|
||||
import javax.validation.Valid;
|
||||
@@ -43,6 +44,7 @@ import org.hibernate.validator.HibernateValidatorFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
@@ -52,18 +54,18 @@ import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public class ValidatorFactoryTests {
|
||||
class ValidatorFactoryTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("cast")
|
||||
public void testSimpleValidation() {
|
||||
void simpleValidation() {
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
@@ -78,15 +80,15 @@ public class ValidatorFactoryTests {
|
||||
|
||||
Validator nativeValidator = validator.unwrap(Validator.class);
|
||||
assertThat(nativeValidator.getClass().getName().startsWith("org.hibernate")).isTrue();
|
||||
assertThat(validator.unwrap(ValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
|
||||
assertThat(validator.unwrap(HibernateValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
|
||||
assertThat(validator.unwrap(ValidatorFactory.class)).isInstanceOf(HibernateValidatorFactory.class);
|
||||
assertThat(validator.unwrap(HibernateValidatorFactory.class)).isInstanceOf(HibernateValidatorFactory.class);
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("cast")
|
||||
public void testSimpleValidationWithCustomProvider() {
|
||||
void simpleValidationWithCustomProvider() {
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.setProviderClass(HibernateValidator.class);
|
||||
validator.afterPropertiesSet();
|
||||
@@ -102,14 +104,15 @@ public class ValidatorFactoryTests {
|
||||
|
||||
Validator nativeValidator = validator.unwrap(Validator.class);
|
||||
assertThat(nativeValidator.getClass().getName().startsWith("org.hibernate")).isTrue();
|
||||
assertThat(validator.unwrap(ValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
|
||||
assertThat(validator.unwrap(HibernateValidatorFactory.class) instanceof HibernateValidatorFactory).isTrue();
|
||||
assertThat(validator.unwrap(ValidatorFactory.class)).isInstanceOf(HibernateValidatorFactory.class);
|
||||
assertThat(validator.unwrap(HibernateValidatorFactory.class)).isInstanceOf(HibernateValidatorFactory.class);
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleValidationWithClassLevel() {
|
||||
void simpleValidationWithClassLevel() {
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
@@ -122,10 +125,13 @@ public class ValidatorFactoryTests {
|
||||
ConstraintViolation<?> cv = iterator.next();
|
||||
assertThat(cv.getPropertyPath().toString()).isEqualTo("");
|
||||
assertThat(cv.getConstraintDescriptor().getAnnotation() instanceof NameAddressValid).isTrue();
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidationFieldType() {
|
||||
void springValidationFieldType() {
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
@@ -135,11 +141,16 @@ public class ValidatorFactoryTests {
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(person, "person");
|
||||
validator.validate(person, errors);
|
||||
assertThat(errors.getErrorCount()).isEqualTo(1);
|
||||
assertThat(errors.getFieldError("address").getRejectedValue()).isInstanceOf(ValidAddress.class);
|
||||
assertThat(errors.getFieldError("address").getRejectedValue())
|
||||
.as("Field/Value type mismatch")
|
||||
.isInstanceOf(ValidAddress.class);
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidation() {
|
||||
void springValidation() {
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
@@ -164,10 +175,13 @@ public class ValidatorFactoryTests {
|
||||
assertThat(errorCodes.contains("NotNull.street")).isTrue();
|
||||
assertThat(errorCodes.contains("NotNull.java.lang.String")).isTrue();
|
||||
assertThat(errorCodes.contains("NotNull")).isTrue();
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidationWithClassLevel() {
|
||||
void springValidationWithClassLevel() {
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
@@ -182,10 +196,12 @@ public class ValidatorFactoryTests {
|
||||
assertThat(errorCodes.size()).isEqualTo(2);
|
||||
assertThat(errorCodes.contains("NameAddressValid.person")).isTrue();
|
||||
assertThat(errorCodes.contains("NameAddressValid")).isTrue();
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidationWithAutowiredValidator() {
|
||||
void springValidationWithAutowiredValidator() {
|
||||
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(
|
||||
LocalValidatorFactoryBean.class);
|
||||
LocalValidatorFactoryBean validator = ctx.getBean(LocalValidatorFactoryBean.class);
|
||||
@@ -202,11 +218,14 @@ public class ValidatorFactoryTests {
|
||||
assertThat(errorCodes.size()).isEqualTo(2);
|
||||
assertThat(errorCodes.contains("NameAddressValid.person")).isTrue();
|
||||
assertThat(errorCodes.contains("NameAddressValid")).isTrue();
|
||||
|
||||
validator.destroy();
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidationWithErrorInListElement() {
|
||||
void springValidationWithErrorInListElement() {
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
@@ -221,10 +240,13 @@ public class ValidatorFactoryTests {
|
||||
assertThat(fieldError.getField()).isEqualTo("address.street");
|
||||
fieldError = result.getFieldError("addressList[0].street");
|
||||
assertThat(fieldError.getField()).isEqualTo("addressList[0].street");
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringValidationWithErrorInSetElement() {
|
||||
void springValidationWithErrorInSetElement() {
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
@@ -239,10 +261,13 @@ public class ValidatorFactoryTests {
|
||||
assertThat(fieldError.getField()).isEqualTo("address.street");
|
||||
fieldError = result.getFieldError("addressSet[].street");
|
||||
assertThat(fieldError.getField()).isEqualTo("addressSet[].street");
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInnerBeanValidation() {
|
||||
void innerBeanValidation() {
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
@@ -251,10 +276,13 @@ public class ValidatorFactoryTests {
|
||||
validator.validate(mainBean, errors);
|
||||
Object rejected = errors.getFieldValue("inner.value");
|
||||
assertThat(rejected).isNull();
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidationWithOptionalField() {
|
||||
void validationWithOptionalField() {
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
@@ -263,10 +291,13 @@ public class ValidatorFactoryTests {
|
||||
validator.validate(mainBean, errors);
|
||||
Object rejected = errors.getFieldValue("inner.value");
|
||||
assertThat(rejected).isNull();
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListValidation() {
|
||||
void listValidation() {
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
@@ -282,6 +313,34 @@ public class ValidatorFactoryTests {
|
||||
assertThat(fieldError).isNotNull();
|
||||
assertThat(fieldError.getRejectedValue()).isEqualTo("X");
|
||||
assertThat(errors.getFieldValue("list[1]")).isEqualTo("X");
|
||||
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
void withConstraintValidatorFactory() {
|
||||
ConstraintValidatorFactory cvf = new SpringConstraintValidatorFactory(new DefaultListableBeanFactory());
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.setConstraintValidatorFactory(cvf);
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
assertThat(validator.getConstraintValidatorFactory()).isSameAs(cvf);
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
void withCustomInitializer() {
|
||||
ConstraintValidatorFactory cvf = new SpringConstraintValidatorFactory(new DefaultListableBeanFactory());
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.setConfigurationInitializer(configuration -> configuration.constraintValidatorFactory(cvf));
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
assertThat(validator.getConstraintValidatorFactory()).isSameAs(cvf);
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
|
||||
@@ -380,8 +439,8 @@ public class ValidatorFactoryTests {
|
||||
}
|
||||
boolean valid = (value.name == null || !value.address.street.contains(value.name));
|
||||
if (!valid && "Phil".equals(value.name)) {
|
||||
context.buildConstraintViolationWithTemplate(
|
||||
context.getDefaultConstraintMessageTemplate()).addPropertyNode("address").addConstraintViolation().disableDefaultConstraintViolation();
|
||||
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
|
||||
.addPropertyNode("address").addConstraintViolation().disableDefaultConstraintViolation();
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
@@ -417,6 +476,7 @@ public class ValidatorFactoryTests {
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
@@ -425,8 +485,8 @@ public class ValidatorFactoryTests {
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Constraint(validatedBy=InnerValidator.class)
|
||||
public static @interface InnerValid {
|
||||
@Constraint(validatedBy = InnerValidator.class)
|
||||
public @interface InnerValid {
|
||||
|
||||
String message() default "NOT VALID";
|
||||
|
||||
@@ -446,7 +506,8 @@ public class ValidatorFactoryTests {
|
||||
public boolean isValid(InnerBean bean, ConstraintValidatorContext context) {
|
||||
context.disableDefaultConstraintViolation();
|
||||
if (bean.getValue() == null) {
|
||||
context.buildConstraintViolationWithTemplate("NULL").addPropertyNode("value").addConstraintViolation();
|
||||
context.buildConstraintViolationWithTemplate("NULL")
|
||||
.addPropertyNode("value").addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -494,7 +555,8 @@ public class ValidatorFactoryTests {
|
||||
boolean valid = true;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if ("X".equals(list.get(i))) {
|
||||
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addBeanNode().inIterable().atIndex(i).addConstraintViolation();
|
||||
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
|
||||
.addBeanNode().inIterable().atIndex(i).addConstraintViolation();
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,9 +37,9 @@ public class SimpleLocaleContext implements LocaleContext {
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SimpleLocaleContext that exposes the specified Locale.
|
||||
* Every {@link #getLocale()} call will return this Locale.
|
||||
* @param locale the Locale to expose, or {@code null} for no specific one
|
||||
* Create a new {@code SimpleLocaleContext} that exposes the specified {@link Locale}.
|
||||
* <p>Every {@link #getLocale()} call will return this locale.
|
||||
* @param locale the {@code Locale} to expose, or {@code null} for no specific one
|
||||
*/
|
||||
public SimpleLocaleContext(@Nullable Locale locale) {
|
||||
this.locale = locale;
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -143,7 +143,7 @@ public class NotificationListenerRegistrar extends NotificationListenerHolder
|
||||
this.actualObjectNames = getResolvedObjectNames();
|
||||
if (this.actualObjectNames != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Registering NotificationListener for MBeans " + Arrays.asList(this.actualObjectNames));
|
||||
logger.debug("Registering NotificationListener for MBeans " + Arrays.toString(this.actualObjectNames));
|
||||
}
|
||||
for (ObjectName actualObjectName : this.actualObjectNames) {
|
||||
this.server.addNotificationListener(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -762,7 +762,7 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
|
||||
* <p>The default implementation delegates to {@link JmxUtils#isMBean},
|
||||
* which checks for {@link javax.management.DynamicMBean} classes as well
|
||||
* as classes with corresponding "*MBean" interface (Standard MBeans)
|
||||
* or corresponding "*MXBean" interface (Java 6 MXBeans).
|
||||
* or corresponding "*MXBean" interface (Java MXBeans).
|
||||
* @param beanClass the bean class to analyze
|
||||
* @return whether the class qualifies as an MBean
|
||||
* @see org.springframework.jmx.support.JmxUtils#isMBean(Class)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 the original author 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,7 +255,7 @@ public abstract class JmxUtils {
|
||||
* Determine whether the given bean class qualifies as an MBean as-is.
|
||||
* <p>This implementation checks for {@link javax.management.DynamicMBean}
|
||||
* classes as well as classes with corresponding "*MBean" interface
|
||||
* (Standard MBeans) or corresponding "*MXBean" interface (Java 6 MXBeans).
|
||||
* (Standard MBeans) or corresponding "*MXBean" interface (Java MXBeans).
|
||||
* @param clazz the bean class to analyze
|
||||
* @return whether the class qualifies as an MBean
|
||||
* @see org.springframework.jmx.export.MBeanExporter#isMBean(Class)
|
||||
@@ -289,7 +289,7 @@ public abstract class JmxUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Java 6 MXBean interface exists for the given class, if any
|
||||
* Return the Java MXBean interface for the given class, if any
|
||||
* (that is, an interface whose name ends with "MXBean" and/or
|
||||
* carries an appropriate MXBean annotation).
|
||||
* @param clazz the class to check
|
||||
|
||||
+26
-2
@@ -72,6 +72,8 @@ import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
* {@link org.springframework.scheduling.concurrent.ConcurrentTaskExecutor} adapter.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rémy Guihard
|
||||
* @author Sam Brannen
|
||||
* @since 2.0
|
||||
* @see org.springframework.core.task.TaskExecutor
|
||||
* @see java.util.concurrent.ThreadPoolExecutor
|
||||
@@ -155,7 +157,7 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
|
||||
|
||||
/**
|
||||
* Set the ThreadPoolExecutor's keep-alive seconds.
|
||||
* Default is 60.
|
||||
* <p>Default is 60.
|
||||
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
|
||||
*/
|
||||
public void setKeepAliveSeconds(int keepAliveSeconds) {
|
||||
@@ -178,7 +180,7 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
|
||||
|
||||
/**
|
||||
* Set the capacity for the ThreadPoolExecutor's BlockingQueue.
|
||||
* Default is {@code Integer.MAX_VALUE}.
|
||||
* <p>Default is {@code Integer.MAX_VALUE}.
|
||||
* <p>Any positive value will lead to a LinkedBlockingQueue instance;
|
||||
* any other value will lead to a SynchronousQueue instance.
|
||||
* @see java.util.concurrent.LinkedBlockingQueue
|
||||
@@ -188,6 +190,15 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
|
||||
this.queueCapacity = queueCapacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the capacity for the ThreadPoolExecutor's BlockingQueue.
|
||||
* @since 5.3.21
|
||||
* @see #setQueueCapacity(int)
|
||||
*/
|
||||
public int getQueueCapacity() {
|
||||
return this.queueCapacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether to allow core threads to time out. This enables dynamic
|
||||
* growing and shrinking even in combination with a non-zero queue (since
|
||||
@@ -316,6 +327,19 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
|
||||
return this.threadPoolExecutor.getPoolSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current queue size.
|
||||
* @since 5.3.21
|
||||
* @see java.util.concurrent.ThreadPoolExecutor#getQueue()
|
||||
*/
|
||||
public int getQueueSize() {
|
||||
if (this.threadPoolExecutor == null) {
|
||||
// Not initialized yet: assume no queued tasks.
|
||||
return 0;
|
||||
}
|
||||
return this.threadPoolExecutor.getQueue().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of currently active threads.
|
||||
* @see java.util.concurrent.ThreadPoolExecutor#getActiveCount()
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author 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.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.scripting.ScriptFactory} implementation based
|
||||
* on the JSR-223 script engine abstraction (as included in Java 6+).
|
||||
* on the JSR-223 script engine abstraction (as included in Java).
|
||||
* Supports JavaScript, Groovy, JRuby, and other JSR-223 compliant engines.
|
||||
*
|
||||
* <p>Typically used in combination with a
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author 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,20 @@ import org.springframework.util.PatternMatchUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Binder that allows for setting property values onto a target object,
|
||||
* including support for validation and binding result analysis.
|
||||
* The binding process can be customized through specifying allowed fields,
|
||||
* Binder that allows for setting property values on a target object, including
|
||||
* support for validation and binding result analysis.
|
||||
*
|
||||
* <p>The binding process can be customized by specifying allowed field patterns,
|
||||
* required fields, custom editors, etc.
|
||||
*
|
||||
* <p>Note that there are potential security implications in failing to set an array
|
||||
* of allowed fields. In the case of HTTP form POST data for example, malicious clients
|
||||
* can attempt to subvert an application by supplying values for fields or properties
|
||||
* that do not exist on the form. In some cases this could lead to illegal data being
|
||||
* set on command objects <i>or their nested objects</i>. For this reason, it is
|
||||
* <b>highly recommended to specify the {@link #setAllowedFields allowedFields} property</b>
|
||||
* on the DataBinder.
|
||||
* <p><strong>WARNING</strong>: Data binding can lead to security issues by exposing
|
||||
* parts of the object graph that are not meant to be accessed or modified by
|
||||
* external clients. Therefore the design and use of data binding should be considered
|
||||
* carefully with regard to security. For more details, please refer to the dedicated
|
||||
* sections on data binding for
|
||||
* <a href="https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-initbinder-model-design">Spring Web MVC</a> and
|
||||
* <a href="https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-ann-initbinder-model-design">Spring WebFlux</a>
|
||||
* in the reference manual.
|
||||
*
|
||||
* <p>The binding results can be examined via the {@link BindingResult} interface,
|
||||
* extending the {@link Errors} interface: see the {@link #getBindingResult()} method.
|
||||
@@ -96,6 +98,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Rob Harrop
|
||||
* @author Stephane Nicoll
|
||||
* @author Kazuki Shimizu
|
||||
* @author Sam Brannen
|
||||
* @see #setAllowedFields
|
||||
* @see #setRequiredFields
|
||||
* @see #registerCustomEditor
|
||||
@@ -418,15 +421,21 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register fields that should be allowed for binding. Default is all fields.
|
||||
* Restrict this for example to avoid unwanted modifications by malicious
|
||||
* Register field patterns that should be allowed for binding.
|
||||
* <p>Default is all fields.
|
||||
* <p>Restrict this for example to avoid unwanted modifications by malicious
|
||||
* users when binding HTTP request parameters.
|
||||
* <p>Supports "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an
|
||||
* arbitrary number of pattern parts), as well as direct equality. More
|
||||
* sophisticated matching can be implemented by overriding the
|
||||
* {@code isAllowed} method.
|
||||
* <p>Alternatively, specify a list of <i>disallowed</i> fields.
|
||||
* @param allowedFields array of field names
|
||||
* <p>Supports {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and
|
||||
* {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as
|
||||
* well as direct equality.
|
||||
* <p>The default implementation of this method stores allowed field patterns
|
||||
* in {@linkplain PropertyAccessorUtils#canonicalPropertyName(String) canonical}
|
||||
* form. Subclasses which override this method must therefore take this into
|
||||
* account.
|
||||
* <p>More sophisticated matching can be implemented by overriding the
|
||||
* {@link #isAllowed} method.
|
||||
* <p>Alternatively, specify a list of <i>disallowed</i> field patterns.
|
||||
* @param allowedFields array of allowed field patterns
|
||||
* @see #setDisallowedFields
|
||||
* @see #isAllowed(String)
|
||||
*/
|
||||
@@ -435,8 +444,9 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fields that should be allowed for binding.
|
||||
* @return array of field names
|
||||
* Return the field patterns that should be allowed for binding.
|
||||
* @return array of allowed field patterns
|
||||
* @see #setAllowedFields(String...)
|
||||
*/
|
||||
@Nullable
|
||||
public String[] getAllowedFields() {
|
||||
@@ -444,25 +454,44 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register fields that should <i>not</i> be allowed for binding. Default
|
||||
* is none. Mark fields as disallowed for example to avoid unwanted
|
||||
* Register field patterns that should <i>not</i> be allowed for binding.
|
||||
* <p>Default is none.
|
||||
* <p>Mark fields as disallowed, for example to avoid unwanted
|
||||
* modifications by malicious users when binding HTTP request parameters.
|
||||
* <p>Supports "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an
|
||||
* arbitrary number of pattern parts), as well as direct equality.
|
||||
* More sophisticated matching can be implemented by overriding the
|
||||
* {@code isAllowed} method.
|
||||
* <p>Alternatively, specify a list of <i>allowed</i> fields.
|
||||
* @param disallowedFields array of field names
|
||||
* <p>Supports {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and
|
||||
* {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as
|
||||
* well as direct equality.
|
||||
* <p>The default implementation of this method stores disallowed field patterns
|
||||
* in {@linkplain PropertyAccessorUtils#canonicalPropertyName(String) canonical}
|
||||
* form. As of Spring Framework 5.2.21, the default implementation also transforms
|
||||
* disallowed field patterns to {@linkplain String#toLowerCase() lowercase} to
|
||||
* support case-insensitive pattern matching in {@link #isAllowed}. Subclasses
|
||||
* which override this method must therefore take both of these transformations
|
||||
* into account.
|
||||
* <p>More sophisticated matching can be implemented by overriding the
|
||||
* {@link #isAllowed} method.
|
||||
* <p>Alternatively, specify a list of <i>allowed</i> field patterns.
|
||||
* @param disallowedFields array of disallowed field patterns
|
||||
* @see #setAllowedFields
|
||||
* @see #isAllowed(String)
|
||||
*/
|
||||
public void setDisallowedFields(@Nullable String... disallowedFields) {
|
||||
this.disallowedFields = PropertyAccessorUtils.canonicalPropertyNames(disallowedFields);
|
||||
if (disallowedFields == null) {
|
||||
this.disallowedFields = null;
|
||||
}
|
||||
else {
|
||||
String[] fieldPatterns = new String[disallowedFields.length];
|
||||
for (int i = 0; i < fieldPatterns.length; i++) {
|
||||
fieldPatterns[i] = PropertyAccessorUtils.canonicalPropertyName(disallowedFields[i]).toLowerCase();
|
||||
}
|
||||
this.disallowedFields = fieldPatterns;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fields that should <i>not</i> be allowed for binding.
|
||||
* @return array of field names
|
||||
* Return the field patterns that should <i>not</i> be allowed for binding.
|
||||
* @return array of disallowed field patterns
|
||||
* @see #setDisallowedFields(String...)
|
||||
*/
|
||||
@Nullable
|
||||
public String[] getDisallowedFields() {
|
||||
@@ -774,16 +803,20 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the given field is allowed for binding.
|
||||
* Invoked for each passed-in property value.
|
||||
* <p>The default implementation checks for "xxx*", "*xxx", "*xxx*" and "xxx*yyy"
|
||||
* matches (with an arbitrary number of pattern parts), as well as direct equality,
|
||||
* in the specified lists of allowed fields and disallowed fields. A field matching
|
||||
* a disallowed pattern will not be accepted even if it also happens to match a
|
||||
* pattern in the allowed list.
|
||||
* <p>Can be overridden in subclasses.
|
||||
* Determine if the given field is allowed for binding.
|
||||
* <p>Invoked for each passed-in property value.
|
||||
* <p>Checks for {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and
|
||||
* {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as
|
||||
* well as direct equality, in the configured lists of allowed field patterns
|
||||
* and disallowed field patterns.
|
||||
* <p>Matching against allowed field patterns is case-sensitive; whereas,
|
||||
* matching against disallowed field patterns is case-insensitive.
|
||||
* <p>A field matching a disallowed pattern will not be accepted even if it
|
||||
* also happens to match a pattern in the allowed list.
|
||||
* <p>Can be overridden in subclasses, but care must be taken to honor the
|
||||
* aforementioned contract.
|
||||
* @param field the field to check
|
||||
* @return if the field is allowed
|
||||
* @return {@code true} if the field is allowed
|
||||
* @see #setAllowedFields
|
||||
* @see #setDisallowedFields
|
||||
* @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String)
|
||||
@@ -792,7 +825,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
|
||||
String[] allowed = getAllowedFields();
|
||||
String[] disallowed = getDisallowedFields();
|
||||
return ((ObjectUtils.isEmpty(allowed) || PatternMatchUtils.simpleMatch(allowed, field)) &&
|
||||
(ObjectUtils.isEmpty(disallowed) || !PatternMatchUtils.simpleMatch(disallowed, field)));
|
||||
(ObjectUtils.isEmpty(disallowed) || !PatternMatchUtils.simpleMatch(disallowed, field.toLowerCase())));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+20
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author 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,6 +26,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.validation.Configuration;
|
||||
import javax.validation.ConstraintValidatorFactory;
|
||||
@@ -113,6 +114,9 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
|
||||
private final Map<String, String> validationPropertyMap = new HashMap<>();
|
||||
|
||||
@Nullable
|
||||
private Consumer<Configuration<?>> configurationInitializer;
|
||||
|
||||
@Nullable
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@@ -234,6 +238,18 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
return this.validationPropertyMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a callback for customizing the Bean Validation {@code Configuration} instance,
|
||||
* as an alternative to overriding the {@link #postProcessConfiguration(Configuration)}
|
||||
* method in custom {@code LocalValidatorFactoryBean} subclasses.
|
||||
* <p>This enables convenient customizations for application purposes. Infrastructure
|
||||
* extensions may keep overriding the {@link #postProcessConfiguration} template method.
|
||||
* @since 5.3.19
|
||||
*/
|
||||
public void setConfigurationInitializer(Consumer<Configuration<?>> configurationInitializer) {
|
||||
this.configurationInitializer = configurationInitializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
@@ -312,6 +328,9 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
|
||||
this.validationPropertyMap.forEach(configuration::addProperty);
|
||||
|
||||
// Allow for custom post-processing before we actually build the ValidatorFactory.
|
||||
if (this.configurationInitializer != null) {
|
||||
this.configurationInitializer.accept(configuration);
|
||||
}
|
||||
postProcessConfiguration(configuration);
|
||||
|
||||
try {
|
||||
|
||||
+103
-2
@@ -21,6 +21,8 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
@@ -31,11 +33,17 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.IntroductionAdvisor;
|
||||
import org.springframework.aop.IntroductionInterceptor;
|
||||
import org.springframework.aop.MethodBeforeAdvice;
|
||||
import org.springframework.aop.SpringProxy;
|
||||
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
|
||||
import org.springframework.aop.aspectj.annotation.AspectMetadata;
|
||||
import org.springframework.aop.config.AopConfigUtils;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.framework.ProxyConfig;
|
||||
import org.springframework.aop.support.AbstractPointcutAdvisor;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
@@ -52,6 +60,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.DecoratingProxy;
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -304,10 +313,26 @@ public class AspectJAutoProxyCreatorTests {
|
||||
@ValueSource(classes = {ProxyTargetClassFalseConfig.class, ProxyTargetClassTrueConfig.class})
|
||||
void lambdaIsAlwaysProxiedWithJdkProxy(Class<?> configClass) {
|
||||
try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(configClass)) {
|
||||
Supplier<?> supplier = context.getBean(Supplier.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
Supplier<String> supplier = context.getBean(Supplier.class);
|
||||
assertThat(AopUtils.isAopProxy(supplier)).as("AOP proxy").isTrue();
|
||||
assertThat(AopUtils.isJdkDynamicProxy(supplier)).as("JDK Dynamic proxy").isTrue();
|
||||
assertThat(supplier.get()).asString().isEqualTo("advised: lambda");
|
||||
assertThat(supplier.getClass().getInterfaces())
|
||||
.containsExactlyInAnyOrder(Supplier.class, SpringProxy.class, Advised.class, DecoratingProxy.class);
|
||||
assertThat(supplier.get()).isEqualTo("advised: lambda");
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "[{index}] {0}")
|
||||
@ValueSource(classes = {MixinProxyTargetClassFalseConfig.class, MixinProxyTargetClassTrueConfig.class})
|
||||
void lambdaIsAlwaysProxiedWithJdkProxyWithIntroductions(Class<?> configClass) {
|
||||
try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(configClass)) {
|
||||
MessageGenerator messageGenerator = context.getBean(MessageGenerator.class);
|
||||
assertThat(AopUtils.isAopProxy(messageGenerator)).as("AOP proxy").isTrue();
|
||||
assertThat(AopUtils.isJdkDynamicProxy(messageGenerator)).as("JDK Dynamic proxy").isTrue();
|
||||
assertThat(messageGenerator.getClass().getInterfaces())
|
||||
.containsExactlyInAnyOrder(MessageGenerator.class, Mixin.class, SpringProxy.class, Advised.class, DecoratingProxy.class);
|
||||
assertThat(messageGenerator.generateMessage()).isEqualTo("mixin: lambda");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,3 +641,79 @@ class ProxyTargetClassFalseConfig extends AbstractProxyTargetClassConfig {
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||
class ProxyTargetClassTrueConfig extends AbstractProxyTargetClassConfig {
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface MessageGenerator {
|
||||
String generateMessage();
|
||||
}
|
||||
|
||||
interface Mixin {
|
||||
}
|
||||
|
||||
class MixinIntroductionInterceptor implements IntroductionInterceptor {
|
||||
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
return "mixin: " + invocation.proceed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean implementsInterface(Class<?> intf) {
|
||||
return Mixin.class.isAssignableFrom(intf);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
class MixinAdvisor extends AbstractPointcutAdvisor implements IntroductionAdvisor {
|
||||
|
||||
@Override
|
||||
public org.springframework.aop.Pointcut getPointcut() {
|
||||
return org.springframework.aop.Pointcut.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Advice getAdvice() {
|
||||
return new MixinIntroductionInterceptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getInterfaces() {
|
||||
return new Class[] { Mixin.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassFilter getClassFilter() {
|
||||
return MessageGenerator.class::isAssignableFrom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateInterfaces() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class AbstractMixinConfig {
|
||||
|
||||
@Bean
|
||||
MessageGenerator messageGenerator() {
|
||||
return () -> "lambda";
|
||||
}
|
||||
|
||||
@Bean
|
||||
MixinAdvisor mixinAdvisor() {
|
||||
return new MixinAdvisor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = false)
|
||||
class MixinProxyTargetClassFalseConfig extends AbstractMixinConfig {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||
class MixinProxyTargetClassTrueConfig extends AbstractMixinConfig {
|
||||
}
|
||||
|
||||
+3
-3
@@ -26,7 +26,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
@@ -35,12 +35,12 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
class SPR3064Tests {
|
||||
|
||||
@Test
|
||||
void testServiceIsAdvised() {
|
||||
void serviceIsAdvised() {
|
||||
ClassPathXmlApplicationContext ctx =
|
||||
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
|
||||
|
||||
Service service = ctx.getBean(Service.class);
|
||||
assertThatExceptionOfType(RuntimeException.class)
|
||||
assertThatRuntimeException()
|
||||
.isThrownBy(service::serveMe)
|
||||
.withMessage("advice invoked");
|
||||
|
||||
|
||||
+26
-31
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -74,9 +74,11 @@ import org.springframework.core.testfixture.io.SerializationTestUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
@@ -431,7 +433,7 @@ public abstract class AbstractAopProxyTests {
|
||||
pc.setTargetSource(mockTargetSource);
|
||||
AopProxy aop = createAopProxy(pc);
|
||||
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() -> {
|
||||
assertThatException().isThrownBy(() -> {
|
||||
ITestBean tb = (ITestBean) aop.getProxy();
|
||||
// Note: exception param below isn't used
|
||||
tb.exceptional(expectedException);
|
||||
@@ -459,8 +461,7 @@ public abstract class AbstractAopProxyTests {
|
||||
AopProxy aop = createAopProxy(pc);
|
||||
ITestBean tb = (ITestBean) aop.getProxy();
|
||||
|
||||
assertThatExceptionOfType(UndeclaredThrowableException.class).isThrownBy(
|
||||
tb::getAge)
|
||||
assertThatExceptionOfType(UndeclaredThrowableException.class).isThrownBy(tb::getAge)
|
||||
.satisfies(ex -> assertThat(ex.getUndeclaredThrowable()).isEqualTo(unexpectedException));
|
||||
}
|
||||
|
||||
@@ -480,8 +481,8 @@ public abstract class AbstractAopProxyTests {
|
||||
AopProxy aop = createAopProxy(pc);
|
||||
ITestBean tb = (ITestBean) aop.getProxy();
|
||||
|
||||
assertThatExceptionOfType(RuntimeException.class).isThrownBy(
|
||||
tb::getAge)
|
||||
assertThatRuntimeException()
|
||||
.isThrownBy(tb::getAge)
|
||||
.matches(unexpectedException::equals);
|
||||
}
|
||||
|
||||
@@ -571,8 +572,7 @@ public abstract class AbstractAopProxyTests {
|
||||
lockable.lock();
|
||||
|
||||
assertThat(itb.getAge()).isEqualTo(newAge);
|
||||
assertThatExceptionOfType(LockedException.class).isThrownBy(() ->
|
||||
itb.setAge(1));
|
||||
assertThatExceptionOfType(LockedException.class).isThrownBy(() -> itb.setAge(1));
|
||||
assertThat(itb.getAge()).isEqualTo(newAge);
|
||||
|
||||
// Unlock
|
||||
@@ -675,7 +675,7 @@ public abstract class AbstractAopProxyTests {
|
||||
target.setAge(21);
|
||||
ProxyFactory pc = new ProxyFactory(target);
|
||||
pc.addAdvisor(new DefaultIntroductionAdvisor(new DummyIntroductionAdviceImpl(), Comparable.class));
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() -> {
|
||||
assertThatException().isThrownBy(() -> {
|
||||
// TODO May fail on either call: may want to tighten up definition
|
||||
ITestBean proxied = (ITestBean) createProxy(pc);
|
||||
proxied.getName();
|
||||
@@ -725,8 +725,7 @@ public abstract class AbstractAopProxyTests {
|
||||
pc.addAdvisor(new DefaultIntroductionAdvisor(new MyDi()));
|
||||
|
||||
TimeStamped ts = (TimeStamped) createProxy(pc);
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(
|
||||
ts::getTimeStamp);
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(ts::getTimeStamp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -754,8 +753,8 @@ public abstract class AbstractAopProxyTests {
|
||||
pc.addAdvice(new NopInterceptor());
|
||||
ITestBean proxied = (ITestBean) createProxy(pc);
|
||||
pc.setFrozen(true);
|
||||
assertThatExceptionOfType(AopConfigException.class).as("Shouldn't be able to add interceptor when frozen").isThrownBy(() ->
|
||||
pc.addAdvice(0, new NopInterceptor()))
|
||||
assertThatExceptionOfType(AopConfigException.class).as("Shouldn't be able to add interceptor when frozen")
|
||||
.isThrownBy(() -> pc.addAdvice(0, new NopInterceptor()))
|
||||
.withMessageContaining("frozen");
|
||||
// Check it still works: proxy factory state shouldn't have been corrupted
|
||||
assertThat(proxied.getAge()).isEqualTo(target.getAge());
|
||||
@@ -777,8 +776,8 @@ public abstract class AbstractAopProxyTests {
|
||||
Advised advised = (Advised) proxied;
|
||||
|
||||
assertThat(pc.isFrozen()).isTrue();
|
||||
assertThatExceptionOfType(AopConfigException.class).as("Shouldn't be able to add Advisor when frozen").isThrownBy(() ->
|
||||
advised.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())))
|
||||
assertThatExceptionOfType(AopConfigException.class).as("Shouldn't be able to add Advisor when frozen")
|
||||
.isThrownBy(() -> advised.addAdvisor(new DefaultPointcutAdvisor(new NopInterceptor())))
|
||||
.withMessageContaining("frozen");
|
||||
// Check it still works: proxy factory state shouldn't have been corrupted
|
||||
assertThat(proxied.getAge()).isEqualTo(target.getAge());
|
||||
@@ -797,8 +796,8 @@ public abstract class AbstractAopProxyTests {
|
||||
Advised advised = (Advised) proxied;
|
||||
|
||||
assertThat(pc.isFrozen()).isTrue();
|
||||
assertThatExceptionOfType(AopConfigException.class).as("Shouldn't be able to remove Advisor when frozen").isThrownBy(() ->
|
||||
advised.removeAdvisor(0))
|
||||
assertThatExceptionOfType(AopConfigException.class).as("Shouldn't be able to remove Advisor when frozen")
|
||||
.isThrownBy(() -> advised.removeAdvisor(0))
|
||||
.withMessageContaining("frozen");
|
||||
// Didn't get removed
|
||||
assertThat(advised.getAdvisors().length).isEqualTo(1);
|
||||
@@ -1311,8 +1310,8 @@ public abstract class AbstractAopProxyTests {
|
||||
assertThat(cca.getCalls()).isEqualTo(2);
|
||||
assertThat(proxied.getAge()).isEqualTo(26);
|
||||
assertThat(cca.getCalls()).isEqualTo(4);
|
||||
assertThatExceptionOfType(SpecializedUncheckedException.class).as("Should have thrown CannotGetJdbcConnectionException").isThrownBy(() ->
|
||||
proxied.exceptional(new SpecializedUncheckedException("foo", (SQLException)null)));
|
||||
assertThatExceptionOfType(SpecializedUncheckedException.class).as("Should have thrown CannotGetJdbcConnectionException")
|
||||
.isThrownBy(() -> proxied.exceptional(new SpecializedUncheckedException("foo", (SQLException)null)));
|
||||
assertThat(cca.getCalls()).isEqualTo(6);
|
||||
}
|
||||
|
||||
@@ -1346,8 +1345,8 @@ public abstract class AbstractAopProxyTests {
|
||||
assertThat(nop1.getCount()).isEqualTo(1);
|
||||
assertThat(nop2.getCount()).isEqualTo(1);
|
||||
// Will fail, after invoking Nop1
|
||||
assertThatExceptionOfType(RuntimeException.class).as("before advice should have ended chain").isThrownBy(() ->
|
||||
proxied.setAge(26))
|
||||
assertThatRuntimeException().as("before advice should have ended chain")
|
||||
.isThrownBy(() -> proxied.setAge(26))
|
||||
.matches(rex::equals);
|
||||
assertThat(ba.getCalls()).isEqualTo(2);
|
||||
assertThat(nop1.getCount()).isEqualTo(2);
|
||||
@@ -1411,8 +1410,7 @@ public abstract class AbstractAopProxyTests {
|
||||
assertThat(car.getCalls()).isEqualTo(2);
|
||||
Exception exc = new Exception();
|
||||
// On exception it won't be invoked
|
||||
assertThatExceptionOfType(Throwable.class).isThrownBy(() ->
|
||||
proxied.exceptional(exc))
|
||||
assertThatExceptionOfType(Throwable.class).isThrownBy(() -> proxied.exceptional(exc))
|
||||
.satisfies(ex -> assertThat(ex).isSameAs(exc));
|
||||
assertThat(car.getCalls()).isEqualTo(2);
|
||||
}
|
||||
@@ -1442,12 +1440,11 @@ public abstract class AbstractAopProxyTests {
|
||||
assertThat(th.getCalls()).isEqualTo(0);
|
||||
Exception ex = new Exception();
|
||||
// Will be advised but doesn't match
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
|
||||
proxied.echoException(1, ex))
|
||||
assertThatException().isThrownBy(() -> proxied.echoException(1, ex))
|
||||
.matches(ex::equals);
|
||||
FileNotFoundException fex = new FileNotFoundException();
|
||||
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
|
||||
proxied.echoException(1, fex))
|
||||
assertThatExceptionOfType(FileNotFoundException.class)
|
||||
.isThrownBy(() -> proxied.echoException(1, fex))
|
||||
.matches(fex::equals);
|
||||
assertThat(th.getCalls("ioException")).isEqualTo(1);
|
||||
}
|
||||
@@ -1468,14 +1465,12 @@ public abstract class AbstractAopProxyTests {
|
||||
assertThat(th.getCalls()).isEqualTo(0);
|
||||
Exception ex = new Exception();
|
||||
// Will be advised but doesn't match
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
|
||||
proxied.echoException(1, ex))
|
||||
assertThatException().isThrownBy(() -> proxied.echoException(1, ex))
|
||||
.matches(ex::equals);
|
||||
|
||||
// Subclass of RemoteException
|
||||
MarshalException mex = new MarshalException("");
|
||||
assertThatExceptionOfType(MarshalException.class).isThrownBy(() ->
|
||||
proxied.echoException(1, mex))
|
||||
assertThatExceptionOfType(MarshalException.class).isThrownBy(() -> proxied.echoException(1, mex))
|
||||
.matches(mex::equals);
|
||||
|
||||
assertThat(th.getCalls("remoteException")).isEqualTo(1);
|
||||
|
||||
+6
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -61,6 +61,7 @@ import org.springframework.core.testfixture.io.SerializationTestUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIOException;
|
||||
|
||||
@@ -310,7 +311,7 @@ public class ProxyFactoryBeanTests {
|
||||
assertThat(config.getAdvisors().length).as("Have correct advisor count").isEqualTo(2);
|
||||
|
||||
ITestBean tb1 = (ITestBean) factory.getBean("test1");
|
||||
assertThatExceptionOfType(Exception.class)
|
||||
assertThatException()
|
||||
.isThrownBy(tb1::toString)
|
||||
.isSameAs(ex);
|
||||
}
|
||||
@@ -438,8 +439,7 @@ public class ProxyFactoryBeanTests {
|
||||
assertThat(cba.getCalls()).isEqualTo(2);
|
||||
assertThat(th.getCalls()).isEqualTo(0);
|
||||
Exception expected = new Exception();
|
||||
assertThatExceptionOfType(Exception.class).isThrownBy(() ->
|
||||
echo.echoException(1, expected))
|
||||
assertThatException().isThrownBy(() -> echo.echoException(1, expected))
|
||||
.matches(expected::equals);
|
||||
// No throws handler method: count should still be 0
|
||||
assertThat(th.getCalls()).isEqualTo(0);
|
||||
@@ -586,8 +586,7 @@ public class ProxyFactoryBeanTests {
|
||||
|
||||
((Lockable) bean1).lock();
|
||||
|
||||
assertThatExceptionOfType(LockedException.class).isThrownBy(() ->
|
||||
bean1.setAge(5));
|
||||
assertThatExceptionOfType(LockedException.class).isThrownBy(() -> bean1.setAge(5));
|
||||
|
||||
bean2.setAge(6); //do not expect LockedException"
|
||||
}
|
||||
@@ -607,8 +606,7 @@ public class ProxyFactoryBeanTests {
|
||||
|
||||
((Lockable) bean1).lock();
|
||||
|
||||
assertThatExceptionOfType(LockedException.class).isThrownBy(() ->
|
||||
bean1.setAge(5));
|
||||
assertThatExceptionOfType(LockedException.class).isThrownBy(() -> bean1.setAge(5));
|
||||
|
||||
// do not expect LockedException
|
||||
bean2.setAge(6);
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,7 +37,7 @@ import org.springframework.context.testfixture.cache.beans.CacheableService;
|
||||
import org.springframework.context.testfixture.cache.beans.DefaultCacheableService;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
|
||||
|
||||
/**
|
||||
* @author Stephane Nicoll
|
||||
@@ -76,8 +76,8 @@ public class CustomInterceptorTests {
|
||||
|
||||
@Test
|
||||
public void customInterceptorAppliesWithCheckedException() {
|
||||
assertThatExceptionOfType(RuntimeException.class).isThrownBy(() ->
|
||||
this.cs.throwChecked(0L))
|
||||
assertThatRuntimeException()
|
||||
.isThrownBy(() -> this.cs.throwChecked(0L))
|
||||
.withCauseExactlyInstanceOf(IOException.class);
|
||||
}
|
||||
|
||||
|
||||
+31
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -148,25 +148,53 @@ class AnnotationConfigApplicationContextTests {
|
||||
void nullReturningBeanPostProcessor() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(AutowiredConfig.class);
|
||||
// 1st BPP always gets invoked
|
||||
context.getBeanFactory().addBeanPostProcessor(new BeanPostProcessor() {
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
if (bean instanceof TestBean) {
|
||||
TestBean testBean = (TestBean) bean;
|
||||
testBean.name = testBean.name + "-before";
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
if (bean instanceof TestBean) {
|
||||
TestBean testBean = (TestBean) bean;
|
||||
testBean.name = testBean.name + "-after";
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
});
|
||||
// 2nd BPP always returns null for a TestBean
|
||||
context.getBeanFactory().addBeanPostProcessor(new BeanPostProcessor() {
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
return (bean instanceof TestBean ? null : bean);
|
||||
}
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
return (bean instanceof TestBean ? null : bean);
|
||||
}
|
||||
});
|
||||
// 3rd BPP never gets invoked with a TestBean
|
||||
context.getBeanFactory().addBeanPostProcessor(new BeanPostProcessor() {
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
bean.getClass().getName();
|
||||
assertThat(bean).isNotInstanceOf(TestBean.class);
|
||||
return bean;
|
||||
}
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
bean.getClass().getName();
|
||||
assertThat(bean).isNotInstanceOf(TestBean.class);
|
||||
return bean;
|
||||
}
|
||||
});
|
||||
context.refresh();
|
||||
TestBean testBean = context.getBean(TestBean.class);
|
||||
assertThat(testBean).isNotNull();
|
||||
assertThat(testBean.name).isEqualTo("foo-before-after");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+3
-3
@@ -52,7 +52,7 @@ import org.springframework.scheduling.support.TaskUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.willThrow;
|
||||
@@ -161,8 +161,8 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen
|
||||
|
||||
RuntimeException thrown = new RuntimeException();
|
||||
willThrow(thrown).given(listener).onApplicationEvent(evt);
|
||||
assertThatExceptionOfType(RuntimeException.class).isThrownBy(() ->
|
||||
smc.multicastEvent(evt))
|
||||
assertThatRuntimeException()
|
||||
.isThrownBy(() -> smc.multicastEvent(evt))
|
||||
.satisfies(ex -> assertThat(ex).isSameAs(thrown));
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,6 +28,7 @@ import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.jndi.JndiTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -132,7 +133,7 @@ public class LocalSlsbInvokerInterceptorTests {
|
||||
pf.addAdvice(si);
|
||||
LocalInterfaceWithBusinessMethods target = (LocalInterfaceWithBusinessMethods) pf.getProxy();
|
||||
|
||||
assertThatExceptionOfType(Exception.class)
|
||||
assertThatException()
|
||||
.isThrownBy(target::targetMethod)
|
||||
.isSameAs(expected);
|
||||
|
||||
|
||||
+6
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,6 +32,7 @@ import org.springframework.jndi.JndiTemplate;
|
||||
import org.springframework.remoting.RemoteAccessException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -195,8 +196,7 @@ public class SimpleRemoteSlsbInvokerInterceptorTests {
|
||||
SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
|
||||
|
||||
RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class);
|
||||
assertThatExceptionOfType(RemoteException.class).isThrownBy(
|
||||
target::targetMethod);
|
||||
assertThatExceptionOfType(RemoteException.class).isThrownBy(target::targetMethod);
|
||||
|
||||
verify(mockContext).close();
|
||||
verify(ejb, times(2)).remove();
|
||||
@@ -245,8 +245,7 @@ public class SimpleRemoteSlsbInvokerInterceptorTests {
|
||||
si.setCacheHome(cacheHome);
|
||||
|
||||
RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class);
|
||||
assertThatExceptionOfType(ConnectException.class).isThrownBy(
|
||||
target::targetMethod);
|
||||
assertThatExceptionOfType(ConnectException.class).isThrownBy(target::targetMethod);
|
||||
|
||||
verify(mockContext, times(lookupCount)).close();
|
||||
verify(ejb, times(2)).remove();
|
||||
@@ -281,8 +280,7 @@ public class SimpleRemoteSlsbInvokerInterceptorTests {
|
||||
SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
|
||||
|
||||
BusinessInterface target = (BusinessInterface) configuredProxy(si, BusinessInterface.class);
|
||||
assertThatExceptionOfType(RemoteAccessException.class).isThrownBy(
|
||||
target::targetMethod);
|
||||
assertThatExceptionOfType(RemoteAccessException.class).isThrownBy(target::targetMethod);
|
||||
|
||||
verify(mockContext).close();
|
||||
verify(ejb).remove();
|
||||
@@ -308,7 +306,7 @@ public class SimpleRemoteSlsbInvokerInterceptorTests {
|
||||
SimpleRemoteSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
|
||||
|
||||
RemoteInterface target = (RemoteInterface) configuredProxy(si, RemoteInterface.class);
|
||||
assertThatExceptionOfType(Exception.class)
|
||||
assertThatException()
|
||||
.isThrownBy(target::targetMethod)
|
||||
.isSameAs(expected);
|
||||
verify(mockContext).close();
|
||||
|
||||
+9
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -132,11 +132,11 @@ public class DateFormattingTests {
|
||||
TypeMismatchException exception = fieldError.unwrap(TypeMismatchException.class);
|
||||
assertThat(exception)
|
||||
.hasMessageContaining("for property 'styleDate'")
|
||||
.hasCauseInstanceOf(ConversionFailedException.class).getCause()
|
||||
.hasCauseInstanceOf(ConversionFailedException.class).cause()
|
||||
.hasMessageContaining("for value '99/01/01'")
|
||||
.hasCauseInstanceOf(IllegalArgumentException.class).getCause()
|
||||
.hasCauseInstanceOf(IllegalArgumentException.class).cause()
|
||||
.hasMessageContaining("Parse attempt failed for value [99/01/01]")
|
||||
.hasCauseInstanceOf(ParseException.class).getCause()
|
||||
.hasCauseInstanceOf(ParseException.class).cause()
|
||||
// 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()
|
||||
@@ -147,7 +147,7 @@ public class DateFormattingTests {
|
||||
"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()
|
||||
.hasCauseInstanceOf(ParseException.class).cause()
|
||||
.hasMessageStartingWith("Unparseable date: \"99/01/01\"")
|
||||
.hasNoCause();
|
||||
}
|
||||
@@ -352,11 +352,11 @@ public class DateFormattingTests {
|
||||
FieldError fieldError = bindingResult.getFieldError(propertyName);
|
||||
assertThat(fieldError.unwrap(TypeMismatchException.class))
|
||||
.hasMessageContaining("for property 'patternDateWithFallbackPatterns'")
|
||||
.hasCauseInstanceOf(ConversionFailedException.class).getCause()
|
||||
.hasCauseInstanceOf(ConversionFailedException.class).cause()
|
||||
.hasMessageContaining("for value '210302'")
|
||||
.hasCauseInstanceOf(IllegalArgumentException.class).getCause()
|
||||
.hasCauseInstanceOf(IllegalArgumentException.class).cause()
|
||||
.hasMessageContaining("Parse attempt failed for value [210302]")
|
||||
.hasCauseInstanceOf(ParseException.class).getCause()
|
||||
.hasCauseInstanceOf(ParseException.class).cause()
|
||||
// Unable to parse date time value "210302" using configuration from
|
||||
// @org.springframework.format.annotation.DateTimeFormat(
|
||||
// pattern=yyyy-MM-dd, style=SS, iso=NONE, fallbackPatterns=[M/d/yy, yyyyMMdd, yyyy.MM.dd])
|
||||
@@ -364,7 +364,7 @@ public class DateFormattingTests {
|
||||
"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")
|
||||
.hasCauseInstanceOf(ParseException.class).getCause()
|
||||
.hasCauseInstanceOf(ParseException.class).cause()
|
||||
.hasMessageStartingWith("Unparseable date: \"210302\"")
|
||||
.hasNoCause();
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -332,11 +332,11 @@ class DateTimeFormattingTests {
|
||||
FieldError fieldError = bindingResult.getFieldError(propertyName);
|
||||
assertThat(fieldError.unwrap(TypeMismatchException.class))
|
||||
.hasMessageContaining("for property 'isoLocalDate'")
|
||||
.hasCauseInstanceOf(ConversionFailedException.class).getCause()
|
||||
.hasCauseInstanceOf(ConversionFailedException.class).cause()
|
||||
.hasMessageContaining("for value '2009-31-10'")
|
||||
.hasCauseInstanceOf(IllegalArgumentException.class).getCause()
|
||||
.hasCauseInstanceOf(IllegalArgumentException.class).cause()
|
||||
.hasMessageContaining("Parse attempt failed for value [2009-31-10]")
|
||||
.hasCauseInstanceOf(DateTimeParseException.class).getCause()
|
||||
.hasCauseInstanceOf(DateTimeParseException.class).cause()
|
||||
// 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()
|
||||
@@ -344,9 +344,9 @@ class DateTimeFormattingTests {
|
||||
.hasMessageContainingAll(
|
||||
"Unable to parse date time value \"2009-31-10\" using configuration from",
|
||||
"@org.springframework.format.annotation.DateTimeFormat", "iso=DATE")
|
||||
.hasCauseInstanceOf(DateTimeParseException.class).getCause()
|
||||
.hasCauseInstanceOf(DateTimeParseException.class).cause()
|
||||
.hasMessageStartingWith("Text '2009-31-10'")
|
||||
.hasCauseInstanceOf(DateTimeException.class).getCause()
|
||||
.hasCauseInstanceOf(DateTimeException.class).cause()
|
||||
.hasMessageContaining("Invalid value for MonthOfYear (valid values 1 - 12): 31")
|
||||
.hasNoCause();
|
||||
}
|
||||
@@ -539,11 +539,11 @@ class DateTimeFormattingTests {
|
||||
FieldError fieldError = bindingResult.getFieldError(propertyName);
|
||||
assertThat(fieldError.unwrap(TypeMismatchException.class))
|
||||
.hasMessageContaining("for property 'patternLocalDateWithFallbackPatterns'")
|
||||
.hasCauseInstanceOf(ConversionFailedException.class).getCause()
|
||||
.hasCauseInstanceOf(ConversionFailedException.class).cause()
|
||||
.hasMessageContaining("for value '210302'")
|
||||
.hasCauseInstanceOf(IllegalArgumentException.class).getCause()
|
||||
.hasCauseInstanceOf(IllegalArgumentException.class).cause()
|
||||
.hasMessageContaining("Parse attempt failed for value [210302]")
|
||||
.hasCauseInstanceOf(DateTimeParseException.class).getCause()
|
||||
.hasCauseInstanceOf(DateTimeParseException.class).cause()
|
||||
// Unable to parse date time value "210302" using configuration from
|
||||
// @org.springframework.format.annotation.DateTimeFormat(
|
||||
// pattern=yyyy-MM-dd, style=SS, iso=NONE, fallbackPatterns=[M/d/yy, yyyyMMdd, yyyy.MM.dd])
|
||||
@@ -551,7 +551,7 @@ class DateTimeFormattingTests {
|
||||
"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")
|
||||
.hasCauseInstanceOf(DateTimeParseException.class).getCause()
|
||||
.hasCauseInstanceOf(DateTimeParseException.class).cause()
|
||||
.hasMessageStartingWith("Text '210302'")
|
||||
.hasNoCause();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,6 +59,7 @@ import org.springframework.jmx.support.RegistrationPolicy;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
|
||||
|
||||
/**
|
||||
* Integration tests for the {@link MBeanExporter} class.
|
||||
@@ -589,8 +590,8 @@ public class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setBeans(beansToExport);
|
||||
exporter.setBeanFactory(factory);
|
||||
|
||||
assertThatExceptionOfType(RuntimeException.class).as("failed during creation of RuntimeExceptionThrowingConstructorBean").isThrownBy(() ->
|
||||
start(exporter));
|
||||
assertThatRuntimeException().as("failed during creation of RuntimeExceptionThrowingConstructorBean")
|
||||
.isThrownBy(() -> start(exporter));
|
||||
|
||||
assertIsNotRegistered("Must have unregistered all previously registered MBeans due to RuntimeException",
|
||||
ObjectNameManager.getInstance(objectName1));
|
||||
|
||||
+44
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author 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,9 @@
|
||||
|
||||
package org.springframework.scheduling.concurrent;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -23,10 +26,15 @@ 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.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.type;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ThreadPoolTaskExecutor}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 5.0.5
|
||||
*/
|
||||
class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
|
||||
@@ -50,8 +58,8 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
|
||||
|
||||
executor.setCorePoolSize(0);
|
||||
|
||||
assertThat(executor.getCorePoolSize()).isEqualTo(0);
|
||||
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(0);
|
||||
assertThat(executor.getCorePoolSize()).isZero();
|
||||
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isZero();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -112,4 +120,37 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
|
||||
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
|
||||
}
|
||||
|
||||
@Test
|
||||
void queueCapacityDefault() {
|
||||
assertThat(executor.getQueueCapacity()).isEqualTo(Integer.MAX_VALUE);
|
||||
assertThat(executor.getThreadPoolExecutor().getQueue())
|
||||
.asInstanceOf(type(LinkedBlockingQueue.class))
|
||||
.extracting(BlockingQueue::remainingCapacity).isEqualTo(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void queueCapacityZero() {
|
||||
executor.setQueueCapacity(0);
|
||||
executor.afterPropertiesSet();
|
||||
|
||||
assertThat(executor.getQueueCapacity()).isZero();
|
||||
assertThat(executor.getThreadPoolExecutor().getQueue())
|
||||
.asInstanceOf(type(SynchronousQueue.class))
|
||||
.extracting(BlockingQueue::remainingCapacity).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void queueSize() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
|
||||
assertThatIllegalStateException().isThrownBy(executor::getThreadPoolExecutor);
|
||||
assertThat(executor.getQueueSize()).isZero();
|
||||
|
||||
executor.afterPropertiesSet();
|
||||
|
||||
assertThat(executor.getThreadPoolExecutor()).isNotNull();
|
||||
assertThat(executor.getThreadPoolExecutor().getQueue()).isEmpty();
|
||||
assertThat(executor.getQueueSize()).isZero();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author 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,51 +22,50 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.support.GenericXmlApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class GroovyAspectIntegrationTests {
|
||||
class GroovyAspectIntegrationTests {
|
||||
|
||||
private GenericXmlApplicationContext context;
|
||||
|
||||
@Test
|
||||
public void testJavaBean() {
|
||||
context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName()+"-java-context.xml");
|
||||
void javaBean() {
|
||||
context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName() + "-java-context.xml");
|
||||
TestService bean = context.getBean("javaBean", TestService.class);
|
||||
LogUserAdvice logAdvice = context.getBean(LogUserAdvice.class);
|
||||
|
||||
assertThat(logAdvice.getCountThrows()).isEqualTo(0);
|
||||
assertThatExceptionOfType(RuntimeException.class).isThrownBy(
|
||||
bean::sayHello)
|
||||
assertThatRuntimeException()
|
||||
.isThrownBy(bean::sayHello)
|
||||
.withMessage("TestServiceImpl");
|
||||
assertThat(logAdvice.getCountThrows()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGroovyBeanInterface() {
|
||||
context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName()+"-groovy-interface-context.xml");
|
||||
void groovyBeanInterface() {
|
||||
context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName() + "-groovy-interface-context.xml");
|
||||
TestService bean = context.getBean("groovyBean", TestService.class);
|
||||
LogUserAdvice logAdvice = context.getBean(LogUserAdvice.class);
|
||||
|
||||
assertThat(logAdvice.getCountThrows()).isEqualTo(0);
|
||||
assertThatExceptionOfType(RuntimeException.class).isThrownBy(
|
||||
bean::sayHello)
|
||||
assertThatRuntimeException()
|
||||
.isThrownBy(bean::sayHello)
|
||||
.withMessage("GroovyServiceImpl");
|
||||
assertThat(logAdvice.getCountThrows()).isEqualTo(1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGroovyBeanDynamic() {
|
||||
context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName()+"-groovy-dynamic-context.xml");
|
||||
void groovyBeanDynamic() {
|
||||
context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName() + "-groovy-dynamic-context.xml");
|
||||
TestService bean = context.getBean("groovyBean", TestService.class);
|
||||
LogUserAdvice logAdvice = context.getBean(LogUserAdvice.class);
|
||||
|
||||
assertThat(logAdvice.getCountThrows()).isEqualTo(0);
|
||||
assertThatExceptionOfType(RuntimeException.class).isThrownBy(
|
||||
bean::sayHello)
|
||||
assertThatRuntimeException()
|
||||
.isThrownBy(bean::sayHello)
|
||||
.withMessage("GroovyServiceImpl");
|
||||
// No proxy here because the pointcut only applies to the concrete class, not the interface
|
||||
assertThat(logAdvice.getCountThrows()).isEqualTo(0);
|
||||
@@ -74,21 +73,21 @@ public class GroovyAspectIntegrationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGroovyBeanProxyTargetClass() {
|
||||
context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName()+"-groovy-proxy-target-class-context.xml");
|
||||
void groovyBeanProxyTargetClass() {
|
||||
context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName() + "-groovy-proxy-target-class-context.xml");
|
||||
TestService bean = context.getBean("groovyBean", TestService.class);
|
||||
LogUserAdvice logAdvice = context.getBean(LogUserAdvice.class);
|
||||
|
||||
assertThat(logAdvice.getCountThrows()).isEqualTo(0);
|
||||
assertThatExceptionOfType(RuntimeException.class).isThrownBy(
|
||||
bean::sayHello)
|
||||
assertThatRuntimeException()
|
||||
.isThrownBy(bean::sayHello)
|
||||
.withMessage("GroovyServiceImpl");
|
||||
assertThat(logAdvice.getCountBefore()).isEqualTo(1);
|
||||
assertThat(logAdvice.getCountThrows()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void close() {
|
||||
void close() {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,6 +46,7 @@ import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
@@ -318,7 +319,7 @@ public class GroovyScriptFactoryTests {
|
||||
|
||||
@Test
|
||||
public void testWithTwoClassesDefinedInTheOneGroovyFile_WrongClassFirst() throws Exception {
|
||||
assertThatExceptionOfType(Exception.class).as("two classes defined in GroovyScriptFactory source, non-Messenger class defined first").isThrownBy(() -> {
|
||||
assertThatException().as("two classes defined in GroovyScriptFactory source, non-Messenger class defined first").isThrownBy(() -> {
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext("twoClassesWrongOneFirst.xml", getClass());
|
||||
ctx.getBean("messenger", Messenger.class);
|
||||
});
|
||||
|
||||
+127
-135
@@ -64,23 +64,26 @@ import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
import org.springframework.format.support.FormattingConversionService;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.tests.sample.beans.BeanWithObjectProperty;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DataBinder}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Kazuki Shimizu
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
class DataBinderTests {
|
||||
|
||||
@Test
|
||||
void testBindingNoErrors() throws BindException {
|
||||
void bindingNoErrors() throws BindException {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod, "person");
|
||||
assertThat(binder.isIgnoreUnknownFields()).isTrue();
|
||||
@@ -110,12 +113,11 @@ class DataBinderTests {
|
||||
assertThat(ex).isEqualTo(binder.getBindingResult());
|
||||
|
||||
other.reject("xxx");
|
||||
boolean condition = !other.equals(binder.getBindingResult());
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(other).isNotEqualTo(binder.getBindingResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithDefaultConversionNoErrors() throws BindException {
|
||||
void bindingWithDefaultConversionNoErrors() throws BindException {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod, "person");
|
||||
assertThat(binder.isIgnoreUnknownFields()).isTrue();
|
||||
@@ -131,7 +133,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedBindingWithDefaultConversionNoErrors() throws BindException {
|
||||
void nestedBindingWithDefaultConversionNoErrors() throws BindException {
|
||||
TestBean rod = new TestBean(new TestBean());
|
||||
DataBinder binder = new DataBinder(rod, "person");
|
||||
assertThat(binder.isIgnoreUnknownFields()).isTrue();
|
||||
@@ -147,7 +149,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingNoErrorsNotIgnoreUnknown() {
|
||||
void bindingNoErrorsNotIgnoreUnknown() {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod, "person");
|
||||
binder.setIgnoreUnknownFields(false);
|
||||
@@ -160,7 +162,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingNoErrorsWithInvalidField() {
|
||||
void bindingNoErrorsWithInvalidField() {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod, "person");
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
@@ -171,7 +173,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingNoErrorsWithIgnoreInvalid() {
|
||||
void bindingNoErrorsWithIgnoreInvalid() throws BindException {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod, "person");
|
||||
binder.setIgnoreInvalidFields(true);
|
||||
@@ -180,10 +182,14 @@ class DataBinderTests {
|
||||
pvs.add("spouse.age", 32);
|
||||
|
||||
binder.bind(pvs);
|
||||
binder.close();
|
||||
|
||||
assertThat(rod.getName()).isEqualTo("Rod");
|
||||
assertThat(rod.getSpouse()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithErrors() {
|
||||
void bindingWithErrors() {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod, "person");
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
@@ -245,7 +251,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithSystemFieldError() {
|
||||
void bindingWithSystemFieldError() {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod, "person");
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
@@ -257,7 +263,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithErrorsAndCustomEditors() {
|
||||
void bindingWithErrorsAndCustomEditors() {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod, "person");
|
||||
binder.registerCustomEditor(String.class, "touchy", new PropertyEditorSupport() {
|
||||
@@ -325,7 +331,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithCustomEditorOnObjectField() {
|
||||
void bindingWithCustomEditorOnObjectField() {
|
||||
BeanWithObjectProperty tb = new BeanWithObjectProperty();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
binder.registerCustomEditor(Integer.class, "object", new CustomNumberEditor(Integer.class, true));
|
||||
@@ -336,7 +342,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithFormatter() {
|
||||
void bindingWithFormatter() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
FormattingConversionService conversionService = new FormattingConversionService();
|
||||
@@ -368,7 +374,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingErrorWithFormatter() {
|
||||
void bindingErrorWithFormatter() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
FormattingConversionService conversionService = new FormattingConversionService();
|
||||
@@ -391,7 +397,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingErrorWithParseExceptionFromFormatter() {
|
||||
void bindingErrorWithParseExceptionFromFormatter() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
FormattingConversionService conversionService = new FormattingConversionService();
|
||||
@@ -419,7 +425,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingErrorWithRuntimeExceptionFromFormatter() {
|
||||
void bindingErrorWithRuntimeExceptionFromFormatter() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
FormattingConversionService conversionService = new FormattingConversionService();
|
||||
@@ -447,7 +453,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithFormatterAgainstList() {
|
||||
void bindingWithFormatterAgainstList() {
|
||||
BeanWithIntegerList tb = new BeanWithIntegerList();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
FormattingConversionService conversionService = new FormattingConversionService();
|
||||
@@ -469,7 +475,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingErrorWithFormatterAgainstList() {
|
||||
void bindingErrorWithFormatterAgainstList() {
|
||||
BeanWithIntegerList tb = new BeanWithIntegerList();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
FormattingConversionService conversionService = new FormattingConversionService();
|
||||
@@ -492,7 +498,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithFormatterAgainstFields() {
|
||||
void bindingWithFormatterAgainstFields() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
FormattingConversionService conversionService = new FormattingConversionService();
|
||||
@@ -525,7 +531,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingErrorWithFormatterAgainstFields() {
|
||||
void bindingErrorWithFormatterAgainstFields() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
binder.initDirectFieldAccess();
|
||||
@@ -549,7 +555,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithCustomFormatter() {
|
||||
void bindingWithCustomFormatter() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
binder.addCustomFormatter(new NumberStyleFormatter(), Float.class);
|
||||
@@ -578,7 +584,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingErrorWithCustomFormatter() {
|
||||
void bindingErrorWithCustomFormatter() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
binder.addCustomFormatter(new NumberStyleFormatter());
|
||||
@@ -599,7 +605,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingErrorWithParseExceptionFromCustomFormatter() {
|
||||
void bindingErrorWithParseExceptionFromCustomFormatter() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
|
||||
@@ -624,7 +630,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingErrorWithRuntimeExceptionFromCustomFormatter() {
|
||||
void bindingErrorWithRuntimeExceptionFromCustomFormatter() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
|
||||
@@ -649,7 +655,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConversionWithInappropriateStringEditor() {
|
||||
void conversionWithInappropriateStringEditor() {
|
||||
DataBinder dataBinder = new DataBinder(null);
|
||||
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
|
||||
dataBinder.setConversionService(conversionService);
|
||||
@@ -662,7 +668,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithAllowedFields() throws BindException {
|
||||
void bindingWithAllowedFields() throws BindException {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod);
|
||||
binder.setAllowedFields("name", "myparam");
|
||||
@@ -672,30 +678,32 @@ class DataBinderTests {
|
||||
|
||||
binder.bind(pvs);
|
||||
binder.close();
|
||||
assertThat(rod.getName().equals("Rod")).as("changed name correctly").isTrue();
|
||||
assertThat(rod.getAge() == 0).as("did not change age").isTrue();
|
||||
|
||||
assertThat(rod.getName()).as("changed name correctly").isEqualTo("Rod");
|
||||
assertThat(rod.getAge()).as("did not change age").isZero();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithDisallowedFields() throws BindException {
|
||||
void bindingWithDisallowedFields() throws BindException {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod);
|
||||
binder.setDisallowedFields("age");
|
||||
binder.setDisallowedFields(" ", "\t", "favouriteColour", null, "age");
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.add("name", "Rod");
|
||||
pvs.add("age", "32x");
|
||||
pvs.add("favouriteColour", "BLUE");
|
||||
|
||||
binder.bind(pvs);
|
||||
binder.close();
|
||||
assertThat(rod.getName().equals("Rod")).as("changed name correctly").isTrue();
|
||||
assertThat(rod.getAge() == 0).as("did not change age").isTrue();
|
||||
String[] disallowedFields = binder.getBindingResult().getSuppressedFields();
|
||||
assertThat(disallowedFields.length).isEqualTo(1);
|
||||
assertThat(disallowedFields[0]).isEqualTo("age");
|
||||
|
||||
assertThat(rod.getName()).as("changed name correctly").isEqualTo("Rod");
|
||||
assertThat(rod.getAge()).as("did not change age").isZero();
|
||||
assertThat(rod.getFavouriteColour()).as("did not change favourite colour").isNull();
|
||||
assertThat(binder.getBindingResult().getSuppressedFields()).containsExactlyInAnyOrder("age", "favouriteColour");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithAllowedAndDisallowedFields() throws BindException {
|
||||
void bindingWithAllowedAndDisallowedFields() throws BindException {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod);
|
||||
binder.setAllowedFields("name", "myparam");
|
||||
@@ -706,34 +714,32 @@ class DataBinderTests {
|
||||
|
||||
binder.bind(pvs);
|
||||
binder.close();
|
||||
assertThat(rod.getName().equals("Rod")).as("changed name correctly").isTrue();
|
||||
assertThat(rod.getAge() == 0).as("did not change age").isTrue();
|
||||
String[] disallowedFields = binder.getBindingResult().getSuppressedFields();
|
||||
assertThat(disallowedFields).hasSize(1);
|
||||
assertThat(disallowedFields[0]).isEqualTo("age");
|
||||
|
||||
assertThat(rod.getName()).as("changed name correctly").isEqualTo("Rod");
|
||||
assertThat(rod.getAge()).as("did not change age").isZero();
|
||||
assertThat(binder.getBindingResult().getSuppressedFields()).containsExactly("age");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithOverlappingAllowedAndDisallowedFields() throws BindException {
|
||||
void bindingWithOverlappingAllowedAndDisallowedFields() throws BindException {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod);
|
||||
binder.setAllowedFields("name", "age");
|
||||
binder.setDisallowedFields("age");
|
||||
binder.setDisallowedFields("AGE");
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.add("name", "Rod");
|
||||
pvs.add("age", "32x");
|
||||
|
||||
binder.bind(pvs);
|
||||
binder.close();
|
||||
assertThat(rod.getName().equals("Rod")).as("changed name correctly").isTrue();
|
||||
assertThat(rod.getAge() == 0).as("did not change age").isTrue();
|
||||
String[] disallowedFields = binder.getBindingResult().getSuppressedFields();
|
||||
assertThat(disallowedFields).hasSize(1);
|
||||
assertThat(disallowedFields[0]).isEqualTo("age");
|
||||
|
||||
assertThat(rod.getName()).as("changed name correctly").isEqualTo("Rod");
|
||||
assertThat(rod.getAge()).as("did not change age").isZero();
|
||||
assertThat(binder.getBindingResult().getSuppressedFields()).containsExactly("age");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithAllowedFieldsUsingAsterisks() throws BindException {
|
||||
void bindingWithAllowedFieldsUsingAsterisks() throws BindException {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod, "person");
|
||||
binder.setAllowedFields("nam*", "*ouchy");
|
||||
@@ -760,11 +766,11 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithAllowedAndDisallowedMapFields() throws BindException {
|
||||
void bindingWithAllowedAndDisallowedMapFields() throws BindException {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod);
|
||||
binder.setAllowedFields("someMap[key1]", "someMap[key2]");
|
||||
binder.setDisallowedFields("someMap['key3']", "someMap[key4]");
|
||||
binder.setDisallowedFields("someMap['KEY3']", "SomeMap[key4]");
|
||||
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.add("someMap[key1]", "value1");
|
||||
@@ -774,21 +780,18 @@ class DataBinderTests {
|
||||
|
||||
binder.bind(pvs);
|
||||
binder.close();
|
||||
assertThat(rod.getSomeMap().get("key1")).isEqualTo("value1");
|
||||
assertThat(rod.getSomeMap().get("key2")).isEqualTo("value2");
|
||||
assertThat(rod.getSomeMap().get("key3")).isNull();
|
||||
assertThat(rod.getSomeMap().get("key4")).isNull();
|
||||
String[] disallowedFields = binder.getBindingResult().getSuppressedFields();
|
||||
assertThat(disallowedFields).hasSize(2);
|
||||
assertThat(ObjectUtils.containsElement(disallowedFields, "someMap[key3]")).isTrue();
|
||||
assertThat(ObjectUtils.containsElement(disallowedFields, "someMap[key4]")).isTrue();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String> someMap = (Map<String, String>) rod.getSomeMap();
|
||||
assertThat(someMap).containsOnly(entry("key1", "value1"), entry("key2", "value2"));
|
||||
assertThat(binder.getBindingResult().getSuppressedFields()).containsExactly("someMap[key3]", "someMap[key4]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for required field, both null, non-existing and empty strings.
|
||||
*/
|
||||
@Test
|
||||
void testBindingWithRequiredFields() {
|
||||
void bindingWithRequiredFields() {
|
||||
TestBean tb = new TestBean();
|
||||
tb.setSpouse(new TestBean());
|
||||
|
||||
@@ -819,7 +822,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithRequiredMapFields() {
|
||||
void bindingWithRequiredMapFields() {
|
||||
TestBean tb = new TestBean();
|
||||
tb.setSpouse(new TestBean());
|
||||
|
||||
@@ -839,7 +842,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingWithNestedObjectCreation() {
|
||||
void bindingWithNestedObjectCreation() {
|
||||
TestBean tb = new TestBean();
|
||||
|
||||
DataBinder binder = new DataBinder(tb, "person");
|
||||
@@ -860,7 +863,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomEditorWithOldValueAccess() {
|
||||
void customEditorWithOldValueAccess() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
|
||||
@@ -885,7 +888,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomEditorForSingleProperty() {
|
||||
void customEditorForSingleProperty() {
|
||||
TestBean tb = new TestBean();
|
||||
tb.setSpouse(new TestBean());
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
@@ -925,7 +928,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomEditorForPrimitiveProperty() {
|
||||
void customEditorForPrimitiveProperty() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
|
||||
@@ -949,7 +952,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomEditorForAllStringProperties() {
|
||||
void customEditorForAllStringProperties() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
|
||||
@@ -981,7 +984,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomFormatterForSingleProperty() {
|
||||
void customFormatterForSingleProperty() {
|
||||
TestBean tb = new TestBean();
|
||||
tb.setSpouse(new TestBean());
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
@@ -1021,7 +1024,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomFormatterForPrimitiveProperty() {
|
||||
void customFormatterForPrimitiveProperty() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
|
||||
@@ -1045,7 +1048,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomFormatterForAllStringProperties() {
|
||||
void customFormatterForAllStringProperties() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
|
||||
@@ -1077,7 +1080,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJavaBeanPropertyConventions() {
|
||||
void javaBeanPropertyConventions() {
|
||||
Book book = new Book();
|
||||
DataBinder binder = new DataBinder(book);
|
||||
|
||||
@@ -1101,7 +1104,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOptionalProperty() {
|
||||
void optionalProperty() {
|
||||
OptionalHolder bean = new OptionalHolder();
|
||||
DataBinder binder = new DataBinder(bean);
|
||||
binder.setConversionService(new DefaultConversionService());
|
||||
@@ -1122,7 +1125,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidatorNoErrors() throws Exception {
|
||||
void validatorNoErrors() throws Exception {
|
||||
TestBean tb = new TestBean();
|
||||
tb.setAge(33);
|
||||
tb.setName("Rod");
|
||||
@@ -1175,15 +1178,13 @@ class DataBinderTests {
|
||||
assertThat(errors.getNestedPath()).isEqualTo("spouse.");
|
||||
|
||||
assertThat(errors.getErrorCount()).isEqualTo(1);
|
||||
boolean condition1 = !errors.hasGlobalErrors();
|
||||
assertThat(condition1).isTrue();
|
||||
assertThat(errors.hasGlobalErrors()).isFalse();
|
||||
assertThat(errors.getFieldErrorCount("age")).isEqualTo(1);
|
||||
boolean condition = !errors.hasFieldErrors("name");
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(errors.hasFieldErrors("name")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidatorWithErrors() {
|
||||
void validatorWithErrors() {
|
||||
TestBean tb = new TestBean();
|
||||
tb.setSpouse(new TestBean());
|
||||
|
||||
@@ -1252,7 +1253,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidatorWithErrorsAndCodesPrefix() {
|
||||
void validatorWithErrorsAndCodesPrefix() {
|
||||
TestBean tb = new TestBean();
|
||||
tb.setSpouse(new TestBean());
|
||||
|
||||
@@ -1324,7 +1325,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidatorWithNestedObjectNull() {
|
||||
void validatorWithNestedObjectNull() {
|
||||
TestBean tb = new TestBean();
|
||||
Errors errors = new BeanPropertyBindingResult(tb, "tb");
|
||||
Validator testValidator = new TestBeanValidator();
|
||||
@@ -1343,7 +1344,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedValidatorWithoutNestedPath() {
|
||||
void nestedValidatorWithoutNestedPath() {
|
||||
TestBean tb = new TestBean();
|
||||
tb.setName("XXX");
|
||||
Errors errors = new BeanPropertyBindingResult(tb, "tb");
|
||||
@@ -1357,7 +1358,8 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingStringArrayToIntegerSet() {
|
||||
@SuppressWarnings("unchecked")
|
||||
void bindingStringArrayToIntegerSet() {
|
||||
IndexedTestBean tb = new IndexedTestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
binder.registerCustomEditor(Set.class, new CustomCollectionEditor(TreeSet.class) {
|
||||
@@ -1371,12 +1373,8 @@ class DataBinderTests {
|
||||
binder.bind(pvs);
|
||||
|
||||
assertThat(binder.getBindingResult().getFieldValue("set")).isEqualTo(tb.getSet());
|
||||
boolean condition = tb.getSet() instanceof TreeSet;
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(tb.getSet().size()).isEqualTo(3);
|
||||
assertThat(tb.getSet().contains(10)).isTrue();
|
||||
assertThat(tb.getSet().contains(20)).isTrue();
|
||||
assertThat(tb.getSet().contains(30)).isTrue();
|
||||
assertThat(tb.getSet()).isInstanceOf(TreeSet.class);
|
||||
assertThat((Set<Integer>) tb.getSet()).containsExactly(10, 20, 30);
|
||||
|
||||
pvs = new MutablePropertyValues();
|
||||
pvs.add("set", null);
|
||||
@@ -1386,7 +1384,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingNullToEmptyCollection() {
|
||||
void bindingNullToEmptyCollection() {
|
||||
IndexedTestBean tb = new IndexedTestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
binder.registerCustomEditor(Set.class, new CustomCollectionEditor(TreeSet.class, true));
|
||||
@@ -1394,13 +1392,12 @@ class DataBinderTests {
|
||||
pvs.add("set", null);
|
||||
binder.bind(pvs);
|
||||
|
||||
boolean condition = tb.getSet() instanceof TreeSet;
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(tb.getSet().isEmpty()).isTrue();
|
||||
assertThat(tb.getSet()).isInstanceOf(TreeSet.class);
|
||||
assertThat(tb.getSet()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingToIndexedField() {
|
||||
void bindingToIndexedField() {
|
||||
IndexedTestBean tb = new IndexedTestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
binder.registerCustomEditor(String.class, "array.name", new PropertyEditorSupport() {
|
||||
@@ -1439,7 +1436,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingToNestedIndexedField() {
|
||||
void bindingToNestedIndexedField() {
|
||||
IndexedTestBean tb = new IndexedTestBean();
|
||||
tb.getArray()[0].setNestedIndexedBean(new IndexedTestBean());
|
||||
tb.getArray()[1].setNestedIndexedBean(new IndexedTestBean());
|
||||
@@ -1470,7 +1467,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEditorForNestedIndexedField() {
|
||||
void editorForNestedIndexedField() {
|
||||
IndexedTestBean tb = new IndexedTestBean();
|
||||
tb.getArray()[0].setNestedIndexedBean(new IndexedTestBean());
|
||||
tb.getArray()[1].setNestedIndexedBean(new IndexedTestBean());
|
||||
@@ -1496,7 +1493,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSpecificEditorForNestedIndexedField() {
|
||||
void specificEditorForNestedIndexedField() {
|
||||
IndexedTestBean tb = new IndexedTestBean();
|
||||
tb.getArray()[0].setNestedIndexedBean(new IndexedTestBean());
|
||||
tb.getArray()[1].setNestedIndexedBean(new IndexedTestBean());
|
||||
@@ -1522,7 +1519,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInnerSpecificEditorForNestedIndexedField() {
|
||||
void innerSpecificEditorForNestedIndexedField() {
|
||||
IndexedTestBean tb = new IndexedTestBean();
|
||||
tb.getArray()[0].setNestedIndexedBean(new IndexedTestBean());
|
||||
tb.getArray()[1].setNestedIndexedBean(new IndexedTestBean());
|
||||
@@ -1548,7 +1545,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDirectBindingToIndexedField() {
|
||||
void directBindingToIndexedField() {
|
||||
IndexedTestBean tb = new IndexedTestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
binder.registerCustomEditor(TestBean.class, "array", new PropertyEditorSupport() {
|
||||
@@ -1601,7 +1598,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDirectBindingToEmptyIndexedFieldWithRegisteredSpecificEditor() {
|
||||
void directBindingToEmptyIndexedFieldWithRegisteredSpecificEditor() {
|
||||
IndexedTestBean tb = new IndexedTestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
binder.registerCustomEditor(TestBean.class, "map[key0]", new PropertyEditorSupport() {
|
||||
@@ -1632,7 +1629,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDirectBindingToEmptyIndexedFieldWithRegisteredGenericEditor() {
|
||||
void directBindingToEmptyIndexedFieldWithRegisteredGenericEditor() {
|
||||
IndexedTestBean tb = new IndexedTestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
binder.registerCustomEditor(TestBean.class, "map", new PropertyEditorSupport() {
|
||||
@@ -1663,7 +1660,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomEditorWithSubclass() {
|
||||
void customEditorWithSubclass() {
|
||||
IndexedTestBean tb = new IndexedTestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
binder.registerCustomEditor(TestBean.class, new PropertyEditorSupport() {
|
||||
@@ -1697,7 +1694,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindToStringArrayWithArrayEditor() {
|
||||
void bindToStringArrayWithArrayEditor() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
binder.registerCustomEditor(String[].class, "stringArray", new PropertyEditorSupport() {
|
||||
@@ -1709,15 +1706,12 @@ class DataBinderTests {
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.add("stringArray", "a1-b2");
|
||||
binder.bind(pvs);
|
||||
boolean condition = !binder.getBindingResult().hasErrors();
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(tb.getStringArray().length).isEqualTo(2);
|
||||
assertThat(tb.getStringArray()[0]).isEqualTo("a1");
|
||||
assertThat(tb.getStringArray()[1]).isEqualTo("b2");
|
||||
assertThat(binder.getBindingResult().hasErrors()).isFalse();
|
||||
assertThat(tb.getStringArray()).containsExactly("a1", "b2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindToStringArrayWithComponentEditor() {
|
||||
void bindToStringArrayWithComponentEditor() {
|
||||
TestBean tb = new TestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
binder.registerCustomEditor(String.class, "stringArray", new PropertyEditorSupport() {
|
||||
@@ -1729,15 +1723,14 @@ class DataBinderTests {
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
pvs.add("stringArray", new String[] {"a1", "b2"});
|
||||
binder.bind(pvs);
|
||||
boolean condition = !binder.getBindingResult().hasErrors();
|
||||
assertThat(condition).isTrue();
|
||||
assertThat(binder.getBindingResult().hasErrors()).isFalse();
|
||||
assertThat(tb.getStringArray().length).isEqualTo(2);
|
||||
assertThat(tb.getStringArray()[0]).isEqualTo("Xa1");
|
||||
assertThat(tb.getStringArray()[1]).isEqualTo("Xb2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingErrors() {
|
||||
void bindingErrors() {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod, "person");
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
@@ -1764,7 +1757,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddAllErrors() {
|
||||
void addAllErrors() {
|
||||
TestBean rod = new TestBean();
|
||||
DataBinder binder = new DataBinder(rod, "person");
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
@@ -1784,7 +1777,7 @@ class DataBinderTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void testBindingWithResortedList() {
|
||||
void bindingWithResortedList() {
|
||||
IndexedTestBean tb = new IndexedTestBean();
|
||||
DataBinder binder = new DataBinder(tb, "tb");
|
||||
MutablePropertyValues pvs = new MutablePropertyValues();
|
||||
@@ -1802,7 +1795,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRejectWithoutDefaultMessage() {
|
||||
void rejectWithoutDefaultMessage() {
|
||||
TestBean tb = new TestBean();
|
||||
tb.setName("myName");
|
||||
tb.setAge(99);
|
||||
@@ -1820,7 +1813,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindExceptionSerializable() throws Exception {
|
||||
void bindExceptionSerializable() throws Exception {
|
||||
SerializablePerson tb = new SerializablePerson();
|
||||
tb.setName("myName");
|
||||
tb.setAge(99);
|
||||
@@ -1849,27 +1842,27 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTrackDisallowedFields() {
|
||||
void trackDisallowedFields() {
|
||||
TestBean testBean = new TestBean();
|
||||
DataBinder binder = new DataBinder(testBean, "testBean");
|
||||
binder.setAllowedFields("name", "age");
|
||||
|
||||
String name = "Rob Harrop";
|
||||
String beanName = "foobar";
|
||||
int age = 42;
|
||||
|
||||
MutablePropertyValues mpvs = new MutablePropertyValues();
|
||||
mpvs.add("name", name);
|
||||
mpvs.add("beanName", beanName);
|
||||
mpvs.add("age", age);
|
||||
mpvs.add("beanName", "foobar");
|
||||
binder.bind(mpvs);
|
||||
|
||||
assertThat(testBean.getName()).isEqualTo(name);
|
||||
String[] disallowedFields = binder.getBindingResult().getSuppressedFields();
|
||||
assertThat(disallowedFields).hasSize(1);
|
||||
assertThat(disallowedFields[0]).isEqualTo("beanName");
|
||||
assertThat(testBean.getAge()).isEqualTo(age);
|
||||
assertThat(binder.getBindingResult().getSuppressedFields()).containsExactly("beanName");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAutoGrowWithinDefaultLimit() {
|
||||
void autoGrowWithinDefaultLimit() {
|
||||
TestBean testBean = new TestBean();
|
||||
DataBinder binder = new DataBinder(testBean, "testBean");
|
||||
|
||||
@@ -1881,7 +1874,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAutoGrowBeyondDefaultLimit() {
|
||||
void autoGrowBeyondDefaultLimit() {
|
||||
TestBean testBean = new TestBean();
|
||||
DataBinder binder = new DataBinder(testBean, "testBean");
|
||||
|
||||
@@ -1894,7 +1887,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAutoGrowWithinCustomLimit() {
|
||||
void autoGrowWithinCustomLimit() {
|
||||
TestBean testBean = new TestBean();
|
||||
DataBinder binder = new DataBinder(testBean, "testBean");
|
||||
binder.setAutoGrowCollectionLimit(10);
|
||||
@@ -1907,7 +1900,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAutoGrowBeyondCustomLimit() {
|
||||
void autoGrowBeyondCustomLimit() {
|
||||
TestBean testBean = new TestBean();
|
||||
DataBinder binder = new DataBinder(testBean, "testBean");
|
||||
binder.setAutoGrowCollectionLimit(10);
|
||||
@@ -1921,7 +1914,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedGrowingList() {
|
||||
void nestedGrowingList() {
|
||||
Form form = new Form();
|
||||
DataBinder binder = new DataBinder(form, "form");
|
||||
MutablePropertyValues mpv = new MutablePropertyValues();
|
||||
@@ -1937,7 +1930,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFieldErrorAccessVariations() {
|
||||
void fieldErrorAccessVariations() {
|
||||
TestBean testBean = new TestBean();
|
||||
DataBinder binder = new DataBinder(testBean, "testBean");
|
||||
assertThat(binder.getBindingResult().getGlobalError()).isNull();
|
||||
@@ -1958,7 +1951,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test // SPR-14888
|
||||
void testSetAutoGrowCollectionLimit() {
|
||||
void setAutoGrowCollectionLimit() {
|
||||
BeanWithIntegerList tb = new BeanWithIntegerList();
|
||||
DataBinder binder = new DataBinder(tb);
|
||||
binder.setAutoGrowCollectionLimit(257);
|
||||
@@ -1972,7 +1965,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test // SPR-14888
|
||||
void testSetAutoGrowCollectionLimitAfterInitialization() {
|
||||
void setAutoGrowCollectionLimitAfterInitialization() {
|
||||
DataBinder binder = new DataBinder(new BeanWithIntegerList());
|
||||
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
|
||||
assertThatIllegalStateException().isThrownBy(() ->
|
||||
@@ -1981,7 +1974,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test // SPR-15009
|
||||
void testSetCustomMessageCodesResolverBeforeInitializeBindingResultForBeanPropertyAccess() {
|
||||
void setCustomMessageCodesResolverBeforeInitializeBindingResultForBeanPropertyAccess() {
|
||||
TestBean testBean = new TestBean();
|
||||
DataBinder binder = new DataBinder(testBean, "testBean");
|
||||
DefaultMessageCodesResolver messageCodesResolver = new DefaultMessageCodesResolver();
|
||||
@@ -1998,7 +1991,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test // SPR-15009
|
||||
void testSetCustomMessageCodesResolverBeforeInitializeBindingResultForDirectFieldAccess() {
|
||||
void setCustomMessageCodesResolverBeforeInitializeBindingResultForDirectFieldAccess() {
|
||||
TestBean testBean = new TestBean();
|
||||
DataBinder binder = new DataBinder(testBean, "testBean");
|
||||
DefaultMessageCodesResolver messageCodesResolver = new DefaultMessageCodesResolver();
|
||||
@@ -2013,7 +2006,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test // SPR-15009
|
||||
void testSetCustomMessageCodesResolverAfterInitializeBindingResult() {
|
||||
void setCustomMessageCodesResolverAfterInitializeBindingResult() {
|
||||
TestBean testBean = new TestBean();
|
||||
DataBinder binder = new DataBinder(testBean, "testBean");
|
||||
binder.initBeanPropertyAccess();
|
||||
@@ -2028,7 +2021,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test // SPR-15009
|
||||
void testSetMessageCodesResolverIsNullAfterInitializeBindingResult() {
|
||||
void setMessageCodesResolverIsNullAfterInitializeBindingResult() {
|
||||
TestBean testBean = new TestBean();
|
||||
DataBinder binder = new DataBinder(testBean, "testBean");
|
||||
binder.initBeanPropertyAccess();
|
||||
@@ -2042,8 +2035,7 @@ class DataBinderTests {
|
||||
}
|
||||
|
||||
@Test // SPR-15009
|
||||
void testCallSetMessageCodesResolverTwice() {
|
||||
|
||||
void callSetMessageCodesResolverTwice() {
|
||||
TestBean testBean = new TestBean();
|
||||
DataBinder binder = new DataBinder(testBean, "testBean");
|
||||
binder.setMessageCodesResolver(new DefaultMessageCodesResolver());
|
||||
|
||||
+36
-5
@@ -31,6 +31,7 @@ import java.util.Set;
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import javax.validation.ConstraintValidatorFactory;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Payload;
|
||||
import javax.validation.Valid;
|
||||
@@ -43,6 +44,7 @@ import org.hibernate.validator.HibernateValidatorFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
@@ -313,6 +315,32 @@ class ValidatorFactoryTests {
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
void withConstraintValidatorFactory() {
|
||||
ConstraintValidatorFactory cvf = new SpringConstraintValidatorFactory(new DefaultListableBeanFactory());
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.setConstraintValidatorFactory(cvf);
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
assertThat(validator.getConstraintValidatorFactory()).isSameAs(cvf);
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
void withCustomInitializer() {
|
||||
ConstraintValidatorFactory cvf = new SpringConstraintValidatorFactory(new DefaultListableBeanFactory());
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.setConfigurationInitializer(configuration -> configuration.constraintValidatorFactory(cvf));
|
||||
validator.afterPropertiesSet();
|
||||
|
||||
assertThat(validator.getConstraintValidatorFactory()).isSameAs(cvf);
|
||||
validator.destroy();
|
||||
}
|
||||
|
||||
|
||||
@NameAddressValid
|
||||
public static class ValidPerson {
|
||||
@@ -409,8 +437,8 @@ class ValidatorFactoryTests {
|
||||
}
|
||||
boolean valid = (value.name == null || !value.address.street.contains(value.name));
|
||||
if (!valid && "Phil".equals(value.name)) {
|
||||
context.buildConstraintViolationWithTemplate(
|
||||
context.getDefaultConstraintMessageTemplate()).addPropertyNode("address").addConstraintViolation().disableDefaultConstraintViolation();
|
||||
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
|
||||
.addPropertyNode("address").addConstraintViolation().disableDefaultConstraintViolation();
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
@@ -446,6 +474,7 @@ class ValidatorFactoryTests {
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
@@ -454,7 +483,7 @@ class ValidatorFactoryTests {
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Constraint(validatedBy=InnerValidator.class)
|
||||
@Constraint(validatedBy = InnerValidator.class)
|
||||
public @interface InnerValid {
|
||||
|
||||
String message() default "NOT VALID";
|
||||
@@ -475,7 +504,8 @@ class ValidatorFactoryTests {
|
||||
public boolean isValid(InnerBean bean, ConstraintValidatorContext context) {
|
||||
context.disableDefaultConstraintViolation();
|
||||
if (bean.getValue() == null) {
|
||||
context.buildConstraintViolationWithTemplate("NULL").addPropertyNode("value").addConstraintViolation();
|
||||
context.buildConstraintViolationWithTemplate("NULL")
|
||||
.addPropertyNode("value").addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -523,7 +553,8 @@ class ValidatorFactoryTests {
|
||||
boolean valid = true;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if ("X".equals(list.get(i))) {
|
||||
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addBeanNode().inIterable().atIndex(i).addConstraintViolation();
|
||||
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
|
||||
.addBeanNode().inIterable().atIndex(i).addConstraintViolation();
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -5,19 +5,19 @@
|
||||
|
||||
<bean id="publisher" class="org.springframework.jmx.export.NotificationPublisherTests$MyNotificationPublisher"/>
|
||||
|
||||
<bean id="publisherMBean" class="org.springframework.jmx.export.NotificationPublisherTests$MyNotificationPublisherMBean"/>
|
||||
<bean id="publisherMBean" class="org.springframework.jmx.export.NotificationPublisherTests$MyNotificationPublisherMBean"/>
|
||||
|
||||
<bean id="publisherStandardMBean" class="org.springframework.jmx.export.NotificationPublisherTests$MyNotificationPublisherStandardMBean"/>
|
||||
<bean id="publisherStandardMBean" class="org.springframework.jmx.export.NotificationPublisherTests$MyNotificationPublisherStandardMBean"/>
|
||||
|
||||
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
|
||||
<property name="beans">
|
||||
<map>
|
||||
<entry key="spring:type=Publisher" value-ref="publisher"/>
|
||||
<entry key="spring:type=PublisherMBean" value-ref="publisherMBean"/>
|
||||
<entry key="spring:type=PublisherStandardMBean" value-ref="publisherStandardMBean"/>
|
||||
<entry key="spring:type=PublisherMBean" value-ref="publisherMBean"/>
|
||||
<entry key="spring:type=PublisherStandardMBean" value-ref="publisherStandardMBean"/>
|
||||
</map>
|
||||
</property>
|
||||
<property name="server" ref="server"/>
|
||||
<property name="server" ref="server"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -76,8 +76,7 @@ jar {
|
||||
dependsOn cglibRepackJar
|
||||
from(zipTree(cglibRepackJar.archivePath)) {
|
||||
include "org/springframework/cglib/**"
|
||||
exclude "org/springframework/cglib/beans/BeanMap.class"
|
||||
exclude "org/springframework/cglib/beans/BeanMap\$*.class"
|
||||
exclude "org/springframework/cglib/beans/**"
|
||||
exclude "org/springframework/cglib/core/AbstractClassGenerator*.class"
|
||||
exclude "org/springframework/cglib/core/AsmApi*.class"
|
||||
exclude "org/springframework/cglib/core/KeyFactory.class"
|
||||
|
||||
@@ -55,7 +55,7 @@ public abstract class AnnotationVisitor {
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of the {@code
|
||||
* ASM}<i>x</i> values in {@link Opcodes}.
|
||||
*/
|
||||
public AnnotationVisitor(final int api) {
|
||||
protected AnnotationVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public abstract class AnnotationVisitor {
|
||||
* @param annotationVisitor the annotation visitor to which this visitor must delegate method
|
||||
* calls. May be {@literal null}.
|
||||
*/
|
||||
public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
|
||||
protected AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
|
||||
if (api != Opcodes.ASM9
|
||||
&& api != Opcodes.ASM8
|
||||
&& api != Opcodes.ASM7
|
||||
|
||||
@@ -65,6 +65,15 @@ public class ByteVector {
|
||||
this.length = data.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual number of bytes in this vector.
|
||||
*
|
||||
* @return the actual number of bytes in this vector.
|
||||
*/
|
||||
public int size() {
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
|
||||
@@ -54,7 +54,7 @@ public abstract class ClassVisitor {
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of the {@code
|
||||
* ASM}<i>x</i> values in {@link Opcodes}.
|
||||
*/
|
||||
public ClassVisitor(final int api) {
|
||||
protected ClassVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public abstract class ClassVisitor {
|
||||
* @param classVisitor the class visitor to which this visitor must delegate method calls. May be
|
||||
* null.
|
||||
*/
|
||||
public ClassVisitor(final int api, final ClassVisitor classVisitor) {
|
||||
protected ClassVisitor(final int api, final ClassVisitor classVisitor) {
|
||||
if (api != Opcodes.ASM9
|
||||
&& api != Opcodes.ASM8
|
||||
&& api != Opcodes.ASM7
|
||||
|
||||
@@ -51,7 +51,7 @@ public abstract class FieldVisitor {
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of the {@code
|
||||
* ASM}<i>x</i> values in {@link Opcodes}.
|
||||
*/
|
||||
public FieldVisitor(final int api) {
|
||||
protected FieldVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public abstract class FieldVisitor {
|
||||
* @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be
|
||||
* null.
|
||||
*/
|
||||
public FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
|
||||
protected FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
|
||||
if (api != Opcodes.ASM9
|
||||
&& api != Opcodes.ASM8
|
||||
&& api != Opcodes.ASM7
|
||||
|
||||
@@ -67,7 +67,7 @@ public abstract class MethodVisitor {
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of the {@code
|
||||
* ASM}<i>x</i> values in {@link Opcodes}.
|
||||
*/
|
||||
public MethodVisitor(final int api) {
|
||||
protected MethodVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public abstract class MethodVisitor {
|
||||
* @param methodVisitor the method visitor to which this visitor must delegate method calls. May
|
||||
* be null.
|
||||
*/
|
||||
public MethodVisitor(final int api, final MethodVisitor methodVisitor) {
|
||||
protected MethodVisitor(final int api, final MethodVisitor methodVisitor) {
|
||||
if (api != Opcodes.ASM9
|
||||
&& api != Opcodes.ASM8
|
||||
&& api != Opcodes.ASM7
|
||||
@@ -349,12 +349,12 @@ public abstract class MethodVisitor {
|
||||
*
|
||||
* @param opcode the opcode of the local variable instruction to be visited. This opcode is either
|
||||
* ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
|
||||
* @param var the operand of the instruction to be visited. This operand is the index of a local
|
||||
* variable.
|
||||
* @param varIndex the operand of the instruction to be visited. This operand is the index of a
|
||||
* local variable.
|
||||
*/
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
public void visitVarInsn(final int opcode, final int varIndex) {
|
||||
if (mv != null) {
|
||||
mv.visitVarInsn(opcode, var);
|
||||
mv.visitVarInsn(opcode, varIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -466,7 +466,8 @@ final class MethodWriter extends MethodVisitor {
|
||||
|
||||
/**
|
||||
* Indicates what must be computed. Must be one of {@link #COMPUTE_ALL_FRAMES}, {@link
|
||||
* #COMPUTE_INSERTED_FRAMES}, {@link #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_NOTHING}.
|
||||
* #COMPUTE_INSERTED_FRAMES}, {@link COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link
|
||||
* #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_NOTHING}.
|
||||
*/
|
||||
private final int compute;
|
||||
|
||||
@@ -904,26 +905,26 @@ final class MethodWriter extends MethodVisitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
public void visitVarInsn(final int opcode, final int varIndex) {
|
||||
lastBytecodeOffset = code.length;
|
||||
// Add the instruction to the bytecode of the method.
|
||||
if (var < 4 && opcode != Opcodes.RET) {
|
||||
if (varIndex < 4 && opcode != Opcodes.RET) {
|
||||
int optimizedOpcode;
|
||||
if (opcode < Opcodes.ISTORE) {
|
||||
optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + var;
|
||||
optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + varIndex;
|
||||
} else {
|
||||
optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + var;
|
||||
optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + varIndex;
|
||||
}
|
||||
code.putByte(optimizedOpcode);
|
||||
} else if (var >= 256) {
|
||||
code.putByte(Constants.WIDE).put12(opcode, var);
|
||||
} else if (varIndex >= 256) {
|
||||
code.putByte(Constants.WIDE).put12(opcode, varIndex);
|
||||
} else {
|
||||
code.put11(opcode, var);
|
||||
code.put11(opcode, varIndex);
|
||||
}
|
||||
// If needed, update the maximum stack size and number of locals, and stack map frames.
|
||||
if (currentBasicBlock != null) {
|
||||
if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
|
||||
currentBasicBlock.frame.execute(opcode, var, null, null);
|
||||
currentBasicBlock.frame.execute(opcode, varIndex, null, null);
|
||||
} else {
|
||||
if (opcode == Opcodes.RET) {
|
||||
// No stack size delta.
|
||||
@@ -945,9 +946,9 @@ final class MethodWriter extends MethodVisitor {
|
||||
|| opcode == Opcodes.DLOAD
|
||||
|| opcode == Opcodes.LSTORE
|
||||
|| opcode == Opcodes.DSTORE) {
|
||||
currentMaxLocals = var + 2;
|
||||
currentMaxLocals = varIndex + 2;
|
||||
} else {
|
||||
currentMaxLocals = var + 1;
|
||||
currentMaxLocals = varIndex + 1;
|
||||
}
|
||||
if (currentMaxLocals > maxLocals) {
|
||||
maxLocals = currentMaxLocals;
|
||||
@@ -1307,21 +1308,21 @@ final class MethodWriter extends MethodVisitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(final int var, final int increment) {
|
||||
public void visitIincInsn(final int varIndex, final int increment) {
|
||||
lastBytecodeOffset = code.length;
|
||||
// Add the instruction to the bytecode of the method.
|
||||
if ((var > 255) || (increment > 127) || (increment < -128)) {
|
||||
code.putByte(Constants.WIDE).put12(Opcodes.IINC, var).putShort(increment);
|
||||
if ((varIndex > 255) || (increment > 127) || (increment < -128)) {
|
||||
code.putByte(Constants.WIDE).put12(Opcodes.IINC, varIndex).putShort(increment);
|
||||
} else {
|
||||
code.putByte(Opcodes.IINC).put11(var, increment);
|
||||
code.putByte(Opcodes.IINC).put11(varIndex, increment);
|
||||
}
|
||||
// If needed, update the maximum stack size and number of locals, and stack map frames.
|
||||
if (currentBasicBlock != null
|
||||
&& (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES)) {
|
||||
currentBasicBlock.frame.execute(Opcodes.IINC, var, null, null);
|
||||
currentBasicBlock.frame.execute(Opcodes.IINC, varIndex, null, null);
|
||||
}
|
||||
if (compute != COMPUTE_NOTHING) {
|
||||
int currentMaxLocals = var + 1;
|
||||
int currentMaxLocals = varIndex + 1;
|
||||
if (currentMaxLocals > maxLocals) {
|
||||
maxLocals = currentMaxLocals;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public abstract class ModuleVisitor {
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6}
|
||||
* or {@link Opcodes#ASM7}.
|
||||
*/
|
||||
public ModuleVisitor(final int api) {
|
||||
protected ModuleVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public abstract class ModuleVisitor {
|
||||
* @param moduleVisitor the module visitor to which this visitor must delegate method calls. May
|
||||
* be null.
|
||||
*/
|
||||
public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) {
|
||||
protected ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) {
|
||||
if (api != Opcodes.ASM9
|
||||
&& api != Opcodes.ASM8
|
||||
&& api != Opcodes.ASM7
|
||||
|
||||
@@ -53,7 +53,7 @@ public abstract class RecordComponentVisitor {
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM8}
|
||||
* or {@link Opcodes#ASM9}.
|
||||
*/
|
||||
public RecordComponentVisitor(final int api) {
|
||||
protected RecordComponentVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public abstract class RecordComponentVisitor {
|
||||
* @param recordComponentVisitor the record component visitor to which this visitor must delegate
|
||||
* method calls. May be null.
|
||||
*/
|
||||
public RecordComponentVisitor(
|
||||
protected RecordComponentVisitor(
|
||||
final int api, final RecordComponentVisitor recordComponentVisitor) {
|
||||
if (api != Opcodes.ASM9
|
||||
&& api != Opcodes.ASM8
|
||||
|
||||
@@ -440,7 +440,7 @@ public final class Type {
|
||||
case '(':
|
||||
return new Type(METHOD, descriptorBuffer, descriptorBegin, descriptorEnd);
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalArgumentException("Invalid descriptor: " + descriptorBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* 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.cglib.beans;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.*;
|
||||
import java.security.ProtectionDomain;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Chris Nokleberg
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class BeanCopier
|
||||
{
|
||||
private static final BeanCopierKey KEY_FACTORY =
|
||||
(BeanCopierKey)KeyFactory.create(BeanCopierKey.class);
|
||||
private static final Type CONVERTER =
|
||||
TypeUtils.parseType("org.springframework.cglib.core.Converter");
|
||||
private static final Type BEAN_COPIER =
|
||||
TypeUtils.parseType("org.springframework.cglib.beans.BeanCopier");
|
||||
private static final Signature COPY =
|
||||
new Signature("copy", Type.VOID_TYPE, new Type[]{ Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER });
|
||||
private static final Signature CONVERT =
|
||||
TypeUtils.parseSignature("Object convert(Object, Class, Object)");
|
||||
|
||||
interface BeanCopierKey {
|
||||
public Object newInstance(String source, String target, boolean useConverter);
|
||||
}
|
||||
|
||||
public static BeanCopier create(Class source, Class target, boolean useConverter) {
|
||||
Generator gen = new Generator();
|
||||
gen.setSource(source);
|
||||
gen.setTarget(target);
|
||||
gen.setUseConverter(useConverter);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
abstract public void copy(Object from, Object to, Converter converter);
|
||||
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(BeanCopier.class.getName());
|
||||
private Class source;
|
||||
private Class target;
|
||||
private boolean useConverter;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public void setSource(Class source) {
|
||||
if(!Modifier.isPublic(source.getModifiers())){
|
||||
setNamePrefix(source.getName());
|
||||
}
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public void setTarget(Class target) {
|
||||
if(!Modifier.isPublic(target.getModifiers())){
|
||||
setNamePrefix(target.getName());
|
||||
}
|
||||
this.target = target;
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(target);
|
||||
// SPRING PATCH END
|
||||
}
|
||||
|
||||
public void setUseConverter(boolean useConverter) {
|
||||
this.useConverter = useConverter;
|
||||
}
|
||||
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return source.getClassLoader();
|
||||
}
|
||||
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(source);
|
||||
}
|
||||
|
||||
public BeanCopier create() {
|
||||
Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter);
|
||||
return (BeanCopier)super.create(key);
|
||||
}
|
||||
|
||||
public void generateClass(ClassVisitor v) {
|
||||
Type sourceType = Type.getType(source);
|
||||
Type targetType = Type.getType(target);
|
||||
ClassEmitter ce = new ClassEmitter(v);
|
||||
ce.begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
getClassName(),
|
||||
BEAN_COPIER,
|
||||
null,
|
||||
Constants.SOURCE_FILE);
|
||||
|
||||
EmitUtils.null_constructor(ce);
|
||||
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null);
|
||||
PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(source);
|
||||
PropertyDescriptor[] setters = ReflectUtils.getBeanSetters(target);
|
||||
|
||||
Map names = new HashMap();
|
||||
for (int i = 0; i < getters.length; i++) {
|
||||
names.put(getters[i].getName(), getters[i]);
|
||||
}
|
||||
Local targetLocal = e.make_local();
|
||||
Local sourceLocal = e.make_local();
|
||||
if (useConverter) {
|
||||
e.load_arg(1);
|
||||
e.checkcast(targetType);
|
||||
e.store_local(targetLocal);
|
||||
e.load_arg(0);
|
||||
e.checkcast(sourceType);
|
||||
e.store_local(sourceLocal);
|
||||
} else {
|
||||
e.load_arg(1);
|
||||
e.checkcast(targetType);
|
||||
e.load_arg(0);
|
||||
e.checkcast(sourceType);
|
||||
}
|
||||
for (int i = 0; i < setters.length; i++) {
|
||||
PropertyDescriptor setter = setters[i];
|
||||
PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName());
|
||||
if (getter != null) {
|
||||
MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());
|
||||
MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());
|
||||
if (useConverter) {
|
||||
Type setterType = write.getSignature().getArgumentTypes()[0];
|
||||
e.load_local(targetLocal);
|
||||
e.load_arg(2);
|
||||
e.load_local(sourceLocal);
|
||||
e.invoke(read);
|
||||
e.box(read.getSignature().getReturnType());
|
||||
EmitUtils.load_class(e, setterType);
|
||||
e.push(write.getSignature().getName());
|
||||
e.invoke_interface(CONVERTER, CONVERT);
|
||||
e.unbox_or_zero(setterType);
|
||||
e.invoke(write);
|
||||
} else if (compatible(getter, setter)) {
|
||||
e.dup2();
|
||||
e.invoke(read);
|
||||
e.invoke(write);
|
||||
}
|
||||
}
|
||||
}
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
ce.end_class();
|
||||
}
|
||||
|
||||
private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) {
|
||||
// TODO: allow automatic widening conversions?
|
||||
return setter.getPropertyType().isAssignableFrom(getter.getPropertyType());
|
||||
}
|
||||
|
||||
protected Object firstInstance(Class type) {
|
||||
return ReflectUtils.newInstance(type);
|
||||
}
|
||||
|
||||
protected Object nextInstance(Object instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* 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.cglib.beans;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
/**
|
||||
* @author Juozas Baliuka, Chris Nokleberg
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class BeanGenerator extends AbstractClassGenerator
|
||||
{
|
||||
private static final Source SOURCE = new Source(BeanGenerator.class.getName());
|
||||
private static final BeanGeneratorKey KEY_FACTORY =
|
||||
(BeanGeneratorKey)KeyFactory.create(BeanGeneratorKey.class);
|
||||
|
||||
interface BeanGeneratorKey {
|
||||
public Object newInstance(String superclass, Map props);
|
||||
}
|
||||
|
||||
private Class superclass;
|
||||
private Map props = new HashMap();
|
||||
private boolean classOnly;
|
||||
|
||||
public BeanGenerator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class which the generated class will extend. The class
|
||||
* must not be declared as final, and must have a non-private
|
||||
* no-argument constructor.
|
||||
* @param superclass class to extend, or null to extend Object
|
||||
*/
|
||||
public void setSuperclass(Class superclass) {
|
||||
if (superclass != null && superclass.equals(Object.class)) {
|
||||
superclass = null;
|
||||
}
|
||||
this.superclass = superclass;
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(superclass);
|
||||
// SPRING PATCH END
|
||||
}
|
||||
|
||||
public void addProperty(String name, Class type) {
|
||||
if (props.containsKey(name)) {
|
||||
throw new IllegalArgumentException("Duplicate property name \"" + name + "\"");
|
||||
}
|
||||
props.put(name, Type.getType(type));
|
||||
}
|
||||
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
if (superclass != null) {
|
||||
return superclass.getClassLoader();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(superclass);
|
||||
}
|
||||
|
||||
public Object create() {
|
||||
classOnly = false;
|
||||
return createHelper();
|
||||
}
|
||||
|
||||
public Object createClass() {
|
||||
classOnly = true;
|
||||
return createHelper();
|
||||
}
|
||||
|
||||
private Object createHelper() {
|
||||
if (superclass != null) {
|
||||
setNamePrefix(superclass.getName());
|
||||
}
|
||||
String superName = (superclass != null) ? superclass.getName() : "java.lang.Object";
|
||||
Object key = KEY_FACTORY.newInstance(superName, props);
|
||||
return super.create(key);
|
||||
}
|
||||
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
int size = props.size();
|
||||
String[] names = (String[])props.keySet().toArray(new String[size]);
|
||||
Type[] types = new Type[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
types[i] = (Type)props.get(names[i]);
|
||||
}
|
||||
ClassEmitter ce = new ClassEmitter(v);
|
||||
ce.begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
getClassName(),
|
||||
superclass != null ? Type.getType(superclass) : Constants.TYPE_OBJECT,
|
||||
null,
|
||||
null);
|
||||
EmitUtils.null_constructor(ce);
|
||||
EmitUtils.add_properties(ce, names, types);
|
||||
ce.end_class();
|
||||
}
|
||||
|
||||
protected Object firstInstance(Class type) {
|
||||
if (classOnly) {
|
||||
return type;
|
||||
} else {
|
||||
return ReflectUtils.newInstance(type);
|
||||
}
|
||||
}
|
||||
|
||||
protected Object nextInstance(Object instance) {
|
||||
Class protoclass = (instance instanceof Class) ? (Class)instance : instance.getClass();
|
||||
if (classOnly) {
|
||||
return protoclass;
|
||||
} else {
|
||||
return ReflectUtils.newInstance(protoclass);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addProperties(BeanGenerator gen, Map props) {
|
||||
for (Iterator it = props.keySet().iterator(); it.hasNext();) {
|
||||
String name = (String)it.next();
|
||||
gen.addProperty(name, (Class)props.get(name));
|
||||
}
|
||||
}
|
||||
|
||||
public static void addProperties(BeanGenerator gen, Class type) {
|
||||
addProperties(gen, ReflectUtils.getBeanProperties(type));
|
||||
}
|
||||
|
||||
public static void addProperties(BeanGenerator gen, PropertyDescriptor[] descriptors) {
|
||||
for (int i = 0; i < descriptors.length; i++) {
|
||||
gen.addProperty(descriptors[i].getName(), descriptors[i].getPropertyType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,9 @@ abstract public class BeanMap implements Map {
|
||||
this.bean = bean;
|
||||
if (bean != null) {
|
||||
beanClass = bean.getClass();
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(beanClass);
|
||||
// SPRING PATCH END
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* 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.cglib.beans;
|
||||
|
||||
import java.beans.*;
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Label;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class BeanMapEmitter extends ClassEmitter {
|
||||
private static final Type BEAN_MAP =
|
||||
TypeUtils.parseType("org.springframework.cglib.beans.BeanMap");
|
||||
private static final Type FIXED_KEY_SET =
|
||||
TypeUtils.parseType("org.springframework.cglib.beans.FixedKeySet");
|
||||
private static final Signature CSTRUCT_OBJECT =
|
||||
TypeUtils.parseConstructor("Object");
|
||||
private static final Signature CSTRUCT_STRING_ARRAY =
|
||||
TypeUtils.parseConstructor("String[]");
|
||||
private static final Signature BEAN_MAP_GET =
|
||||
TypeUtils.parseSignature("Object get(Object, Object)");
|
||||
private static final Signature BEAN_MAP_PUT =
|
||||
TypeUtils.parseSignature("Object put(Object, Object, Object)");
|
||||
private static final Signature KEY_SET =
|
||||
TypeUtils.parseSignature("java.util.Set keySet()");
|
||||
private static final Signature NEW_INSTANCE =
|
||||
new Signature("newInstance", BEAN_MAP, new Type[]{ Constants.TYPE_OBJECT });
|
||||
private static final Signature GET_PROPERTY_TYPE =
|
||||
TypeUtils.parseSignature("Class getPropertyType(String)");
|
||||
|
||||
public BeanMapEmitter(ClassVisitor v, String className, Class type, int require) {
|
||||
super(v);
|
||||
|
||||
begin_class(Constants.V1_8, Constants.ACC_PUBLIC, className, BEAN_MAP, null, Constants.SOURCE_FILE);
|
||||
EmitUtils.null_constructor(this);
|
||||
EmitUtils.factory_method(this, NEW_INSTANCE);
|
||||
generateConstructor();
|
||||
|
||||
Map getters = makePropertyMap(ReflectUtils.getBeanGetters(type));
|
||||
Map setters = makePropertyMap(ReflectUtils.getBeanSetters(type));
|
||||
Map allProps = new HashMap();
|
||||
allProps.putAll(getters);
|
||||
allProps.putAll(setters);
|
||||
|
||||
if (require != 0) {
|
||||
for (Iterator it = allProps.keySet().iterator(); it.hasNext();) {
|
||||
String name = (String)it.next();
|
||||
if ((((require & BeanMap.REQUIRE_GETTER) != 0) && !getters.containsKey(name)) ||
|
||||
(((require & BeanMap.REQUIRE_SETTER) != 0) && !setters.containsKey(name))) {
|
||||
it.remove();
|
||||
getters.remove(name);
|
||||
setters.remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
generateGet(type, getters);
|
||||
generatePut(type, setters);
|
||||
|
||||
String[] allNames = getNames(allProps);
|
||||
generateKeySet(allNames);
|
||||
generateGetPropertyType(allProps, allNames);
|
||||
end_class();
|
||||
}
|
||||
|
||||
private Map makePropertyMap(PropertyDescriptor[] props) {
|
||||
Map names = new HashMap();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
names.put(props[i].getName(), props[i]);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
private String[] getNames(Map propertyMap) {
|
||||
return (String[])propertyMap.keySet().toArray(new String[propertyMap.size()]);
|
||||
}
|
||||
|
||||
private void generateConstructor() {
|
||||
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null);
|
||||
e.load_this();
|
||||
e.load_arg(0);
|
||||
e.super_invoke_constructor(CSTRUCT_OBJECT);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
private void generateGet(Class type, final Map getters) {
|
||||
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_GET, null);
|
||||
e.load_arg(0);
|
||||
e.checkcast(Type.getType(type));
|
||||
e.load_arg(1);
|
||||
e.checkcast(Constants.TYPE_STRING);
|
||||
EmitUtils.string_switch(e, getNames(getters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
|
||||
public void processCase(Object key, Label end) {
|
||||
PropertyDescriptor pd = (PropertyDescriptor)getters.get(key);
|
||||
MethodInfo method = ReflectUtils.getMethodInfo(pd.getReadMethod());
|
||||
e.invoke(method);
|
||||
e.box(method.getSignature().getReturnType());
|
||||
e.return_value();
|
||||
}
|
||||
public void processDefault() {
|
||||
e.aconst_null();
|
||||
e.return_value();
|
||||
}
|
||||
});
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
private void generatePut(Class type, final Map setters) {
|
||||
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_PUT, null);
|
||||
e.load_arg(0);
|
||||
e.checkcast(Type.getType(type));
|
||||
e.load_arg(1);
|
||||
e.checkcast(Constants.TYPE_STRING);
|
||||
EmitUtils.string_switch(e, getNames(setters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
|
||||
public void processCase(Object key, Label end) {
|
||||
PropertyDescriptor pd = (PropertyDescriptor)setters.get(key);
|
||||
if (pd.getReadMethod() == null) {
|
||||
e.aconst_null();
|
||||
} else {
|
||||
MethodInfo read = ReflectUtils.getMethodInfo(pd.getReadMethod());
|
||||
e.dup();
|
||||
e.invoke(read);
|
||||
e.box(read.getSignature().getReturnType());
|
||||
}
|
||||
e.swap(); // move old value behind bean
|
||||
e.load_arg(2); // new value
|
||||
MethodInfo write = ReflectUtils.getMethodInfo(pd.getWriteMethod());
|
||||
e.unbox(write.getSignature().getArgumentTypes()[0]);
|
||||
e.invoke(write);
|
||||
e.return_value();
|
||||
}
|
||||
public void processDefault() {
|
||||
// fall-through
|
||||
}
|
||||
});
|
||||
e.aconst_null();
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
private void generateKeySet(String[] allNames) {
|
||||
// static initializer
|
||||
declare_field(Constants.ACC_STATIC | Constants.ACC_PRIVATE, "keys", FIXED_KEY_SET, null);
|
||||
|
||||
CodeEmitter e = begin_static();
|
||||
e.new_instance(FIXED_KEY_SET);
|
||||
e.dup();
|
||||
EmitUtils.push_array(e, allNames);
|
||||
e.invoke_constructor(FIXED_KEY_SET, CSTRUCT_STRING_ARRAY);
|
||||
e.putfield("keys");
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
// keySet
|
||||
e = begin_method(Constants.ACC_PUBLIC, KEY_SET, null);
|
||||
e.load_this();
|
||||
e.getfield("keys");
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
private void generateGetPropertyType(final Map allProps, String[] allNames) {
|
||||
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_TYPE, null);
|
||||
e.load_arg(0);
|
||||
EmitUtils.string_switch(e, allNames, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
|
||||
public void processCase(Object key, Label end) {
|
||||
PropertyDescriptor pd = (PropertyDescriptor)allProps.get(key);
|
||||
EmitUtils.load_class(e, Type.getType(pd.getPropertyType()));
|
||||
e.return_value();
|
||||
}
|
||||
public void processDefault() {
|
||||
e.aconst_null();
|
||||
e.return_value();
|
||||
}
|
||||
});
|
||||
e.end_method();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* 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.cglib.beans;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
|
||||
/**
|
||||
* @author Juozas Baliuka
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class BulkBean
|
||||
{
|
||||
private static final BulkBeanKey KEY_FACTORY =
|
||||
(BulkBeanKey)KeyFactory.create(BulkBeanKey.class);
|
||||
|
||||
interface BulkBeanKey {
|
||||
public Object newInstance(String target, String[] getters, String[] setters, String[] types);
|
||||
}
|
||||
|
||||
protected Class target;
|
||||
protected String[] getters, setters;
|
||||
protected Class[] types;
|
||||
|
||||
protected BulkBean() { }
|
||||
|
||||
abstract public void getPropertyValues(Object bean, Object[] values);
|
||||
abstract public void setPropertyValues(Object bean, Object[] values);
|
||||
|
||||
public Object[] getPropertyValues(Object bean) {
|
||||
Object[] values = new Object[getters.length];
|
||||
getPropertyValues(bean, values);
|
||||
return values;
|
||||
}
|
||||
|
||||
public Class[] getPropertyTypes() {
|
||||
return types.clone();
|
||||
}
|
||||
|
||||
public String[] getGetters() {
|
||||
return getters.clone();
|
||||
}
|
||||
|
||||
public String[] getSetters() {
|
||||
return setters.clone();
|
||||
}
|
||||
|
||||
public static BulkBean create(Class target, String[] getters, String[] setters, Class[] types) {
|
||||
Generator gen = new Generator();
|
||||
gen.setTarget(target);
|
||||
gen.setGetters(getters);
|
||||
gen.setSetters(setters);
|
||||
gen.setTypes(types);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(BulkBean.class.getName());
|
||||
private Class target;
|
||||
private String[] getters;
|
||||
private String[] setters;
|
||||
private Class[] types;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public void setTarget(Class target) {
|
||||
this.target = target;
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(target);
|
||||
// SPRING PATCH END
|
||||
}
|
||||
|
||||
public void setGetters(String[] getters) {
|
||||
this.getters = getters;
|
||||
}
|
||||
|
||||
public void setSetters(String[] setters) {
|
||||
this.setters = setters;
|
||||
}
|
||||
|
||||
public void setTypes(Class[] types) {
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return target.getClassLoader();
|
||||
}
|
||||
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(target);
|
||||
}
|
||||
|
||||
public BulkBean create() {
|
||||
setNamePrefix(target.getName());
|
||||
String targetClassName = target.getName();
|
||||
String[] typeClassNames = ReflectUtils.getNames(types);
|
||||
Object key = KEY_FACTORY.newInstance(targetClassName, getters, setters, typeClassNames);
|
||||
return (BulkBean)super.create(key);
|
||||
}
|
||||
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
new BulkBeanEmitter(v, getClassName(), target, getters, setters, types);
|
||||
}
|
||||
|
||||
protected Object firstInstance(Class type) {
|
||||
BulkBean instance = (BulkBean)ReflectUtils.newInstance(type);
|
||||
instance.target = target;
|
||||
|
||||
int length = getters.length;
|
||||
instance.getters = new String[length];
|
||||
System.arraycopy(getters, 0, instance.getters, 0, length);
|
||||
|
||||
instance.setters = new String[length];
|
||||
System.arraycopy(setters, 0, instance.setters, 0, length);
|
||||
|
||||
instance.types = new Class[types.length];
|
||||
System.arraycopy(types, 0, instance.types, 0, types.length);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
protected Object nextInstance(Object instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* 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.cglib.beans;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class BulkBeanEmitter extends ClassEmitter {
|
||||
private static final Signature GET_PROPERTY_VALUES =
|
||||
TypeUtils.parseSignature("void getPropertyValues(Object, Object[])");
|
||||
private static final Signature SET_PROPERTY_VALUES =
|
||||
TypeUtils.parseSignature("void setPropertyValues(Object, Object[])");
|
||||
private static final Signature CSTRUCT_EXCEPTION =
|
||||
TypeUtils.parseConstructor("Throwable, int");
|
||||
private static final Type BULK_BEAN =
|
||||
TypeUtils.parseType("org.springframework.cglib.beans.BulkBean");
|
||||
private static final Type BULK_BEAN_EXCEPTION =
|
||||
TypeUtils.parseType("org.springframework.cglib.beans.BulkBeanException");
|
||||
|
||||
public BulkBeanEmitter(ClassVisitor v,
|
||||
String className,
|
||||
Class target,
|
||||
String[] getterNames,
|
||||
String[] setterNames,
|
||||
Class[] types) {
|
||||
super(v);
|
||||
|
||||
Method[] getters = new Method[getterNames.length];
|
||||
Method[] setters = new Method[setterNames.length];
|
||||
validate(target, getterNames, setterNames, types, getters, setters);
|
||||
|
||||
begin_class(Constants.V1_8, Constants.ACC_PUBLIC, className, BULK_BEAN, null, Constants.SOURCE_FILE);
|
||||
EmitUtils.null_constructor(this);
|
||||
generateGet(target, getters);
|
||||
generateSet(target, setters);
|
||||
end_class();
|
||||
}
|
||||
|
||||
private void generateGet(final Class target, final Method[] getters) {
|
||||
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_VALUES, null);
|
||||
if (getters.length > 0) {
|
||||
e.load_arg(0);
|
||||
e.checkcast(Type.getType(target));
|
||||
Local bean = e.make_local();
|
||||
e.store_local(bean);
|
||||
for (int i = 0; i < getters.length; i++) {
|
||||
if (getters[i] != null) {
|
||||
MethodInfo getter = ReflectUtils.getMethodInfo(getters[i]);
|
||||
e.load_arg(1);
|
||||
e.push(i);
|
||||
e.load_local(bean);
|
||||
e.invoke(getter);
|
||||
e.box(getter.getSignature().getReturnType());
|
||||
e.aastore();
|
||||
}
|
||||
}
|
||||
}
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
private void generateSet(final Class target, final Method[] setters) {
|
||||
// setPropertyValues
|
||||
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SET_PROPERTY_VALUES, null);
|
||||
if (setters.length > 0) {
|
||||
Local index = e.make_local(Type.INT_TYPE);
|
||||
e.push(0);
|
||||
e.store_local(index);
|
||||
e.load_arg(0);
|
||||
e.checkcast(Type.getType(target));
|
||||
e.load_arg(1);
|
||||
Block handler = e.begin_block();
|
||||
int lastIndex = 0;
|
||||
for (int i = 0; i < setters.length; i++) {
|
||||
if (setters[i] != null) {
|
||||
MethodInfo setter = ReflectUtils.getMethodInfo(setters[i]);
|
||||
int diff = i - lastIndex;
|
||||
if (diff > 0) {
|
||||
e.iinc(index, diff);
|
||||
lastIndex = i;
|
||||
}
|
||||
e.dup2();
|
||||
e.aaload(i);
|
||||
e.unbox(setter.getSignature().getArgumentTypes()[0]);
|
||||
e.invoke(setter);
|
||||
}
|
||||
}
|
||||
handler.end();
|
||||
e.return_value();
|
||||
e.catch_exception(handler, Constants.TYPE_THROWABLE);
|
||||
e.new_instance(BULK_BEAN_EXCEPTION);
|
||||
e.dup_x1();
|
||||
e.swap();
|
||||
e.load_local(index);
|
||||
e.invoke_constructor(BULK_BEAN_EXCEPTION, CSTRUCT_EXCEPTION);
|
||||
e.athrow();
|
||||
} else {
|
||||
e.return_value();
|
||||
}
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
private static void validate(Class target,
|
||||
String[] getters,
|
||||
String[] setters,
|
||||
Class[] types,
|
||||
Method[] getters_out,
|
||||
Method[] setters_out) {
|
||||
int i = -1;
|
||||
if (setters.length != types.length || getters.length != types.length) {
|
||||
throw new BulkBeanException("accessor array length must be equal type array length", i);
|
||||
}
|
||||
try {
|
||||
for (i = 0; i < types.length; i++) {
|
||||
if (getters[i] != null) {
|
||||
Method method = ReflectUtils.findDeclaredMethod(target, getters[i], null);
|
||||
if (method.getReturnType() != types[i]) {
|
||||
throw new BulkBeanException("Specified type " + types[i] +
|
||||
" does not match declared type " + method.getReturnType(), i);
|
||||
}
|
||||
if (Modifier.isPrivate(method.getModifiers())) {
|
||||
throw new BulkBeanException("Property is private", i);
|
||||
}
|
||||
getters_out[i] = method;
|
||||
}
|
||||
if (setters[i] != null) {
|
||||
Method method = ReflectUtils.findDeclaredMethod(target, setters[i], new Class[]{ types[i] });
|
||||
if (Modifier.isPrivate(method.getModifiers()) ){
|
||||
throw new BulkBeanException("Property is private", i);
|
||||
}
|
||||
setters_out[i] = method;
|
||||
}
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new BulkBeanException("Cannot find specified property", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* 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.cglib.beans;
|
||||
|
||||
import org.springframework.cglib.core.CodeGenerationException;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked", "serial"})
|
||||
public class BulkBeanException extends RuntimeException
|
||||
{
|
||||
private int index;
|
||||
private Throwable cause;
|
||||
|
||||
public BulkBeanException(String message, int index) {
|
||||
super(message);
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public BulkBeanException(Throwable cause, int index) {
|
||||
super(cause.getMessage());
|
||||
this.index = index;
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public Throwable getCause() {
|
||||
return cause;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* 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.cglib.beans;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public /* need it for class loading */ class FixedKeySet extends AbstractSet {
|
||||
private Set set;
|
||||
private int size;
|
||||
|
||||
public FixedKeySet(String[] keys) {
|
||||
size = keys.length;
|
||||
set = Collections.unmodifiableSet(new HashSet(Arrays.asList(keys)));
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* 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.cglib.beans;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.ProtectionDomain;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
/**
|
||||
* @author Chris Nokleberg
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class ImmutableBean
|
||||
{
|
||||
private static final Type ILLEGAL_STATE_EXCEPTION =
|
||||
TypeUtils.parseType("IllegalStateException");
|
||||
private static final Signature CSTRUCT_OBJECT =
|
||||
TypeUtils.parseConstructor("Object");
|
||||
private static final Class[] OBJECT_CLASSES = { Object.class };
|
||||
private static final String FIELD_NAME = "CGLIB$RWBean";
|
||||
|
||||
private ImmutableBean() {
|
||||
}
|
||||
|
||||
public static Object create(Object bean) {
|
||||
Generator gen = new Generator();
|
||||
gen.setBean(bean);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(ImmutableBean.class.getName());
|
||||
private Object bean;
|
||||
private Class target;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
target = bean.getClass();
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(target);
|
||||
// SPRING PATCH END
|
||||
}
|
||||
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return target.getClassLoader();
|
||||
}
|
||||
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(target);
|
||||
}
|
||||
|
||||
public Object create() {
|
||||
String name = target.getName();
|
||||
setNamePrefix(name);
|
||||
return super.create(name);
|
||||
}
|
||||
|
||||
public void generateClass(ClassVisitor v) {
|
||||
Type targetType = Type.getType(target);
|
||||
ClassEmitter ce = new ClassEmitter(v);
|
||||
ce.begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
getClassName(),
|
||||
targetType,
|
||||
null,
|
||||
Constants.SOURCE_FILE);
|
||||
|
||||
ce.declare_field(Constants.ACC_FINAL | Constants.ACC_PRIVATE, FIELD_NAME, targetType, null);
|
||||
|
||||
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null);
|
||||
e.load_this();
|
||||
e.super_invoke_constructor();
|
||||
e.load_this();
|
||||
e.load_arg(0);
|
||||
e.checkcast(targetType);
|
||||
e.putfield(FIELD_NAME);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
PropertyDescriptor[] descriptors = ReflectUtils.getBeanProperties(target);
|
||||
Method[] getters = ReflectUtils.getPropertyMethods(descriptors, true, false);
|
||||
Method[] setters = ReflectUtils.getPropertyMethods(descriptors, false, true);
|
||||
|
||||
for (int i = 0; i < getters.length; i++) {
|
||||
MethodInfo getter = ReflectUtils.getMethodInfo(getters[i]);
|
||||
e = EmitUtils.begin_method(ce, getter, Constants.ACC_PUBLIC);
|
||||
e.load_this();
|
||||
e.getfield(FIELD_NAME);
|
||||
e.invoke(getter);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
for (int i = 0; i < setters.length; i++) {
|
||||
MethodInfo setter = ReflectUtils.getMethodInfo(setters[i]);
|
||||
e = EmitUtils.begin_method(ce, setter, Constants.ACC_PUBLIC);
|
||||
e.throw_exception(ILLEGAL_STATE_EXCEPTION, "Bean is immutable");
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
ce.end_class();
|
||||
}
|
||||
|
||||
protected Object firstInstance(Class type) {
|
||||
return ReflectUtils.newInstance(type, OBJECT_CLASSES, new Object[]{ bean });
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
protected Object nextInstance(Object instance) {
|
||||
return firstInstance(instance.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Spring's repackaging of the
|
||||
* <a href="http://cglib.sourceforge.net">CGLIB</a> beans package
|
||||
* <a href="https://github.com/cglib/cglib">CGLIB</a> beans package
|
||||
* (for internal use only).
|
||||
*
|
||||
* <p>As this repackaging happens at the class file level, sources
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Spring's repackaging of the
|
||||
* <a href="http://cglib.sourceforge.net">CGLIB</a> core package
|
||||
* <a href="https://github.com/cglib/cglib">CGLIB</a> core package
|
||||
* (for internal use only).
|
||||
*
|
||||
* <p>As this repackaging happens at the class file level, sources
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Spring's repackaging of the
|
||||
* <a href="http://cglib.sourceforge.net">CGLIB</a> proxy package
|
||||
* <a href="https://github.com/cglib/cglib">CGLIB</a> proxy package
|
||||
* (for internal use only).
|
||||
*
|
||||
* <p>As this repackaging happens at the class file level, sources
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,7 +47,7 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public final class Property {
|
||||
|
||||
private static Map<Property, Annotation[]> annotationCache = new ConcurrentReferenceHashMap<>();
|
||||
private static final Map<Property, Annotation[]> annotationCache = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
private final Class<?> objectType;
|
||||
|
||||
|
||||
+52
-35
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,8 +17,8 @@
|
||||
package org.springframework.core.convert.support;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collections;
|
||||
@@ -41,21 +41,27 @@ import org.springframework.util.ReflectionUtils;
|
||||
* <h3>Conversion Algorithm</h3>
|
||||
* <ol>
|
||||
* <li>Invoke a non-static {@code to[targetType.simpleName]()} method on the
|
||||
* source object that has a return type equal to {@code targetType}, if such
|
||||
* source object that has a return type assignable to {@code targetType}, if such
|
||||
* a method exists. For example, {@code org.example.Bar Foo#toBar()} is a
|
||||
* method that follows this convention.
|
||||
* <li>Otherwise invoke a <em>static</em> {@code valueOf(sourceType)} or Java
|
||||
* 8 style <em>static</em> {@code of(sourceType)} or {@code from(sourceType)}
|
||||
* method on the {@code targetType}, if such a method exists.
|
||||
* method on the {@code targetType} that has a return type <em>related</em> to
|
||||
* {@code targetType}, if such a method exists. For example, a static
|
||||
* {@code Foo.of(sourceType)} method that returns a {@code Foo},
|
||||
* {@code SuperFooType}, or {@code SubFooType} is a method that follows this
|
||||
* convention. {@link java.time.ZoneId#of(String)} is a concrete example of
|
||||
* such a static factory method which returns a subtype of {@code ZoneId}.
|
||||
* <li>Otherwise invoke a constructor on the {@code targetType} that accepts
|
||||
* a single {@code sourceType} argument, if such a constructor exists.
|
||||
* <li>Otherwise throw a {@link ConversionFailedException}.
|
||||
* <li>Otherwise throw a {@link ConversionFailedException} or
|
||||
* {@link IllegalStateException}.
|
||||
* </ol>
|
||||
*
|
||||
* <p><strong>Warning</strong>: this converter does <em>not</em> support the
|
||||
* {@link Object#toString()} method for converting from a {@code sourceType}
|
||||
* to {@code java.lang.String}. For {@code toString()} support, use
|
||||
* {@link FallbackObjectToStringConverter} instead.
|
||||
* {@link Object#toString()} or {@link String#valueOf(Object)} methods for converting
|
||||
* from a {@code sourceType} to {@code java.lang.String}. For {@code toString()}
|
||||
* support, use {@link FallbackObjectToStringConverter} instead.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
@@ -65,8 +71,9 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
final class ObjectToObjectConverter implements ConditionalGenericConverter {
|
||||
|
||||
// Cache for the latest to-method resolved on a given Class
|
||||
private static final Map<Class<?>, Member> conversionMemberCache =
|
||||
// Cache for the latest to-method, static factory method, or factory constructor
|
||||
// resolved on a given Class
|
||||
private static final Map<Class<?>, Executable> conversionExecutableCache =
|
||||
new ConcurrentReferenceHashMap<>(32);
|
||||
|
||||
|
||||
@@ -89,11 +96,11 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
|
||||
}
|
||||
Class<?> sourceClass = sourceType.getType();
|
||||
Class<?> targetClass = targetType.getType();
|
||||
Member member = getValidatedMember(targetClass, sourceClass);
|
||||
Executable executable = getValidatedExecutable(targetClass, sourceClass);
|
||||
|
||||
try {
|
||||
if (member instanceof Method) {
|
||||
Method method = (Method) member;
|
||||
if (executable instanceof Method) {
|
||||
Method method = (Method) executable;
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
if (!Modifier.isStatic(method.getModifiers())) {
|
||||
return method.invoke(source);
|
||||
@@ -102,8 +109,8 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
|
||||
return method.invoke(null, source);
|
||||
}
|
||||
}
|
||||
else if (member instanceof Constructor) {
|
||||
Constructor<?> ctor = (Constructor<?>) member;
|
||||
else if (executable instanceof Constructor) {
|
||||
Constructor<?> ctor = (Constructor<?>) executable;
|
||||
ReflectionUtils.makeAccessible(ctor);
|
||||
return ctor.newInstance(source);
|
||||
}
|
||||
@@ -124,42 +131,41 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
|
||||
}
|
||||
|
||||
|
||||
|
||||
static boolean hasConversionMethodOrConstructor(Class<?> targetClass, Class<?> sourceClass) {
|
||||
return (getValidatedMember(targetClass, sourceClass) != null);
|
||||
return (getValidatedExecutable(targetClass, sourceClass) != null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Member getValidatedMember(Class<?> targetClass, Class<?> sourceClass) {
|
||||
Member member = conversionMemberCache.get(targetClass);
|
||||
if (isApplicable(member, sourceClass)) {
|
||||
return member;
|
||||
private static Executable getValidatedExecutable(Class<?> targetClass, Class<?> sourceClass) {
|
||||
Executable executable = conversionExecutableCache.get(targetClass);
|
||||
if (isApplicable(executable, sourceClass)) {
|
||||
return executable;
|
||||
}
|
||||
|
||||
member = determineToMethod(targetClass, sourceClass);
|
||||
if (member == null) {
|
||||
member = determineFactoryMethod(targetClass, sourceClass);
|
||||
if (member == null) {
|
||||
member = determineFactoryConstructor(targetClass, sourceClass);
|
||||
if (member == null) {
|
||||
executable = determineToMethod(targetClass, sourceClass);
|
||||
if (executable == null) {
|
||||
executable = determineFactoryMethod(targetClass, sourceClass);
|
||||
if (executable == null) {
|
||||
executable = determineFactoryConstructor(targetClass, sourceClass);
|
||||
if (executable == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conversionMemberCache.put(targetClass, member);
|
||||
return member;
|
||||
conversionExecutableCache.put(targetClass, executable);
|
||||
return executable;
|
||||
}
|
||||
|
||||
private static boolean isApplicable(Member member, Class<?> sourceClass) {
|
||||
if (member instanceof Method) {
|
||||
Method method = (Method) member;
|
||||
private static boolean isApplicable(Executable executable, Class<?> sourceClass) {
|
||||
if (executable instanceof Method) {
|
||||
Method method = (Method) executable;
|
||||
return (!Modifier.isStatic(method.getModifiers()) ?
|
||||
ClassUtils.isAssignable(method.getDeclaringClass(), sourceClass) :
|
||||
method.getParameterTypes()[0] == sourceClass);
|
||||
}
|
||||
else if (member instanceof Constructor) {
|
||||
Constructor<?> ctor = (Constructor<?>) member;
|
||||
else if (executable instanceof Constructor) {
|
||||
Constructor<?> ctor = (Constructor<?>) executable;
|
||||
return (ctor.getParameterTypes()[0] == sourceClass);
|
||||
}
|
||||
else {
|
||||
@@ -193,7 +199,18 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
|
||||
method = ClassUtils.getStaticMethod(targetClass, "from", sourceClass);
|
||||
}
|
||||
}
|
||||
return method;
|
||||
|
||||
return (method != null && areRelatedTypes(targetClass, method.getReturnType()) ? method : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the two types reside in the same type hierarchy (i.e., type 1
|
||||
* is assignable to type 2 or vice versa).
|
||||
* @since 5.3.21
|
||||
* @see ClassUtils#isAssignable(Class, Class)
|
||||
*/
|
||||
private static boolean areRelatedTypes(Class<?> type1, Class<?> type2) {
|
||||
return (ClassUtils.isAssignable(type1, type2) || ClassUtils.isAssignable(type2, type1));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2022 the original author 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 org.springframework.util.StringUtils;
|
||||
* Converts from a String to a {@link java.util.Locale}.
|
||||
*
|
||||
* <p>Accepts the classic {@link Locale} String format ({@link Locale#toString()})
|
||||
* as well as BCP 47 language tags ({@link Locale#forLanguageTag} on Java 7+).
|
||||
* as well as BCP 47 language tags ({@link Locale#forLanguageTag}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -299,7 +299,7 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
||||
public void setActiveProfiles(String... profiles) {
|
||||
Assert.notNull(profiles, "Profile array must not be null");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Activating profiles " + Arrays.asList(profiles));
|
||||
logger.debug("Activating profiles " + Arrays.toString(profiles));
|
||||
}
|
||||
synchronized (this.activeProfiles) {
|
||||
this.activeProfiles.clear();
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -182,8 +182,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns a File reference for the given URI-identified
|
||||
* resource, provided that it refers to a file in the file system.
|
||||
* Determine whether the given {@link URI} represents a file in a file system.
|
||||
* @since 5.0
|
||||
* @see #getFile(URI)
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,7 +50,7 @@ public abstract class AbstractResource implements Resource {
|
||||
/**
|
||||
* This implementation checks whether a File can be opened,
|
||||
* falling back to whether an InputStream can be opened.
|
||||
* This will cover both directories and content resources.
|
||||
* <p>This will cover both directories and content resources.
|
||||
*/
|
||||
@Override
|
||||
public boolean exists() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user