mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e5d99ecf98 |
@@ -1,33 +0,0 @@
|
||||
name: Send notification
|
||||
description: Sends a Google Chat message as a notification of the job's outcome
|
||||
inputs:
|
||||
webhook-url:
|
||||
description: 'Google Chat Webhook URL'
|
||||
required: true
|
||||
status:
|
||||
description: 'Status of the job'
|
||||
required: true
|
||||
build-scan-url:
|
||||
description: 'URL of the build scan to include in the notification'
|
||||
run-name:
|
||||
description: 'Name of the run to include in the notification'
|
||||
default: ${{ format('{0} {1}', github.ref_name, github.job) }}
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- shell: bash
|
||||
run: |
|
||||
echo "BUILD_SCAN=${{ inputs.build-scan-url == '' && ' [build scan unavailable]' || format(' [<{0}|Build Scan>]', inputs.build-scan-url) }}" >> "$GITHUB_ENV"
|
||||
echo "RUN_URL=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> "$GITHUB_ENV"
|
||||
- shell: bash
|
||||
if: ${{ inputs.status == 'success' }}
|
||||
run: |
|
||||
curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<${{ env.RUN_URL }}|${{ inputs.run-name }}> was successful ${{ env.BUILD_SCAN }}"}' || true
|
||||
- shell: bash
|
||||
if: ${{ inputs.status == 'failure' }}
|
||||
run: |
|
||||
curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<users/all> *<${{ env.RUN_URL }}|${{ inputs.run-name }}> failed* ${{ env.BUILD_SCAN }}"}' || true
|
||||
- shell: bash
|
||||
if: ${{ inputs.status == 'cancelled' }}
|
||||
run: |
|
||||
curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<${{ env.RUN_URL }}|${{ inputs.run-name }}> was cancelled"}' || true
|
||||
@@ -1,34 +0,0 @@
|
||||
name: Backport Bot
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
pull_request:
|
||||
types: [labeled]
|
||||
push:
|
||||
branches:
|
||||
- '*.x'
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
build:
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'liberica'
|
||||
java-version: 17
|
||||
- name: Download BackportBot
|
||||
run: wget https://github.com/spring-io/backport-bot/releases/download/latest/backport-bot-0.0.1-SNAPSHOT.jar
|
||||
- name: Backport
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_EVENT: ${{ toJSON(github.event) }}
|
||||
run: java -jar backport-bot-0.0.1-SNAPSHOT.jar --github.accessToken="$GITHUB_TOKEN" --github.event_name "$GITHUB_EVENT_NAME" --github.event "$GITHUB_EVENT"
|
||||
@@ -1,63 +0,0 @@
|
||||
name: Build and deploy snapshot
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 5.3.x
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
jobs:
|
||||
build-and-deploy-snapshot:
|
||||
if: ${{ github.repository == 'spring-projects/spring-framework' }}
|
||||
name: Build and deploy snapshot
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'liberica'
|
||||
java-version: 8
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5
|
||||
with:
|
||||
cache-read-only: false
|
||||
- name: Configure Gradle properties
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p $HOME/.gradle
|
||||
echo 'systemProp.user.name=spring-builds+github' >> $HOME/.gradle/gradle.properties
|
||||
echo 'systemProp.org.gradle.internal.launcher.welcomeMessageEnabled=false' >> $HOME/.gradle/gradle.properties
|
||||
echo 'org.gradle.daemon=false' >> $HOME/.gradle/gradle.properties
|
||||
echo 'org.gradle.daemon=4' >> $HOME/.gradle/gradle.properties
|
||||
- name: Build and publish
|
||||
id: build
|
||||
env:
|
||||
CI: 'true'
|
||||
GRADLE_ENTERPRISE_URL: 'https://ge.spring.io'
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
|
||||
run: ./gradlew -PdeploymentRepository=$(pwd)/deployment-repository build publishAllPublicationsToDeploymentRepository
|
||||
- name: Deploy
|
||||
uses: spring-io/artifactory-deploy-action@v0.0.1
|
||||
with:
|
||||
uri: 'https://repo.spring.io'
|
||||
username: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
password: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
build-name: ${{ format('spring-framework-{0}', github.ref_name)}}
|
||||
repository: 'libs-snapshot-local'
|
||||
folder: 'deployment-repository'
|
||||
signing-key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}
|
||||
artifact-properties: |
|
||||
/**/spring-*.zip::zip.name=spring-framework,zip.deployed=false
|
||||
/**/spring-*-docs.zip::zip.type=docs
|
||||
/**/spring-*-dist.zip::zip.type=dist
|
||||
/**/spring-*-schema.zip::zip.type=schema
|
||||
- name: Send notification
|
||||
uses: ./.github/actions/send-notification
|
||||
if: always()
|
||||
with:
|
||||
webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}
|
||||
status: ${{ job.status }}
|
||||
build-scan-url: ${{ steps.build.outputs.build-scan-url }}
|
||||
run-name: ${{ format('{0} | Linux | Java 8', github.ref_name) }}
|
||||
@@ -1,80 +0,0 @@
|
||||
name: CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 5.3.x
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
jobs:
|
||||
ci:
|
||||
if: ${{ github.repository == 'spring-projects/spring-framework' }}
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- id: ubuntu-latest
|
||||
name: Linux
|
||||
java:
|
||||
- version: 8
|
||||
toolchain: false
|
||||
- version: 17
|
||||
toolchain: true
|
||||
- version: 21
|
||||
toolchain: true
|
||||
exclude:
|
||||
- os:
|
||||
name: Linux
|
||||
java:
|
||||
version: 8
|
||||
name: '${{ matrix.os.name}} | Java ${{ matrix.java.version}}'
|
||||
runs-on: ${{ matrix.os.id }}
|
||||
steps:
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'liberica'
|
||||
java-version: |
|
||||
${{ matrix.java.version }}
|
||||
${{ matrix.java.toolchain && '8' || '' }}
|
||||
- name: Prepare Windows runner
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
run: |
|
||||
git config --global core.autocrlf true
|
||||
git config --global core.longPaths true
|
||||
Stop-Service -name Docker
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5
|
||||
with:
|
||||
cache-read-only: false
|
||||
- name: Configure Gradle properties
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p $HOME/.gradle
|
||||
echo 'systemProp.user.name=spring-builds+github' >> $HOME/.gradle/gradle.properties
|
||||
echo 'systemProp.org.gradle.internal.launcher.welcomeMessageEnabled=false' >> $HOME/.gradle/gradle.properties
|
||||
echo 'org.gradle.daemon=false' >> $HOME/.gradle/gradle.properties
|
||||
echo 'org.gradle.daemon=4' >> $HOME/.gradle/gradle.properties
|
||||
- name: Configure toolchain properties
|
||||
if: ${{ matrix.java.toolchain }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo toolchainVersion=${{ matrix.java.version }} >> $HOME/.gradle/gradle.properties
|
||||
echo systemProp.org.gradle.java.installations.auto-detect=false >> $HOME/.gradle/gradle.properties
|
||||
echo systemProp.org.gradle.java.installations.auto-download=false >> $HOME/.gradle/gradle.properties
|
||||
echo systemProp.org.gradle.java.installations.paths=${{ format('$JAVA_HOME_{0}_X64', matrix.java.version) }} >> $HOME/.gradle/gradle.properties
|
||||
- name: Build
|
||||
id: build
|
||||
env:
|
||||
CI: 'true'
|
||||
GRADLE_ENTERPRISE_URL: 'https://ge.spring.io'
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
|
||||
run: ./gradlew check
|
||||
- name: Send notification
|
||||
uses: ./.github/actions/send-notification
|
||||
if: always()
|
||||
with:
|
||||
webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}
|
||||
status: ${{ job.status }}
|
||||
build-scan-url: ${{ steps.build.outputs.build-scan-url }}
|
||||
run-name: ${{ format('{0} | {1} | Java {2}', github.ref_name, matrix.os.name, matrix.java.version) }}
|
||||
@@ -9,5 +9,5 @@ jobs:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: gradle/wrapper-validation-action@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
|
||||
@@ -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.382-librca
|
||||
java=8.0.372-librca
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# <img src="framework-docs/src/docs/spring-framework.png" width="80" height="80"> Spring Framework [](https://github.com/spring-projects/spring-framework/actions/workflows/build-and-deploy-snapshot.yml?query=branch%3A5.3.x) [](https://ge.spring.io/scans?search.rootProjectNames=spring)
|
||||
# <img src="src/docs/spring-framework.png" width="80" height="80"> Spring Framework [](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.3.x?groups=Build") [](https://ge.spring.io/scans?search.rootProjectNames=spring)
|
||||
|
||||
This is the home of the Spring Framework: the foundation for all [Spring projects](https://spring.io/projects). Collectively the Spring Framework and the family of Spring projects are often referred to simply as "Spring".
|
||||
|
||||
|
||||
+16
-18
@@ -28,18 +28,18 @@ configure(allprojects) { project ->
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.7"
|
||||
mavenBom "io.netty:netty-bom:4.1.109.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.44"
|
||||
mavenBom "io.netty:netty-bom:4.1.95.Final"
|
||||
mavenBom "io.projectreactor:reactor-bom:2020.0.34"
|
||||
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR13"
|
||||
mavenBom "io.rsocket:rsocket-bom:1.1.3"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.54.v20240208"
|
||||
mavenBom "org.eclipse.jetty:jetty-bom:9.4.51.v20230217"
|
||||
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"
|
||||
mavenBom "org.junit:junit-bom:5.8.2"
|
||||
}
|
||||
dependencies {
|
||||
dependencySet(group: 'org.apache.logging.log4j', version: '2.21.1') {
|
||||
dependencySet(group: 'org.apache.logging.log4j', version: '2.20.0') {
|
||||
entry 'log4j-api'
|
||||
entry 'log4j-core'
|
||||
entry 'log4j-jul'
|
||||
@@ -67,9 +67,9 @@ 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.8"
|
||||
dependency "io.smallrye.reactive:mutiny:1.9.0"
|
||||
dependency "io.projectreactor.tools:blockhound:1.0.8.RELEASE"
|
||||
dependency "io.reactivex.rxjava3:rxjava:3.1.5"
|
||||
dependency "io.smallrye.reactive:mutiny:1.8.0"
|
||||
dependency "io.projectreactor.tools:blockhound:1.0.6.RELEASE"
|
||||
|
||||
dependency "com.caucho:hessian:4.0.63"
|
||||
dependency "com.fasterxml:aalto-xml:1.3.1"
|
||||
@@ -96,7 +96,7 @@ configure(allprojects) { project ->
|
||||
|
||||
dependency "com.h2database:h2:2.1.214"
|
||||
dependency "com.github.ben-manes.caffeine:caffeine:2.9.3"
|
||||
dependency "com.github.librepdf:openpdf:1.3.33"
|
||||
dependency "com.github.librepdf:openpdf:1.3.30"
|
||||
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.82') {
|
||||
dependencySet(group: 'org.apache.tomcat', version: '9.0.78') {
|
||||
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.82') {
|
||||
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.78') {
|
||||
entry 'tomcat-embed-core'
|
||||
entry 'tomcat-embed-websocket'
|
||||
}
|
||||
dependencySet(group: 'io.undertow', version: '2.2.29.Final') {
|
||||
dependencySet(group: 'io.undertow', version: '2.2.25.Final') {
|
||||
entry 'undertow-core'
|
||||
entry('undertow-servlet') {
|
||||
exclude group: "org.jboss.spec.javax.servlet", name: "jboss-servlet-api_4.0_spec"
|
||||
@@ -340,7 +340,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "10.12.7"
|
||||
toolVersion = "10.12.1"
|
||||
configDirectory.set(rootProject.file("src/checkstyle"))
|
||||
}
|
||||
|
||||
@@ -362,7 +362,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
// JSR-305 only used for non-required meta-annotations
|
||||
compileOnly("com.google.code.findbugs:jsr305")
|
||||
testCompileOnly("com.google.code.findbugs:jsr305")
|
||||
checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.41")
|
||||
checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.31")
|
||||
}
|
||||
|
||||
ext.javadocLinks = [
|
||||
@@ -375,9 +375,8 @@ configure([rootProject] + javaProjects) { project ->
|
||||
"https://tiles.apache.org/tiles-request/apidocs/",
|
||||
"https://tiles.apache.org/framework/apidocs/",
|
||||
"https://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
|
||||
// Temporarily commenting out Ehcache and Quartz since javadoc on JDK 8 cannot access them.
|
||||
// "https://www.ehcache.org/apidocs/2.10.4/",
|
||||
// "https://www.quartz-scheduler.org/api/2.3.0/",
|
||||
"https://www.ehcache.org/apidocs/2.10.4/",
|
||||
"https://www.quartz-scheduler.org/api/2.3.0/",
|
||||
"https://www.javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/2.12.7/",
|
||||
"https://www.javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/2.12.7/",
|
||||
"https://www.javadoc.io/doc/com.fasterxml.jackson.dataformat/jackson-dataformat-xml/2.12.7/",
|
||||
@@ -389,8 +388,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
// "https://junit.org/junit5/docs/5.8.2/api/",
|
||||
"https://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/",
|
||||
"https://javadoc.io/static/io.rsocket/rsocket-core/1.1.1/",
|
||||
// Temporarily commenting out R2DBC since javadoc on JDK 8 cannot access it.
|
||||
// "https://r2dbc.io/spec/0.8.5.RELEASE/api/",
|
||||
"https://r2dbc.io/spec/0.8.5.RELEASE/api/",
|
||||
// The external Javadoc link for JSR 305 must come last to ensure that types from
|
||||
// JSR 250 (such as @PostConstruct) are still supported. This is due to the fact
|
||||
// that JSR 250 and JSR 305 both define types in javax.annotation, which results
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
== Spring Framework Concourse pipeline
|
||||
|
||||
NOTE: CI is being migrated to GitHub Actions.
|
||||
|
||||
The Spring Framework uses https://concourse-ci.org/[Concourse] for its CI build and other automated tasks.
|
||||
The Spring team has a dedicated Concourse instance available at https://ci.spring.io with a build pipeline
|
||||
for https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.3.x[Spring Framework 5.3.x].
|
||||
|
||||
@@ -17,4 +17,4 @@ changelog:
|
||||
- "type: dependency-upgrade"
|
||||
contributors:
|
||||
exclude:
|
||||
names: ["bclozel", "jhoeller", "poutsma", "rstoyanchev", "sbrannen", "sdeleuze", "snicoll", "simonbasle"]
|
||||
names: ["bclozel", "jhoeller", "poutsma", "rstoyanchev", "sbrannen", "sdeleuze", "snicoll"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:jammy-20240125
|
||||
FROM ubuntu:jammy-20230624
|
||||
|
||||
ADD setup.sh /setup.sh
|
||||
ADD get-jdk-url.sh /get-jdk-url.sh
|
||||
|
||||
@@ -3,10 +3,10 @@ set -e
|
||||
|
||||
case "$1" in
|
||||
java8)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/8u402%2B7/bellsoft-jdk8u402+7-linux-amd64.tar.gz"
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/8u372+7/bellsoft-jdk8u372+7-linux-amd64.tar.gz"
|
||||
;;
|
||||
java17)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.10%2B13/bellsoft-jdk17.0.10+13-linux-amd64.tar.gz"
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.7+7/bellsoft-jdk17.0.7+7-linux-amd64.tar.gz"
|
||||
;;
|
||||
*)
|
||||
echo $"Unknown java version"
|
||||
|
||||
@@ -8,3 +8,4 @@ milestone: "5.3.x"
|
||||
build-name: "spring-framework"
|
||||
pipeline-name: "spring-framework"
|
||||
concourse-url: "https://ci.spring.io"
|
||||
task-timeout: 1h00m
|
||||
|
||||
+122
-14
@@ -5,7 +5,9 @@ anchors:
|
||||
password: ((github-ci-release-token))
|
||||
branch: ((branch))
|
||||
gradle-enterprise-task-params: &gradle-enterprise-task-params
|
||||
DEVELOCITY_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
|
||||
sonatype-task-params: &sonatype-task-params
|
||||
SONATYPE_USERNAME: ((sonatype-username))
|
||||
SONATYPE_PASSWORD: ((sonatype-password))
|
||||
@@ -21,6 +23,14 @@ anchors:
|
||||
docker-resource-source: &docker-resource-source
|
||||
username: ((docker-hub-username))
|
||||
password: ((docker-hub-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!>
|
||||
[$TEXT_FILE_CONTENT]
|
||||
text_file: git-repo/build/build-scan-uri.txt
|
||||
silent: true
|
||||
icon_emoji: ":concourse:"
|
||||
username: concourse-ci
|
||||
changelog-task-params: &changelog-task-params
|
||||
name: generated-changelog/tag
|
||||
tag: generated-changelog/tag
|
||||
@@ -35,7 +45,7 @@ resource_types:
|
||||
source:
|
||||
<<: *docker-resource-source
|
||||
repository: concourse/registry-image-resource
|
||||
tag: 1.8.0
|
||||
tag: 1.7.1
|
||||
- name: artifactory-resource
|
||||
type: registry-image
|
||||
source:
|
||||
@@ -54,12 +64,25 @@ resource_types:
|
||||
<<: *docker-resource-source
|
||||
repository: dpb587/github-status-resource
|
||||
tag: master
|
||||
- name: slack-notification
|
||||
type: registry-image
|
||||
source:
|
||||
<<: *docker-resource-source
|
||||
repository: cfcommunity/slack-notification-resource
|
||||
tag: latest
|
||||
resources:
|
||||
- name: git-repo
|
||||
type: git
|
||||
icon: github
|
||||
source:
|
||||
<<: *git-repo-resource-source
|
||||
- name: every-morning
|
||||
type: time
|
||||
icon: alarm
|
||||
source:
|
||||
start: 8:00 AM
|
||||
stop: 9:00 AM
|
||||
location: Europe/Vienna
|
||||
- name: ci-images-git-repo
|
||||
type: git
|
||||
icon: github
|
||||
@@ -82,6 +105,27 @@ resources:
|
||||
username: ((artifactory-username))
|
||||
password: ((artifactory-password))
|
||||
build_name: ((build-name))
|
||||
- name: repo-status-build
|
||||
type: github-status-resource
|
||||
icon: eye-check-outline
|
||||
source:
|
||||
repository: ((github-repo-name))
|
||||
access_token: ((github-ci-status-token))
|
||||
branch: ((branch))
|
||||
context: build
|
||||
- name: repo-status-jdk17-build
|
||||
type: github-status-resource
|
||||
icon: eye-check-outline
|
||||
source:
|
||||
repository: ((github-repo-name))
|
||||
access_token: ((github-ci-status-token))
|
||||
branch: ((branch))
|
||||
context: jdk17-build
|
||||
- name: slack-alert
|
||||
type: slack-notification
|
||||
icon: slack
|
||||
source:
|
||||
url: ((slack-webhook-url))
|
||||
- name: github-pre-release
|
||||
type: github-release
|
||||
icon: briefcase-download-outline
|
||||
@@ -116,23 +160,37 @@ jobs:
|
||||
- put: ci-image
|
||||
params:
|
||||
image: ci-image/image.tar
|
||||
- name: stage-milestone
|
||||
- name: build
|
||||
serial: true
|
||||
public: true
|
||||
plan:
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
trigger: false
|
||||
- task: stage
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/stage-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: M
|
||||
<<: *gradle-enterprise-task-params
|
||||
trigger: true
|
||||
- put: repo-status-build
|
||||
params: { state: "pending", commit: "git-repo" }
|
||||
- do:
|
||||
- task: build-project
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/build-project.yml
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
params:
|
||||
<<: *build-project-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-build
|
||||
params: { state: "failure", commit: "git-repo" }
|
||||
- put: slack-alert
|
||||
params:
|
||||
<<: *slack-fail-params
|
||||
- put: repo-status-build
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- put: artifactory-repo
|
||||
params: &artifactory-params
|
||||
signing_key: ((signing-key))
|
||||
signing_passphrase: ((signing-passphrase))
|
||||
repo: libs-staging-local
|
||||
repo: libs-snapshot-local
|
||||
folder: distribution-repository
|
||||
build_uri: "https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}"
|
||||
build_number: "${BUILD_PIPELINE_NAME}-${BUILD_JOB_NAME}-${BUILD_NAME}"
|
||||
@@ -157,9 +215,55 @@ jobs:
|
||||
- "/**/spring-*-schema.zip"
|
||||
properties:
|
||||
"zip.type": "schema"
|
||||
- put: git-repo
|
||||
params:
|
||||
repository: stage-git-repo
|
||||
get_params:
|
||||
threads: 8
|
||||
- name: jdk17-build
|
||||
serial: true
|
||||
public: true
|
||||
plan:
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
- get: every-morning
|
||||
trigger: true
|
||||
- put: repo-status-jdk17-build
|
||||
params: { state: "pending", commit: "git-repo" }
|
||||
- do:
|
||||
- task: check-project
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/check-project.yml
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
params:
|
||||
TEST_TOOLCHAIN: 17
|
||||
<<: *build-project-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-jdk17-build
|
||||
params: { state: "failure", commit: "git-repo" }
|
||||
- put: slack-alert
|
||||
params:
|
||||
<<: *slack-fail-params
|
||||
- put: repo-status-jdk17-build
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- name: stage-milestone
|
||||
serial: true
|
||||
plan:
|
||||
- get: ci-image
|
||||
- get: git-repo
|
||||
trigger: false
|
||||
- task: stage
|
||||
image: ci-image
|
||||
file: git-repo/ci/tasks/stage-version.yml
|
||||
params:
|
||||
RELEASE_TYPE: M
|
||||
<<: *gradle-enterprise-task-params
|
||||
- put: artifactory-repo
|
||||
params:
|
||||
<<: *artifactory-params
|
||||
repo: libs-staging-local
|
||||
- put: git-repo
|
||||
params:
|
||||
repository: stage-git-repo
|
||||
- name: promote-milestone
|
||||
serial: true
|
||||
plan:
|
||||
@@ -200,6 +304,7 @@ jobs:
|
||||
- put: artifactory-repo
|
||||
params:
|
||||
<<: *artifactory-params
|
||||
repo: libs-staging-local
|
||||
- put: git-repo
|
||||
params:
|
||||
repository: stage-git-repo
|
||||
@@ -243,6 +348,7 @@ jobs:
|
||||
- put: artifactory-repo
|
||||
params:
|
||||
<<: *artifactory-params
|
||||
repo: libs-staging-local
|
||||
- put: git-repo
|
||||
params:
|
||||
repository: stage-git-repo
|
||||
@@ -285,6 +391,8 @@ jobs:
|
||||
<<: *changelog-task-params
|
||||
|
||||
groups:
|
||||
- name: "builds"
|
||||
jobs: ["build", "jdk17-build"]
|
||||
- name: "releases"
|
||||
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
|
||||
- name: "ci-images"
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
source $(dirname $0)/common.sh
|
||||
|
||||
pushd git-repo > /dev/null
|
||||
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 check
|
||||
popd > /dev/null
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
source $(dirname $0)/common.sh
|
||||
repository=$(pwd)/distribution-repository
|
||||
|
||||
pushd git-repo > /dev/null
|
||||
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 -PdeploymentRepository=${repository} build publishAllPublicationsToDeploymentRepository
|
||||
popd > /dev/null
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
source $(dirname $0)/common.sh
|
||||
|
||||
pushd git-repo > /dev/null
|
||||
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK17 \
|
||||
-PmainToolchain=${MAIN_TOOLCHAIN} -PtestToolchain=${TEST_TOOLCHAIN} --no-daemon --max-workers=4 check
|
||||
popd > /dev/null
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
source $(dirname $0)/common.sh
|
||||
CONFIG_DIR=git-repo/ci/config
|
||||
|
||||
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
|
||||
|
||||
@@ -26,5 +26,4 @@ run:
|
||||
cat > /root/.docker/config.json <<EOF
|
||||
{ "auths": { "https://index.docker.io/v1/": { "auth": "$DOCKER_HUB_AUTH" }}}
|
||||
EOF
|
||||
build
|
||||
|
||||
build
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
platform: linux
|
||||
inputs:
|
||||
- name: git-repo
|
||||
caches:
|
||||
- path: gradle
|
||||
params:
|
||||
BRANCH:
|
||||
CI: true
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY:
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME:
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD:
|
||||
GRADLE_ENTERPRISE_URL: https://ge.spring.io
|
||||
run:
|
||||
path: bash
|
||||
args:
|
||||
- -ec
|
||||
- |
|
||||
${PWD}/git-repo/ci/scripts/build-pr.sh
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
platform: linux
|
||||
inputs:
|
||||
- name: git-repo
|
||||
outputs:
|
||||
- name: distribution-repository
|
||||
- name: git-repo
|
||||
caches:
|
||||
- path: gradle
|
||||
params:
|
||||
BRANCH:
|
||||
CI: true
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY:
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME:
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD:
|
||||
GRADLE_ENTERPRISE_URL: https://ge.spring.io
|
||||
run:
|
||||
path: bash
|
||||
args:
|
||||
- -ec
|
||||
- |
|
||||
${PWD}/git-repo/ci/scripts/build-project.sh
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
platform: linux
|
||||
inputs:
|
||||
- name: git-repo
|
||||
outputs:
|
||||
- name: distribution-repository
|
||||
- name: git-repo
|
||||
caches:
|
||||
- path: gradle
|
||||
params:
|
||||
BRANCH:
|
||||
CI: true
|
||||
MAIN_TOOLCHAIN:
|
||||
TEST_TOOLCHAIN:
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY:
|
||||
GRADLE_ENTERPRISE_CACHE_USERNAME:
|
||||
GRADLE_ENTERPRISE_CACHE_PASSWORD:
|
||||
GRADLE_ENTERPRISE_URL: https://ge.spring.io
|
||||
run:
|
||||
path: bash
|
||||
args:
|
||||
- -ec
|
||||
- |
|
||||
${PWD}/git-repo/ci/scripts/check-project.sh
|
||||
@@ -4,7 +4,7 @@ image_resource:
|
||||
type: registry-image
|
||||
source:
|
||||
repository: springio/github-changelog-generator
|
||||
tag: '0.0.8'
|
||||
tag: '0.0.7'
|
||||
username: ((docker-hub-username))
|
||||
password: ((docker-hub-password))
|
||||
inputs:
|
||||
|
||||
@@ -4,7 +4,7 @@ image_resource:
|
||||
type: registry-image
|
||||
source:
|
||||
repository: springio/concourse-release-scripts
|
||||
tag: '0.4.0'
|
||||
tag: '0.3.4'
|
||||
username: ((docker-hub-username))
|
||||
password: ((docker-hub-password))
|
||||
inputs:
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=5.3.35
|
||||
version=5.3.30
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
@@ -5,7 +5,7 @@ tasks.findByName("dokkaHtmlPartial")?.configure {
|
||||
sourceRoots.setFrom(file("src/main/kotlin"))
|
||||
classpath.from(sourceSets["main"].runtimeClasspath)
|
||||
externalDocumentationLink {
|
||||
url.set(new URL("https://docs.spring.io/spring-framework/docs/5.3.x/javadoc-api/"))
|
||||
url.set(new URL("https://docs.spring.io/spring-framework/docs/current/javadoc-api/"))
|
||||
}
|
||||
externalDocumentationLink {
|
||||
url.set(new URL("https://projectreactor.io/docs/core/release/api/"))
|
||||
|
||||
+3
-3
@@ -7,8 +7,8 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "com.gradle.develocity" version "3.17.2"
|
||||
id "io.spring.ge.conventions" version "0.0.17"
|
||||
id "com.gradle.enterprise" version "3.12.1"
|
||||
id "io.spring.ge.conventions" version "0.0.13"
|
||||
}
|
||||
|
||||
include "spring-aop"
|
||||
@@ -42,7 +42,7 @@ rootProject.children.each {project ->
|
||||
}
|
||||
|
||||
settings.gradle.projectsLoaded {
|
||||
develocity {
|
||||
gradleEnterprise {
|
||||
buildScan {
|
||||
File buildDir = settings.gradle.rootProject.getBuildDir()
|
||||
buildDir.mkdirs()
|
||||
|
||||
+10
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -174,30 +174,25 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
@Override
|
||||
public ClassFilter getClassFilter() {
|
||||
checkExpression();
|
||||
obtainPointcutExpression();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
checkExpression();
|
||||
obtainPointcutExpression();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether this pointcut is ready to match.
|
||||
* Check whether this pointcut is ready to match,
|
||||
* lazily building the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
private void checkExpression() {
|
||||
private PointcutExpression obtainPointcutExpression() {
|
||||
if (getExpression() == null) {
|
||||
throw new IllegalStateException("Must set property 'expression' before attempting to match");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
private PointcutExpression obtainPointcutExpression() {
|
||||
if (this.pointcutExpression == null) {
|
||||
this.pointcutClassLoader = determinePointcutClassLoader();
|
||||
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
|
||||
@@ -274,9 +269,10 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
@Override
|
||||
public boolean matches(Class<?> targetClass) {
|
||||
PointcutExpression pointcutExpression = obtainPointcutExpression();
|
||||
try {
|
||||
try {
|
||||
return obtainPointcutExpression().couldMatchJoinPointsInType(targetClass);
|
||||
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
|
||||
}
|
||||
catch (ReflectionWorldException ex) {
|
||||
logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
|
||||
@@ -287,9 +283,6 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException | IllegalStateException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("PointcutExpression matching rejected target class", ex);
|
||||
}
|
||||
@@ -298,6 +291,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
|
||||
obtainPointcutExpression();
|
||||
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
|
||||
|
||||
// Special handling for this, target, @this, @target, @annotation
|
||||
@@ -335,6 +329,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass, Object... args) {
|
||||
obtainPointcutExpression();
|
||||
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
|
||||
|
||||
// Bind Spring AOP proxy to AspectJ "this" and Spring AOP target to AspectJ target,
|
||||
|
||||
+31
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
@@ -56,6 +57,8 @@ import org.springframework.lang.Nullable;
|
||||
*/
|
||||
public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFactory {
|
||||
|
||||
private static final String AJC_MAGIC = "ajc$";
|
||||
|
||||
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
|
||||
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
|
||||
|
||||
@@ -66,11 +69,37 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
protected final ParameterNameDiscoverer parameterNameDiscoverer = new AspectJAnnotationParameterNameDiscoverer();
|
||||
|
||||
|
||||
/**
|
||||
* We consider something to be an AspectJ aspect suitable for use by the Spring AOP system
|
||||
* if it has the @Aspect annotation, and was not compiled by ajc. The reason for this latter test
|
||||
* is that aspects written in the code-style (AspectJ language) also have the annotation present
|
||||
* when compiled by ajc with the -1.5 flag, yet they cannot be consumed by Spring AOP.
|
||||
*/
|
||||
@Override
|
||||
public boolean isAspect(Class<?> clazz) {
|
||||
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
|
||||
}
|
||||
|
||||
private boolean hasAspectAnnotation(Class<?> clazz) {
|
||||
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to detect this as "code-style" AspectJ aspects should not be
|
||||
* interpreted by Spring AOP.
|
||||
*/
|
||||
private boolean compiledByAjc(Class<?> clazz) {
|
||||
// The AJTypeSystem goes to great lengths to provide a uniform appearance between code-style and
|
||||
// annotation-style aspects. Therefore there is no 'clean' way to tell them apart. Here we rely on
|
||||
// an implementation detail of the AspectJ compiler.
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.getName().startsWith(AJC_MAGIC)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Class<?> aspectClass) throws AopConfigException {
|
||||
// If the parent has the annotation and isn't abstract it's an error
|
||||
@@ -95,7 +124,6 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find and return the first AspectJ annotation on the given method
|
||||
* (there <i>should</i> only be one anyway...).
|
||||
@@ -135,7 +163,7 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
|
||||
|
||||
/**
|
||||
* Class modeling an AspectJ annotation, exposing its type enumeration and
|
||||
* Class modelling an AspectJ annotation, exposing its type enumeration and
|
||||
* pointcut String.
|
||||
* @param <A> the annotation type
|
||||
*/
|
||||
|
||||
+5
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -126,16 +126,10 @@ public class AspectMetadata implements Serializable {
|
||||
* Extract contents from String of form {@code pertarget(contents)}.
|
||||
*/
|
||||
private String findPerClause(Class<?> aspectClass) {
|
||||
Aspect ann = aspectClass.getAnnotation(Aspect.class);
|
||||
if (ann == null) {
|
||||
return "";
|
||||
}
|
||||
String value = ann.value();
|
||||
int beginIndex = value.indexOf('(');
|
||||
if (beginIndex < 0) {
|
||||
return "";
|
||||
}
|
||||
return value.substring(beginIndex + 1, value.length() - 1);
|
||||
String str = aspectClass.getAnnotation(Aspect.class).value();
|
||||
int beginIndex = str.indexOf('(') + 1;
|
||||
int endIndex = str.length() - 1;
|
||||
return str.substring(beginIndex, endIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,8 +35,7 @@ import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Internal implementation of AspectJPointcutAdvisor.
|
||||
*
|
||||
* <p>Note that there will be one instance of this advisor for each target method.
|
||||
* Note that there will be one instance of this advisor for each target method.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -294,7 +293,7 @@ final class InstantiationModelAwarePointcutAdvisorImpl
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass, Object... args) {
|
||||
// This can match only on declared pointcut.
|
||||
return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass, args));
|
||||
return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass));
|
||||
}
|
||||
|
||||
private boolean isAspectMaterialized() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,8 +44,7 @@ import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Base class for AOP proxy configuration managers.
|
||||
*
|
||||
* <p>These are not themselves AOP proxies, but subclasses of this class are
|
||||
* These are not themselves AOP proxies, but subclasses of this class are
|
||||
* normally factories from which AOP proxy instances are obtained directly.
|
||||
*
|
||||
* <p>This class frees subclasses of the housekeeping of Advices
|
||||
@@ -53,8 +52,7 @@ import org.springframework.util.CollectionUtils;
|
||||
* methods, which are provided by subclasses.
|
||||
*
|
||||
* <p>This class is serializable; subclasses need not be.
|
||||
*
|
||||
* <p>This class is used to hold snapshots of proxies.
|
||||
* This class is used to hold snapshots of proxies.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -106,7 +104,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@code AdvisedSupport} instance with the given parameters.
|
||||
* Create a AdvisedSupport instance with the given parameters.
|
||||
* @param interfaces the proxied interfaces
|
||||
*/
|
||||
public AdvisedSupport(Class<?>... interfaces) {
|
||||
@@ -117,7 +115,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
|
||||
/**
|
||||
* Set the given object as target.
|
||||
* <p>Will create a SingletonTargetSource for the object.
|
||||
* Will create a SingletonTargetSource for the object.
|
||||
* @see #setTargetSource
|
||||
* @see org.springframework.aop.target.SingletonTargetSource
|
||||
*/
|
||||
@@ -346,7 +344,8 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
private void validateIntroductionAdvisor(IntroductionAdvisor advisor) {
|
||||
advisor.validateInterfaces();
|
||||
// If the advisor passed validation, we can make the change.
|
||||
for (Class<?> ifc : advisor.getInterfaces()) {
|
||||
Class<?>[] ifcs = advisor.getInterfaces();
|
||||
for (Class<?> ifc : ifcs) {
|
||||
addInterface(ifc);
|
||||
}
|
||||
}
|
||||
@@ -492,9 +491,9 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the AOP configuration from the given {@link AdvisedSupport} object,
|
||||
* but allow substitution of a fresh {@link TargetSource} and a given interceptor chain.
|
||||
* @param other the {@code AdvisedSupport} object to take proxy configuration from
|
||||
* Copy the AOP configuration from the given AdvisedSupport object,
|
||||
* but allow substitution of a fresh TargetSource and a given interceptor chain.
|
||||
* @param other the AdvisedSupport object to take proxy configuration from
|
||||
* @param targetSource the new TargetSource
|
||||
* @param advisors the Advisors for the chain
|
||||
*/
|
||||
@@ -514,8 +513,8 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a configuration-only copy of this {@link AdvisedSupport},
|
||||
* replacing the {@link TargetSource}.
|
||||
* Build a configuration-only copy of this AdvisedSupport,
|
||||
* replacing the TargetSource.
|
||||
*/
|
||||
AdvisedSupport getConfigurationOnlyCopy() {
|
||||
AdvisedSupport copy = new AdvisedSupport();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -186,10 +186,10 @@ public abstract class AopUtils {
|
||||
* this method resolves bridge methods in order to retrieve attributes from
|
||||
* the <i>original</i> method definition.
|
||||
* @param method the method to be invoked, which may come from an interface
|
||||
* @param targetClass the target class for the current invocation
|
||||
* (can be {@code null} or may not even implement the method)
|
||||
* @param targetClass the target class for the current invocation.
|
||||
* May be {@code null} or may not even implement the method.
|
||||
* @return the specific target method, or the original method if the
|
||||
* {@code targetClass} does not implement it
|
||||
* {@code targetClass} doesn't implement it or is {@code null}
|
||||
* @see org.springframework.util.ClassUtils#getMostSpecificMethod
|
||||
*/
|
||||
public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) {
|
||||
|
||||
+39
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.Map;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.aspectj.weaver.tools.PointcutExpression;
|
||||
import org.aspectj.weaver.tools.PointcutPrimitive;
|
||||
import org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import test.annotation.EmptySpringAnnotation;
|
||||
@@ -39,6 +42,7 @@ import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.beans.testfixture.beans.subpkg.DeepBean;
|
||||
|
||||
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;
|
||||
|
||||
@@ -61,7 +65,7 @@ public class AspectJExpressionPointcutTests {
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws NoSuchMethodException {
|
||||
public void setUp() throws NoSuchMethodException {
|
||||
getAge = TestBean.class.getMethod("getAge");
|
||||
setAge = TestBean.class.getMethod("setAge", int.class);
|
||||
setSomeNumber = TestBean.class.getMethod("setSomeNumber", Number.class);
|
||||
@@ -171,25 +175,25 @@ public class AspectJExpressionPointcutTests {
|
||||
@Test
|
||||
public void testFriendlyErrorOnNoLocationClassMatching() {
|
||||
AspectJExpressionPointcut pc = new AspectJExpressionPointcut();
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> pc.getClassFilter().matches(ITestBean.class))
|
||||
.withMessageContaining("expression");
|
||||
assertThatIllegalStateException().isThrownBy(() ->
|
||||
pc.matches(ITestBean.class))
|
||||
.withMessageContaining("expression");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFriendlyErrorOnNoLocation2ArgMatching() {
|
||||
AspectJExpressionPointcut pc = new AspectJExpressionPointcut();
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> pc.getMethodMatcher().matches(getAge, ITestBean.class))
|
||||
.withMessageContaining("expression");
|
||||
assertThatIllegalStateException().isThrownBy(() ->
|
||||
pc.matches(getAge, ITestBean.class))
|
||||
.withMessageContaining("expression");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFriendlyErrorOnNoLocation3ArgMatching() {
|
||||
AspectJExpressionPointcut pc = new AspectJExpressionPointcut();
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> pc.getMethodMatcher().matches(getAge, ITestBean.class, (Object[]) null))
|
||||
.withMessageContaining("expression");
|
||||
assertThatIllegalStateException().isThrownBy(() ->
|
||||
pc.matches(getAge, ITestBean.class, (Object[]) null))
|
||||
.withMessageContaining("expression");
|
||||
}
|
||||
|
||||
|
||||
@@ -206,10 +210,8 @@ public class AspectJExpressionPointcutTests {
|
||||
// not currently testable in a reliable fashion
|
||||
//assertDoesNotMatchStringClass(classFilter);
|
||||
|
||||
assertThat(methodMatcher.matches(setSomeNumber, TestBean.class, 12D))
|
||||
.as("Should match with setSomeNumber with Double input").isTrue();
|
||||
assertThat(methodMatcher.matches(setSomeNumber, TestBean.class, 11))
|
||||
.as("Should not match setSomeNumber with Integer input").isFalse();
|
||||
assertThat(methodMatcher.matches(setSomeNumber, TestBean.class, 12D)).as("Should match with setSomeNumber with Double input").isTrue();
|
||||
assertThat(methodMatcher.matches(setSomeNumber, TestBean.class, 11)).as("Should not match setSomeNumber with Integer input").isFalse();
|
||||
assertThat(methodMatcher.matches(getAge, TestBean.class)).as("Should not match getAge").isFalse();
|
||||
assertThat(methodMatcher.isRuntime()).as("Should be a runtime match").isTrue();
|
||||
}
|
||||
@@ -244,13 +246,14 @@ public class AspectJExpressionPointcutTests {
|
||||
@Test
|
||||
public void testInvalidExpression() {
|
||||
String expression = "execution(void org.springframework.beans.testfixture.beans.TestBean.setSomeNumber(Number) && args(Double)";
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> getPointcut(expression).getClassFilter().matches(Object.class));
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
getPointcut(expression)::getClassFilter); // call to getClassFilter forces resolution
|
||||
}
|
||||
|
||||
private TestBean getAdvisedProxy(String pointcutExpression, CallCountingInterceptor interceptor) {
|
||||
TestBean target = new TestBean();
|
||||
|
||||
AspectJExpressionPointcut pointcut = getPointcut(pointcutExpression);
|
||||
Pointcut pointcut = getPointcut(pointcutExpression);
|
||||
|
||||
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
|
||||
advisor.setAdvice(interceptor);
|
||||
@@ -274,29 +277,40 @@ public class AspectJExpressionPointcutTests {
|
||||
@Test
|
||||
public void testWithUnsupportedPointcutPrimitive() {
|
||||
String expression = "call(int org.springframework.beans.testfixture.beans.TestBean.getAge())";
|
||||
assertThat(getPointcut(expression).getClassFilter().matches(Object.class)).isFalse();
|
||||
assertThatExceptionOfType(UnsupportedPointcutPrimitiveException.class).isThrownBy(() ->
|
||||
getPointcut(expression).getClassFilter()) // call to getClassFilter forces resolution...
|
||||
.satisfies(ex -> assertThat(ex.getUnsupportedPrimitive()).isEqualTo(PointcutPrimitive.CALL));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAndSubstitution() {
|
||||
AspectJExpressionPointcut pc = getPointcut("execution(* *(..)) and args(String)");
|
||||
String expr = pc.getPointcutExpression().getPointcutExpression();
|
||||
assertThat(expr).isEqualTo("execution(* *(..)) && args(String)");
|
||||
Pointcut pc = getPointcut("execution(* *(..)) and args(String)");
|
||||
PointcutExpression expr = ((AspectJExpressionPointcut) pc).getPointcutExpression();
|
||||
assertThat(expr.getPointcutExpression()).isEqualTo("execution(* *(..)) && args(String)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleAndSubstitutions() {
|
||||
AspectJExpressionPointcut pc = getPointcut("execution(* *(..)) and args(String) and this(Object)");
|
||||
String expr = pc.getPointcutExpression().getPointcutExpression();
|
||||
assertThat(expr).isEqualTo("execution(* *(..)) && args(String) && this(Object)");
|
||||
Pointcut pc = getPointcut("execution(* *(..)) and args(String) and this(Object)");
|
||||
PointcutExpression expr = ((AspectJExpressionPointcut) pc).getPointcutExpression();
|
||||
assertThat(expr.getPointcutExpression()).isEqualTo("execution(* *(..)) && args(String) && this(Object)");
|
||||
}
|
||||
|
||||
private AspectJExpressionPointcut getPointcut(String expression) {
|
||||
private Pointcut getPointcut(String expression) {
|
||||
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
pointcut.setExpression(expression);
|
||||
return pointcut;
|
||||
}
|
||||
|
||||
|
||||
public static class OtherIOther implements IOther {
|
||||
|
||||
@Override
|
||||
public void absquatulate() {
|
||||
// Empty
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchGenericArgument() {
|
||||
String expression = "execution(* set*(java.util.List<org.springframework.beans.testfixture.beans.TestBean>) )";
|
||||
@@ -491,15 +505,6 @@ public class AspectJExpressionPointcutTests {
|
||||
}
|
||||
|
||||
|
||||
public static class OtherIOther implements IOther {
|
||||
|
||||
@Override
|
||||
public void absquatulate() {
|
||||
// Empty
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class HasGeneric {
|
||||
|
||||
public void setFriends(List<TestBean> friends) {
|
||||
|
||||
+51
-70
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2019 the original author 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,67 +38,56 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
class ArgumentBindingTests {
|
||||
public class ArgumentBindingTests {
|
||||
|
||||
@Test
|
||||
void annotationArgumentNameBinding() {
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TransactionalBean());
|
||||
proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
|
||||
ITransactionalBean proxiedTestBean = proxyFactory.getProxy();
|
||||
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(proxiedTestBean::doInTransaction)
|
||||
.withMessage("Invoked with @Transactional");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindingInPointcutUsedByAdvice() {
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
|
||||
public void testBindingInPointcutUsedByAdvice() {
|
||||
TestBean tb = new TestBean();
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
|
||||
proxyFactory.addAspect(NamedPointcutWithArgs.class);
|
||||
ITestBean proxiedTestBean = proxyFactory.getProxy();
|
||||
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> proxiedTestBean.setName("enigma"))
|
||||
.withMessage("enigma");
|
||||
ITestBean proxiedTestBean = proxyFactory.getProxy();
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
proxiedTestBean.setName("Supercalifragalisticexpialidocious"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindingWithDynamicAdvice() {
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
|
||||
proxyFactory.addAspect(DynamicPointcutWithArgs.class);
|
||||
ITestBean proxiedTestBean = proxyFactory.getProxy();
|
||||
public void testAnnotationArgumentNameBinding() {
|
||||
TransactionalBean tb = new TransactionalBean();
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
|
||||
proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
|
||||
|
||||
proxiedTestBean.applyName(1);
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> proxiedTestBean.applyName("enigma"))
|
||||
.withMessage("enigma");
|
||||
ITransactionalBean proxiedTestBean = proxyFactory.getProxy();
|
||||
assertThatIllegalStateException().isThrownBy(
|
||||
proxiedTestBean::doInTransaction);
|
||||
}
|
||||
|
||||
@Test
|
||||
void parameterNameDiscoverWithReferencePointcut() throws Exception {
|
||||
public void testParameterNameDiscoverWithReferencePointcut() throws Exception {
|
||||
AspectJAdviceParameterNameDiscoverer discoverer =
|
||||
new AspectJAdviceParameterNameDiscoverer("somepc(formal) && set(* *)");
|
||||
discoverer.setRaiseExceptions(true);
|
||||
Method method = getClass().getDeclaredMethod("methodWithOneParam", String.class);
|
||||
assertThat(discoverer.getParameterNames(method)).containsExactly("formal");
|
||||
Method methodUsedForParameterTypeDiscovery =
|
||||
getClass().getMethod("methodWithOneParam", String.class);
|
||||
String[] pnames = discoverer.getParameterNames(methodUsedForParameterTypeDiscovery);
|
||||
assertThat(pnames.length).as("one parameter name").isEqualTo(1);
|
||||
assertThat(pnames[0]).isEqualTo("formal");
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void methodWithOneParam(String aParam) {
|
||||
public void methodWithOneParam(String aParam) {
|
||||
}
|
||||
|
||||
|
||||
interface ITransactionalBean {
|
||||
public interface ITransactionalBean {
|
||||
|
||||
@Transactional
|
||||
void doInTransaction();
|
||||
}
|
||||
|
||||
|
||||
static class TransactionalBean implements ITransactionalBean {
|
||||
public static class TransactionalBean implements ITransactionalBean {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@@ -106,46 +95,38 @@ class ArgumentBindingTests {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Mimics Spring's @Transactional annotation without actually introducing the dependency.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Transactional {
|
||||
}
|
||||
/**
|
||||
* Represents Spring's Transactional annotation without actually introducing the dependency
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Transactional {
|
||||
}
|
||||
|
||||
|
||||
@Aspect
|
||||
static class PointcutWithAnnotationArgument {
|
||||
@Aspect
|
||||
class PointcutWithAnnotationArgument {
|
||||
|
||||
@Around("execution(* org.springframework..*.*(..)) && @annotation(transactional)")
|
||||
public Object around(ProceedingJoinPoint pjp, Transactional transactional) throws Throwable {
|
||||
throw new IllegalStateException("Invoked with @Transactional");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Aspect
|
||||
static class NamedPointcutWithArgs {
|
||||
|
||||
@Pointcut("execution(* *(..)) && args(s,..)")
|
||||
public void pointcutWithArgs(String s) {}
|
||||
|
||||
@Around("pointcutWithArgs(aString)")
|
||||
public Object doAround(ProceedingJoinPoint pjp, String aString) throws Throwable {
|
||||
throw new IllegalArgumentException(aString);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Aspect("pertarget(execution(* *(..)))")
|
||||
static class DynamicPointcutWithArgs {
|
||||
|
||||
@Around("execution(* *(..)) && args(java.lang.String)")
|
||||
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
|
||||
throw new IllegalArgumentException(String.valueOf(pjp.getArgs()[0]));
|
||||
}
|
||||
@Around(value = "execution(* org.springframework..*.*(..)) && @annotation(transaction)")
|
||||
public Object around(ProceedingJoinPoint pjp, Transactional transaction) throws Throwable {
|
||||
System.out.println("Invoked with transaction " + transaction);
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Aspect
|
||||
class NamedPointcutWithArgs {
|
||||
|
||||
@Pointcut("execution(* *(..)) && args(s,..)")
|
||||
public void pointcutWithArgs(String s) {}
|
||||
|
||||
@Around("pointcutWithArgs(aString)")
|
||||
public Object doAround(ProceedingJoinPoint pjp, String aString) throws Throwable {
|
||||
System.out.println("got '" + aString + "' at '" + pjp + "'");
|
||||
throw new IllegalArgumentException(aString);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2019 the original author 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,35 +17,29 @@
|
||||
package org.springframework.aop.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
|
||||
import org.springframework.aop.target.EmptyTargetSource;
|
||||
import org.springframework.aop.testfixture.interceptor.NopInterceptor;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.testfixture.io.SerializationTestUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @author Chris Beams
|
||||
* @author Sebastien Deleuze
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
class AopUtilsTests {
|
||||
public class AopUtilsTests {
|
||||
|
||||
@Test
|
||||
void testPointcutCanNeverApply() {
|
||||
public void testPointcutCanNeverApply() {
|
||||
class TestPointcut extends StaticMethodMatcherPointcut {
|
||||
@Override
|
||||
public boolean matches(Method method, @Nullable Class<?> clazzy) {
|
||||
@@ -58,13 +52,13 @@ class AopUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPointcutAlwaysApplies() {
|
||||
public void testPointcutAlwaysApplies() {
|
||||
assertThat(AopUtils.canApply(new DefaultPointcutAdvisor(new NopInterceptor()), Object.class)).isTrue();
|
||||
assertThat(AopUtils.canApply(new DefaultPointcutAdvisor(new NopInterceptor()), TestBean.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPointcutAppliesToOneMethodOnObject() {
|
||||
public void testPointcutAppliesToOneMethodOnObject() {
|
||||
class TestPointcut extends StaticMethodMatcherPointcut {
|
||||
@Override
|
||||
public boolean matches(Method method, @Nullable Class<?> clazz) {
|
||||
@@ -84,7 +78,7 @@ class AopUtilsTests {
|
||||
* that's subverted the singleton construction limitation.
|
||||
*/
|
||||
@Test
|
||||
void testCanonicalFrameworkClassesStillCanonicalOnDeserialization() throws Exception {
|
||||
public void testCanonicalFrameworkClassesStillCanonicalOnDeserialization() throws Exception {
|
||||
assertThat(SerializationTestUtils.serializeAndDeserialize(MethodMatcher.TRUE)).isSameAs(MethodMatcher.TRUE);
|
||||
assertThat(SerializationTestUtils.serializeAndDeserialize(ClassFilter.TRUE)).isSameAs(ClassFilter.TRUE);
|
||||
assertThat(SerializationTestUtils.serializeAndDeserialize(Pointcut.TRUE)).isSameAs(Pointcut.TRUE);
|
||||
@@ -94,45 +88,4 @@ class AopUtilsTests {
|
||||
assertThat(SerializationTestUtils.serializeAndDeserialize(ExposeInvocationInterceptor.INSTANCE)).isSameAs(ExposeInvocationInterceptor.INSTANCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInvokeJoinpointUsingReflection() throws Throwable {
|
||||
String name = "foo";
|
||||
TestBean testBean = new TestBean(name);
|
||||
Method method = ReflectionUtils.findMethod(TestBean.class, "getName");
|
||||
Object result = AopUtils.invokeJoinpointUsingReflection(testBean, method, new Object[0]);
|
||||
assertThat(result).isEqualTo(name);
|
||||
}
|
||||
|
||||
@Test // gh-32365
|
||||
void mostSpecificMethodBetweenJdkProxyAndTarget() throws Exception {
|
||||
Class<?> proxyClass = new ProxyFactory(new WithInterface()).getProxy(getClass().getClassLoader()).getClass();
|
||||
Method specificMethod = AopUtils.getMostSpecificMethod(proxyClass.getMethod("handle", List.class), WithInterface.class);
|
||||
assertThat(ResolvableType.forMethodParameter(specificMethod, 0).getGeneric().toClass()).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
@Test // gh-32365
|
||||
void mostSpecificMethodBetweenCglibProxyAndTarget() throws Exception {
|
||||
Class<?> proxyClass = new ProxyFactory(new WithoutInterface()).getProxy(getClass().getClassLoader()).getClass();
|
||||
Method specificMethod = AopUtils.getMostSpecificMethod(proxyClass.getMethod("handle", List.class), WithoutInterface.class);
|
||||
assertThat(ResolvableType.forMethodParameter(specificMethod, 0).getGeneric().toClass()).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
|
||||
interface ProxyInterface {
|
||||
|
||||
void handle(List<String> list);
|
||||
}
|
||||
|
||||
static class WithInterface implements ProxyInterface {
|
||||
|
||||
public void handle(List<String> list) {
|
||||
}
|
||||
}
|
||||
|
||||
static class WithoutInterface {
|
||||
|
||||
public void handle(List<String> list) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -1004,20 +1004,18 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
*/
|
||||
protected abstract static class PropertyHandler {
|
||||
|
||||
@Nullable
|
||||
private final Class<?> propertyType;
|
||||
|
||||
private final boolean readable;
|
||||
|
||||
private final boolean writable;
|
||||
|
||||
public PropertyHandler(@Nullable Class<?> propertyType, boolean readable, boolean writable) {
|
||||
public PropertyHandler(Class<?> propertyType, boolean readable, boolean writable) {
|
||||
this.propertyType = propertyType;
|
||||
this.readable = readable;
|
||||
this.writable = writable;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Class<?> getPropertyType() {
|
||||
return this.propertyType;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.time.temporal.Temporal;
|
||||
@@ -31,7 +30,6 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -789,28 +787,38 @@ public abstract class BeanUtils {
|
||||
if (editable != null) {
|
||||
if (!editable.isInstance(target)) {
|
||||
throw new IllegalArgumentException("Target class [" + target.getClass().getName() +
|
||||
"] not assignable to editable class [" + editable.getName() + "]");
|
||||
"] not assignable to Editable class [" + editable.getName() + "]");
|
||||
}
|
||||
actualEditable = editable;
|
||||
}
|
||||
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
|
||||
Set<String> ignoredProps = (ignoreProperties != null ? new HashSet<>(Arrays.asList(ignoreProperties)) : null);
|
||||
CachedIntrospectionResults sourceResults = (actualEditable != source.getClass() ?
|
||||
CachedIntrospectionResults.forClass(source.getClass()) : null);
|
||||
List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);
|
||||
|
||||
for (PropertyDescriptor targetPd : targetPds) {
|
||||
Method writeMethod = targetPd.getWriteMethod();
|
||||
if (writeMethod != null && (ignoredProps == null || !ignoredProps.contains(targetPd.getName()))) {
|
||||
PropertyDescriptor sourcePd = (sourceResults != null ?
|
||||
sourceResults.getPropertyDescriptor(targetPd.getName()) : targetPd);
|
||||
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
|
||||
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
|
||||
if (sourcePd != null) {
|
||||
Method readMethod = sourcePd.getReadMethod();
|
||||
if (readMethod != null) {
|
||||
if (isAssignable(writeMethod, readMethod)) {
|
||||
ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod);
|
||||
ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0);
|
||||
|
||||
// Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
|
||||
boolean isAssignable =
|
||||
(sourceResolvableType.hasUnresolvableGenerics() || targetResolvableType.hasUnresolvableGenerics() ?
|
||||
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) :
|
||||
targetResolvableType.isAssignableFrom(sourceResolvableType));
|
||||
|
||||
if (isAssignable) {
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(readMethod);
|
||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
|
||||
readMethod.setAccessible(true);
|
||||
}
|
||||
Object value = readMethod.invoke(source);
|
||||
ReflectionUtils.makeAccessible(writeMethod);
|
||||
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
|
||||
writeMethod.setAccessible(true);
|
||||
}
|
||||
writeMethod.invoke(target, value);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
@@ -824,24 +832,6 @@ public abstract class BeanUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAssignable(Method writeMethod, Method readMethod) {
|
||||
Type paramType = writeMethod.getGenericParameterTypes()[0];
|
||||
if (paramType instanceof Class) {
|
||||
return ClassUtils.isAssignable((Class<?>) paramType, readMethod.getReturnType());
|
||||
}
|
||||
else if (paramType.equals(readMethod.getGenericReturnType())) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
ResolvableType sourceType = ResolvableType.forMethodReturnType(readMethod);
|
||||
ResolvableType targetType = ResolvableType.forMethodParameter(writeMethod, 0);
|
||||
// Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
|
||||
return (sourceType.hasUnresolvableGenerics() || targetType.hasUnresolvableGenerics() ?
|
||||
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) :
|
||||
targetType.isAssignableFrom(sourceType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to avoid a hard dependency on Kotlin at runtime.
|
||||
@@ -902,6 +892,7 @@ public abstract class BeanUtils {
|
||||
}
|
||||
return kotlinConstructor.callBy(argParameters);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -129,6 +129,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
|
||||
ReflectionUtils.makeAccessible(this.field);
|
||||
return this.field.get(getWrappedInstance());
|
||||
}
|
||||
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new InvalidPropertyException(getWrappedClass(),
|
||||
this.field.getName(), "Field is not accessible", ex);
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -292,7 +292,7 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
||||
if (actualValue != null) {
|
||||
actualValue = typeConverter.convertIfNecessary(actualValue, expectedValue.getClass());
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(expectedValue, actualValue)) {
|
||||
if (!expectedValue.equals(actualValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -97,10 +97,10 @@ import org.springframework.util.StringUtils;
|
||||
* Supports autowiring constructors, properties by name, and properties by type.
|
||||
*
|
||||
* <p>The main template method to be implemented by subclasses is
|
||||
* {@link #resolveDependency(DependencyDescriptor, String, Set, TypeConverter)}, used for
|
||||
* autowiring. In case of a {@link org.springframework.beans.factory.ListableBeanFactory}
|
||||
* which is capable of searching its bean definitions, matching beans will typically be
|
||||
* implemented through such a search. Otherwise, simplified matching can be implemented.
|
||||
* {@link #resolveDependency(DependencyDescriptor, String, Set, TypeConverter)},
|
||||
* used for autowiring by type. In case of a factory which is capable of searching
|
||||
* its bean definitions, matching beans will typically be implemented through such
|
||||
* a search. For other factory styles, simplified matching algorithms can be implemented.
|
||||
*
|
||||
* <p>Note that this class does <i>not</i> assume or implement bean definition
|
||||
* registry capabilities. See {@link DefaultListableBeanFactory} for an implementation
|
||||
@@ -675,7 +675,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
// Apply SmartInstantiationAwareBeanPostProcessors to predict the
|
||||
// eventual type after a before-instantiation shortcut.
|
||||
if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
|
||||
boolean matchingOnlyFactoryBean = (typesToMatch.length == 1 && typesToMatch[0] == FactoryBean.class);
|
||||
boolean matchingOnlyFactoryBean = typesToMatch.length == 1 && typesToMatch[0] == FactoryBean.class;
|
||||
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
|
||||
Class<?> predicted = bp.predictBeanType(targetType, beanName);
|
||||
if (predicted != null &&
|
||||
@@ -835,11 +835,11 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
/**
|
||||
* This implementation attempts to query the FactoryBean's generic parameter metadata
|
||||
* if present to determine the object type. If not present, i.e. the FactoryBean is
|
||||
* declared as a raw type, it checks the FactoryBean's {@code getObjectType} method
|
||||
* declared as a raw type, checks the FactoryBean's {@code getObjectType} method
|
||||
* on a plain instance of the FactoryBean, without bean properties applied yet.
|
||||
* If this doesn't return a type yet and {@code allowInit} is {@code true}, full
|
||||
* creation of the FactoryBean is attempted as fallback (through delegation to the
|
||||
* superclass implementation).
|
||||
* If this doesn't return a type yet, and {@code allowInit} is {@code true} a
|
||||
* full creation of the FactoryBean is used as fallback (through delegation to the
|
||||
* superclass's implementation).
|
||||
* <p>The shortcut check for a FactoryBean is only applied in case of a singleton
|
||||
* FactoryBean. If the FactoryBean instance itself is not kept as singleton,
|
||||
* it will be fully created to check the type of its exposed object.
|
||||
|
||||
+6
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -166,9 +166,6 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
/** Map from scope identifier String to corresponding Scope. */
|
||||
private final Map<String, Scope> scopes = new LinkedHashMap<>(8);
|
||||
|
||||
/** Application startup metrics. **/
|
||||
private ApplicationStartup applicationStartup = ApplicationStartup.DEFAULT;
|
||||
|
||||
/** Security context used when running with a SecurityManager. */
|
||||
@Nullable
|
||||
private SecurityContextProvider securityContextProvider;
|
||||
@@ -183,6 +180,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
|
||||
new NamedThreadLocal<>("Prototype beans currently in creation");
|
||||
|
||||
/** Application startup metrics. **/
|
||||
private ApplicationStartup applicationStartup = ApplicationStartup.DEFAULT;
|
||||
|
||||
/**
|
||||
* Create a new AbstractBeanFactory.
|
||||
@@ -750,7 +749,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
aliases.add(fullBeanName);
|
||||
}
|
||||
String[] retrievedAliases = super.getAliases(beanName);
|
||||
String prefix = (factoryPrefix ? FACTORY_BEAN_PREFIX : "");
|
||||
String prefix = factoryPrefix ? FACTORY_BEAN_PREFIX : "";
|
||||
for (String retrievedAlias : retrievedAliases) {
|
||||
String alias = prefix + retrievedAlias;
|
||||
if (!alias.equals(name)) {
|
||||
@@ -1080,7 +1079,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
|
||||
@Override
|
||||
public void setApplicationStartup(ApplicationStartup applicationStartup) {
|
||||
Assert.notNull(applicationStartup, "ApplicationStartup must not be null");
|
||||
Assert.notNull(applicationStartup, "applicationStartup should not be null");
|
||||
this.applicationStartup = applicationStartup;
|
||||
}
|
||||
|
||||
@@ -1695,7 +1694,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
* already. The implementation is allowed to instantiate the target factory bean if
|
||||
* {@code allowInit} is {@code true} and the type cannot be determined another way;
|
||||
* otherwise it is restricted to introspecting signatures and related metadata.
|
||||
* <p>If no {@link FactoryBean#OBJECT_TYPE_ATTRIBUTE} is set on the bean definition
|
||||
* <p>If no {@link FactoryBean#OBJECT_TYPE_ATTRIBUTE} if set on the bean definition
|
||||
* and {@code allowInit} is {@code true}, the default implementation will create
|
||||
* the FactoryBean via {@code getBean} to call its {@code getObjectType} method.
|
||||
* Subclasses are encouraged to optimize this, typically by inspecting the generic
|
||||
|
||||
+12
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -107,7 +107,11 @@ class ConstructorResolver {
|
||||
|
||||
/**
|
||||
* "autowire constructor" (with constructor arguments by type) behavior.
|
||||
* Also applied if explicit constructor argument values are specified.
|
||||
* Also applied if explicit constructor argument values are specified,
|
||||
* matching all remaining arguments with beans from the bean factory.
|
||||
* <p>This corresponds to constructor injection: In this mode, a Spring
|
||||
* bean factory is able to host components that expect constructor-based
|
||||
* dependency resolution.
|
||||
* @param beanName the name of the bean
|
||||
* @param mbd the merged bean definition for the bean
|
||||
* @param chosenCtors chosen candidate constructors (or {@code null} if none)
|
||||
@@ -600,10 +604,13 @@ class ConstructorResolver {
|
||||
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"No matching factory method found on class [" + factoryClass.getName() + "]: " +
|
||||
(mbd.getFactoryBeanName() != null ? "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
|
||||
(mbd.getFactoryBeanName() != null ?
|
||||
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
|
||||
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
|
||||
"Check that a method with the specified name " + (minNrOfArgs > 0 ? "and arguments " : "") +
|
||||
"exists and that it is " + (isStatic ? "static" : "non-static") + ".");
|
||||
"Check that a method with the specified name " +
|
||||
(minNrOfArgs > 0 ? "and arguments " : "") +
|
||||
"exists and that it is " +
|
||||
(isStatic ? "static" : "non-static") + ".");
|
||||
}
|
||||
else if (void.class == factoryMethodToUse.getReturnType()) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -567,16 +567,16 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
*/
|
||||
protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
|
||||
// Trigger destruction of dependent beans first...
|
||||
Set<String> dependentBeanNames;
|
||||
Set<String> dependencies;
|
||||
synchronized (this.dependentBeanMap) {
|
||||
// Within full synchronization in order to guarantee a disconnected Set
|
||||
dependentBeanNames = this.dependentBeanMap.remove(beanName);
|
||||
dependencies = this.dependentBeanMap.remove(beanName);
|
||||
}
|
||||
if (dependentBeanNames != null) {
|
||||
if (dependencies != null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependentBeanNames);
|
||||
logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
|
||||
}
|
||||
for (String dependentBeanName : dependentBeanNames) {
|
||||
for (String dependentBeanName : dependencies) {
|
||||
destroySingleton(dependentBeanName);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -78,10 +78,8 @@ public class PathEditor extends PropertyEditorSupport {
|
||||
if (nioPathCandidate && !text.startsWith("/")) {
|
||||
try {
|
||||
URI uri = new URI(text);
|
||||
String scheme = uri.getScheme();
|
||||
if (scheme != null) {
|
||||
// No NIO candidate except for "C:" style drive letters
|
||||
nioPathCandidate = (scheme.length() == 1);
|
||||
if (uri.getScheme() != null) {
|
||||
nioPathCandidate = false;
|
||||
// Let's try NIO file system providers via Paths.get(URI)
|
||||
setValue(Paths.get(uri).normalize());
|
||||
return;
|
||||
@@ -111,8 +109,7 @@ public class PathEditor extends PropertyEditorSupport {
|
||||
setValue(resource.getFile().toPath());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not retrieve file for " + resource + ": " + ex.getMessage());
|
||||
throw new IllegalArgumentException("Failed to retrieve file for " + resource, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,10 +33,6 @@ public interface ITestBean extends AgeHolder {
|
||||
|
||||
void setName(String name);
|
||||
|
||||
default void applyName(Object name) {
|
||||
setName(String.valueOf(name));
|
||||
}
|
||||
|
||||
ITestBean getSpouse();
|
||||
|
||||
void setSpouse(ITestBean spouse);
|
||||
|
||||
Vendored
+1
-1
@@ -236,7 +236,7 @@ public class CaffeineCacheManager implements CacheManager {
|
||||
* Build a common {@link CaffeineCache} instance for the specified cache name,
|
||||
* using the common Caffeine configuration specified on this cache manager.
|
||||
* <p>Delegates to {@link #adaptCaffeineCache} as the adaptation method to
|
||||
* Spring's cache abstraction (allowing for centralized decoration etc.),
|
||||
* Spring's cache abstraction (allowing for centralized decoration etc),
|
||||
* passing in a freshly built native Caffeine Cache instance.
|
||||
* @param name the name of the cache
|
||||
* @return the Spring CaffeineCache adapter (or a decorator thereof)
|
||||
|
||||
+3
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,7 +32,6 @@ import java.lang.annotation.Target;
|
||||
* @author Stephane Nicoll
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
* @see Cacheable
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -43,10 +42,8 @@ public @interface CacheConfig {
|
||||
* Names of the default caches to consider for caching operations defined
|
||||
* in the annotated class.
|
||||
* <p>If none is set at the operation level, these are used instead of the default.
|
||||
* <p>Names may be used to determine the target cache(s), to be resolved via the
|
||||
* configured {@link #cacheResolver()} which typically delegates to
|
||||
* {@link org.springframework.cache.CacheManager#getCache}.
|
||||
* For further details see {@link Cacheable#cacheNames()}.
|
||||
* <p>May be used to determine the target cache (or caches), matching the
|
||||
* qualifier value or the bean names of a specific bean definition.
|
||||
*/
|
||||
String[] cacheNames() default {};
|
||||
|
||||
|
||||
+2
-6
@@ -68,12 +68,8 @@ public @interface Cacheable {
|
||||
|
||||
/**
|
||||
* Names of the caches in which method invocation results are stored.
|
||||
* <p>Names may be used to determine the target cache(s), to be resolved via the
|
||||
* configured {@link #cacheResolver()} which typically delegates to
|
||||
* {@link org.springframework.cache.CacheManager#getCache}.
|
||||
* <p>This will usually be a single cache name. If multiple names are specified,
|
||||
* they will be consulted for a cache hit in the order of definition, and they
|
||||
* will all receive a put/evict request for the same newly cached value.
|
||||
* <p>Names may be used to determine the target cache (or caches), matching
|
||||
* the qualifier value or bean name of a specific bean definition.
|
||||
* @since 4.2
|
||||
* @see #value
|
||||
* @see CacheConfig#cacheNames
|
||||
|
||||
+3
-3
@@ -547,10 +547,10 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect a {@link CachePutRequest} for every {@link CacheOperation}
|
||||
* using the specified result value.
|
||||
* Collect the {@link CachePutRequest} for all {@link CacheOperation} using
|
||||
* the specified result value.
|
||||
* @param contexts the contexts to handle
|
||||
* @param result the result value
|
||||
* @param result the result value (never {@code null})
|
||||
* @param putRequests the collection to update
|
||||
*/
|
||||
private void collectPutRequests(Collection<CacheOperationContext> contexts,
|
||||
|
||||
Vendored
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,7 @@ import org.springframework.lang.Nullable;
|
||||
* Abstract the invocation of a cache operation.
|
||||
*
|
||||
* <p>Does not provide a way to transmit checked exceptions but
|
||||
* provides a special exception that should be used to wrap any
|
||||
* provide a special exception that should be used to wrap any
|
||||
* exception that was thrown by the underlying invocation.
|
||||
* Callers are expected to handle this issue type specifically.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -121,7 +121,7 @@ public interface SmartLifecycle extends Lifecycle, Phased {
|
||||
/**
|
||||
* Return the phase that this lifecycle object is supposed to run in.
|
||||
* <p>The default implementation returns {@link #DEFAULT_PHASE} in order to
|
||||
* let {@code stop()} callbacks execute before regular {@code Lifecycle}
|
||||
* let {@code stop()} callbacks execute after regular {@code Lifecycle}
|
||||
* implementations.
|
||||
* @see #isAutoStartup()
|
||||
* @see #start()
|
||||
|
||||
+10
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -62,13 +62,11 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* A component provider that scans for candidate components starting from a
|
||||
* specified base package. Can use the {@linkplain CandidateComponentsIndex component
|
||||
* index}, if it is available, and scans the classpath otherwise.
|
||||
*
|
||||
* <p>Candidate components are identified by applying exclude and include filters.
|
||||
* {@link AnnotationTypeFilter} and {@link AssignableTypeFilter} include filters
|
||||
* for an annotation/target-type that is annotated with {@link Indexed} are
|
||||
* A component provider that provides candidate components from a base package. Can
|
||||
* use {@link CandidateComponentsIndex the index} if it is available of scans the
|
||||
* classpath otherwise. Candidate components are identified by applying exclude and
|
||||
* include filters. {@link AnnotationTypeFilter}, {@link AssignableTypeFilter} include
|
||||
* filters on an annotation/superclass that are annotated with {@link Indexed} are
|
||||
* supported: if any other include filter is specified, the index is ignored and
|
||||
* classpath scanning is used instead.
|
||||
*
|
||||
@@ -306,7 +304,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
|
||||
|
||||
/**
|
||||
* Scan the component index or class path for candidate components.
|
||||
* Scan the class path for candidate components.
|
||||
* @param basePackage the package to check for annotated classes
|
||||
* @return a corresponding Set of autodetected bean definitions
|
||||
*/
|
||||
@@ -320,7 +318,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the component index can be used by this instance.
|
||||
* Determine if the index can be used by this instance.
|
||||
* @return {@code true} if the index is available and the configuration of this
|
||||
* instance is supported by it, {@code false} otherwise
|
||||
* @since 5.0
|
||||
@@ -456,7 +454,8 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, ex);
|
||||
throw new BeanDefinitionStoreException(
|
||||
"Failed to read candidate component class: " + resource, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -402,8 +402,8 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
|
||||
return;
|
||||
}
|
||||
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
|
||||
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
|
||||
}
|
||||
@@ -413,9 +413,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
|
||||
}
|
||||
}
|
||||
else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
|
||||
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@EJB annotation is not supported on static methods");
|
||||
}
|
||||
@@ -425,9 +423,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
|
||||
}
|
||||
}
|
||||
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
|
||||
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@Resource annotation is not supported on static methods");
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -104,8 +104,8 @@ import org.springframework.stereotype.Component;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>{@code @Configuration} classes may not only be bootstrapped using component
|
||||
* scanning, but may also themselves <em>configure</em> component scanning using
|
||||
* <p>{@code @Configuration} classes may not only be bootstrapped using
|
||||
* component scanning, but may also themselves <em>configure</em> component scanning using
|
||||
* the {@link ComponentScan @ComponentScan} annotation:
|
||||
*
|
||||
* <pre class="code">
|
||||
|
||||
+15
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -72,6 +72,7 @@ final class ConfigurationClass {
|
||||
* Create a new {@link ConfigurationClass} with the given name.
|
||||
* @param metadataReader reader used to parse the underlying {@link Class}
|
||||
* @param beanName must not be {@code null}
|
||||
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
|
||||
*/
|
||||
ConfigurationClass(MetadataReader metadataReader, String beanName) {
|
||||
Assert.notNull(beanName, "Bean name must not be null");
|
||||
@@ -85,10 +86,10 @@ final class ConfigurationClass {
|
||||
* using the {@link Import} annotation or automatically processed as a nested
|
||||
* configuration class (if importedBy is not {@code null}).
|
||||
* @param metadataReader reader used to parse the underlying {@link Class}
|
||||
* @param importedBy the configuration class importing this one
|
||||
* @param importedBy the configuration class importing this one or {@code null}
|
||||
* @since 3.1.1
|
||||
*/
|
||||
ConfigurationClass(MetadataReader metadataReader, ConfigurationClass importedBy) {
|
||||
ConfigurationClass(MetadataReader metadataReader, @Nullable ConfigurationClass importedBy) {
|
||||
this.metadata = metadataReader.getAnnotationMetadata();
|
||||
this.resource = metadataReader.getResource();
|
||||
this.importedBy.add(importedBy);
|
||||
@@ -98,6 +99,7 @@ final class ConfigurationClass {
|
||||
* Create a new {@link ConfigurationClass} with the given name.
|
||||
* @param clazz the underlying {@link Class} to represent
|
||||
* @param beanName name of the {@code @Configuration} class bean
|
||||
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
|
||||
*/
|
||||
ConfigurationClass(Class<?> clazz, String beanName) {
|
||||
Assert.notNull(beanName, "Bean name must not be null");
|
||||
@@ -111,10 +113,10 @@ final class ConfigurationClass {
|
||||
* using the {@link Import} annotation or automatically processed as a nested
|
||||
* configuration class (if imported is {@code true}).
|
||||
* @param clazz the underlying {@link Class} to represent
|
||||
* @param importedBy the configuration class importing this one
|
||||
* @param importedBy the configuration class importing this one (or {@code null})
|
||||
* @since 3.1.1
|
||||
*/
|
||||
ConfigurationClass(Class<?> clazz, ConfigurationClass importedBy) {
|
||||
ConfigurationClass(Class<?> clazz, @Nullable ConfigurationClass importedBy) {
|
||||
this.metadata = AnnotationMetadata.introspect(clazz);
|
||||
this.resource = new DescriptiveResource(clazz.getName());
|
||||
this.importedBy.add(importedBy);
|
||||
@@ -124,6 +126,7 @@ final class ConfigurationClass {
|
||||
* Create a new {@link ConfigurationClass} with the given name.
|
||||
* @param metadata the metadata for the underlying class to represent
|
||||
* @param beanName name of the {@code @Configuration} class bean
|
||||
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
|
||||
*/
|
||||
ConfigurationClass(AnnotationMetadata metadata, String beanName) {
|
||||
Assert.notNull(beanName, "Bean name must not be null");
|
||||
@@ -145,12 +148,12 @@ final class ConfigurationClass {
|
||||
return ClassUtils.getShortName(getMetadata().getClassName());
|
||||
}
|
||||
|
||||
void setBeanName(@Nullable String beanName) {
|
||||
void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getBeanName() {
|
||||
public String getBeanName() {
|
||||
return this.beanName;
|
||||
}
|
||||
|
||||
@@ -160,7 +163,7 @@ final class ConfigurationClass {
|
||||
* @since 3.1.1
|
||||
* @see #getImportedBy()
|
||||
*/
|
||||
boolean isImported() {
|
||||
public boolean isImported() {
|
||||
return !this.importedBy.isEmpty();
|
||||
}
|
||||
|
||||
@@ -194,10 +197,6 @@ final class ConfigurationClass {
|
||||
this.importedResources.put(importedResource, readerClass);
|
||||
}
|
||||
|
||||
Map<String, Class<? extends BeanDefinitionReader>> getImportedResources() {
|
||||
return this.importedResources;
|
||||
}
|
||||
|
||||
void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
|
||||
this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
|
||||
}
|
||||
@@ -206,6 +205,10 @@ final class ConfigurationClass {
|
||||
return this.importBeanDefinitionRegistrars;
|
||||
}
|
||||
|
||||
Map<String, Class<? extends BeanDefinitionReader>> getImportedResources() {
|
||||
return this.importedResources;
|
||||
}
|
||||
|
||||
void validate(ProblemReporter problemReporter) {
|
||||
// A configuration class may not be final (CGLIB limitation) unless it declares proxyBeanMethods=false
|
||||
Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
|
||||
|
||||
+26
-37
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -137,40 +137,31 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
implements ConfigurableApplicationContext {
|
||||
|
||||
/**
|
||||
* The name of the {@link MessageSource} bean in the context.
|
||||
* Name of the MessageSource bean in the factory.
|
||||
* If none is supplied, message resolution is delegated to the parent.
|
||||
* @see org.springframework.context.MessageSource
|
||||
* @see org.springframework.context.support.ResourceBundleMessageSource
|
||||
* @see org.springframework.context.support.ReloadableResourceBundleMessageSource
|
||||
* @see #getMessage(MessageSourceResolvable, Locale)
|
||||
* @see MessageSource
|
||||
*/
|
||||
public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
|
||||
|
||||
/**
|
||||
* The name of the {@link ApplicationEventMulticaster} bean in the context.
|
||||
* If none is supplied, a {@link SimpleApplicationEventMulticaster} is used.
|
||||
* Name of the LifecycleProcessor bean in the factory.
|
||||
* If none is supplied, a DefaultLifecycleProcessor is used.
|
||||
* @see org.springframework.context.LifecycleProcessor
|
||||
* @see org.springframework.context.support.DefaultLifecycleProcessor
|
||||
*/
|
||||
public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor";
|
||||
|
||||
/**
|
||||
* Name of the ApplicationEventMulticaster bean in the factory.
|
||||
* If none is supplied, a default SimpleApplicationEventMulticaster is used.
|
||||
* @see org.springframework.context.event.ApplicationEventMulticaster
|
||||
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
|
||||
* @see #publishEvent(ApplicationEvent)
|
||||
* @see #addApplicationListener(ApplicationListener)
|
||||
*/
|
||||
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
|
||||
|
||||
/**
|
||||
* The name of the {@link LifecycleProcessor} bean in the context.
|
||||
* If none is supplied, a {@link DefaultLifecycleProcessor} is used.
|
||||
* @since 3.0
|
||||
* @see org.springframework.context.LifecycleProcessor
|
||||
* @see org.springframework.context.support.DefaultLifecycleProcessor
|
||||
* @see #start()
|
||||
* @see #stop()
|
||||
*/
|
||||
public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor";
|
||||
|
||||
|
||||
/**
|
||||
* Boolean flag controlled by a {@code spring.spel.ignore} system property that
|
||||
* instructs Spring to ignore SpEL, i.e. to not initialize the SpEL infrastructure.
|
||||
* Boolean flag controlled by a {@code spring.spel.ignore} system property that instructs Spring to
|
||||
* ignore SpEL, i.e. to not initialize the SpEL infrastructure.
|
||||
* <p>The default is "false".
|
||||
*/
|
||||
private static final boolean shouldIgnoreSpel = SpringProperties.getFlag("spring.spel.ignore");
|
||||
@@ -212,7 +203,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
/** Flag that indicates whether this context has been closed already. */
|
||||
private final AtomicBoolean closed = new AtomicBoolean();
|
||||
|
||||
/** Synchronization monitor for "refresh" and "close". */
|
||||
/** Synchronization monitor for the "refresh" and "destroy". */
|
||||
private final Object startupShutdownMonitor = new Object();
|
||||
|
||||
/** Reference to the JVM shutdown hook, if registered. */
|
||||
@@ -220,7 +211,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
private Thread shutdownHook;
|
||||
|
||||
/** ResourcePatternResolver used by this context. */
|
||||
private final ResourcePatternResolver resourcePatternResolver;
|
||||
private ResourcePatternResolver resourcePatternResolver;
|
||||
|
||||
/** LifecycleProcessor for managing the lifecycle of beans within this context. */
|
||||
@Nullable
|
||||
@@ -571,6 +562,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
|
||||
// Invoke factory processors registered as beans in the context.
|
||||
invokeBeanFactoryPostProcessors(beanFactory);
|
||||
|
||||
// Register bean processors that intercept bean creation.
|
||||
registerBeanPostProcessors(beanFactory);
|
||||
beanPostProcess.end();
|
||||
@@ -774,9 +766,8 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the {@link MessageSource}.
|
||||
* <p>Uses parent's {@code MessageSource} if none defined in this context.
|
||||
* @see #MESSAGE_SOURCE_BEAN_NAME
|
||||
* Initialize the MessageSource.
|
||||
* Use parent's if none defined in this context.
|
||||
*/
|
||||
protected void initMessageSource() {
|
||||
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
|
||||
@@ -808,9 +799,8 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the {@link ApplicationEventMulticaster}.
|
||||
* <p>Uses {@link SimpleApplicationEventMulticaster} if none defined in the context.
|
||||
* @see #APPLICATION_EVENT_MULTICASTER_BEAN_NAME
|
||||
* Initialize the ApplicationEventMulticaster.
|
||||
* Uses SimpleApplicationEventMulticaster if none defined in the context.
|
||||
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
|
||||
*/
|
||||
protected void initApplicationEventMulticaster() {
|
||||
@@ -833,16 +823,15 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the {@link LifecycleProcessor}.
|
||||
* <p>Uses {@link DefaultLifecycleProcessor} if none defined in the context.
|
||||
* @since 3.0
|
||||
* @see #LIFECYCLE_PROCESSOR_BEAN_NAME
|
||||
* Initialize the LifecycleProcessor.
|
||||
* Uses DefaultLifecycleProcessor if none defined in the context.
|
||||
* @see org.springframework.context.support.DefaultLifecycleProcessor
|
||||
*/
|
||||
protected void initLifecycleProcessor() {
|
||||
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
|
||||
if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
|
||||
this.lifecycleProcessor = beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
|
||||
this.lifecycleProcessor =
|
||||
beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -126,7 +126,6 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
|
||||
try {
|
||||
DefaultListableBeanFactory beanFactory = createBeanFactory();
|
||||
beanFactory.setSerializationId(getId());
|
||||
beanFactory.setApplicationStartup(getApplicationStartup());
|
||||
customizeBeanFactory(beanFactory);
|
||||
loadBeanDefinitions(beanFactory);
|
||||
this.beanFactory = beanFactory;
|
||||
|
||||
+1
-2
@@ -55,7 +55,7 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
|
||||
// override classes that have not been loaded yet. If not accessible, we will
|
||||
// always override requested classes, even when the classes have been loaded
|
||||
// by the parent ClassLoader already and cannot be transformed anymore anyway.
|
||||
Method method;
|
||||
Method method = null;
|
||||
try {
|
||||
method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
@@ -63,7 +63,6 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
|
||||
catch (Throwable ex) {
|
||||
// Typically a JDK 9+ InaccessibleObjectException...
|
||||
// Avoid through JVM startup with --add-opens=java.base/java.lang=ALL-UNNAMED
|
||||
method = null;
|
||||
LogFactory.getLog(ContextTypeMatchClassLoader.class).debug(
|
||||
"ClassLoader.findLoadedClass not accessible -> will always override requested class", ex);
|
||||
}
|
||||
|
||||
+4
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,7 +27,6 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
@@ -144,7 +143,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
|
||||
/**
|
||||
* Set the PropertiesPersister to use for parsing properties files.
|
||||
* <p>The default is {@code ResourcePropertiesPersister}.
|
||||
* <p>The default is ResourcePropertiesPersister.
|
||||
* @see ResourcePropertiesPersister#INSTANCE
|
||||
*/
|
||||
public void setPropertiesPersister(@Nullable PropertiesPersister propertiesPersister) {
|
||||
@@ -402,7 +401,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
|
||||
/**
|
||||
* Refresh the PropertiesHolder for the given bundle filename.
|
||||
* <p>The holder can be {@code null} if not cached before, or a timed-out cache entry
|
||||
* The holder can be {@code null} if not cached before, or a timed-out cache entry
|
||||
* (potentially getting re-validated against the current last-modified timestamp).
|
||||
* @param filename the bundle filename (basename + Locale)
|
||||
* @param propHolder the current PropertiesHolder for the bundle
|
||||
@@ -563,7 +562,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractResourceBased
|
||||
|
||||
private volatile long refreshTimestamp = -2;
|
||||
|
||||
private final Lock refreshLock = new ReentrantLock();
|
||||
private final ReentrantLock refreshLock = new ReentrantLock();
|
||||
|
||||
/** Cache to hold already generated MessageFormats per message code. */
|
||||
private final ConcurrentMap<String, Map<Locale, MessageFormat>> cachedMessageFormats =
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,7 +29,7 @@ import org.springframework.lang.Nullable;
|
||||
* {@link Runnable Runnables} based on different kinds of triggers.
|
||||
*
|
||||
* <p>This interface is separate from {@link SchedulingTaskExecutor} since it
|
||||
* usually represents a different kind of backend, i.e. a thread pool with
|
||||
* usually represents for a different kind of backend, i.e. a thread pool with
|
||||
* different characteristics and capabilities. Implementations may implement
|
||||
* both interfaces if they can handle both kinds of execution characteristics.
|
||||
*
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -100,9 +100,9 @@ public @interface Scheduled {
|
||||
|
||||
/**
|
||||
* A time zone for which the cron expression will be resolved. By default, this
|
||||
* attribute is the empty String (i.e. the scheduler's time zone will be used).
|
||||
* attribute is the empty String (i.e. the server's local time zone will be used).
|
||||
* @return a zone id accepted by {@link java.util.TimeZone#getTimeZone(String)},
|
||||
* or an empty String to indicate the scheduler's default time zone
|
||||
* or an empty String to indicate the server's default time zone
|
||||
* @since 4.0
|
||||
* @see org.springframework.scheduling.support.CronTrigger#CronTrigger(String, java.util.TimeZone)
|
||||
* @see java.util.TimeZone
|
||||
|
||||
+7
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,6 +27,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -83,7 +84,7 @@ import org.springframework.util.StringValueResolver;
|
||||
* "fixedRate", "fixedDelay", or "cron" expression provided via the annotation.
|
||||
*
|
||||
* <p>This post-processor is automatically registered by Spring's
|
||||
* {@code <task:annotation-driven>} XML element and also by the
|
||||
* {@code <task:annotation-driven>} XML element, and also by the
|
||||
* {@link EnableScheduling @EnableScheduling} annotation.
|
||||
*
|
||||
* <p>Autodetects any {@link SchedulingConfigurer} instances in the container,
|
||||
@@ -433,14 +434,14 @@ public class ScheduledAnnotationBeanPostProcessor
|
||||
Assert.isTrue(initialDelay == -1, "'initialDelay' not supported for cron triggers");
|
||||
processedSchedule = true;
|
||||
if (!Scheduled.CRON_DISABLED.equals(cron)) {
|
||||
CronTrigger trigger;
|
||||
TimeZone timeZone;
|
||||
if (StringUtils.hasText(zone)) {
|
||||
trigger = new CronTrigger(cron, StringUtils.parseTimeZoneString(zone));
|
||||
timeZone = StringUtils.parseTimeZoneString(zone);
|
||||
}
|
||||
else {
|
||||
trigger = new CronTrigger(cron);
|
||||
timeZone = TimeZone.getDefault();
|
||||
}
|
||||
tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, trigger)));
|
||||
tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -133,6 +133,11 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche
|
||||
* execution callback (which may be a wrapper around the user-supplied task).
|
||||
* <p>The primary use case is to set some execution context around the task's
|
||||
* invocation, or to provide some monitoring/statistics for task execution.
|
||||
* <p><b>NOTE:</b> Exception handling in {@code TaskDecorator} implementations
|
||||
* is limited to plain {@code Runnable} execution via {@code execute} calls.
|
||||
* In case of {@code #submit} calls, the exposed {@code Runnable} will be a
|
||||
* {@code FutureTask} which does not propagate any exceptions; you might
|
||||
* have to cast it and call {@code Future#get} to evaluate exceptions.
|
||||
* @since 4.3
|
||||
*/
|
||||
public final void setTaskDecorator(TaskDecorator taskDecorator) {
|
||||
@@ -173,10 +178,11 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche
|
||||
}
|
||||
|
||||
|
||||
private TaskExecutorAdapter getAdaptedExecutor(Executor originalExecutor) {
|
||||
TaskExecutorAdapter adapter =
|
||||
(managedExecutorServiceClass != null && managedExecutorServiceClass.isInstance(originalExecutor) ?
|
||||
new ManagedTaskExecutorAdapter(originalExecutor) : new TaskExecutorAdapter(originalExecutor));
|
||||
private TaskExecutorAdapter getAdaptedExecutor(Executor concurrentExecutor) {
|
||||
if (managedExecutorServiceClass != null && managedExecutorServiceClass.isInstance(concurrentExecutor)) {
|
||||
return new ManagedTaskExecutorAdapter(concurrentExecutor);
|
||||
}
|
||||
TaskExecutorAdapter adapter = new TaskExecutorAdapter(concurrentExecutor);
|
||||
if (this.taskDecorator != null) {
|
||||
adapter.setTaskDecorator(this.taskDecorator);
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -177,7 +177,6 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
|
||||
* @see Clock#systemDefaultZone()
|
||||
*/
|
||||
public void setClock(Clock clock) {
|
||||
Assert.notNull(clock, "Clock must not be null");
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
|
||||
+3
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author 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,9 +45,8 @@ import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
|
||||
/**
|
||||
* A standard implementation of Spring's {@link TaskScheduler} interface, wrapping
|
||||
* a native {@link java.util.concurrent.ScheduledThreadPoolExecutor} and providing
|
||||
* all applicable configuration options for it.
|
||||
* Implementation of Spring's {@link TaskScheduler} interface, wrapping
|
||||
* a native {@link java.util.concurrent.ScheduledThreadPoolExecutor}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
@@ -155,7 +154,6 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
|
||||
* @see Clock#systemDefaultZone()
|
||||
*/
|
||||
public void setClock(Clock clock) {
|
||||
Assert.notNull(clock, "Clock must not be null");
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
|
||||
+28
-24
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,15 +29,17 @@ import org.springframework.util.StringUtils;
|
||||
* Created using the {@code parse*} methods.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Juergen Hoeller
|
||||
* @since 5.3
|
||||
*/
|
||||
final class BitsCronField extends CronField {
|
||||
|
||||
public static final BitsCronField ZERO_NANOS = forZeroNanos();
|
||||
|
||||
private static final long MASK = 0xFFFFFFFFFFFFFFFFL;
|
||||
|
||||
|
||||
@Nullable
|
||||
private static BitsCronField zeroNanos = null;
|
||||
|
||||
|
||||
// we store at most 60 bits, for seconds and minutes, so a 64-bit long suffices
|
||||
private long bits;
|
||||
|
||||
@@ -46,14 +48,16 @@ final class BitsCronField extends CronField {
|
||||
super(type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a {@code BitsCronField} enabled for 0 nanoseconds.
|
||||
*/
|
||||
private static BitsCronField forZeroNanos() {
|
||||
BitsCronField field = new BitsCronField(Type.NANO);
|
||||
field.setBit(0);
|
||||
return field;
|
||||
public static BitsCronField zeroNanos() {
|
||||
if (zeroNanos == null) {
|
||||
BitsCronField field = new BitsCronField(Type.NANO);
|
||||
field.setBit(0);
|
||||
zeroNanos = field;
|
||||
}
|
||||
return zeroNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,6 +108,7 @@ final class BitsCronField extends CronField {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static BitsCronField parseDate(String value, BitsCronField.Type type) {
|
||||
if (value.equals("?")) {
|
||||
value = "*";
|
||||
@@ -169,7 +174,6 @@ final class BitsCronField extends CronField {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T extends Temporal & Comparable<? super T>> T nextOrSame(T temporal) {
|
||||
@@ -213,6 +217,7 @@ final class BitsCronField extends CronField {
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void setBits(ValueRange range) {
|
||||
@@ -242,20 +247,7 @@ final class BitsCronField extends CronField {
|
||||
}
|
||||
|
||||
private void clearBit(int index) {
|
||||
this.bits &= ~(1L << index);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof BitsCronField)) {
|
||||
return false;
|
||||
}
|
||||
BitsCronField otherField = (BitsCronField) other;
|
||||
return (type() == otherField.type() && this.bits == otherField.bits);
|
||||
this.bits &= ~(1L << index);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -263,6 +255,18 @@ final class BitsCronField extends CronField {
|
||||
return Long.hashCode(this.bits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof BitsCronField)) {
|
||||
return false;
|
||||
}
|
||||
BitsCronField other = (BitsCronField) o;
|
||||
return type() == other.type() && this.bits == other.bits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(type().toString());
|
||||
|
||||
+36
-23
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,14 +29,9 @@ import org.springframework.util.StringUtils;
|
||||
* <a href="https://www.manpagez.com/man/5/crontab/">crontab expression</a>
|
||||
* that can calculate the next time it matches.
|
||||
*
|
||||
* <p>{@code CronExpression} instances are created through {@link #parse(String)};
|
||||
* the next match is determined with {@link #next(Temporal)}.
|
||||
*
|
||||
* <p>Supports a Quartz day-of-month/week field with an L/# expression. Follows
|
||||
* common cron conventions in every other respect, including 0-6 for SUN-SAT
|
||||
* (plus 7 for SUN as well). Note that Quartz deviates from the day-of-week
|
||||
* convention in cron through 1-7 for SUN-SAT whereas Spring strictly follows
|
||||
* cron even in combination with the optional Quartz-specific L/# expressions.
|
||||
* <p>{@code CronExpression} instances are created through
|
||||
* {@link #parse(String)}; the next match is determined with
|
||||
* {@link #next(Temporal)}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.3
|
||||
@@ -62,12 +57,18 @@ public final class CronExpression {
|
||||
private final String expression;
|
||||
|
||||
|
||||
private CronExpression(CronField seconds, CronField minutes, CronField hours,
|
||||
CronField daysOfMonth, CronField months, CronField daysOfWeek, String expression) {
|
||||
private CronExpression(
|
||||
CronField seconds,
|
||||
CronField minutes,
|
||||
CronField hours,
|
||||
CronField daysOfMonth,
|
||||
CronField months,
|
||||
CronField daysOfWeek,
|
||||
String expression) {
|
||||
|
||||
// Reverse order, to make big changes first.
|
||||
// To make sure we end up at 0 nanos, we add an extra field.
|
||||
this.fields = new CronField[] {daysOfWeek, months, daysOfMonth, hours, minutes, seconds, CronField.zeroNanos()};
|
||||
// reverse order, to make big changes first
|
||||
// to make sure we end up at 0 nanos, we add an extra field
|
||||
this.fields = new CronField[]{daysOfWeek, months, daysOfMonth, hours, minutes, seconds, CronField.zeroNanos()};
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@@ -120,8 +121,11 @@ public final class CronExpression {
|
||||
* {@code LW}), it means "the last weekday of the month".
|
||||
* </li>
|
||||
* <li>
|
||||
* In the "day of week" field, {@code dL} or {@code DDDL} stands for
|
||||
* "the last day of week {@code d} (or {@code DDD}) in the month".
|
||||
* In the "day of week" field, {@code L} stands for "the last day of the
|
||||
* week".
|
||||
* If prefixed by a number or three-letter name (i.e. {@code dL} or
|
||||
* {@code DDDL}), it means "the last day of week {@code d} (or {@code DDD})
|
||||
* in the month".
|
||||
* </li>
|
||||
* </ul>
|
||||
* </li>
|
||||
@@ -173,7 +177,7 @@ public final class CronExpression {
|
||||
* the cron format
|
||||
*/
|
||||
public static CronExpression parse(String expression) {
|
||||
Assert.hasLength(expression, "Expression must not be empty");
|
||||
Assert.hasLength(expression, "Expression string must not be empty");
|
||||
|
||||
expression = resolveMacros(expression);
|
||||
|
||||
@@ -266,19 +270,28 @@ public final class CronExpression {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
return (this == other || (other instanceof CronExpression &&
|
||||
Arrays.equals(this.fields, ((CronExpression) other).fields)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(this.fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof CronExpression) {
|
||||
CronExpression other = (CronExpression) o;
|
||||
return Arrays.equals(this.fields, other.fields);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the expression string used to create this {@code CronExpression}.
|
||||
* @return the expression string
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,24 +29,17 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Single field in a cron pattern. Created using the {@code parse*} methods,
|
||||
* the main and only entry point is {@link #nextOrSame(Temporal)}.
|
||||
*
|
||||
* <p>Supports a Quartz day-of-month/week field with an L/# expression. Follows
|
||||
* common cron conventions in every other respect, including 0-6 for SUN-SAT
|
||||
* (plus 7 for SUN as well). Note that Quartz deviates from the day-of-week
|
||||
* convention in cron through 1-7 for SUN-SAT whereas Spring strictly follows
|
||||
* cron even in combination with the optional Quartz-specific L/# expressions.
|
||||
* main and only entry point is {@link #nextOrSame(Temporal)}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.3
|
||||
*/
|
||||
abstract class CronField {
|
||||
|
||||
private static final String[] MONTHS = new String[]
|
||||
{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
|
||||
private static final String[] MONTHS = new String[]{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP",
|
||||
"OCT", "NOV", "DEC"};
|
||||
|
||||
private static final String[] DAYS = new String[]
|
||||
{"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
|
||||
private static final String[] DAYS = new String[]{"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
|
||||
|
||||
private final Type type;
|
||||
|
||||
@@ -55,12 +48,11 @@ abstract class CronField {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a {@code CronField} enabled for 0 nanoseconds.
|
||||
*/
|
||||
public static CronField zeroNanos() {
|
||||
return BitsCronField.ZERO_NANOS;
|
||||
return BitsCronField.zeroNanos();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,7 +169,6 @@ abstract class CronField {
|
||||
* day-of-month, month, day-of-week.
|
||||
*/
|
||||
protected enum Type {
|
||||
|
||||
NANO(ChronoField.NANO_OF_SECOND, ChronoUnit.SECONDS),
|
||||
SECOND(ChronoField.SECOND_OF_MINUTE, ChronoUnit.MINUTES, ChronoField.NANO_OF_SECOND),
|
||||
MINUTE(ChronoField.MINUTE_OF_HOUR, ChronoUnit.HOURS, ChronoField.SECOND_OF_MINUTE, ChronoField.NANO_OF_SECOND),
|
||||
@@ -186,18 +177,21 @@ abstract class CronField {
|
||||
MONTH(ChronoField.MONTH_OF_YEAR, ChronoUnit.YEARS, ChronoField.DAY_OF_MONTH, ChronoField.HOUR_OF_DAY, ChronoField.MINUTE_OF_HOUR, ChronoField.SECOND_OF_MINUTE, ChronoField.NANO_OF_SECOND),
|
||||
DAY_OF_WEEK(ChronoField.DAY_OF_WEEK, ChronoUnit.WEEKS, ChronoField.HOUR_OF_DAY, ChronoField.MINUTE_OF_HOUR, ChronoField.SECOND_OF_MINUTE, ChronoField.NANO_OF_SECOND);
|
||||
|
||||
|
||||
private final ChronoField field;
|
||||
|
||||
private final ChronoUnit higherOrder;
|
||||
|
||||
private final ChronoField[] lowerOrders;
|
||||
|
||||
|
||||
Type(ChronoField field, ChronoUnit higherOrder, ChronoField... lowerOrders) {
|
||||
this.field = field;
|
||||
this.higherOrder = higherOrder;
|
||||
this.lowerOrders = lowerOrders;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the value of this type for the given temporal.
|
||||
* @return the value of this type
|
||||
|
||||
+16
-25
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,14 +27,8 @@ import org.springframework.scheduling.TriggerContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Trigger} implementation for cron expressions. Wraps a
|
||||
* {@link CronExpression} which parses according to common crontab conventions.
|
||||
*
|
||||
* <p>Supports a Quartz day-of-month/week field with an L/# expression. Follows
|
||||
* common cron conventions in every other respect, including 0-6 for SUN-SAT
|
||||
* (plus 7 for SUN as well). Note that Quartz deviates from the day-of-week
|
||||
* convention in cron through 1-7 for SUN-SAT whereas Spring strictly follows
|
||||
* cron even in combination with the optional Quartz-specific L/# expressions.
|
||||
* {@link Trigger} implementation for cron expressions.
|
||||
* Wraps a {@link CronExpression}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Arjen Poutsma
|
||||
@@ -45,7 +39,6 @@ public class CronTrigger implements Trigger {
|
||||
|
||||
private final CronExpression expression;
|
||||
|
||||
@Nullable
|
||||
private final ZoneId zoneId;
|
||||
|
||||
|
||||
@@ -55,8 +48,7 @@ public class CronTrigger implements Trigger {
|
||||
* expression conventions
|
||||
*/
|
||||
public CronTrigger(String expression) {
|
||||
this.expression = CronExpression.parse(expression);
|
||||
this.zoneId = null;
|
||||
this(expression, ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,9 +58,7 @@ public class CronTrigger implements Trigger {
|
||||
* @param timeZone a time zone in which the trigger times will be generated
|
||||
*/
|
||||
public CronTrigger(String expression, TimeZone timeZone) {
|
||||
this.expression = CronExpression.parse(expression);
|
||||
Assert.notNull(timeZone, "TimeZone must not be null");
|
||||
this.zoneId = timeZone.toZoneId();
|
||||
this(expression, timeZone.toZoneId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,8 +70,10 @@ public class CronTrigger implements Trigger {
|
||||
* @see CronExpression#parse(String)
|
||||
*/
|
||||
public CronTrigger(String expression, ZoneId zoneId) {
|
||||
this.expression = CronExpression.parse(expression);
|
||||
Assert.hasLength(expression, "Expression must not be empty");
|
||||
Assert.notNull(zoneId, "ZoneId must not be null");
|
||||
|
||||
this.expression = CronExpression.parse(expression);
|
||||
this.zoneId = zoneId;
|
||||
}
|
||||
|
||||
@@ -102,23 +94,22 @@ public class CronTrigger implements Trigger {
|
||||
*/
|
||||
@Override
|
||||
public Date nextExecutionTime(TriggerContext triggerContext) {
|
||||
Date timestamp = triggerContext.lastCompletionTime();
|
||||
if (timestamp != null) {
|
||||
Date date = triggerContext.lastCompletionTime();
|
||||
if (date != null) {
|
||||
Date scheduled = triggerContext.lastScheduledExecutionTime();
|
||||
if (scheduled != null && timestamp.before(scheduled)) {
|
||||
if (scheduled != null && date.before(scheduled)) {
|
||||
// Previous task apparently executed too early...
|
||||
// Let's simply use the last calculated execution time then,
|
||||
// in order to prevent accidental re-fires in the same second.
|
||||
timestamp = scheduled;
|
||||
date = scheduled;
|
||||
}
|
||||
}
|
||||
else {
|
||||
timestamp = new Date(triggerContext.getClock().millis());
|
||||
date = new Date(triggerContext.getClock().millis());
|
||||
}
|
||||
ZoneId zone = (this.zoneId != null ? this.zoneId : triggerContext.getClock().getZone());
|
||||
ZonedDateTime zonedTimestamp = ZonedDateTime.ofInstant(timestamp.toInstant(), zone);
|
||||
ZonedDateTime nextTimestamp = this.expression.next(zonedTimestamp);
|
||||
return (nextTimestamp != null ? Date.from(nextTimestamp.toInstant()) : null);
|
||||
ZonedDateTime dateTime = ZonedDateTime.ofInstant(date.toInstant(), this.zoneId);
|
||||
ZonedDateTime next = this.expression.next(dateTime);
|
||||
return (next != null ? Date.from(next.toInstant()) : null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+41
-46
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,16 +29,10 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Extension of {@link CronField} for
|
||||
* <a href="https://www.quartz-scheduler.org">Quartz</a>-specific fields.
|
||||
* <a href="https://www.quartz-scheduler.org>Quartz</a> -specific fields.
|
||||
* Created using the {@code parse*} methods, uses a {@link TemporalAdjuster}
|
||||
* internally.
|
||||
*
|
||||
* <p>Supports a Quartz day-of-month/week field with an L/# expression. Follows
|
||||
* common cron conventions in every other respect, including 0-6 for SUN-SAT
|
||||
* (plus 7 for SUN as well). Note that Quartz deviates from the day-of-week
|
||||
* convention in cron through 1-7 for SUN-SAT whereas Spring strictly follows
|
||||
* cron even in combination with the optional Quartz-specific L/# expressions.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.3
|
||||
*/
|
||||
@@ -66,18 +60,16 @@ final class QuartzCronField extends CronField {
|
||||
this.rollForwardType = rollForwardType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the given value is a Quartz day-of-month field.
|
||||
* Returns whether the given value is a Quartz day-of-month field.
|
||||
*/
|
||||
public static boolean isQuartzDaysOfMonthField(String value) {
|
||||
return value.contains("L") || value.contains("W");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given value into a days of months {@code QuartzCronField},
|
||||
* the fourth entry of a cron expression.
|
||||
* <p>Expects a "L" or "W" in the given value.
|
||||
* Parse the given value into a days of months {@code QuartzCronField}, the fourth entry of a cron expression.
|
||||
* Expects a "L" or "W" in the given value.
|
||||
*/
|
||||
public static QuartzCronField parseDaysOfMonth(String value) {
|
||||
int idx = value.lastIndexOf('L');
|
||||
@@ -86,14 +78,14 @@ final class QuartzCronField extends CronField {
|
||||
if (idx != 0) {
|
||||
throw new IllegalArgumentException("Unrecognized characters before 'L' in '" + value + "'");
|
||||
}
|
||||
else if (value.length() == 2 && value.charAt(1) == 'W') { // "LW"
|
||||
else if (value.length() == 2 && value.charAt(1) == 'W') { // "LW"
|
||||
adjuster = lastWeekdayOfMonth();
|
||||
}
|
||||
else {
|
||||
if (value.length() == 1) { // "L"
|
||||
if (value.length() == 1) { // "L"
|
||||
adjuster = lastDayOfMonth();
|
||||
}
|
||||
else { // "L-[0-9]+"
|
||||
else { // "L-[0-9]+"
|
||||
int offset = Integer.parseInt(value.substring(idx + 1));
|
||||
if (offset >= 0) {
|
||||
throw new IllegalArgumentException("Offset '" + offset + " should be < 0 '" + value + "'");
|
||||
@@ -111,7 +103,7 @@ final class QuartzCronField extends CronField {
|
||||
else if (idx != value.length() - 1) {
|
||||
throw new IllegalArgumentException("Unrecognized characters after 'W' in '" + value + "'");
|
||||
}
|
||||
else { // "[0-9]+W"
|
||||
else { // "[0-9]+W"
|
||||
int dayOfMonth = Integer.parseInt(value.substring(0, idx));
|
||||
dayOfMonth = Type.DAY_OF_MONTH.checkValidValue(dayOfMonth);
|
||||
TemporalAdjuster adjuster = weekdayNearestTo(dayOfMonth);
|
||||
@@ -122,16 +114,15 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given value is a Quartz day-of-week field.
|
||||
* Returns whether the given value is a Quartz day-of-week field.
|
||||
*/
|
||||
public static boolean isQuartzDaysOfWeekField(String value) {
|
||||
return value.contains("L") || value.contains("#");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given value into a days of week {@code QuartzCronField},
|
||||
* the sixth entry of a cron expression.
|
||||
* <p>Expects a "L" or "#" in the given value.
|
||||
* Parse the given value into a days of week {@code QuartzCronField}, the sixth entry of a cron expression.
|
||||
* Expects a "L" or "#" in the given value.
|
||||
*/
|
||||
public static QuartzCronField parseDaysOfWeek(String value) {
|
||||
int idx = value.lastIndexOf('L');
|
||||
@@ -144,7 +135,7 @@ final class QuartzCronField extends CronField {
|
||||
if (idx == 0) {
|
||||
throw new IllegalArgumentException("No day-of-week before 'L' in '" + value + "'");
|
||||
}
|
||||
else { // "[0-7]L"
|
||||
else { // "[0-7]L"
|
||||
DayOfWeek dayOfWeek = parseDayOfWeek(value.substring(0, idx));
|
||||
adjuster = lastInMonth(dayOfWeek);
|
||||
}
|
||||
@@ -166,6 +157,7 @@ final class QuartzCronField extends CronField {
|
||||
throw new IllegalArgumentException("Ordinal '" + ordinal + "' in '" + value +
|
||||
"' must be positive number ");
|
||||
}
|
||||
|
||||
TemporalAdjuster adjuster = dayOfWeekInMonth(ordinal, dayOfWeek);
|
||||
return new QuartzCronField(Type.DAY_OF_WEEK, Type.DAY_OF_MONTH, adjuster, value);
|
||||
}
|
||||
@@ -175,13 +167,14 @@ final class QuartzCronField extends CronField {
|
||||
private static DayOfWeek parseDayOfWeek(String value) {
|
||||
int dayOfWeek = Integer.parseInt(value);
|
||||
if (dayOfWeek == 0) {
|
||||
dayOfWeek = 7; // cron is 0 based; java.time 1 based
|
||||
dayOfWeek = 7; // cron is 0 based; java.time 1 based
|
||||
}
|
||||
try {
|
||||
return DayOfWeek.of(dayOfWeek);
|
||||
}
|
||||
catch (DateTimeException ex) {
|
||||
throw new IllegalArgumentException(ex.getMessage() + " '" + value + "'", ex);
|
||||
String msg = ex.getMessage() + " '" + value + "'";
|
||||
throw new IllegalArgumentException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,10 +213,10 @@ final class QuartzCronField extends CronField {
|
||||
Temporal lastDom = adjuster.adjustInto(temporal);
|
||||
Temporal result;
|
||||
int dow = lastDom.get(ChronoField.DAY_OF_WEEK);
|
||||
if (dow == 6) { // Saturday
|
||||
if (dow == 6) { // Saturday
|
||||
result = lastDom.minus(1, ChronoUnit.DAYS);
|
||||
}
|
||||
else if (dow == 7) { // Sunday
|
||||
else if (dow == 7) { // Sunday
|
||||
result = lastDom.minus(2, ChronoUnit.DAYS);
|
||||
}
|
||||
else {
|
||||
@@ -234,7 +227,7 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a temporal adjuster that finds the nth-to-last day of the month.
|
||||
* Return a temporal adjuster that finds the nth-to-last day of the month.
|
||||
* @param offset the negative offset, i.e. -3 means third-to-last
|
||||
* @return a nth-to-last day-of-month adjuster
|
||||
*/
|
||||
@@ -248,7 +241,7 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a temporal adjuster that finds the weekday nearest to the given
|
||||
* Return a temporal adjuster that finds the weekday nearest to the given
|
||||
* day-of-month. If {@code dayOfMonth} falls on a Saturday, the date is
|
||||
* moved back to Friday; if it falls on a Sunday (or if {@code dayOfMonth}
|
||||
* is 1 and it falls on a Saturday), it is moved forward to Monday.
|
||||
@@ -260,10 +253,10 @@ final class QuartzCronField extends CronField {
|
||||
int current = Type.DAY_OF_MONTH.get(temporal);
|
||||
DayOfWeek dayOfWeek = DayOfWeek.from(temporal);
|
||||
|
||||
if ((current == dayOfMonth && isWeekday(dayOfWeek)) || // dayOfMonth is a weekday
|
||||
(dayOfWeek == DayOfWeek.FRIDAY && current == dayOfMonth - 1) || // dayOfMonth is a Saturday, so Friday before
|
||||
(dayOfWeek == DayOfWeek.MONDAY && current == dayOfMonth + 1) || // dayOfMonth is a Sunday, so Monday after
|
||||
(dayOfWeek == DayOfWeek.MONDAY && dayOfMonth == 1 && current == 3)) { // dayOfMonth is Saturday 1st, so Monday 3rd
|
||||
if ((current == dayOfMonth && isWeekday(dayOfWeek)) || // dayOfMonth is a weekday
|
||||
(dayOfWeek == DayOfWeek.FRIDAY && current == dayOfMonth - 1) || // dayOfMonth is a Saturday, so Friday before
|
||||
(dayOfWeek == DayOfWeek.MONDAY && current == dayOfMonth + 1) || // dayOfMonth is a Sunday, so Monday after
|
||||
(dayOfWeek == DayOfWeek.MONDAY && dayOfMonth == 1 && current == 3)) { // dayOfMonth is Saturday 1st, so Monday 3rd
|
||||
return temporal;
|
||||
}
|
||||
int count = 0;
|
||||
@@ -299,7 +292,7 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a temporal adjuster that finds the last of the given day-of-week
|
||||
* Return a temporal adjuster that finds the last of the given doy-of-week
|
||||
* in a month.
|
||||
*/
|
||||
private static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) {
|
||||
@@ -336,7 +329,6 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T extends Temporal & Comparable<? super T>> T nextOrSame(T temporal) {
|
||||
T result = adjust(temporal);
|
||||
@@ -353,6 +345,7 @@ final class QuartzCronField extends CronField {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends Temporal & Comparable<? super T>> T adjust(T temporal) {
|
||||
@@ -360,26 +353,28 @@ final class QuartzCronField extends CronField {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof QuartzCronField)) {
|
||||
return false;
|
||||
}
|
||||
QuartzCronField otherField = (QuartzCronField) other;
|
||||
return (type() == otherField.type() && this.value.equals(otherField.value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof QuartzCronField)) {
|
||||
return false;
|
||||
}
|
||||
QuartzCronField other = (QuartzCronField) o;
|
||||
return type() == other.type() &&
|
||||
this.value.equals(other.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type() + " '" + this.value + "'";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+44
-51
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 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.
|
||||
@@ -92,7 +92,7 @@ public class ProxyFactoryBeanTests {
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws Exception {
|
||||
public void setUp() throws Exception {
|
||||
DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
|
||||
parent.registerBeanDefinition("target2", new RootBeanDefinition(TestApplicationListener.class));
|
||||
this.factory = new DefaultListableBeanFactory(parent);
|
||||
@@ -139,24 +139,22 @@ public class ProxyFactoryBeanTests {
|
||||
private void testDoubleTargetSourceIsRejected(String name) {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(DBL_TARGETSOURCE_CONTEXT, CLASS));
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class).as("Should not allow TargetSource to be specified in interceptorNames as well as targetSource property")
|
||||
.isThrownBy(() -> bf.getBean(name))
|
||||
.havingCause()
|
||||
.isInstanceOf(AopConfigException.class)
|
||||
.withMessageContaining("TargetSource");
|
||||
.isThrownBy(() -> bf.getBean(name))
|
||||
.havingCause()
|
||||
.isInstanceOf(AopConfigException.class)
|
||||
.withMessageContaining("TargetSource");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTargetSourceNotAtEndOfInterceptorNamesIsRejected() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(NOTLAST_TARGETSOURCE_CONTEXT, CLASS));
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class).as("TargetSource or non-advised object must be last in interceptorNames")
|
||||
.isThrownBy(() -> bf.getBean("targetSourceNotLast"))
|
||||
.havingCause()
|
||||
.isInstanceOf(AopConfigException.class)
|
||||
.withMessageContaining("interceptorNames");
|
||||
.isThrownBy(() -> bf.getBean("targetSourceNotLast"))
|
||||
.havingCause()
|
||||
.isInstanceOf(AopConfigException.class)
|
||||
.withMessageContaining("interceptorNames");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -169,11 +167,11 @@ public class ProxyFactoryBeanTests {
|
||||
assertThat(cba.getCalls()).isEqualTo(0);
|
||||
|
||||
ITestBean tb = (ITestBean) bf.getBean("directTarget");
|
||||
assertThat(tb.getName()).isEqualTo("Adam");
|
||||
assertThat(tb.getName().equals("Adam")).isTrue();
|
||||
assertThat(cba.getCalls()).isEqualTo(1);
|
||||
|
||||
ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&directTarget");
|
||||
assertThat(pfb.getObjectType()).isAssignableTo(TestBean.class);
|
||||
assertThat(TestBean.class.isAssignableFrom(pfb.getObjectType())).as("Has correct object type").isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -181,9 +179,9 @@ public class ProxyFactoryBeanTests {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(TARGETSOURCE_CONTEXT, CLASS));
|
||||
ITestBean tb = (ITestBean) bf.getBean("viaTargetSource");
|
||||
assertThat(tb.getName()).isEqualTo("Adam");
|
||||
assertThat(tb.getName().equals("Adam")).isTrue();
|
||||
ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&viaTargetSource");
|
||||
assertThat(pfb.getObjectType()).isAssignableTo(TestBean.class);
|
||||
assertThat(TestBean.class.isAssignableFrom(pfb.getObjectType())).as("Has correct object type").isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -192,15 +190,11 @@ public class ProxyFactoryBeanTests {
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource(TARGETSOURCE_CONTEXT, CLASS));
|
||||
|
||||
ITestBean tb = (ITestBean) bf.getBean("noTarget");
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(tb::getName).withMessage("getName");
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
|
||||
tb.getName())
|
||||
.withMessage("getName");
|
||||
FactoryBean<?> pfb = (ProxyFactoryBean) bf.getBean("&noTarget");
|
||||
assertThat(pfb.getObjectType()).isAssignableTo(ITestBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetObjectTypeOnUninitializedFactoryBean() {
|
||||
ProxyFactoryBean pfb = new ProxyFactoryBean();
|
||||
assertThat(pfb.getObjectType()).isNull();
|
||||
assertThat(ITestBean.class.isAssignableFrom(pfb.getObjectType())).as("Has correct object type").isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,20 +219,20 @@ public class ProxyFactoryBeanTests {
|
||||
pc1.addAdvice(1, di);
|
||||
assertThat(pc2.getAdvisors()).isEqualTo(pc1.getAdvisors());
|
||||
assertThat(pc2.getAdvisors().length).as("Now have one more advisor").isEqualTo((oldLength + 1));
|
||||
assertThat(di.getCount()).isEqualTo(0);
|
||||
assertThat(0).isEqualTo(di.getCount());
|
||||
test1.setAge(5);
|
||||
assertThat(test1.getAge()).isEqualTo(test1_1.getAge());
|
||||
assertThat(di.getCount()).isEqualTo(3);
|
||||
assertThat(3).isEqualTo(di.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrototypeInstancesAreNotEqual() {
|
||||
assertThat(factory.getType("prototype")).isAssignableTo(ITestBean.class);
|
||||
assertThat(ITestBean.class.isAssignableFrom(factory.getType("prototype"))).as("Has correct object type").isTrue();
|
||||
ITestBean test2 = (ITestBean) factory.getBean("prototype");
|
||||
ITestBean test2_1 = (ITestBean) factory.getBean("prototype");
|
||||
assertThat(test2).as("Prototype instances !=").isNotSameAs(test2_1);
|
||||
assertThat(test2).as("Prototype instances equal").isEqualTo(test2_1);
|
||||
assertThat(factory.getType("prototype")).isAssignableTo(ITestBean.class);
|
||||
assertThat(test2 != test2_1).as("Prototype instances !=").isTrue();
|
||||
assertThat(test2.equals(test2_1)).as("Prototype instances equal").isTrue();
|
||||
assertThat(ITestBean.class.isAssignableFrom(factory.getType("prototype"))).as("Has correct object type").isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,7 +262,7 @@ public class ProxyFactoryBeanTests {
|
||||
assertThat(prototype2FirstInstance.getCount()).isEqualTo(INITIAL_COUNT + 1);
|
||||
|
||||
SideEffectBean prototype2SecondInstance = (SideEffectBean) bf.getBean(beanName);
|
||||
assertThat(prototype2FirstInstance).as("Prototypes are not ==").isNotSameAs(prototype2SecondInstance);
|
||||
assertThat(prototype2FirstInstance == prototype2SecondInstance).as("Prototypes are not ==").isFalse();
|
||||
assertThat(prototype2SecondInstance.getCount()).isEqualTo(INITIAL_COUNT);
|
||||
assertThat(prototype2FirstInstance.getCount()).isEqualTo(INITIAL_COUNT + 1);
|
||||
|
||||
@@ -291,19 +285,19 @@ public class ProxyFactoryBeanTests {
|
||||
TestBean target = (TestBean) factory.getBean("test");
|
||||
target.setName(name);
|
||||
ITestBean autoInvoker = (ITestBean) factory.getBean("autoInvoker");
|
||||
assertThat(autoInvoker.getName()).isEqualTo(name);
|
||||
assertThat(autoInvoker.getName().equals(name)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanGetFactoryReferenceAndManipulate() {
|
||||
ProxyFactoryBean config = (ProxyFactoryBean) factory.getBean("&test1");
|
||||
assertThat(config.getObjectType()).isAssignableTo(ITestBean.class);
|
||||
assertThat(factory.getType("test1")).isAssignableTo(ITestBean.class);
|
||||
assertThat(ITestBean.class.isAssignableFrom(config.getObjectType())).as("Has correct object type").isTrue();
|
||||
assertThat(ITestBean.class.isAssignableFrom(factory.getType("test1"))).as("Has correct object type").isTrue();
|
||||
// Trigger lazy initialization.
|
||||
config.getObject();
|
||||
assertThat(config.getAdvisors().length).as("Have one advisors").isEqualTo(1);
|
||||
assertThat(config.getObjectType()).isAssignableTo(ITestBean.class);
|
||||
assertThat(factory.getType("test1")).isAssignableTo(ITestBean.class);
|
||||
assertThat(ITestBean.class.isAssignableFrom(config.getObjectType())).as("Has correct object type").isTrue();
|
||||
assertThat(ITestBean.class.isAssignableFrom(factory.getType("test1"))).as("Has correct object type").isTrue();
|
||||
|
||||
ITestBean tb = (ITestBean) factory.getBean("test1");
|
||||
// no exception
|
||||
@@ -314,7 +308,7 @@ public class ProxyFactoryBeanTests {
|
||||
config.addAdvice(0, (MethodInterceptor) invocation -> {
|
||||
throw ex;
|
||||
});
|
||||
assertThat(config.getAdvisors()).as("Have correct advisor count").hasSize(2);
|
||||
assertThat(config.getAdvisors().length).as("Have correct advisor count").isEqualTo(2);
|
||||
|
||||
ITestBean tb1 = (ITestBean) factory.getBean("test1");
|
||||
assertThatException()
|
||||
@@ -354,31 +348,31 @@ public class ProxyFactoryBeanTests {
|
||||
// Add to head of interceptor chain
|
||||
int oldCount = config.getAdvisors().length;
|
||||
config.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class));
|
||||
assertThat(config.getAdvisors()).hasSize(oldCount + 1);
|
||||
assertThat(config.getAdvisors().length == oldCount + 1).isTrue();
|
||||
|
||||
TimeStamped ts = (TimeStamped) factory.getBean("test2");
|
||||
assertThat(ts.getTimeStamp()).isEqualTo(time);
|
||||
|
||||
// Can remove
|
||||
config.removeAdvice(ti);
|
||||
assertThat(config.getAdvisors()).hasSize(oldCount);
|
||||
assertThat(config.getAdvisors().length == oldCount).isTrue();
|
||||
|
||||
// Check no change on existing object reference
|
||||
assertThat(ts.getTimeStamp()).isEqualTo(time);
|
||||
assertThat(ts.getTimeStamp() == time).isTrue();
|
||||
|
||||
assertThat(factory.getBean("test2")).as("Should no longer implement TimeStamped")
|
||||
.isNotInstanceOf(TimeStamped.class);
|
||||
|
||||
// Now check non-effect of removing interceptor that isn't there
|
||||
config.removeAdvice(new DebugInterceptor());
|
||||
assertThat(config.getAdvisors()).hasSize(oldCount);
|
||||
assertThat(config.getAdvisors().length == oldCount).isTrue();
|
||||
|
||||
ITestBean it = (ITestBean) ts;
|
||||
DebugInterceptor debugInterceptor = new DebugInterceptor();
|
||||
config.addAdvice(0, debugInterceptor);
|
||||
it.getSpouse();
|
||||
// Won't affect existing reference
|
||||
assertThat(debugInterceptor.getCount()).isEqualTo(0);
|
||||
assertThat(debugInterceptor.getCount() == 0).isTrue();
|
||||
it = (ITestBean) factory.getBean("test2");
|
||||
it.getSpouse();
|
||||
assertThat(debugInterceptor.getCount()).isEqualTo(1);
|
||||
@@ -418,16 +412,16 @@ public class ProxyFactoryBeanTests {
|
||||
public void testMethodPointcuts() {
|
||||
ITestBean tb = (ITestBean) factory.getBean("pointcuts");
|
||||
PointcutForVoid.reset();
|
||||
assertThat(PointcutForVoid.methodNames).as("No methods intercepted").isEmpty();
|
||||
assertThat(PointcutForVoid.methodNames.isEmpty()).as("No methods intercepted").isTrue();
|
||||
tb.getAge();
|
||||
assertThat(PointcutForVoid.methodNames).as("Not void: shouldn't have intercepted").isEmpty();
|
||||
assertThat(PointcutForVoid.methodNames.isEmpty()).as("Not void: shouldn't have intercepted").isTrue();
|
||||
tb.setAge(1);
|
||||
tb.getAge();
|
||||
tb.setName("Tristan");
|
||||
tb.toString();
|
||||
assertThat(PointcutForVoid.methodNames).as("Recorded wrong number of invocations").hasSize(2);
|
||||
assertThat(PointcutForVoid.methodNames.get(0)).isEqualTo("setAge");
|
||||
assertThat(PointcutForVoid.methodNames.get(1)).isEqualTo("setName");
|
||||
assertThat(PointcutForVoid.methodNames.size()).as("Recorded wrong number of invocations").isEqualTo(2);
|
||||
assertThat(PointcutForVoid.methodNames.get(0).equals("setAge")).isTrue();
|
||||
assertThat(PointcutForVoid.methodNames.get(1).equals("setName")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -504,17 +498,17 @@ public class ProxyFactoryBeanTests {
|
||||
@Test
|
||||
public void testGlobalsCanAddAspectInterfaces() {
|
||||
AddedGlobalInterface agi = (AddedGlobalInterface) factory.getBean("autoInvoker");
|
||||
assertThat(agi.globalsAdded()).isEqualTo(-1);
|
||||
assertThat(agi.globalsAdded() == -1).isTrue();
|
||||
|
||||
ProxyFactoryBean pfb = (ProxyFactoryBean) factory.getBean("&validGlobals");
|
||||
// Trigger lazy initialization.
|
||||
pfb.getObject();
|
||||
// 2 globals + 2 explicit
|
||||
assertThat(pfb.getAdvisors()).as("Have 2 globals and 2 explicit advisors").hasSize(3);
|
||||
assertThat(pfb.getAdvisors().length).as("Have 2 globals and 2 explicit advisors").isEqualTo(3);
|
||||
|
||||
ApplicationListener<?> l = (ApplicationListener<?>) factory.getBean("validGlobals");
|
||||
agi = (AddedGlobalInterface) l;
|
||||
assertThat(agi.globalsAdded()).isEqualTo(-1);
|
||||
assertThat(agi.globalsAdded() == -1).isTrue();
|
||||
|
||||
assertThat(factory.getBean("test1")).as("Aspect interface shouldn't be implemented without globals")
|
||||
.isNotInstanceOf(AddedGlobalInterface.class);
|
||||
@@ -715,7 +709,6 @@ public class ProxyFactoryBeanTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Aspect interface
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
*/
|
||||
class ScopedProxyTests {
|
||||
public class ScopedProxyTests {
|
||||
|
||||
private static final Class<?> CLASS = ScopedProxyTests.class;
|
||||
private static final String CLASSNAME = CLASS.getSimpleName();
|
||||
@@ -51,24 +51,27 @@ class ScopedProxyTests {
|
||||
|
||||
|
||||
@Test // SPR-2108
|
||||
void testProxyAssignable() {
|
||||
public void testProxyAssignable() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(MAP_CONTEXT);
|
||||
Object baseMap = bf.getBean("singletonMap");
|
||||
assertThat(baseMap instanceof Map).isTrue();
|
||||
boolean condition = baseMap instanceof Map;
|
||||
assertThat(condition).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleProxy() {
|
||||
public void testSimpleProxy() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(MAP_CONTEXT);
|
||||
Object simpleMap = bf.getBean("simpleMap");
|
||||
assertThat(simpleMap instanceof Map).isTrue();
|
||||
assertThat(simpleMap instanceof HashMap).isTrue();
|
||||
boolean condition1 = simpleMap instanceof Map;
|
||||
assertThat(condition1).isTrue();
|
||||
boolean condition = simpleMap instanceof HashMap;
|
||||
assertThat(condition).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testScopedOverride() {
|
||||
public void testScopedOverride() throws Exception {
|
||||
GenericApplicationContext ctx = new GenericApplicationContext();
|
||||
new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(OVERRIDE_CONTEXT);
|
||||
SimpleMapScope scope = new SimpleMapScope();
|
||||
@@ -84,7 +87,7 @@ class ScopedProxyTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJdkScopedProxy() throws Exception {
|
||||
public void testJdkScopedProxy() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(TESTBEAN_CONTEXT);
|
||||
bf.setSerializationId("X");
|
||||
@@ -94,7 +97,8 @@ class ScopedProxyTests {
|
||||
ITestBean bean = (ITestBean) bf.getBean("testBean");
|
||||
assertThat(bean).isNotNull();
|
||||
assertThat(AopUtils.isJdkDynamicProxy(bean)).isTrue();
|
||||
assertThat(bean instanceof ScopedObject).isTrue();
|
||||
boolean condition1 = bean instanceof ScopedObject;
|
||||
assertThat(condition1).isTrue();
|
||||
ScopedObject scoped = (ScopedObject) bean;
|
||||
assertThat(scoped.getTargetObject().getClass()).isEqualTo(TestBean.class);
|
||||
bean.setAge(101);
|
||||
@@ -106,7 +110,8 @@ class ScopedProxyTests {
|
||||
assertThat(deserialized).isNotNull();
|
||||
assertThat(AopUtils.isJdkDynamicProxy(deserialized)).isTrue();
|
||||
assertThat(bean.getAge()).isEqualTo(101);
|
||||
assertThat(deserialized instanceof ScopedObject).isTrue();
|
||||
boolean condition = deserialized instanceof ScopedObject;
|
||||
assertThat(condition).isTrue();
|
||||
ScopedObject scopedDeserialized = (ScopedObject) deserialized;
|
||||
assertThat(scopedDeserialized.getTargetObject().getClass()).isEqualTo(TestBean.class);
|
||||
|
||||
@@ -114,7 +119,7 @@ class ScopedProxyTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCglibScopedProxy() throws Exception {
|
||||
public void testCglibScopedProxy() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(LIST_CONTEXT);
|
||||
bf.setSerializationId("Y");
|
||||
@@ -123,7 +128,8 @@ class ScopedProxyTests {
|
||||
|
||||
TestBean tb = (TestBean) bf.getBean("testBean");
|
||||
assertThat(AopUtils.isCglibProxy(tb.getFriends())).isTrue();
|
||||
assertThat(tb.getFriends() instanceof ScopedObject).isTrue();
|
||||
boolean condition1 = tb.getFriends() instanceof ScopedObject;
|
||||
assertThat(condition1).isTrue();
|
||||
ScopedObject scoped = (ScopedObject) tb.getFriends();
|
||||
assertThat(scoped.getTargetObject().getClass()).isEqualTo(ArrayList.class);
|
||||
tb.getFriends().add("myFriend");
|
||||
@@ -131,11 +137,12 @@ class ScopedProxyTests {
|
||||
assertThat(scope.getMap().containsKey("scopedTarget.scopedList")).isTrue();
|
||||
assertThat(scope.getMap().get("scopedTarget.scopedList").getClass()).isEqualTo(ArrayList.class);
|
||||
|
||||
ArrayList<Object> deserialized = (ArrayList<Object>) SerializationTestUtils.serializeAndDeserialize(tb.getFriends());
|
||||
ArrayList<?> deserialized = (ArrayList<?>) SerializationTestUtils.serializeAndDeserialize(tb.getFriends());
|
||||
assertThat(deserialized).isNotNull();
|
||||
assertThat(AopUtils.isCglibProxy(deserialized)).isTrue();
|
||||
assertThat(deserialized).contains("myFriend");
|
||||
assertThat(deserialized instanceof ScopedObject).isTrue();
|
||||
assertThat(deserialized.contains("myFriend")).isTrue();
|
||||
boolean condition = deserialized instanceof ScopedObject;
|
||||
assertThat(condition).isTrue();
|
||||
ScopedObject scopedDeserialized = (ScopedObject) deserialized;
|
||||
assertThat(scopedDeserialized.getTargetObject().getClass()).isEqualTo(ArrayList.class);
|
||||
|
||||
|
||||
+52
-61
@@ -63,12 +63,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
new RootBeanDefinition(QualifiedFieldTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -81,13 +81,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -101,10 +100,9 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -207,13 +205,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedFieldTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -230,13 +227,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedMethodParameterTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -253,10 +249,9 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -379,13 +374,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedFieldWithDefaultValueTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -457,13 +451,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -514,13 +507,12 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedFieldWithMultipleAttributesTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getRootCause()).isInstanceOf(NoSuchBeanDefinitionException.class);
|
||||
assertThat(ex.getBeanName()).isEqualTo("autowired");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -582,10 +574,9 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
|
||||
assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.satisfies(ex -> assertThat(ex.getBeanName()).isEqualTo("autowired"));
|
||||
}
|
||||
|
||||
|
||||
@@ -761,7 +752,7 @@ public class QualifierAnnotationAutowireContextTests {
|
||||
@Qualifier
|
||||
@interface TestQualifierWithMultipleAttributes {
|
||||
|
||||
String[] value() default "default";
|
||||
String value() default "default";
|
||||
|
||||
int number();
|
||||
}
|
||||
|
||||
+6
-8
@@ -58,10 +58,9 @@ public class QualifierAnnotationTests {
|
||||
BeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
|
||||
reader.loadBeanDefinitions(CONFIG_LOCATION);
|
||||
context.registerSingleton("testBean", NonQualifiedTestBean.class);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.withMessageContaining("found 6");
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.withMessageContaining("found 6");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -192,10 +191,9 @@ public class QualifierAnnotationTests {
|
||||
BeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
|
||||
reader.loadBeanDefinitions(CONFIG_LOCATION);
|
||||
context.registerSingleton("testBean", QualifiedByAttributesTestBean.class);
|
||||
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(context::refresh)
|
||||
.withMessageContaining("found 6");
|
||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||
context::refresh)
|
||||
.withMessageContaining("found 6");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -268,7 +268,6 @@ public class ClassPathBeanDefinitionScannerTests {
|
||||
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
|
||||
scanner.setIncludeAnnotationConfig(false);
|
||||
scanner.scan("org.springframework.context.annotation2");
|
||||
|
||||
assertThatIllegalStateException().isThrownBy(() -> scanner.scan(BASE_PACKAGE))
|
||||
.withMessageContaining("myNamedDao")
|
||||
.withMessageContaining(NamedStubDao.class.getName())
|
||||
|
||||
+3
-22
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -215,7 +215,7 @@ public class CommonAnnotationBeanPostProcessorTests {
|
||||
bf.registerBeanDefinition("testBean4", tbd);
|
||||
|
||||
bf.registerResolvableDependency(BeanFactory.class, bf);
|
||||
bf.registerResolvableDependency(INestedTestBean.class, (ObjectFactory<Object>) NestedTestBean::new);
|
||||
bf.registerResolvableDependency(INestedTestBean.class, (ObjectFactory<Object>) () -> new NestedTestBean());
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer ppc = new org.springframework.beans.factory.config.PropertyPlaceholderConfigurer();
|
||||
@@ -233,7 +233,7 @@ public class CommonAnnotationBeanPostProcessorTests {
|
||||
assertThat(tb).isNotSameAs(anotherBean.getTestBean6());
|
||||
|
||||
String[] depBeans = bf.getDependenciesForBean("annotatedBean");
|
||||
assertThat(depBeans).hasSize(1);
|
||||
assertThat(depBeans.length).isEqualTo(1);
|
||||
assertThat(depBeans[0]).isEqualTo("testBean4");
|
||||
}
|
||||
|
||||
@@ -508,25 +508,6 @@ public class CommonAnnotationBeanPostProcessorTests {
|
||||
assertThat(tb.getName()).isEqualTo("notLazyAnymore");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyResolutionWithFallbackTypeMatch() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
|
||||
CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(LazyResourceCglibInjectionBean.class));
|
||||
bf.registerBeanDefinition("tb", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
LazyResourceCglibInjectionBean bean = (LazyResourceCglibInjectionBean) bf.getBean("annotatedBean");
|
||||
assertThat(bf.containsSingleton("tb")).isFalse();
|
||||
bean.testBean.setName("notLazyAnymore");
|
||||
assertThat(bf.containsSingleton("tb")).isTrue();
|
||||
TestBean tb = (TestBean) bf.getBean("tb");
|
||||
assertThat(tb.getName()).isEqualTo("notLazyAnymore");
|
||||
}
|
||||
|
||||
|
||||
public static class AnnotatedInitDestroyBean {
|
||||
|
||||
|
||||
+40
-60
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,9 +29,7 @@ import org.springframework.beans.factory.support.AbstractBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -41,62 +39,51 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* {@link FactoryBean FactoryBeans} defined in the configuration.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
class ConfigurationWithFactoryBeanEarlyDeductionTests {
|
||||
public class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
|
||||
|
||||
@Test
|
||||
void preFreezeDirect() {
|
||||
public void preFreezeDirect() {
|
||||
assertPreFreeze(DirectConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void postFreezeDirect() {
|
||||
public void postFreezeDirect() {
|
||||
assertPostFreeze(DirectConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void preFreezeGenericMethod() {
|
||||
public void preFreezeGenericMethod() {
|
||||
assertPreFreeze(GenericMethodConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void postFreezeGenericMethod() {
|
||||
public void postFreezeGenericMethod() {
|
||||
assertPostFreeze(GenericMethodConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void preFreezeGenericClass() {
|
||||
public void preFreezeGenericClass() {
|
||||
assertPreFreeze(GenericClassConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void postFreezeGenericClass() {
|
||||
public void postFreezeGenericClass() {
|
||||
assertPostFreeze(GenericClassConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void preFreezeAttribute() {
|
||||
public void preFreezeAttribute() {
|
||||
assertPreFreeze(AttributeClassConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void postFreezeAttribute() {
|
||||
public void postFreezeAttribute() {
|
||||
assertPostFreeze(AttributeClassConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void preFreezeTargetType() {
|
||||
assertPreFreeze(TargetTypeConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void postFreezeTargetType() {
|
||||
assertPostFreeze(TargetTypeConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void preFreezeUnresolvedGenericFactoryBean() {
|
||||
public void preFreezeUnresolvedGenericFactoryBean() {
|
||||
// Covers the case where a @Configuration is picked up via component scanning
|
||||
// and its bean definition only has a String bean class. In such cases
|
||||
// beanDefinition.hasBeanClass() returns false so we need to actually
|
||||
@@ -121,13 +108,14 @@ class ConfigurationWithFactoryBeanEarlyDeductionTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void assertPostFreeze(Class<?> configurationClass) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(configurationClass);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
configurationClass);
|
||||
assertContainsMyBeanName(context);
|
||||
}
|
||||
|
||||
private void assertPreFreeze(Class<?> configurationClass, BeanFactoryPostProcessor... postProcessors) {
|
||||
private void assertPreFreeze(Class<?> configurationClass,
|
||||
BeanFactoryPostProcessor... postProcessors) {
|
||||
NameCollectingBeanFactoryPostProcessor postProcessor = new NameCollectingBeanFactoryPostProcessor();
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
try {
|
||||
@@ -150,38 +138,41 @@ class ConfigurationWithFactoryBeanEarlyDeductionTests {
|
||||
assertThat(names).containsExactly("myBean");
|
||||
}
|
||||
|
||||
|
||||
private static class NameCollectingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
|
||||
private static class NameCollectingBeanFactoryPostProcessor
|
||||
implements BeanFactoryPostProcessor {
|
||||
|
||||
private String[] names;
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
ResolvableType typeToMatch = ResolvableType.forClassWithGenerics(MyBean.class, String.class);
|
||||
this.names = beanFactory.getBeanNamesForType(typeToMatch, true, false);
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
this.names = beanFactory.getBeanNamesForType(MyBean.class, true, false);
|
||||
}
|
||||
|
||||
public String[] getNames() {
|
||||
return this.names;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DirectConfiguration {
|
||||
|
||||
@Bean
|
||||
MyBean<String> myBean() {
|
||||
return new MyBean<>();
|
||||
MyBean myBean() {
|
||||
return new MyBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class GenericMethodConfiguration {
|
||||
|
||||
@Bean
|
||||
FactoryBean<MyBean<String>> myBean() {
|
||||
return new TestFactoryBean<>(new MyBean<>());
|
||||
FactoryBean<MyBean> myBean() {
|
||||
return new TestFactoryBean<>(new MyBean());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -191,11 +182,13 @@ class ConfigurationWithFactoryBeanEarlyDeductionTests {
|
||||
MyFactoryBean myBean() {
|
||||
return new MyFactoryBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(AttributeClassRegistrar.class)
|
||||
static class AttributeClassConfiguration {
|
||||
|
||||
}
|
||||
|
||||
static class AttributeClassRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
@@ -204,34 +197,16 @@ class ConfigurationWithFactoryBeanEarlyDeductionTests {
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||
BeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
RawWithAbstractObjectTypeFactoryBean.class).getBeanDefinition();
|
||||
definition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE,
|
||||
ResolvableType.forClassWithGenerics(MyBean.class, String.class));
|
||||
definition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, MyBean.class);
|
||||
registry.registerBeanDefinition("myBean", definition);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(TargetTypeRegistrar.class)
|
||||
static class TargetTypeConfiguration {
|
||||
}
|
||||
|
||||
static class TargetTypeRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||
RootBeanDefinition definition = new RootBeanDefinition(RawWithAbstractObjectTypeFactoryBean.class);
|
||||
definition.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class,
|
||||
ResolvableType.forClassWithGenerics(MyBean.class, String.class)));
|
||||
definition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE,
|
||||
ResolvableType.forClassWithGenerics(MyBean.class, String.class));
|
||||
registry.registerBeanDefinition("myBean", definition);
|
||||
}
|
||||
}
|
||||
|
||||
abstract static class AbstractMyBean {
|
||||
}
|
||||
|
||||
static class MyBean<T> extends AbstractMyBean {
|
||||
static class MyBean extends AbstractMyBean {
|
||||
}
|
||||
|
||||
static class TestFactoryBean<T> implements FactoryBean<T> {
|
||||
@@ -243,7 +218,7 @@ class ConfigurationWithFactoryBeanEarlyDeductionTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getObject() {
|
||||
public T getObject() throws Exception {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
@@ -251,26 +226,31 @@ class ConfigurationWithFactoryBeanEarlyDeductionTests {
|
||||
public Class<?> getObjectType() {
|
||||
return this.instance.getClass();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MyFactoryBean extends TestFactoryBean<MyBean<String>> {
|
||||
static class MyFactoryBean extends TestFactoryBean<MyBean> {
|
||||
|
||||
public MyFactoryBean() {
|
||||
super(new MyBean<>());
|
||||
super(new MyBean());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class RawWithAbstractObjectTypeFactoryBean implements FactoryBean<Object> {
|
||||
|
||||
private final Object object = new MyBean();
|
||||
|
||||
@Override
|
||||
public Object getObject() throws Exception {
|
||||
throw new IllegalStateException();
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return MyBean.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -138,8 +138,8 @@ class PropertySourceAnnotationTests {
|
||||
@Test
|
||||
void withUnresolvablePlaceholder() {
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class)
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithUnresolvablePlaceholder.class))
|
||||
.withCauseInstanceOf(IllegalArgumentException.class);
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithUnresolvablePlaceholder.class))
|
||||
.withCauseInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -170,8 +170,8 @@ class PropertySourceAnnotationTests {
|
||||
@Test
|
||||
void withEmptyResourceLocations() {
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class)
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithEmptyResourceLocations.class))
|
||||
.withCauseInstanceOf(IllegalArgumentException.class);
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithEmptyResourceLocations.class))
|
||||
.withCauseInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -253,8 +253,8 @@ class PropertySourceAnnotationTests {
|
||||
@Test
|
||||
void withMissingPropertySource() {
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class)
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithMissingPropertySource.class))
|
||||
.withCauseInstanceOf(FileNotFoundException.class);
|
||||
.isThrownBy(() -> new AnnotationConfigApplicationContext(ConfigWithMissingPropertySource.class))
|
||||
.withCauseInstanceOf(FileNotFoundException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+8
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,10 +36,6 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> GenericTestEvent<T> createGenericTestEvent(T payload) {
|
||||
return new GenericTestEvent<>(this, payload);
|
||||
}
|
||||
|
||||
|
||||
protected static class GenericTestEvent<T> extends ApplicationEvent {
|
||||
|
||||
@@ -55,7 +51,6 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static class SmartGenericTestEvent<T> extends GenericTestEvent<T> implements ResolvableTypeProvider {
|
||||
|
||||
private final ResolvableType resolvableType;
|
||||
@@ -72,7 +67,6 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static class StringEvent extends GenericTestEvent<String> {
|
||||
|
||||
public StringEvent(Object source, String payload) {
|
||||
@@ -80,7 +74,6 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static class LongEvent extends GenericTestEvent<Long> {
|
||||
|
||||
public LongEvent(Object source, Long payload) {
|
||||
@@ -88,31 +81,31 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> GenericTestEvent<T> createGenericTestEvent(T payload) {
|
||||
return new GenericTestEvent<>(this, payload);
|
||||
}
|
||||
|
||||
|
||||
static class GenericEventListener implements ApplicationListener<GenericTestEvent<?>> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(GenericTestEvent<?> event) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class ObjectEventListener implements ApplicationListener<GenericTestEvent<Object>> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(GenericTestEvent<Object> event) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class UpperBoundEventListener implements ApplicationListener<GenericTestEvent<? extends RuntimeException>> {
|
||||
static class UpperBoundEventListener
|
||||
implements ApplicationListener<GenericTestEvent<? extends RuntimeException>> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(GenericTestEvent<? extends RuntimeException> event) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class StringEventListener implements ApplicationListener<GenericTestEvent<String>> {
|
||||
|
||||
@Override
|
||||
@@ -120,7 +113,6 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
static class RawApplicationListener implements ApplicationListener {
|
||||
|
||||
@@ -129,10 +121,10 @@ public abstract class AbstractApplicationEventListenerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class TestEvents {
|
||||
|
||||
public GenericTestEvent<?> wildcardEvent;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -104,8 +104,7 @@ public class GenericApplicationListenerAdapterTests extends AbstractApplicationE
|
||||
|
||||
@Test
|
||||
public void genericListenerStrictTypeSubClass() {
|
||||
supportsEventType(false, ObjectEventListener.class,
|
||||
ResolvableType.forClassWithGenerics(GenericTestEvent.class, Long.class));
|
||||
supportsEventType(false, ObjectEventListener.class, ResolvableType.forClassWithGenerics(GenericTestEvent.class, Long.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 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.
|
||||
@@ -102,16 +102,16 @@ class GenericApplicationContextTests {
|
||||
|
||||
assertThat(context.getBean(String.class)).isSameAs(context.getBean("testBean"));
|
||||
assertThat(context.getAutowireCapableBeanFactory().getBean(String.class))
|
||||
.isSameAs(context.getAutowireCapableBeanFactory().getBean("testBean"));
|
||||
.isSameAs(context.getAutowireCapableBeanFactory().getBean("testBean"));
|
||||
|
||||
context.close();
|
||||
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> context.getBean(String.class));
|
||||
.isThrownBy(() -> context.getBean(String.class));
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> context.getAutowireCapableBeanFactory().getBean(String.class));
|
||||
.isThrownBy(() -> context.getAutowireCapableBeanFactory().getBean(String.class));
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> context.getAutowireCapableBeanFactory().getBean("testBean"));
|
||||
.isThrownBy(() -> context.getAutowireCapableBeanFactory().getBean("testBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author 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.scheduling.concurrent;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.RunnableFuture;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -52,8 +52,8 @@ class ConcurrentTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
|
||||
@AfterEach
|
||||
void shutdownExecutor() {
|
||||
for (Runnable task : concurrentExecutor.shutdownNow()) {
|
||||
if (task instanceof Future) {
|
||||
((Future<?>) task).cancel(true);
|
||||
if (task instanceof RunnableFuture) {
|
||||
((RunnableFuture<?>) task).cancel(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutorTests {
|
||||
public class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutorTests {
|
||||
|
||||
private final ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
|
||||
@@ -97,7 +97,7 @@ class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void scheduleOneTimeFailingTaskWithoutErrorHandler() {
|
||||
void scheduleOneTimeFailingTaskWithoutErrorHandler() throws Exception {
|
||||
TestTask task = new TestTask(this.testName, 0);
|
||||
Future<?> future = scheduler.schedule(task, new Date());
|
||||
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() -> future.get(1000, TimeUnit.MILLISECONDS));
|
||||
@@ -149,7 +149,7 @@ class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutorTests {
|
||||
catch (InterruptedException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
assertThat(latch.getCount()).as("latch did not count down").isEqualTo(0);
|
||||
assertThat(latch.getCount()).as("latch did not count down,").isEqualTo(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+8
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,32 +35,27 @@ class BitsCronFieldTests {
|
||||
@Test
|
||||
void parse() {
|
||||
assertThat(BitsCronField.parseSeconds("42")).has(clearRange(0, 41)).has(set(42)).has(clearRange(43, 59));
|
||||
assertThat(BitsCronField.parseSeconds("0-4,8-12")).has(setRange(0, 4)).has(clearRange(5,7))
|
||||
.has(setRange(8, 12)).has(clearRange(13,59));
|
||||
assertThat(BitsCronField.parseSeconds("57/2")).has(clearRange(0, 56)).has(set(57))
|
||||
.has(clear(58)).has(set(59));
|
||||
assertThat(BitsCronField.parseSeconds("0-4,8-12")).has(setRange(0, 4)).has(clearRange(5,7)).has(setRange(8, 12)).has(clearRange(13,59));
|
||||
assertThat(BitsCronField.parseSeconds("57/2")).has(clearRange(0, 56)).has(set(57)).has(clear(58)).has(set(59));
|
||||
|
||||
assertThat(BitsCronField.parseMinutes("30")).has(set(30)).has(clearRange(1, 29)).has(clearRange(31, 59));
|
||||
|
||||
assertThat(BitsCronField.parseHours("23")).has(set(23)).has(clearRange(0, 23));
|
||||
assertThat(BitsCronField.parseHours("0-23/2")).has(set(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22))
|
||||
.has(clear(1,3,5,7,9,11,13,15,17,19,21,23));
|
||||
assertThat(BitsCronField.parseHours("0-23/2")).has(set(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22)).has(clear(1,3,5,7,9,11,13,15,17,19,21,23));
|
||||
|
||||
assertThat(BitsCronField.parseDaysOfMonth("1")).has(set(1)).has(clearRange(2, 31));
|
||||
|
||||
assertThat(BitsCronField.parseMonth("1")).has(set(1)).has(clearRange(2, 12));
|
||||
|
||||
assertThat(BitsCronField.parseDaysOfWeek("0")).has(set(7, 7)).has(clearRange(0, 6));
|
||||
assertThat(BitsCronField.parseDaysOfWeek("7-5")).has(clear(0)).has(setRange(1, 5))
|
||||
.has(clear(6)).has(set(7));
|
||||
|
||||
assertThat(BitsCronField.parseDaysOfWeek("7-5")).has(clear(0)).has(setRange(1, 5)).has(clear(6)).has(set(7));
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseLists() {
|
||||
assertThat(BitsCronField.parseSeconds("15,30")).has(set(15, 30)).has(clearRange(1, 15))
|
||||
.has(clearRange(31, 59));
|
||||
assertThat(BitsCronField.parseMinutes("1,2,5,9")).has(set(1, 2, 5, 9)).has(clear(0))
|
||||
.has(clearRange(3, 4)).has(clearRange(6, 8)).has(clearRange(10, 59));
|
||||
assertThat(BitsCronField.parseSeconds("15,30")).has(set(15, 30)).has(clearRange(1, 15)).has(clearRange(31, 59));
|
||||
assertThat(BitsCronField.parseMinutes("1,2,5,9")).has(set(1, 2, 5, 9)).has(clear(0)).has(clearRange(3, 4)).has(clearRange(6, 8)).has(clearRange(10, 59));
|
||||
assertThat(BitsCronField.parseHours("1,2,3")).has(set(1, 2, 3)).has(clearRange(4, 23));
|
||||
assertThat(BitsCronField.parseDaysOfMonth("1,2,3")).has(set(1, 2, 3)).has(clearRange(4, 31));
|
||||
assertThat(BitsCronField.parseMonth("1,2,3")).has(set(1, 2, 3)).has(clearRange(4, 12));
|
||||
@@ -112,7 +107,6 @@ class BitsCronFieldTests {
|
||||
.has(clear(0)).has(setRange(1, 7));
|
||||
}
|
||||
|
||||
|
||||
private static Condition<BitsCronField> set(int... indices) {
|
||||
return new Condition<BitsCronField>(String.format("set bits %s", Arrays.toString(indices))) {
|
||||
@Override
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -848,7 +848,6 @@ class CronTriggerTests {
|
||||
assertThat(nextExecutionTime).isEqualTo(this.calendar.getTime());
|
||||
}
|
||||
|
||||
|
||||
private static void roundup(Calendar calendar) {
|
||||
calendar.add(Calendar.SECOND, 1);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
@@ -862,7 +861,9 @@ class CronTriggerTests {
|
||||
}
|
||||
|
||||
private static TriggerContext getTriggerContext(Date lastCompletionTime) {
|
||||
return new SimpleTriggerContext(null, null, lastCompletionTime);
|
||||
SimpleTriggerContext context = new SimpleTriggerContext();
|
||||
context.update(null, null, lastCompletionTime);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-42
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,7 +28,6 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
* Unit tests for {@link QuartzCronField}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
class QuartzCronFieldTests {
|
||||
|
||||
@@ -72,46 +71,6 @@ class QuartzCronFieldTests {
|
||||
assertThat(field.nextOrSame(last)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dayOfWeek_0(){
|
||||
// third Sunday (0) of the month
|
||||
QuartzCronField field = QuartzCronField.parseDaysOfWeek("0#3");
|
||||
|
||||
LocalDate last = LocalDate.of(2024, 1, 1);
|
||||
LocalDate expected = LocalDate.of(2024, 1, 21);
|
||||
assertThat(field.nextOrSame(last)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dayOfWeek_1(){
|
||||
// third Monday (1) of the month
|
||||
QuartzCronField field = QuartzCronField.parseDaysOfWeek("1#3");
|
||||
|
||||
LocalDate last = LocalDate.of(2024, 1, 1);
|
||||
LocalDate expected = LocalDate.of(2024, 1, 15);
|
||||
assertThat(field.nextOrSame(last)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dayOfWeek_2(){
|
||||
// third Tuesday (2) of the month
|
||||
QuartzCronField field = QuartzCronField.parseDaysOfWeek("2#3");
|
||||
|
||||
LocalDate last = LocalDate.of(2024, 1, 1);
|
||||
LocalDate expected = LocalDate.of(2024, 1, 16);
|
||||
assertThat(field.nextOrSame(last)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void dayOfWeek_7() {
|
||||
// third Sunday (7 as alternative to 0) of the month
|
||||
QuartzCronField field = QuartzCronField.parseDaysOfWeek("7#3");
|
||||
|
||||
LocalDate last = LocalDate.of(2024, 1, 1);
|
||||
LocalDate expected = LocalDate.of(2024, 1, 21);
|
||||
assertThat(field.nextOrSame(last)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidValues() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfMonth(""));
|
||||
|
||||
+21
-12
@@ -3,6 +3,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<!--
|
||||
Not yet in use: illustration of possible approach
|
||||
-->
|
||||
<bean id="overrideOneMethod" class="org.springframework.beans.factory.xml.OverrideOneMethod">
|
||||
|
||||
<lookup-method name="getPrototypeDependency" bean="jenny"/>
|
||||
@@ -24,34 +27,39 @@
|
||||
|
||||
<lookup-method name="protectedOverrideSingleton" bean="david"/>
|
||||
|
||||
<!-- This method is not overloaded, so we don't need to specify any arg types -->
|
||||
<!--
|
||||
This method is not overloaded, so we don't need to specify any arg types
|
||||
-->
|
||||
<replaced-method name="doSomething" replacer="doSomethingReplacer"/>
|
||||
|
||||
</bean>
|
||||
|
||||
<bean id="replaceVoidMethod" parent="someParent" class="org.springframework.beans.factory.xml.OverrideOneMethodSubclass"/>
|
||||
<bean id="replaceVoidMethod" parent="someParent"
|
||||
class="org.springframework.beans.factory.xml.OverrideOneMethodSubclass">
|
||||
|
||||
<bean id="replaceEchoMethod" class="org.springframework.beans.factory.xml.EchoService">
|
||||
<!-- This method is not overloaded, so we don't need to specify any arg types -->
|
||||
<replaced-method name="echo" replacer="reverseArrayReplacer" />
|
||||
</bean>
|
||||
|
||||
<bean id="reverseReplacer" class="org.springframework.beans.factory.xml.ReverseMethodReplacer"/>
|
||||
<bean id="reverseReplacer"
|
||||
class="org.springframework.beans.factory.xml.ReverseMethodReplacer"/>
|
||||
|
||||
<bean id="reverseArrayReplacer" class="org.springframework.beans.factory.xml.ReverseArrayMethodReplacer"/>
|
||||
<bean id="fixedReplacer"
|
||||
class="org.springframework.beans.factory.xml.FixedMethodReplacer"/>
|
||||
|
||||
<bean id="fixedReplacer" class="org.springframework.beans.factory.xml.FixedMethodReplacer"/>
|
||||
<bean id="doSomethingReplacer"
|
||||
class="org.springframework.beans.factory.xml.XmlBeanFactoryTests$DoSomethingReplacer"/>
|
||||
|
||||
<bean id="doSomethingReplacer" class="org.springframework.beans.factory.xml.XmlBeanFactoryTests$DoSomethingReplacer"/>
|
||||
<bean id="serializableReplacer"
|
||||
class="org.springframework.beans.factory.xml.SerializableMethodReplacerCandidate">
|
||||
|
||||
<bean id="serializableReplacer" class="org.springframework.beans.factory.xml.SerializableMethodReplacerCandidate">
|
||||
<!-- Arbitrary method replacer -->
|
||||
<replaced-method name="replaceMe" replacer="reverseReplacer">
|
||||
<arg-type>String</arg-type>
|
||||
</replaced-method>
|
||||
|
||||
</bean>
|
||||
|
||||
<bean id="jenny" class="org.springframework.beans.testfixture.beans.TestBean" scope="prototype">
|
||||
<bean id="jenny" class="org.springframework.beans.testfixture.beans.TestBean"
|
||||
scope="prototype">
|
||||
<property name="name"><value>Jenny</value></property>
|
||||
<property name="age"><value>30</value></property>
|
||||
<property name="spouse">
|
||||
@@ -60,7 +68,8 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="david" class="org.springframework.beans.testfixture.beans.TestBean" scope="singleton">
|
||||
<bean id="david" class="org.springframework.beans.testfixture.beans.TestBean"
|
||||
scope="singleton">
|
||||
<description>
|
||||
Simple bean, without any collections.
|
||||
</description>
|
||||
|
||||
@@ -16,24 +16,12 @@
|
||||
package org.springframework.cglib.beans;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.*;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.cglib.core.AbstractClassGenerator;
|
||||
import org.springframework.cglib.core.ClassEmitter;
|
||||
import org.springframework.cglib.core.CodeEmitter;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.Converter;
|
||||
import org.springframework.cglib.core.EmitUtils;
|
||||
import org.springframework.cglib.core.KeyFactory;
|
||||
import org.springframework.cglib.core.Local;
|
||||
import org.springframework.cglib.core.MethodInfo;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.cglib.core.Signature;
|
||||
import org.springframework.cglib.core.TypeUtils;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Chris Nokleberg
|
||||
@@ -41,154 +29,151 @@ import org.springframework.cglib.core.TypeUtils;
|
||||
@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)");
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 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 Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public void setSource(Class source) {
|
||||
this.source = source;
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(source);
|
||||
setNamePrefix(source.getName());
|
||||
// SPRING PATCH END
|
||||
}
|
||||
|
||||
public void setTarget(Class target) {
|
||||
this.target = target;
|
||||
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);
|
||||
setNamePrefix(target.getName());
|
||||
// SPRING PATCH END
|
||||
}
|
||||
}
|
||||
|
||||
public void setUseConverter(boolean useConverter) {
|
||||
this.useConverter = useConverter;
|
||||
}
|
||||
public void setUseConverter(boolean useConverter) {
|
||||
this.useConverter = useConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return source.getClassLoader();
|
||||
}
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return source.getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(source);
|
||||
}
|
||||
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 BeanCopier create() {
|
||||
Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter);
|
||||
return (BeanCopier)super.create(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
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);
|
||||
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 (PropertyDescriptor getter : getters) {
|
||||
names.put(getter.getName(), getter);
|
||||
}
|
||||
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 (PropertyDescriptor setter : setters) {
|
||||
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();
|
||||
}
|
||||
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());
|
||||
}
|
||||
private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) {
|
||||
// TODO: allow automatic widening conversions?
|
||||
return setter.getPropertyType().isAssignableFrom(getter.getPropertyType());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object firstInstance(Class type) {
|
||||
return ReflectUtils.newInstance(type);
|
||||
}
|
||||
protected Object firstInstance(Class type) {
|
||||
return ReflectUtils.newInstance(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object nextInstance(Object instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
protected Object nextInstance(Object instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,18 +17,10 @@ package org.springframework.cglib.beans;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.cglib.core.AbstractClassGenerator;
|
||||
import org.springframework.cglib.core.ClassEmitter;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.EmitUtils;
|
||||
import org.springframework.cglib.core.KeyFactory;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
|
||||
/**
|
||||
* @author Juozas Baliuka, Chris Nokleberg
|
||||
@@ -36,131 +28,126 @@ import org.springframework.cglib.core.ReflectUtils;
|
||||
@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);
|
||||
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);
|
||||
}
|
||||
|
||||
interface BeanGeneratorKey {
|
||||
public Object newInstance(String superclass, Map props);
|
||||
}
|
||||
private Class superclass;
|
||||
private Map props = new HashMap();
|
||||
private boolean classOnly;
|
||||
|
||||
private Class superclass;
|
||||
private Map props = new HashMap();
|
||||
private boolean classOnly;
|
||||
public BeanGenerator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
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;
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
public void addProperty(String name, Class type) {
|
||||
if (props.containsKey(name)) {
|
||||
throw new IllegalArgumentException("Duplicate property name \"" + name + "\"");
|
||||
}
|
||||
props.put(name, Type.getType(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
if (superclass != null) {
|
||||
return superclass.getClassLoader();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
if (superclass != null) {
|
||||
return superclass.getClassLoader();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(superclass);
|
||||
}
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(superclass);
|
||||
}
|
||||
|
||||
public Object create() {
|
||||
classOnly = false;
|
||||
return createHelper();
|
||||
}
|
||||
public Object create() {
|
||||
classOnly = false;
|
||||
return createHelper();
|
||||
}
|
||||
|
||||
public Object createClass() {
|
||||
classOnly = true;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object firstInstance(Class type) {
|
||||
if (classOnly) {
|
||||
return type;
|
||||
} else {
|
||||
return ReflectUtils.newInstance(type);
|
||||
}
|
||||
}
|
||||
protected Object firstInstance(Class type) {
|
||||
if (classOnly) {
|
||||
return type;
|
||||
} else {
|
||||
return ReflectUtils.newInstance(type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object nextInstance(Object instance) {
|
||||
Class protoclass = (instance instanceof Class) ? (Class)instance : instance.getClass();
|
||||
if (classOnly) {
|
||||
return protoclass;
|
||||
} else {
|
||||
return ReflectUtils.newInstance(protoclass);
|
||||
}
|
||||
}
|
||||
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, 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, Class type) {
|
||||
addProperties(gen, ReflectUtils.getBeanProperties(type));
|
||||
}
|
||||
|
||||
public static void addProperties(BeanGenerator gen, PropertyDescriptor[] descriptors) {
|
||||
for (PropertyDescriptor descriptor : descriptors) {
|
||||
gen.addProperty(descriptor.getName(), descriptor.getPropertyType());
|
||||
}
|
||||
}
|
||||
public static void addProperties(BeanGenerator gen, PropertyDescriptor[] descriptors) {
|
||||
for (int i = 0; i < descriptors.length; i++) {
|
||||
gen.addProperty(descriptors[i].getName(), descriptors[i].getPropertyType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,310 +41,293 @@ import org.springframework.cglib.core.ReflectUtils;
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class BeanMap implements Map {
|
||||
/**
|
||||
* Limit the properties reflected in the key set of the map
|
||||
* to readable properties.
|
||||
* @see BeanMap.Generator#setRequire
|
||||
*/
|
||||
public static final int REQUIRE_GETTER = 1;
|
||||
/**
|
||||
* Limit the properties reflected in the key set of the map
|
||||
* to readable properties.
|
||||
* @see BeanMap.Generator#setRequire
|
||||
*/
|
||||
public static final int REQUIRE_GETTER = 1;
|
||||
|
||||
/**
|
||||
* Limit the properties reflected in the key set of the map
|
||||
* to writable properties.
|
||||
* @see BeanMap.Generator#setRequire
|
||||
*/
|
||||
public static final int REQUIRE_SETTER = 2;
|
||||
/**
|
||||
* Limit the properties reflected in the key set of the map
|
||||
* to writable properties.
|
||||
* @see BeanMap.Generator#setRequire
|
||||
*/
|
||||
public static final int REQUIRE_SETTER = 2;
|
||||
|
||||
/**
|
||||
* Helper method to create a new <code>BeanMap</code>. For finer
|
||||
* control over the generated instance, use a new instance of
|
||||
* <code>BeanMap.Generator</code> instead of this static method.
|
||||
* @param bean the JavaBean underlying the map
|
||||
* @return a new <code>BeanMap</code> instance
|
||||
*/
|
||||
public static BeanMap create(Object bean) {
|
||||
Generator gen = new Generator();
|
||||
gen.setBean(bean);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a new <code>BeanMap</code>. For finer
|
||||
* control over the generated instance, use a new instance of
|
||||
* <code>BeanMap.Generator</code> instead of this static method.
|
||||
* @param bean the JavaBean underlying the map
|
||||
* @return a new <code>BeanMap</code> instance
|
||||
*/
|
||||
public static BeanMap 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(BeanMap.class.getName());
|
||||
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(BeanMap.class.getName());
|
||||
private static final BeanMapKey KEY_FACTORY =
|
||||
(BeanMapKey)KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME);
|
||||
|
||||
private static final BeanMapKey KEY_FACTORY =
|
||||
(BeanMapKey)KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME);
|
||||
interface BeanMapKey {
|
||||
public Object newInstance(Class type, int require);
|
||||
}
|
||||
|
||||
private Object bean;
|
||||
private Class beanClass;
|
||||
private int require;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
interface BeanMapKey {
|
||||
public Object newInstance(Class type, int require);
|
||||
}
|
||||
|
||||
private Object bean;
|
||||
private Class beanClass;
|
||||
private int require;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean that the generated map should reflect. The bean may be swapped
|
||||
* out for another bean of the same type using {@link #setBean}.
|
||||
* Calling this method overrides any value previously set using {@link #setBeanClass}.
|
||||
* You must call either this method or {@link #setBeanClass} before {@link #create}.
|
||||
* @param bean the initial bean
|
||||
*/
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
if (bean != null) {
|
||||
/**
|
||||
* Set the bean that the generated map should reflect. The bean may be swapped
|
||||
* out for another bean of the same type using {@link #setBean}.
|
||||
* Calling this method overrides any value previously set using {@link #setBeanClass}.
|
||||
* You must call either this method or {@link #setBeanClass} before {@link #create}.
|
||||
* @param bean the initial bean
|
||||
*/
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
if (bean != null) {
|
||||
beanClass = bean.getClass();
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(beanClass);
|
||||
// SPRING PATCH END
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class of the bean that the generated map should support.
|
||||
* You must call either this method or {@link #setBeanClass} before {@link #create}.
|
||||
* @param beanClass the class of the bean
|
||||
*/
|
||||
public void setBeanClass(Class beanClass) {
|
||||
this.beanClass = beanClass;
|
||||
}
|
||||
/**
|
||||
* Set the class of the bean that the generated map should support.
|
||||
* You must call either this method or {@link #setBeanClass} before {@link #create}.
|
||||
* @param beanClass the class of the bean
|
||||
*/
|
||||
public void setBeanClass(Class beanClass) {
|
||||
this.beanClass = beanClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit the properties reflected by the generated map.
|
||||
* @param require any combination of {@link #REQUIRE_GETTER} and
|
||||
* {@link #REQUIRE_SETTER}; default is zero (any property allowed)
|
||||
*/
|
||||
public void setRequire(int require) {
|
||||
this.require = require;
|
||||
}
|
||||
/**
|
||||
* Limit the properties reflected by the generated map.
|
||||
* @param require any combination of {@link #REQUIRE_GETTER} and
|
||||
* {@link #REQUIRE_SETTER}; default is zero (any property allowed)
|
||||
*/
|
||||
public void setRequire(int require) {
|
||||
this.require = require;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return beanClass.getClassLoader();
|
||||
}
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return beanClass.getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(beanClass);
|
||||
}
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(beanClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the <code>BeanMap</code>. An existing
|
||||
* generated class will be reused if possible.
|
||||
*/
|
||||
public BeanMap create() {
|
||||
if (beanClass == null) {
|
||||
throw new IllegalArgumentException("Class of bean unknown");
|
||||
}
|
||||
setNamePrefix(beanClass.getName());
|
||||
return (BeanMap)super.create(KEY_FACTORY.newInstance(beanClass, require));
|
||||
}
|
||||
/**
|
||||
* Create a new instance of the <code>BeanMap</code>. An existing
|
||||
* generated class will be reused if possible.
|
||||
*/
|
||||
public BeanMap create() {
|
||||
if (beanClass == null)
|
||||
throw new IllegalArgumentException("Class of bean unknown");
|
||||
setNamePrefix(beanClass.getName());
|
||||
return (BeanMap)super.create(KEY_FACTORY.newInstance(beanClass, require));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
new BeanMapEmitter(v, getClassName(), beanClass, require);
|
||||
}
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
new BeanMapEmitter(v, getClassName(), beanClass, require);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object firstInstance(Class type) {
|
||||
return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean);
|
||||
}
|
||||
protected Object firstInstance(Class type) {
|
||||
return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object nextInstance(Object instance) {
|
||||
return ((BeanMap)instance).newInstance(bean);
|
||||
}
|
||||
}
|
||||
protected Object nextInstance(Object instance) {
|
||||
return ((BeanMap)instance).newInstance(bean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new <code>BeanMap</code> instance using the specified bean.
|
||||
* This is faster than using the {@link #create} static method.
|
||||
* @param bean the JavaBean underlying the map
|
||||
* @return a new <code>BeanMap</code> instance
|
||||
*/
|
||||
abstract public BeanMap newInstance(Object bean);
|
||||
/**
|
||||
* Create a new <code>BeanMap</code> instance using the specified bean.
|
||||
* This is faster than using the {@link #create} static method.
|
||||
* @param bean the JavaBean underlying the map
|
||||
* @return a new <code>BeanMap</code> instance
|
||||
*/
|
||||
abstract public BeanMap newInstance(Object bean);
|
||||
|
||||
/**
|
||||
* Get the type of a property.
|
||||
* @param name the name of the JavaBean property
|
||||
* @return the type of the property, or null if the property does not exist
|
||||
*/
|
||||
abstract public Class getPropertyType(String name);
|
||||
/**
|
||||
* Get the type of a property.
|
||||
* @param name the name of the JavaBean property
|
||||
* @return the type of the property, or null if the property does not exist
|
||||
*/
|
||||
abstract public Class getPropertyType(String name);
|
||||
|
||||
protected Object bean;
|
||||
protected Object bean;
|
||||
|
||||
protected BeanMap() {
|
||||
}
|
||||
protected BeanMap() {
|
||||
}
|
||||
|
||||
protected BeanMap(Object bean) {
|
||||
setBean(bean);
|
||||
}
|
||||
protected BeanMap(Object bean) {
|
||||
setBean(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return get(bean, key);
|
||||
}
|
||||
public Object get(Object key) {
|
||||
return get(bean, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
return put(bean, key, value);
|
||||
}
|
||||
public Object put(Object key, Object value) {
|
||||
return put(bean, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the property of a bean. This allows a <code>BeanMap</code>
|
||||
* to be used statically for multiple beans--the bean instance tied to the
|
||||
* map is ignored and the bean passed to this method is used instead.
|
||||
* @param bean the bean to query; must be compatible with the type of
|
||||
* this <code>BeanMap</code>
|
||||
* @param key must be a String
|
||||
* @return the current value, or null if there is no matching property
|
||||
*/
|
||||
abstract public Object get(Object bean, Object key);
|
||||
/**
|
||||
* Get the property of a bean. This allows a <code>BeanMap</code>
|
||||
* to be used statically for multiple beans--the bean instance tied to the
|
||||
* map is ignored and the bean passed to this method is used instead.
|
||||
* @param bean the bean to query; must be compatible with the type of
|
||||
* this <code>BeanMap</code>
|
||||
* @param key must be a String
|
||||
* @return the current value, or null if there is no matching property
|
||||
*/
|
||||
abstract public Object get(Object bean, Object key);
|
||||
|
||||
/**
|
||||
* Set the property of a bean. This allows a <code>BeanMap</code>
|
||||
* to be used statically for multiple beans--the bean instance tied to the
|
||||
* map is ignored and the bean passed to this method is used instead.
|
||||
* @param key must be a String
|
||||
* @return the old value, if there was one, or null
|
||||
*/
|
||||
abstract public Object put(Object bean, Object key, Object value);
|
||||
/**
|
||||
* Set the property of a bean. This allows a <code>BeanMap</code>
|
||||
* to be used statically for multiple beans--the bean instance tied to the
|
||||
* map is ignored and the bean passed to this method is used instead.
|
||||
* @param key must be a String
|
||||
* @return the old value, if there was one, or null
|
||||
*/
|
||||
abstract public Object put(Object bean, Object key, Object value);
|
||||
|
||||
/**
|
||||
* Change the underlying bean this map should use.
|
||||
* @param bean the new JavaBean
|
||||
* @see #getBean
|
||||
*/
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
}
|
||||
/**
|
||||
* Change the underlying bean this map should use.
|
||||
* @param bean the new JavaBean
|
||||
* @see #getBean
|
||||
*/
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean currently in use by this map.
|
||||
* @return the current JavaBean
|
||||
* @see #setBean
|
||||
*/
|
||||
public Object getBean() {
|
||||
return bean;
|
||||
}
|
||||
/**
|
||||
* Return the bean currently in use by this map.
|
||||
* @return the current JavaBean
|
||||
* @see #setBean
|
||||
*/
|
||||
public Object getBean() {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return keySet().contains(key);
|
||||
}
|
||||
public boolean containsKey(Object key) {
|
||||
return keySet().contains(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object v = get(it.next());
|
||||
if (((value == null) && (v == null)) || (value != null && value.equals(v))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public boolean containsValue(Object value) {
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object v = get(it.next());
|
||||
if (((value == null) && (v == null)) || (value != null && value.equals(v)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return keySet().size();
|
||||
}
|
||||
public int size() {
|
||||
return keySet().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public Object remove(Object key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map t) {
|
||||
for (Object key : t.keySet()) {
|
||||
put(key, t.get(key));
|
||||
}
|
||||
}
|
||||
public void putAll(Map t) {
|
||||
for (Iterator it = t.keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
put(key, t.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || !(o instanceof Map)) {
|
||||
return false;
|
||||
}
|
||||
Map other = (Map)o;
|
||||
if (size() != other.size()) {
|
||||
return false;
|
||||
}
|
||||
for (Object key : keySet()) {
|
||||
if (!other.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
Object v1 = get(key);
|
||||
Object v2 = other.get(key);
|
||||
if (!((v1 == null) ? v2 == null : v1.equals(v2))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || !(o instanceof Map)) {
|
||||
return false;
|
||||
}
|
||||
Map other = (Map)o;
|
||||
if (size() != other.size()) {
|
||||
return false;
|
||||
}
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
if (!other.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
Object v1 = get(key);
|
||||
Object v2 = other.get(key);
|
||||
if (!((v1 == null) ? v2 == null : v1.equals(v2))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = 0;
|
||||
for (Object key : keySet()) {
|
||||
Object value = get(key);
|
||||
code += ((key == null) ? 0 : key.hashCode()) ^
|
||||
((value == null) ? 0 : value.hashCode());
|
||||
}
|
||||
return code;
|
||||
}
|
||||
public int hashCode() {
|
||||
int code = 0;
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
Object value = get(key);
|
||||
code += ((key == null) ? 0 : key.hashCode()) ^
|
||||
((value == null) ? 0 : value.hashCode());
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
@Override
|
||||
public Set entrySet() {
|
||||
HashMap copy = new HashMap();
|
||||
for (Object key : keySet()) {
|
||||
copy.put(key, get(key));
|
||||
}
|
||||
return Collections.unmodifiableMap(copy).entrySet();
|
||||
}
|
||||
// TODO: optimize
|
||||
public Set entrySet() {
|
||||
HashMap copy = new HashMap();
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
copy.put(key, get(key));
|
||||
}
|
||||
return Collections.unmodifiableMap(copy).entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection values() {
|
||||
Set keys = keySet();
|
||||
List values = new ArrayList(keys.size());
|
||||
for (Iterator it = keys.iterator(); it.hasNext();) {
|
||||
values.add(get(it.next()));
|
||||
}
|
||||
return Collections.unmodifiableCollection(values);
|
||||
}
|
||||
public Collection values() {
|
||||
Set keys = keySet();
|
||||
List values = new ArrayList(keys.size());
|
||||
for (Iterator it = keys.iterator(); it.hasNext();) {
|
||||
values.add(get(it.next()));
|
||||
}
|
||||
return Collections.unmodifiableCollection(values);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see java.util.AbstractMap#toString
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('{');
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
sb.append(key);
|
||||
sb.append('=');
|
||||
sb.append(get(key));
|
||||
if (it.hasNext()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
/*
|
||||
* @see java.util.AbstractMap#toString
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append('{');
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
Object key = it.next();
|
||||
sb.append(key);
|
||||
sb.append('=');
|
||||
sb.append(get(key));
|
||||
if (it.hasNext()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,23 +15,12 @@
|
||||
*/
|
||||
package org.springframework.cglib.beans;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
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;
|
||||
import org.springframework.cglib.core.ClassEmitter;
|
||||
import org.springframework.cglib.core.CodeEmitter;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.EmitUtils;
|
||||
import org.springframework.cglib.core.MethodInfo;
|
||||
import org.springframework.cglib.core.ObjectSwitchCallback;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.cglib.core.Signature;
|
||||
import org.springframework.cglib.core.TypeUtils;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class BeanMapEmitter extends ClassEmitter {
|
||||
@@ -61,7 +50,7 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
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();
|
||||
@@ -90,8 +79,8 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
|
||||
private Map makePropertyMap(PropertyDescriptor[] props) {
|
||||
Map names = new HashMap();
|
||||
for (PropertyDescriptor prop : props) {
|
||||
names.put(prop.getName(), prop);
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
names.put(props[i].getName(), props[i]);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
@@ -108,7 +97,7 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
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);
|
||||
@@ -116,16 +105,14 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
e.load_arg(1);
|
||||
e.checkcast(Constants.TYPE_STRING);
|
||||
EmitUtils.string_switch(e, getNames(getters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
|
||||
@Override
|
||||
public void processCase(Object key, Label end) {
|
||||
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();
|
||||
}
|
||||
@Override
|
||||
public void processDefault() {
|
||||
public void processDefault() {
|
||||
e.aconst_null();
|
||||
e.return_value();
|
||||
}
|
||||
@@ -140,8 +127,7 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
e.load_arg(1);
|
||||
e.checkcast(Constants.TYPE_STRING);
|
||||
EmitUtils.string_switch(e, getNames(setters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
|
||||
@Override
|
||||
public void processCase(Object key, Label end) {
|
||||
public void processCase(Object key, Label end) {
|
||||
PropertyDescriptor pd = (PropertyDescriptor)setters.get(key);
|
||||
if (pd.getReadMethod() == null) {
|
||||
e.aconst_null();
|
||||
@@ -158,8 +144,7 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
e.invoke(write);
|
||||
e.return_value();
|
||||
}
|
||||
@Override
|
||||
public void processDefault() {
|
||||
public void processDefault() {
|
||||
// fall-through
|
||||
}
|
||||
});
|
||||
@@ -167,7 +152,7 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
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);
|
||||
@@ -193,14 +178,12 @@ class BeanMapEmitter extends ClassEmitter {
|
||||
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() {
|
||||
@Override
|
||||
public void processCase(Object key, Label end) {
|
||||
public void processCase(Object key, Label end) {
|
||||
PropertyDescriptor pd = (PropertyDescriptor)allProps.get(key);
|
||||
EmitUtils.load_class(e, Type.getType(pd.getPropertyType()));
|
||||
e.return_value();
|
||||
}
|
||||
@Override
|
||||
public void processDefault() {
|
||||
public void processDefault() {
|
||||
e.aconst_null();
|
||||
e.return_value();
|
||||
}
|
||||
|
||||
@@ -16,11 +16,8 @@
|
||||
package org.springframework.cglib.beans;
|
||||
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.cglib.core.AbstractClassGenerator;
|
||||
import org.springframework.cglib.core.KeyFactory;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
|
||||
/**
|
||||
* @author Juozas Baliuka
|
||||
@@ -28,123 +25,118 @@ import org.springframework.cglib.core.ReflectUtils;
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class BulkBean
|
||||
{
|
||||
private static final BulkBeanKey KEY_FACTORY =
|
||||
(BulkBeanKey)KeyFactory.create(BulkBeanKey.class);
|
||||
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);
|
||||
|
||||
interface BulkBeanKey {
|
||||
public Object newInstance(String target, String[] getters, String[] setters, String[] types);
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
protected Class target;
|
||||
protected String[] getters, setters;
|
||||
protected Class[] types;
|
||||
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();
|
||||
}
|
||||
|
||||
protected BulkBean() { }
|
||||
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;
|
||||
|
||||
abstract public void getPropertyValues(Object bean, Object[] values);
|
||||
abstract public void setPropertyValues(Object bean, Object[] values);
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
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;
|
||||
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 setGetters(String[] getters) {
|
||||
this.getters = getters;
|
||||
}
|
||||
|
||||
public void setSetters(String[] setters) {
|
||||
this.setters = setters;
|
||||
}
|
||||
public void setSetters(String[] setters) {
|
||||
this.setters = setters;
|
||||
}
|
||||
|
||||
public void setTypes(Class[] types) {
|
||||
this.types = types;
|
||||
}
|
||||
public void setTypes(Class[] types) {
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return target.getClassLoader();
|
||||
}
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return target.getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(target);
|
||||
}
|
||||
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 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
new BulkBeanEmitter(v, getClassName(), target, getters, setters, types);
|
||||
}
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
new BulkBeanEmitter(v, getClassName(), target, getters, setters, types);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object firstInstance(Class type) {
|
||||
BulkBean instance = (BulkBean)ReflectUtils.newInstance(type);
|
||||
instance.target = target;
|
||||
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);
|
||||
|
||||
int length = getters.length;
|
||||
instance.getters = new String[length];
|
||||
System.arraycopy(getters, 0, instance.getters, 0, length);
|
||||
return instance;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object nextInstance(Object instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
protected Object nextInstance(Object instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,19 +17,9 @@ package org.springframework.cglib.beans;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.cglib.core.Block;
|
||||
import org.springframework.cglib.core.ClassEmitter;
|
||||
import org.springframework.cglib.core.CodeEmitter;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.EmitUtils;
|
||||
import org.springframework.cglib.core.Local;
|
||||
import org.springframework.cglib.core.MethodInfo;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.cglib.core.Signature;
|
||||
import org.springframework.cglib.core.TypeUtils;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class BulkBeanEmitter extends ClassEmitter {
|
||||
@@ -43,7 +33,7 @@ class BulkBeanEmitter extends ClassEmitter {
|
||||
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,
|
||||
@@ -126,7 +116,7 @@ class BulkBeanEmitter extends ClassEmitter {
|
||||
}
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
|
||||
private static void validate(Class target,
|
||||
String[] getters,
|
||||
String[] setters,
|
||||
|
||||
@@ -20,7 +20,7 @@ public class BulkBeanException extends RuntimeException
|
||||
{
|
||||
private int index;
|
||||
private Throwable cause;
|
||||
|
||||
|
||||
public BulkBeanException(String message, int index) {
|
||||
super(message);
|
||||
this.index = index;
|
||||
@@ -35,9 +35,8 @@ public class BulkBeanException extends RuntimeException
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getCause() {
|
||||
|
||||
public Throwable getCause() {
|
||||
return cause;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,7 @@
|
||||
*/
|
||||
package org.springframework.cglib.beans;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public /* need it for class loading */ class FixedKeySet extends AbstractSet {
|
||||
@@ -32,13 +27,11 @@ public /* need it for class loading */ class FixedKeySet extends AbstractSet {
|
||||
set = Collections.unmodifiableSet(new HashSet(Arrays.asList(keys)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator iterator() {
|
||||
public Iterator iterator() {
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,129 +18,115 @@ 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;
|
||||
import org.springframework.cglib.core.AbstractClassGenerator;
|
||||
import org.springframework.cglib.core.ClassEmitter;
|
||||
import org.springframework.cglib.core.CodeEmitter;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.EmitUtils;
|
||||
import org.springframework.cglib.core.MethodInfo;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.cglib.core.Signature;
|
||||
import org.springframework.cglib.core.TypeUtils;
|
||||
/**
|
||||
* @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 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() {
|
||||
}
|
||||
private ImmutableBean() {
|
||||
}
|
||||
|
||||
public static Object create(Object bean) {
|
||||
Generator gen = new Generator();
|
||||
gen.setBean(bean);
|
||||
return gen.create();
|
||||
}
|
||||
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 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 Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
target = bean.getClass();
|
||||
public void setBean(Object bean) {
|
||||
this.bean = bean;
|
||||
target = bean.getClass();
|
||||
// SPRING PATCH BEGIN
|
||||
setContextClass(target);
|
||||
// SPRING PATCH END
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return target.getClassLoader();
|
||||
}
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return target.getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(target);
|
||||
}
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(target);
|
||||
}
|
||||
|
||||
public Object create() {
|
||||
String name = target.getName();
|
||||
setNamePrefix(name);
|
||||
return super.create(name);
|
||||
}
|
||||
public Object create() {
|
||||
String name = target.getName();
|
||||
setNamePrefix(name);
|
||||
return super.create(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
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);
|
||||
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();
|
||||
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);
|
||||
PropertyDescriptor[] descriptors = ReflectUtils.getBeanProperties(target);
|
||||
Method[] getters = ReflectUtils.getPropertyMethods(descriptors, true, false);
|
||||
Method[] setters = ReflectUtils.getPropertyMethods(descriptors, false, true);
|
||||
|
||||
for (Method getter2 : getters) {
|
||||
MethodInfo getter = ReflectUtils.getMethodInfo(getter2);
|
||||
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 < 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 (Method setter2 : setters) {
|
||||
MethodInfo setter = ReflectUtils.getMethodInfo(setter2);
|
||||
e = EmitUtils.begin_method(ce, setter, Constants.ACC_PUBLIC);
|
||||
e.throw_exception(ILLEGAL_STATE_EXCEPTION, "Bean is immutable");
|
||||
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();
|
||||
}
|
||||
ce.end_class();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object firstInstance(Class type) {
|
||||
return ReflectUtils.newInstance(type, OBJECT_CLASSES, new Object[]{ bean });
|
||||
}
|
||||
protected Object firstInstance(Class type) {
|
||||
return ReflectUtils.newInstance(type, OBJECT_CLASSES, new Object[]{ bean });
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
@Override
|
||||
protected Object nextInstance(Object instance) {
|
||||
return firstInstance(instance.getClass());
|
||||
}
|
||||
}
|
||||
// TODO: optimize
|
||||
protected Object nextInstance(Object instance) {
|
||||
return firstInstance(instance.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author 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,6 @@ import org.springframework.util.ReflectionUtils;
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sam Brannen
|
||||
* @since 4.2.3
|
||||
*/
|
||||
public final class MethodIntrospector {
|
||||
@@ -76,7 +75,6 @@ public final class MethodIntrospector {
|
||||
if (result != null) {
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
||||
if (bridgedMethod == specificMethod || bridgedMethod == method ||
|
||||
bridgedMethod.equals(specificMethod) || bridgedMethod.equals(method) ||
|
||||
metadataLookup.inspect(bridgedMethod) == null) {
|
||||
methodMap.put(specificMethod, result);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -98,9 +98,7 @@ public final class ReactiveTypeDescriptor {
|
||||
*/
|
||||
public Object getEmptyValue() {
|
||||
Assert.state(this.emptySupplier != null, "Empty values not supported");
|
||||
Object emptyValue = this.emptySupplier.get();
|
||||
Assert.notNull(emptyValue, "Invalid null return value from emptySupplier");
|
||||
return emptyValue;
|
||||
return this.emptySupplier.get();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,7 +130,7 @@ public final class ReactiveTypeDescriptor {
|
||||
|
||||
|
||||
/**
|
||||
* Descriptor for a reactive type that can produce {@code 0..N} values.
|
||||
* Descriptor for a reactive type that can produce 0..N values.
|
||||
* @param type the reactive type
|
||||
* @param emptySupplier a supplier of an empty-value instance of the reactive type
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -138,7 +138,7 @@ public class ResolvableType implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* Private constructor used to create a new {@code ResolvableType} for cache key purposes,
|
||||
* Private constructor used to create a new {@link ResolvableType} for cache key purposes,
|
||||
* with no upfront resolution.
|
||||
*/
|
||||
private ResolvableType(
|
||||
@@ -153,7 +153,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor used to create a new {@code ResolvableType} for cache value purposes,
|
||||
* Private constructor used to create a new {@link ResolvableType} for cache value purposes,
|
||||
* with upfront resolution and a pre-calculated hash.
|
||||
* @since 4.2
|
||||
*/
|
||||
@@ -169,7 +169,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor used to create a new {@code ResolvableType} for uncached purposes,
|
||||
* Private constructor used to create a new {@link ResolvableType} for uncached purposes,
|
||||
* with upfront resolution but lazily calculated hash.
|
||||
*/
|
||||
private ResolvableType(Type type, @Nullable TypeProvider typeProvider,
|
||||
@@ -184,7 +184,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor used to create a new {@code ResolvableType} on a {@link Class} basis.
|
||||
* Private constructor used to create a new {@link ResolvableType} on a {@link Class} basis.
|
||||
* <p>Avoids all {@code instanceof} checks in order to create a straight {@link Class} wrapper.
|
||||
* @since 4.2
|
||||
*/
|
||||
@@ -223,7 +223,7 @@ public class ResolvableType implements Serializable {
|
||||
|
||||
/**
|
||||
* Return the underlying source of the resolvable type. Will return a {@link Field},
|
||||
* {@link MethodParameter} or {@link Type} depending on how the {@code ResolvableType}
|
||||
* {@link MethodParameter} or {@link Type} depending on how the {@link ResolvableType}
|
||||
* was constructed. This method is primarily to provide access to additional type
|
||||
* information or meta-data that alternative JVM languages may provide.
|
||||
*/
|
||||
@@ -341,14 +341,13 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
}
|
||||
if (ourResolved == null) {
|
||||
ourResolved = toClass();
|
||||
ourResolved = resolve(Object.class);
|
||||
}
|
||||
Class<?> otherResolved = other.toClass();
|
||||
|
||||
// We need an exact type match for generics
|
||||
// List<CharSequence> is not assignable from List<String>
|
||||
if (exactMatch ? !ourResolved.equals(otherResolved) :
|
||||
!ClassUtils.isAssignable(ourResolved, otherResolved)) {
|
||||
if (exactMatch ? !ourResolved.equals(otherResolved) : !ClassUtils.isAssignable(ourResolved, otherResolved)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -359,15 +358,13 @@ public class ResolvableType implements Serializable {
|
||||
if (ourGenerics.length != typeGenerics.length) {
|
||||
return false;
|
||||
}
|
||||
if (ourGenerics.length > 0) {
|
||||
if (matchedBefore == null) {
|
||||
matchedBefore = new IdentityHashMap<>(1);
|
||||
}
|
||||
matchedBefore.put(this.type, other.type);
|
||||
for (int i = 0; i < ourGenerics.length; i++) {
|
||||
if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], matchedBefore)) {
|
||||
return false;
|
||||
}
|
||||
if (matchedBefore == null) {
|
||||
matchedBefore = new IdentityHashMap<>(1);
|
||||
}
|
||||
matchedBefore.put(this.type, other.type);
|
||||
for (int i = 0; i < ourGenerics.length; i++) {
|
||||
if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], matchedBefore)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -432,12 +429,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this type as a {@code ResolvableType} of the specified class. Searches
|
||||
* Return this type as a {@link ResolvableType} of the specified class. Searches
|
||||
* {@link #getSuperType() supertype} and {@link #getInterfaces() interface}
|
||||
* hierarchies to find a match, returning {@link #NONE} if this type does not
|
||||
* implement or extend the specified class.
|
||||
* @param type the required type (typically narrowed)
|
||||
* @return a {@code ResolvableType} representing this object as the specified
|
||||
* @return a {@link ResolvableType} representing this object as the specified
|
||||
* type, or {@link #NONE} if not resolvable as that type
|
||||
* @see #asCollection()
|
||||
* @see #asMap()
|
||||
@@ -462,9 +459,9 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} representing the direct supertype of this type.
|
||||
* Return a {@link ResolvableType} representing the direct supertype of this type.
|
||||
* <p>If no supertype is available this method returns {@link #NONE}.
|
||||
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
|
||||
* @see #getInterfaces()
|
||||
*/
|
||||
public ResolvableType getSuperType() {
|
||||
@@ -491,10 +488,10 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} array representing the direct interfaces
|
||||
* Return a {@link ResolvableType} array representing the direct interfaces
|
||||
* implemented by this type. If this type does not implement any interfaces an
|
||||
* empty array is returned.
|
||||
* <p>Note: The resulting {@code ResolvableType} instances may not be {@link Serializable}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instances may not be {@link Serializable}.
|
||||
* @see #getSuperType()
|
||||
*/
|
||||
public ResolvableType[] getInterfaces() {
|
||||
@@ -624,17 +621,17 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified nesting level.
|
||||
* Return a {@link ResolvableType} for the specified nesting level.
|
||||
* <p>See {@link #getNested(int, Map)} for details.
|
||||
* @param nestingLevel the nesting level
|
||||
* @return the {@code ResolvableType} type, or {@code #NONE}
|
||||
* @return the {@link ResolvableType} type, or {@code #NONE}
|
||||
*/
|
||||
public ResolvableType getNested(int nestingLevel) {
|
||||
return getNested(nestingLevel, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified nesting level.
|
||||
* Return a {@link ResolvableType} for the specified nesting level.
|
||||
* <p>The nesting level refers to the specific generic parameter that should be returned.
|
||||
* A nesting level of 1 indicates this type; 2 indicates the first nested generic;
|
||||
* 3 the second; and so on. For example, given {@code List<Set<Integer>>} level 1 refers
|
||||
@@ -651,7 +648,7 @@ public class ResolvableType implements Serializable {
|
||||
* current type, 2 for the first nested generic, 3 for the second and so on
|
||||
* @param typeIndexesPerLevel a map containing the generic index for a given
|
||||
* nesting level (may be {@code null})
|
||||
* @return a {@code ResolvableType} for the nested level, or {@link #NONE}
|
||||
* @return a {@link ResolvableType} for the nested level, or {@link #NONE}
|
||||
*/
|
||||
public ResolvableType getNested(int nestingLevel, @Nullable Map<Integer, Integer> typeIndexesPerLevel) {
|
||||
ResolvableType result = this;
|
||||
@@ -673,7 +670,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} representing the generic parameter for the
|
||||
* Return a {@link ResolvableType} representing the generic parameter for the
|
||||
* given indexes. Indexes are zero based; for example given the type
|
||||
* {@code Map<Integer, List<String>>}, {@code getGeneric(0)} will access the
|
||||
* {@code Integer}. Nested generics can be accessed by specifying multiple indexes;
|
||||
@@ -683,7 +680,7 @@ public class ResolvableType implements Serializable {
|
||||
* <p>If no generic is available at the specified indexes {@link #NONE} is returned.
|
||||
* @param indexes the indexes that refer to the generic parameter
|
||||
* (may be omitted to return the first generic)
|
||||
* @return a {@code ResolvableType} for the specified generic, or {@link #NONE}
|
||||
* @return a {@link ResolvableType} for the specified generic, or {@link #NONE}
|
||||
* @see #hasGenerics()
|
||||
* @see #getGenerics()
|
||||
* @see #resolveGeneric(int...)
|
||||
@@ -706,12 +703,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of {@code ResolvableType ResolvableTypes} representing the generic parameters of
|
||||
* Return an array of {@link ResolvableType ResolvableTypes} representing the generic parameters of
|
||||
* this type. If no generics are available an empty array is returned. If you need to
|
||||
* access a specific generic consider using the {@link #getGeneric(int...)} method as
|
||||
* it allows access to nested generics and protects against
|
||||
* {@code IndexOutOfBoundsExceptions}.
|
||||
* @return an array of {@code ResolvableType ResolvableTypes} representing the generic parameters
|
||||
* @return an array of {@link ResolvableType ResolvableTypes} representing the generic parameters
|
||||
* (never {@code null})
|
||||
* @see #hasGenerics()
|
||||
* @see #getGeneric(int...)
|
||||
@@ -750,7 +747,7 @@ public class ResolvableType implements Serializable {
|
||||
* Convenience method that will {@link #getGenerics() get} and
|
||||
* {@link #resolve() resolve} generic parameters.
|
||||
* @return an array of resolved generic parameters (the resulting array
|
||||
* will never be {@code null}, but it may contain {@code null} elements)
|
||||
* will never be {@code null}, but it may contain {@code null} elements})
|
||||
* @see #getGenerics()
|
||||
* @see #resolve()
|
||||
*/
|
||||
@@ -783,7 +780,7 @@ public class ResolvableType implements Serializable {
|
||||
|
||||
/**
|
||||
* Convenience method that will {@link #getGeneric(int...) get} and
|
||||
* {@link #resolve() resolve} a specific generic parameter.
|
||||
* {@link #resolve() resolve} a specific generic parameters.
|
||||
* @param indexes the indexes that refer to the generic parameter
|
||||
* (may be omitted to return the first generic)
|
||||
* @return a resolved {@link Class} or {@code null}
|
||||
@@ -845,7 +842,7 @@ public class ResolvableType implements Serializable {
|
||||
|
||||
/**
|
||||
* Resolve this type by a single level, returning the resolved value or {@link #NONE}.
|
||||
* <p>Note: The returned {@code ResolvableType} should only be used as an intermediary
|
||||
* <p>Note: The returned {@link ResolvableType} should only be used as an intermediary
|
||||
* as it cannot be serialized.
|
||||
*/
|
||||
ResolvableType resolveType() {
|
||||
@@ -967,7 +964,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts this {@code ResolvableType} to a {@link VariableResolver}.
|
||||
* Adapts this {@link ResolvableType} to a {@link VariableResolver}.
|
||||
*/
|
||||
@Nullable
|
||||
VariableResolver asVariableResolver() {
|
||||
@@ -1014,12 +1011,12 @@ public class ResolvableType implements Serializable {
|
||||
// Factory methods
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Class},
|
||||
* Return a {@link ResolvableType} for the specified {@link Class},
|
||||
* using the full generic type information for assignability checks.
|
||||
* <p>For example: {@code ResolvableType.forClass(MyArrayList.class)}.
|
||||
* @param clazz the class to introspect ({@code null} is semantically
|
||||
* equivalent to {@code Object.class} for typical use cases here)
|
||||
* @return a {@code ResolvableType} for the specified class
|
||||
* @return a {@link ResolvableType} for the specified class
|
||||
* @see #forClass(Class, Class)
|
||||
* @see #forClassWithGenerics(Class, Class...)
|
||||
*/
|
||||
@@ -1028,13 +1025,13 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Class},
|
||||
* Return a {@link ResolvableType} for the specified {@link Class},
|
||||
* doing assignability checks against the raw class only (analogous to
|
||||
* {@link Class#isAssignableFrom}, which this serves as a wrapper for).
|
||||
* <p>For example: {@code ResolvableType.forRawClass(List.class)}.
|
||||
* @param clazz the class to introspect ({@code null} is semantically
|
||||
* equivalent to {@code Object.class} for typical use cases here)
|
||||
* @return a {@code ResolvableType} for the specified class
|
||||
* @return a {@link ResolvableType} for the specified class
|
||||
* @since 4.2
|
||||
* @see #forClass(Class)
|
||||
* @see #getRawClass()
|
||||
@@ -1058,12 +1055,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified base type
|
||||
* Return a {@link ResolvableType} for the specified base type
|
||||
* (interface or base class) with a given implementation class.
|
||||
* <p>For example: {@code ResolvableType.forClass(List.class, MyArrayList.class)}.
|
||||
* @param baseType the base type (must not be {@code null})
|
||||
* @param implementationClass the implementation class
|
||||
* @return a {@code ResolvableType} for the specified base type backed by the
|
||||
* @return a {@link ResolvableType} for the specified base type backed by the
|
||||
* given implementation class
|
||||
* @see #forClass(Class)
|
||||
* @see #forClassWithGenerics(Class, Class...)
|
||||
@@ -1075,10 +1072,10 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Class} with pre-declared generics.
|
||||
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
|
||||
* @param clazz the class (or interface) to introspect
|
||||
* @param generics the generics of the class
|
||||
* @return a {@code ResolvableType} for the specific class and generics
|
||||
* @return a {@link ResolvableType} for the specific class and generics
|
||||
* @see #forClassWithGenerics(Class, ResolvableType...)
|
||||
*/
|
||||
public static ResolvableType forClassWithGenerics(Class<?> clazz, Class<?>... generics) {
|
||||
@@ -1092,10 +1089,10 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Class} with pre-declared generics.
|
||||
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
|
||||
* @param clazz the class (or interface) to introspect
|
||||
* @param generics the generics of the class
|
||||
* @return a {@code ResolvableType} for the specific class and generics
|
||||
* @return a {@link ResolvableType} for the specific class and generics
|
||||
* @see #forClassWithGenerics(Class, Class...)
|
||||
*/
|
||||
public static ResolvableType forClassWithGenerics(Class<?> clazz, ResolvableType... generics) {
|
||||
@@ -1116,12 +1113,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified instance. The instance does not
|
||||
* Return a {@link ResolvableType} for the specified instance. The instance does not
|
||||
* convey generic information but if it implements {@link ResolvableTypeProvider} a
|
||||
* more precise {@code ResolvableType} can be used than the simple one based on
|
||||
* more precise {@link ResolvableType} can be used than the simple one based on
|
||||
* the {@link #forClass(Class) Class instance}.
|
||||
* @param instance the instance (possibly {@code null})
|
||||
* @return a {@code ResolvableType} for the specified instance,
|
||||
* @return a {@link ResolvableType} for the specified instance,
|
||||
* or {@code NONE} for {@code null}
|
||||
* @since 4.2
|
||||
* @see ResolvableTypeProvider
|
||||
@@ -1137,9 +1134,9 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Field}.
|
||||
* Return a {@link ResolvableType} for the specified {@link Field}.
|
||||
* @param field the source field
|
||||
* @return a {@code ResolvableType} for the specified field
|
||||
* @return a {@link ResolvableType} for the specified field
|
||||
* @see #forField(Field, Class)
|
||||
*/
|
||||
public static ResolvableType forField(Field field) {
|
||||
@@ -1148,13 +1145,13 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Field} with a given
|
||||
* Return a {@link ResolvableType} for the specified {@link Field} with a given
|
||||
* implementation.
|
||||
* <p>Use this variant when the class that declares the field includes generic
|
||||
* parameter variables that are satisfied by the implementation class.
|
||||
* @param field the source field
|
||||
* @param implementationClass the implementation class
|
||||
* @return a {@code ResolvableType} for the specified field
|
||||
* @return a {@link ResolvableType} for the specified field
|
||||
* @see #forField(Field)
|
||||
*/
|
||||
public static ResolvableType forField(Field field, Class<?> implementationClass) {
|
||||
@@ -1164,13 +1161,13 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Field} with a given
|
||||
* Return a {@link ResolvableType} for the specified {@link Field} with a given
|
||||
* implementation.
|
||||
* <p>Use this variant when the class that declares the field includes generic
|
||||
* parameter variables that are satisfied by the implementation type.
|
||||
* @param field the source field
|
||||
* @param implementationType the implementation type
|
||||
* @return a {@code ResolvableType} for the specified field
|
||||
* @return a {@link ResolvableType} for the specified field
|
||||
* @see #forField(Field)
|
||||
*/
|
||||
public static ResolvableType forField(Field field, @Nullable ResolvableType implementationType) {
|
||||
@@ -1181,7 +1178,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Field} with the
|
||||
* Return a {@link ResolvableType} for the specified {@link Field} with the
|
||||
* given nesting level.
|
||||
* @param field the source field
|
||||
* @param nestingLevel the nesting level (1 for the outer level; 2 for a nested
|
||||
@@ -1194,7 +1191,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Field} with a given
|
||||
* Return a {@link ResolvableType} for the specified {@link Field} with a given
|
||||
* implementation and the given nesting level.
|
||||
* <p>Use this variant when the class that declares the field includes generic
|
||||
* parameter variables that are satisfied by the implementation class.
|
||||
@@ -1202,7 +1199,7 @@ public class ResolvableType implements Serializable {
|
||||
* @param nestingLevel the nesting level (1 for the outer level; 2 for a nested
|
||||
* generic type; etc)
|
||||
* @param implementationClass the implementation class
|
||||
* @return a {@code ResolvableType} for the specified field
|
||||
* @return a {@link ResolvableType} for the specified field
|
||||
* @see #forField(Field)
|
||||
*/
|
||||
public static ResolvableType forField(Field field, int nestingLevel, @Nullable Class<?> implementationClass) {
|
||||
@@ -1212,10 +1209,10 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Constructor} parameter.
|
||||
* Return a {@link ResolvableType} for the specified {@link Constructor} parameter.
|
||||
* @param constructor the source constructor (must not be {@code null})
|
||||
* @param parameterIndex the parameter index
|
||||
* @return a {@code ResolvableType} for the specified constructor parameter
|
||||
* @return a {@link ResolvableType} for the specified constructor parameter
|
||||
* @see #forConstructorParameter(Constructor, int, Class)
|
||||
*/
|
||||
public static ResolvableType forConstructorParameter(Constructor<?> constructor, int parameterIndex) {
|
||||
@@ -1224,14 +1221,14 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Constructor} parameter
|
||||
* Return a {@link ResolvableType} for the specified {@link Constructor} parameter
|
||||
* with a given implementation. Use this variant when the class that declares the
|
||||
* constructor includes generic parameter variables that are satisfied by the
|
||||
* implementation class.
|
||||
* @param constructor the source constructor (must not be {@code null})
|
||||
* @param parameterIndex the parameter index
|
||||
* @param implementationClass the implementation class
|
||||
* @return a {@code ResolvableType} for the specified constructor parameter
|
||||
* @return a {@link ResolvableType} for the specified constructor parameter
|
||||
* @see #forConstructorParameter(Constructor, int)
|
||||
*/
|
||||
public static ResolvableType forConstructorParameter(Constructor<?> constructor, int parameterIndex,
|
||||
@@ -1243,9 +1240,9 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Method} return type.
|
||||
* Return a {@link ResolvableType} for the specified {@link Method} return type.
|
||||
* @param method the source for the method return type
|
||||
* @return a {@code ResolvableType} for the specified method return
|
||||
* @return a {@link ResolvableType} for the specified method return
|
||||
* @see #forMethodReturnType(Method, Class)
|
||||
*/
|
||||
public static ResolvableType forMethodReturnType(Method method) {
|
||||
@@ -1254,12 +1251,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Method} return type.
|
||||
* Return a {@link ResolvableType} for the specified {@link Method} return type.
|
||||
* <p>Use this variant when the class that declares the method includes generic
|
||||
* parameter variables that are satisfied by the implementation class.
|
||||
* @param method the source for the method return type
|
||||
* @param implementationClass the implementation class
|
||||
* @return a {@code ResolvableType} for the specified method return
|
||||
* @return a {@link ResolvableType} for the specified method return
|
||||
* @see #forMethodReturnType(Method)
|
||||
*/
|
||||
public static ResolvableType forMethodReturnType(Method method, Class<?> implementationClass) {
|
||||
@@ -1269,10 +1266,10 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Method} parameter.
|
||||
* Return a {@link ResolvableType} for the specified {@link Method} parameter.
|
||||
* @param method the source method (must not be {@code null})
|
||||
* @param parameterIndex the parameter index
|
||||
* @return a {@code ResolvableType} for the specified method parameter
|
||||
* @return a {@link ResolvableType} for the specified method parameter
|
||||
* @see #forMethodParameter(Method, int, Class)
|
||||
* @see #forMethodParameter(MethodParameter)
|
||||
*/
|
||||
@@ -1282,13 +1279,13 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Method} parameter with a
|
||||
* Return a {@link ResolvableType} for the specified {@link Method} parameter with a
|
||||
* given implementation. Use this variant when the class that declares the method
|
||||
* includes generic parameter variables that are satisfied by the implementation class.
|
||||
* @param method the source method (must not be {@code null})
|
||||
* @param parameterIndex the parameter index
|
||||
* @param implementationClass the implementation class
|
||||
* @return a {@code ResolvableType} for the specified method parameter
|
||||
* @return a {@link ResolvableType} for the specified method parameter
|
||||
* @see #forMethodParameter(Method, int, Class)
|
||||
* @see #forMethodParameter(MethodParameter)
|
||||
*/
|
||||
@@ -1299,9 +1296,9 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link MethodParameter}.
|
||||
* Return a {@link ResolvableType} for the specified {@link MethodParameter}.
|
||||
* @param methodParameter the source method parameter (must not be {@code null})
|
||||
* @return a {@code ResolvableType} for the specified method parameter
|
||||
* @return a {@link ResolvableType} for the specified method parameter
|
||||
* @see #forMethodParameter(Method, int)
|
||||
*/
|
||||
public static ResolvableType forMethodParameter(MethodParameter methodParameter) {
|
||||
@@ -1309,12 +1306,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link MethodParameter} with a
|
||||
* Return a {@link ResolvableType} for the specified {@link MethodParameter} with a
|
||||
* given implementation type. Use this variant when the class that declares the method
|
||||
* includes generic parameter variables that are satisfied by the implementation type.
|
||||
* @param methodParameter the source method parameter (must not be {@code null})
|
||||
* @param implementationType the implementation type
|
||||
* @return a {@code ResolvableType} for the specified method parameter
|
||||
* @return a {@link ResolvableType} for the specified method parameter
|
||||
* @see #forMethodParameter(MethodParameter)
|
||||
*/
|
||||
public static ResolvableType forMethodParameter(MethodParameter methodParameter,
|
||||
@@ -1329,11 +1326,11 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link MethodParameter},
|
||||
* Return a {@link ResolvableType} for the specified {@link MethodParameter},
|
||||
* overriding the target type to resolve with a specific given type.
|
||||
* @param methodParameter the source method parameter (must not be {@code null})
|
||||
* @param targetType the type to resolve (a part of the method parameter's type)
|
||||
* @return a {@code ResolvableType} for the specified method parameter
|
||||
* @return a {@link ResolvableType} for the specified method parameter
|
||||
* @see #forMethodParameter(Method, int)
|
||||
*/
|
||||
public static ResolvableType forMethodParameter(MethodParameter methodParameter, @Nullable Type targetType) {
|
||||
@@ -1342,13 +1339,13 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link MethodParameter} at
|
||||
* Return a {@link ResolvableType} for the specified {@link MethodParameter} at
|
||||
* a specific nesting level, overriding the target type to resolve with a specific
|
||||
* given type.
|
||||
* @param methodParameter the source method parameter (must not be {@code null})
|
||||
* @param targetType the type to resolve (a part of the method parameter's type)
|
||||
* @param nestingLevel the nesting level to use
|
||||
* @return a {@code ResolvableType} for the specified method parameter
|
||||
* @return a {@link ResolvableType} for the specified method parameter
|
||||
* @since 5.2
|
||||
* @see #forMethodParameter(Method, int)
|
||||
*/
|
||||
@@ -1361,9 +1358,9 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} as an array of the specified {@code componentType}.
|
||||
* Return a {@link ResolvableType} as an array of the specified {@code componentType}.
|
||||
* @param componentType the component type
|
||||
* @return a {@code ResolvableType} as an array of the specified component type
|
||||
* @return a {@link ResolvableType} as an array of the specified component type
|
||||
*/
|
||||
public static ResolvableType forArrayComponent(ResolvableType componentType) {
|
||||
Assert.notNull(componentType, "Component type must not be null");
|
||||
@@ -1372,10 +1369,10 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Type}.
|
||||
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
|
||||
* Return a {@link ResolvableType} for the specified {@link Type}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
|
||||
* @param type the source type (potentially {@code null})
|
||||
* @return a {@code ResolvableType} for the specified {@link Type}
|
||||
* @return a {@link ResolvableType} for the specified {@link Type}
|
||||
* @see #forType(Type, ResolvableType)
|
||||
*/
|
||||
public static ResolvableType forType(@Nullable Type type) {
|
||||
@@ -1383,12 +1380,12 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Type} backed by the given
|
||||
* Return a {@link ResolvableType} for the specified {@link Type} backed by the given
|
||||
* owner type.
|
||||
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
|
||||
* @param type the source type or {@code null}
|
||||
* @param owner the owner type used to resolve variables
|
||||
* @return a {@code ResolvableType} for the specified {@link Type} and owner
|
||||
* @return a {@link ResolvableType} for the specified {@link Type} and owner
|
||||
* @see #forType(Type)
|
||||
*/
|
||||
public static ResolvableType forType(@Nullable Type type, @Nullable ResolvableType owner) {
|
||||
@@ -1401,10 +1398,10 @@ public class ResolvableType implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link ParameterizedTypeReference}.
|
||||
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
|
||||
* Return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
|
||||
* @param typeReference the reference to obtain the source type from
|
||||
* @return a {@code ResolvableType} for the specified {@link ParameterizedTypeReference}
|
||||
* @return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}
|
||||
* @since 4.3.12
|
||||
* @see #forType(Type)
|
||||
*/
|
||||
@@ -1413,23 +1410,23 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Type} backed by a given
|
||||
* Return a {@link ResolvableType} for the specified {@link Type} backed by a given
|
||||
* {@link VariableResolver}.
|
||||
* @param type the source type or {@code null}
|
||||
* @param variableResolver the variable resolver or {@code null}
|
||||
* @return a {@code ResolvableType} for the specified {@link Type} and {@link VariableResolver}
|
||||
* @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver}
|
||||
*/
|
||||
static ResolvableType forType(@Nullable Type type, @Nullable VariableResolver variableResolver) {
|
||||
return forType(type, null, variableResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@code ResolvableType} for the specified {@link Type} backed by a given
|
||||
* Return a {@link ResolvableType} for the specified {@link Type} backed by a given
|
||||
* {@link VariableResolver}.
|
||||
* @param type the source type or {@code null}
|
||||
* @param typeProvider the type provider or {@code null}
|
||||
* @param variableResolver the variable resolver or {@code null}
|
||||
* @return a {@code ResolvableType} for the specified {@link Type} and {@link VariableResolver}
|
||||
* @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver}
|
||||
*/
|
||||
static ResolvableType forType(
|
||||
@Nullable Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user