mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
253 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3bea4682b7 | |||
| be17c8d85f | |||
| b73f5fcac2 | |||
| bc1511d667 | |||
| db9b139cf0 | |||
| bd029b9218 | |||
| 5f2264816a | |||
| a8f31f5b9e | |||
| 90627b4345 | |||
| 4acc71b282 | |||
| cd0379a67f | |||
| e262e98bab | |||
| 59c65fa940 | |||
| 695601aa06 | |||
| 8f5a1fe7e2 | |||
| 073226d792 | |||
| 1abe155663 | |||
| 33ef9107e0 | |||
| 8463eade33 | |||
| e77faf7484 | |||
| b23cc01cb7 | |||
| 01f97887ea | |||
| cef597bedd | |||
| 01fabfe66d | |||
| c811428512 | |||
| b5b115e52c | |||
| 310344cf61 | |||
| 2bac371c5b | |||
| cef9166833 | |||
| d6460e0d57 | |||
| 842490beeb | |||
| e746230de6 | |||
| 8161316b1d | |||
| 1734deca1e | |||
| dd97ee4e99 | |||
| 90b0f451f0 | |||
| 9fb61c57ae | |||
| f9cb0eba87 | |||
| d1d2d5943e | |||
| 281736f14e | |||
| 6bfc70b61e | |||
| 95883b9eb7 | |||
| f0eb43a6af | |||
| 6c8ebc7f7e | |||
| 69c8f8e9c7 | |||
| 02f2d94f57 | |||
| 7fcbc869a6 | |||
| 4eed2ced74 | |||
| 98f1287f3a | |||
| 8234fa2a13 | |||
| 8b9d2e3f95 | |||
| 534d1cd35b | |||
| ca545ac3d4 | |||
| ca7c2779bf | |||
| 4a90257a84 | |||
| 49a4ed2ffa | |||
| 717d03a29d | |||
| 2b427efe7f | |||
| 3632bea51e | |||
| 1efa162cf0 | |||
| a8b7a5e037 | |||
| 807325916f | |||
| d451d6adcc | |||
| 8fca258207 | |||
| d126b99c91 | |||
| c5f0f7bb11 | |||
| 3a36d51473 | |||
| fe6589d5af | |||
| b374824319 | |||
| 7e905e3e00 | |||
| 491ae1e3be | |||
| 66cdf43b56 | |||
| 2ba206f8ba | |||
| 5ba6944145 | |||
| 5609e67100 | |||
| b2be07c73c | |||
| ce2689eead | |||
| 2184d4e80e | |||
| 50d01ce405 | |||
| 0c0cda9815 | |||
| 47aca90c58 | |||
| ddd6b123bb | |||
| ec270c7135 | |||
| 7cc72ddf7a | |||
| 5f0ee2e4dd | |||
| 43031509c8 | |||
| e66c80667f | |||
| 84714fbae9 | |||
| 0ca02ce677 | |||
| db29b65399 | |||
| 18adf905a8 | |||
| ce9a72f95c | |||
| dfb4a951ae | |||
| d9776941bf | |||
| 24b359d519 | |||
| ae70bf7c38 | |||
| c68e986b75 | |||
| 2bc1aa7827 | |||
| 570d21ebbd | |||
| 800b13492b | |||
| 4e896c8125 | |||
| 9421fe1d75 | |||
| 37a4e84450 | |||
| c27a5687dc | |||
| 4e8162c6dd | |||
| 202fa5cdb3 | |||
| 8010de8b63 | |||
| 5529294ec9 | |||
| 935c29e3dd | |||
| 4a3518b4d6 | |||
| dd4a34778b | |||
| 46bd6add15 | |||
| 19384ac8ad | |||
| a0358a4650 | |||
| 88bc504625 | |||
| 3af8efbdc7 | |||
| 2e08a07d7c | |||
| df4e7d1929 | |||
| 2a5eab4b89 | |||
| 1de36abc07 | |||
| 97b5af8a55 | |||
| 4751769a7c | |||
| 1f8e9f5c55 | |||
| c3ce847871 | |||
| cd8955fa72 | |||
| d18bcb3f3d | |||
| e17f5c50a8 | |||
| 00be19c647 | |||
| a6dab10309 | |||
| b617e16d8d | |||
| 9cf7b0e230 | |||
| 3431b2330a | |||
| 99e54fec3a | |||
| 7e32f504b0 | |||
| 268e3fec99 | |||
| 9b50c0d590 | |||
| 2e5d0470dc | |||
| d2868f5dd0 | |||
| 1acbc97b16 | |||
| e88ec06a36 | |||
| 2302358606 | |||
| d213522dfc | |||
| 95710646d1 | |||
| 6cd67412cc | |||
| e427ea8086 | |||
| d8fbd35467 | |||
| a31cfba992 | |||
| 14973fd6f3 | |||
| ffe7ec4a99 | |||
| 9b811a01f6 | |||
| 2b23d1693d | |||
| 9011ce9c68 | |||
| 29fe0a3c6a | |||
| c20efba45c | |||
| fa95bf4dc1 | |||
| eea000d034 | |||
| a6338fcc43 | |||
| dafc7a2aab | |||
| b7288a4073 | |||
| 004a144bdc | |||
| 09b60220d8 | |||
| 7f1b81ff53 | |||
| 8175a3bf09 | |||
| 7eadedae36 | |||
| cb4f93561e | |||
| f3cb331e4e | |||
| 74f6725a37 | |||
| edf0ae77e5 | |||
| 95481018d0 | |||
| 56523d5014 | |||
| 8ebd746d69 | |||
| 162c09d036 | |||
| 7766b518d3 | |||
| 24de8c6f4c | |||
| d9500e60a1 | |||
| e5d20a4f9d | |||
| 37458d28d9 | |||
| c9aba1eaad | |||
| 3854861a8a | |||
| 3dd0fbfb57 | |||
| 57b838ddda | |||
| 8c784085d2 | |||
| c0a1e1718e | |||
| fe29e734ae | |||
| 50c3a62589 | |||
| a936a6a8ce | |||
| 8d112b8514 | |||
| f8cb0fa2a0 | |||
| c56c16d7ba | |||
| df1f8139cc | |||
| 9624ea392a | |||
| 682a4d5353 | |||
| 4419d56178 | |||
| 244c97993b | |||
| 9d28fe90f5 | |||
| d2a4ac519c | |||
| dbbebf541d | |||
| fe73c630da | |||
| 3456fd054f | |||
| 5fd75dd27b | |||
| 6c29a5779e | |||
| e9413b93c6 | |||
| 4cc02fe3bc | |||
| b1cf832c28 | |||
| 34e5ce9360 | |||
| 375114defa | |||
| 00c2c1d2a1 | |||
| 7c9fc575ff | |||
| c859211f7a | |||
| 4dbe9d6709 | |||
| acedbfbaba | |||
| 5d6f151031 | |||
| a09495d4e9 | |||
| 5cab6a1f3a | |||
| a02a017e6e | |||
| 9f2f93129b | |||
| 475ac6ef5d | |||
| 79f43041ad | |||
| edb4a3467a | |||
| 024d02225c | |||
| 9305a64a50 | |||
| 40672c3715 | |||
| 7c50464bba | |||
| 0d10d4beee | |||
| f60bec986f | |||
| 6825a842b5 | |||
| 7ace9aa429 | |||
| 8979ac789f | |||
| 9cb4c5565a | |||
| 08f38c52c7 | |||
| afa936e985 | |||
| 3677d3597b | |||
| 76bc7deb8e | |||
| 6c3cb5d2e0 | |||
| 3ce71932c0 | |||
| 3a9c7524f0 | |||
| ce66b251ab | |||
| 626a7fc52a | |||
| 3d8455b257 | |||
| fd38c23699 | |||
| e47418c948 | |||
| d6de374424 | |||
| b437b7be34 | |||
| 2d56505ea9 | |||
| 8a44b6445d | |||
| 6d24e62e83 | |||
| 2d62be8590 | |||
| 2e1374b459 | |||
| bb6150e44e | |||
| 38a4f23f16 | |||
| 6739ca82ce | |||
| 88e6544d9d | |||
| 1999c78350 |
+1
-1
@@ -29,7 +29,7 @@ spring-test/test-output/
|
||||
|
||||
# Maven artifacts
|
||||
pom.xml
|
||||
target/
|
||||
/target/
|
||||
|
||||
# Eclipse artifacts, including WTP generated manifests
|
||||
bin
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# <img src="framework-docs/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)
|
||||
# <img src="framework-docs/src/docs/spring-framework.png" width="80" height="80"> Spring Framework [](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-6.0.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".
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# Security Policy
|
||||
|
||||
## JAR signing
|
||||
|
||||
Spring Framework JARs released on Maven Central are signed.
|
||||
You'll find more information about the key here: https://spring.io/GPG-KEY-spring.txt
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Please see the
|
||||
|
||||
+11
-13
@@ -1,16 +1,16 @@
|
||||
plugins {
|
||||
id 'io.spring.nohttp' version '0.0.11'
|
||||
id 'io.freefair.aspectj' version '6.5.0.3' apply false
|
||||
id 'io.freefair.aspectj' version '8.0.1' apply false
|
||||
// kotlinVersion is managed in gradle.properties
|
||||
id 'org.jetbrains.kotlin.plugin.serialization' version "${kotlinVersion}" apply false
|
||||
id 'org.jetbrains.dokka' version '1.7.20'
|
||||
id 'org.jetbrains.dokka' version '1.8.10'
|
||||
id 'org.asciidoctor.jvm.convert' version '3.3.2' apply false
|
||||
id 'org.asciidoctor.jvm.pdf' version '3.3.2' apply false
|
||||
id 'org.unbroken-dome.xjc' version '2.0.0' apply false
|
||||
id 'com.github.ben-manes.versions' version '0.42.0'
|
||||
id 'com.github.johnrengelman.shadow' version '7.1.2' apply false
|
||||
id 'de.undercouch.download' version '5.1.0'
|
||||
id 'me.champeau.jmh' version '0.6.8' apply false
|
||||
id 'com.github.ben-manes.versions' version '0.46.0'
|
||||
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
|
||||
id 'de.undercouch.download' version '5.4.0'
|
||||
id 'me.champeau.jmh' version '0.7.0' apply false
|
||||
}
|
||||
|
||||
ext {
|
||||
@@ -78,7 +78,7 @@ configure([rootProject] + javaProjects) { project ->
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
toolVersion = "10.7.0"
|
||||
toolVersion = "10.9.3"
|
||||
configDirectory.set(rootProject.file("src/checkstyle"))
|
||||
}
|
||||
|
||||
@@ -105,11 +105,11 @@ configure([rootProject] + javaProjects) { project ->
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-suite-engine")
|
||||
testRuntimeOnly("org.apache.logging.log4j:log4j-core")
|
||||
testRuntimeOnly("org.apache.logging.log4j:log4j-jul")
|
||||
testRuntimeOnly("org.apache.logging.log4j:log4j-slf4j-impl")
|
||||
testRuntimeOnly("org.apache.logging.log4j:log4j-slf4j2-impl")
|
||||
// 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.31")
|
||||
checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.38")
|
||||
}
|
||||
|
||||
ext.javadocLinks = [
|
||||
@@ -127,10 +127,8 @@ configure([rootProject] + javaProjects) { project ->
|
||||
"https://hc.apache.org/httpcomponents-client-5.2.x/current/httpclient5/apidocs/",
|
||||
"https://projectreactor.io/docs/test/release/api/",
|
||||
"https://junit.org/junit4/javadoc/4.13.2/",
|
||||
// TODO Uncomment link to JUnit 5 docs once we have sorted out
|
||||
// the following warning in the build.
|
||||
//
|
||||
// warning: The code being documented uses packages in the unnamed module, but the packages defined in https://junit.org/junit5/docs/5.9.2/api/ are in named modules.
|
||||
// TODO Uncomment link to JUnit 5 docs once we execute Gradle with Java 18+.
|
||||
// See https://github.com/spring-projects/spring-framework/issues/27497
|
||||
//
|
||||
// "https://junit.org/junit5/docs/5.9.2/api/",
|
||||
"https://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/",
|
||||
|
||||
@@ -26,8 +26,8 @@ import org.gradle.testretry.TestRetryTaskExtension;
|
||||
* Conventions that are applied in the presence of the {@link JavaBasePlugin}. When the
|
||||
* plugin is applied:
|
||||
* <ul>
|
||||
* <li>The {@link TestRetryPlugin Test Retry} plugins is applied so that flaky tests
|
||||
* are retried 3 times when running on the CI.
|
||||
* <li>The {@link TestRetryPlugin Test Retry} plugin is applied so that flaky tests
|
||||
* are retried 3 times when running on the CI server.
|
||||
* </ul>
|
||||
*
|
||||
* @author Brian Clozel
|
||||
@@ -41,7 +41,7 @@ class TestConventions {
|
||||
|
||||
private void configureTestConventions(Project project) {
|
||||
project.getTasks().withType(Test.class,
|
||||
(test) -> project.getPlugins().withType(TestRetryPlugin.class, (testRetryPlugin) -> {
|
||||
test -> project.getPlugins().withType(TestRetryPlugin.class, testRetryPlugin -> {
|
||||
TestRetryTaskExtension testRetry = test.getExtensions().getByType(TestRetryTaskExtension.class);
|
||||
testRetry.getFailOnPassedAfterRetry().set(true);
|
||||
testRetry.getMaxRetries().set(isCi() ? 3 : 0);
|
||||
|
||||
@@ -6,6 +6,6 @@ RUN ./setup.sh
|
||||
|
||||
ENV JAVA_HOME /opt/openjdk/java17
|
||||
ENV JDK17 /opt/openjdk/java17
|
||||
ENV JDK19 /opt/openjdk/java19
|
||||
ENV JDK20 /opt/openjdk/java20
|
||||
|
||||
ENV PATH $JAVA_HOME/bin:$PATH
|
||||
|
||||
@@ -5,8 +5,8 @@ case "$1" in
|
||||
java17)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.6+10/bellsoft-jdk17.0.6+10-linux-amd64.tar.gz"
|
||||
;;
|
||||
java19)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/19.0.2+9/bellsoft-jdk19.0.2+9-linux-amd64.tar.gz"
|
||||
java20)
|
||||
echo "https://github.com/bell-sw/Liberica/releases/download/20%2B37/bellsoft-jdk20+37-linux-amd64.tar.gz"
|
||||
;;
|
||||
*)
|
||||
echo $"Unknown java version"
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/c
|
||||
|
||||
mkdir -p /opt/openjdk
|
||||
pushd /opt/openjdk > /dev/null
|
||||
for jdk in java17 java19
|
||||
for jdk in java17 java20
|
||||
do
|
||||
JDK_URL=$( /get-jdk-url.sh $jdk )
|
||||
mkdir $jdk
|
||||
|
||||
+8
-8
@@ -127,14 +127,14 @@ resources:
|
||||
access_token: ((github-ci-status-token))
|
||||
branch: ((branch))
|
||||
context: build
|
||||
- name: repo-status-jdk19-build
|
||||
- name: repo-status-jdk20-build
|
||||
type: github-status-resource
|
||||
icon: eye-check-outline
|
||||
source:
|
||||
repository: ((github-repo-name))
|
||||
access_token: ((github-ci-status-token))
|
||||
branch: ((branch))
|
||||
context: jdk19-build
|
||||
context: jdk20-build
|
||||
- name: slack-alert
|
||||
type: slack-notification
|
||||
icon: slack
|
||||
@@ -231,7 +231,7 @@ jobs:
|
||||
"zip.type": "schema"
|
||||
get_params:
|
||||
threads: 8
|
||||
- name: jdk19-build
|
||||
- name: jdk20-build
|
||||
serial: true
|
||||
public: true
|
||||
plan:
|
||||
@@ -239,7 +239,7 @@ jobs:
|
||||
- get: git-repo
|
||||
- get: every-morning
|
||||
trigger: true
|
||||
- put: repo-status-jdk19-build
|
||||
- put: repo-status-jdk20-build
|
||||
params: { state: "pending", commit: "git-repo" }
|
||||
- do:
|
||||
- task: check-project
|
||||
@@ -248,16 +248,16 @@ jobs:
|
||||
privileged: true
|
||||
timeout: ((task-timeout))
|
||||
params:
|
||||
TEST_TOOLCHAIN: 19
|
||||
TEST_TOOLCHAIN: 20
|
||||
<<: *build-project-task-params
|
||||
on_failure:
|
||||
do:
|
||||
- put: repo-status-jdk19-build
|
||||
- put: repo-status-jdk20-build
|
||||
params: { state: "failure", commit: "git-repo" }
|
||||
- put: slack-alert
|
||||
params:
|
||||
<<: *slack-fail-params
|
||||
- put: repo-status-jdk19-build
|
||||
- put: repo-status-jdk20-build
|
||||
params: { state: "success", commit: "git-repo" }
|
||||
- name: build-pull-requests
|
||||
serial: true
|
||||
@@ -441,7 +441,7 @@ jobs:
|
||||
|
||||
groups:
|
||||
- name: "builds"
|
||||
jobs: ["build", "jdk19-build"]
|
||||
jobs: ["build", "jdk20-build"]
|
||||
- name: "releases"
|
||||
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
|
||||
- name: "ci-images"
|
||||
|
||||
@@ -4,6 +4,6 @@ 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,JDK19 \
|
||||
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false -Porg.gradle.java.installations.fromEnv=JDK17,JDK20 \
|
||||
-PmainToolchain=${MAIN_TOOLCHAIN} -PtestToolchain=${TEST_TOOLCHAIN} --no-daemon --max-workers=4 check
|
||||
popd > /dev/null
|
||||
|
||||
@@ -28,7 +28,7 @@ javadoc {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
asciidoctorExtensions "io.spring.asciidoctor.backends:spring-asciidoctor-backends:0.0.4"
|
||||
asciidoctorExtensions "io.spring.asciidoctor.backends:spring-asciidoctor-backends:0.0.5"
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
aot=core.aot
|
||||
aot-basics=core.aot.basics
|
||||
aot-refresh=core.aot.refresh
|
||||
aot-bean-factory-initialization-contributions=core.aot.bean-factory-initialization-contributions
|
||||
aot-bean-registration-contributions=core.aot.bean-registration-contributions
|
||||
aot-hints=core.aot.hints
|
||||
aot-hints-import-runtime-hints=core.aot.hints.import-runtime-hints
|
||||
aot-hints-reflective=core.aot.hints.reflective
|
||||
aot-hints-register-reflection-for-binding=core.aot.hints.register-reflection-for-binding
|
||||
@@ -1,6 +1,11 @@
|
||||
// Spring Portfolio
|
||||
:docs-site: https://docs.spring.io
|
||||
:docs-spring-boot: {docs-site}/spring-boot/docs/current/reference
|
||||
:docs-spring-gemfire: {docs-site}/spring-gemfire/docs/current/reference
|
||||
:docs-spring-security: {docs-site}/spring-security/reference
|
||||
// spring-asciidoctor-backends Settings
|
||||
:chomp: default headers packages
|
||||
:fold: all
|
||||
:docs-site: https://docs.spring.io
|
||||
// Spring Framework
|
||||
:docs-spring-framework: {docs-site}/spring-framework/docs/{spring-version}
|
||||
:api-spring-framework: {docs-spring-framework}/javadoc-api/org/springframework
|
||||
@@ -8,10 +13,6 @@
|
||||
:docs-kotlin: {docdir}/../../main/kotlin/org/springframework/docs
|
||||
:docs-resources: {docdir}/../../main/resources
|
||||
:spring-framework-main-code: https://github.com/spring-projects/spring-framework/tree/main
|
||||
// Spring portfolio Links
|
||||
:docs-spring-boot: {docs-site}/spring-boot/docs/current/reference
|
||||
:docs-spring-gemfire: {docs-site}/spring-gemfire/docs/current/reference
|
||||
:docs-spring-security: {docs-site}/spring-security/reference
|
||||
// Third-party Links
|
||||
:docs-graalvm: https://www.graalvm.org/22.3/reference-manual
|
||||
:gh-rsocket: https://github.com/rsocket
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,9 +16,9 @@ Applying such optimizations early implies the following restrictions:
|
||||
* The classpath is fixed and fully defined at build time.
|
||||
* The beans defined in your application cannot change at runtime, meaning:
|
||||
** `@Profile`, in particular profile-specific configuration needs to be chosen at build time.
|
||||
** Environment properties that impact the presence of a bean (`@Conditional`) are only considered at build time.
|
||||
* Bean definitions with instance suppliers (lambdas or method references) can't be transformed Ahead of Time (see https://github.com/spring-projects/spring-framework/issues/29555[spring-framework#29555] related issue)
|
||||
* The return type of methods annotated with `@Bean` should be the most specific one in order to allow proper hint inference (typically the concrete class, not an interface).
|
||||
** `Environment` properties that impact the presence of a bean (`@Conditional`) are only considered at build time.
|
||||
* Bean definitions with instance suppliers (lambdas or method references) cannot be transformed ahead-of-time (see related https://github.com/spring-projects/spring-framework/issues/29555[spring-framework#29555] issue).
|
||||
* The return type of methods annotated with `@Bean` should be the most specific type possible (typically the concrete class, not an interface) in order to support proper type inference without invoking the corresponding `@Bean` method at build time.
|
||||
|
||||
When these restrictions are in place, it becomes possible to perform ahead-of-time processing at build time and generate additional assets.
|
||||
A Spring AOT processed application typically generates:
|
||||
|
||||
@@ -123,7 +123,7 @@ easy to do in Spring. You do not actually have to do anything or know anything a
|
||||
the Spring internals (or even about classes such as the `FieldRetrievingFactoryBean`).
|
||||
The following example enumeration shows how easy injecting an enum value is:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package jakarta.persistence;
|
||||
@@ -134,7 +134,7 @@ The following example enumeration shows how easy injecting an enum value is:
|
||||
EXTENDED
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package jakarta.persistence
|
||||
@@ -148,7 +148,7 @@ The following example enumeration shows how easy injecting an enum value is:
|
||||
|
||||
Now consider the following setter of type `PersistenceContextType` and the corresponding bean definition:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package example;
|
||||
@@ -162,7 +162,7 @@ Now consider the following setter of type `PersistenceContextType` and the corre
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package example
|
||||
@@ -796,7 +796,7 @@ element results in a single `SimpleDateFormat` bean definition). Spring features
|
||||
number of convenience classes that support this scenario. In the following example, we
|
||||
use the `NamespaceHandlerSupport` class:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package org.springframework.samples.xml;
|
||||
@@ -810,7 +810,7 @@ use the `NamespaceHandlerSupport` class:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package org.springframework.samples.xml
|
||||
@@ -847,7 +847,7 @@ responsible for parsing one distinct top-level XML element defined in the schema
|
||||
the parser, we' have access to the XML element (and thus to its subelements, too) so that
|
||||
we can parse our custom XML content, as you can see in the following example:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package org.springframework.samples.xml;
|
||||
@@ -884,7 +884,7 @@ the basic grunt work of creating a single `BeanDefinition`.
|
||||
<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our
|
||||
single `BeanDefinition` represents.
|
||||
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package org.springframework.samples.xml
|
||||
@@ -1056,7 +1056,7 @@ setter method for the `components` property. This makes it hard (or rather impos
|
||||
to configure a bean definition for the `Component` class by using setter injection.
|
||||
The following listing shows the `Component` class:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package com.foo;
|
||||
@@ -1087,7 +1087,7 @@ The following listing shows the `Component` class:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package com.foo
|
||||
@@ -1114,7 +1114,7 @@ The typical solution to this issue is to create a custom `FactoryBean` that expo
|
||||
setter property for the `components` property. The following listing shows such a custom
|
||||
`FactoryBean`:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package com.foo;
|
||||
@@ -1154,7 +1154,7 @@ setter property for the `components` property. The following listing shows such
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package com.foo
|
||||
@@ -1226,7 +1226,7 @@ listing shows:
|
||||
Again following <<core.appendix.xsd-custom-introduction, the process described earlier>>,
|
||||
we then create a custom `NamespaceHandler`:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package com.foo;
|
||||
@@ -1240,7 +1240,7 @@ we then create a custom `NamespaceHandler`:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package com.foo
|
||||
@@ -1259,7 +1259,7 @@ Next up is the custom `BeanDefinitionParser`. Remember that we are creating
|
||||
a `BeanDefinition` that describes a `ComponentFactoryBean`. The following
|
||||
listing shows our custom `BeanDefinitionParser` implementation:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package com.foo;
|
||||
@@ -1300,7 +1300,7 @@ listing shows our custom `BeanDefinitionParser` implementation:
|
||||
}
|
||||
|
||||
private static void parseChildComponents(List<Element> childElements, BeanDefinitionBuilder factory) {
|
||||
ManagedList<BeanDefinition> children = new ManagedList<BeanDefinition>(childElements.size());
|
||||
ManagedList<BeanDefinition> children = new ManagedList<>(childElements.size());
|
||||
for (Element element : childElements) {
|
||||
children.add(parseComponentElement(element));
|
||||
}
|
||||
@@ -1308,7 +1308,7 @@ listing shows our custom `BeanDefinitionParser` implementation:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package com.foo
|
||||
@@ -1403,14 +1403,14 @@ the named JCache for us. We can also modify the existing `BeanDefinition` for th
|
||||
`'checkingAccountService'` so that it has a dependency on this new
|
||||
JCache-initializing `BeanDefinition`. The following listing shows our `JCacheInitializer`:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package com.foo;
|
||||
|
||||
public class JCacheInitializer {
|
||||
|
||||
private String name;
|
||||
private final String name;
|
||||
|
||||
public JCacheInitializer(String name) {
|
||||
this.name = name;
|
||||
@@ -1421,7 +1421,7 @@ JCache-initializing `BeanDefinition`. The following listing shows our `JCacheIni
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package com.foo
|
||||
@@ -1453,7 +1453,7 @@ the XSD schema that describes the custom attribute, as follows:
|
||||
|
||||
Next, we need to create the associated `NamespaceHandler`, as follows:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package com.foo;
|
||||
@@ -1469,7 +1469,7 @@ Next, we need to create the associated `NamespaceHandler`, as follows:
|
||||
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package com.foo
|
||||
@@ -1490,7 +1490,7 @@ Next, we need to create the parser. Note that, in this case, because we are goin
|
||||
an XML attribute, we write a `BeanDefinitionDecorator` rather than a `BeanDefinitionParser`.
|
||||
The following listing shows our `BeanDefinitionDecorator` implementation:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package com.foo;
|
||||
@@ -1544,7 +1544,7 @@ The following listing shows our `BeanDefinitionDecorator` implementation:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package com.foo
|
||||
|
||||
@@ -949,7 +949,7 @@ order in which the constructor arguments are defined in a bean definition is the
|
||||
in which those arguments are supplied to the appropriate constructor when the bean is
|
||||
being instantiated. Consider the following class:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package x.y;
|
||||
@@ -961,7 +961,7 @@ being instantiated. Consider the following class:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package x.y
|
||||
@@ -993,7 +993,7 @@ case with the preceding example). When a simple type is used, such as
|
||||
`<value>true</value>`, Spring cannot determine the type of the value, and so cannot match
|
||||
by type without help. Consider the following class:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package examples;
|
||||
@@ -1012,7 +1012,7 @@ by type without help. Consider the following class:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package examples
|
||||
@@ -1077,7 +1077,7 @@ https://download.oracle.com/javase/8/docs/api/java/beans/ConstructorProperties.h
|
||||
JDK annotation to explicitly name your constructor arguments. The sample class would
|
||||
then have to look as follows:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package examples;
|
||||
@@ -1093,7 +1093,7 @@ then have to look as follows:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package examples
|
||||
@@ -2276,10 +2276,9 @@ and by <<beans-factory-client,making a `getBean("B")` call to the container>> as
|
||||
typically new) bean B instance every time bean A needs it. The following example
|
||||
shows this approach:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages",fold="none"]
|
||||
.Java
|
||||
----
|
||||
// a class that uses a stateful Command-style class to perform some processing
|
||||
package fiona.apple;
|
||||
|
||||
// Spring-API imports
|
||||
@@ -2287,6 +2286,10 @@ shows this approach:
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
/**
|
||||
* A class that uses a stateful Command-style class to perform
|
||||
* some processing.
|
||||
*/
|
||||
public class CommandManager implements ApplicationContextAware {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
@@ -2310,16 +2313,17 @@ shows this approach:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages",fold="none"]
|
||||
.Kotlin
|
||||
----
|
||||
// a class that uses a stateful Command-style class to perform some processing
|
||||
package fiona.apple
|
||||
|
||||
// Spring-API imports
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.context.ApplicationContextAware
|
||||
|
||||
// A class that uses a stateful Command-style class to perform
|
||||
// some processing.
|
||||
class CommandManager : ApplicationContextAware {
|
||||
|
||||
private lateinit var applicationContext: ApplicationContext
|
||||
@@ -2382,7 +2386,7 @@ Spring container dynamically overrides the implementation of the `createCommand(
|
||||
method. The `CommandManager` class does not have any Spring dependencies, as
|
||||
the reworked example shows:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages",fold="none"]
|
||||
.Java
|
||||
----
|
||||
package fiona.apple;
|
||||
@@ -2403,7 +2407,7 @@ the reworked example shows:
|
||||
protected abstract Command createCommand();
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages",fold="none"]
|
||||
.Kotlin
|
||||
----
|
||||
package fiona.apple
|
||||
@@ -4214,7 +4218,7 @@ it is created by the container and prints the resulting string to the system con
|
||||
|
||||
The following listing shows the custom `BeanPostProcessor` implementation class definition:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package scripting;
|
||||
@@ -4234,9 +4238,11 @@ The following listing shows the custom `BeanPostProcessor` implementation class
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package scripting
|
||||
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor
|
||||
|
||||
class InstantiationTracingBeanPostProcessor : BeanPostProcessor {
|
||||
@@ -7183,7 +7189,7 @@ You can add the following dependency to your file pom.xml:
|
||||
<dependency>
|
||||
<groupId>jakarta.inject</groupId>
|
||||
<artifactId>jakarta.inject-api</artifactId>
|
||||
<version>1</version>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
----
|
||||
=====
|
||||
|
||||
@@ -293,7 +293,7 @@ being placed in it. The following example shows how to do so:
|
||||
.Java
|
||||
----
|
||||
class Simple {
|
||||
public List<Boolean> booleanList = new ArrayList<Boolean>();
|
||||
public List<Boolean> booleanList = new ArrayList<>();
|
||||
}
|
||||
|
||||
Simple simple = new Simple();
|
||||
@@ -1478,7 +1478,7 @@ show how to use the `#this` and `#root` variables:
|
||||
.Java
|
||||
----
|
||||
// create an array of integers
|
||||
List<Integer> primes = new ArrayList<Integer>();
|
||||
List<Integer> primes = new ArrayList<>();
|
||||
primes.addAll(Arrays.asList(2,3,5,7,11,13,17));
|
||||
|
||||
// create parser and set variable 'primes' as the array of integers
|
||||
@@ -1978,7 +1978,7 @@ The definition of `TemplateParserContext` follows:
|
||||
|
||||
This section lists the classes used in the examples throughout this chapter.
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Inventor.Java
|
||||
----
|
||||
package org.spring.samples.spel.inventor;
|
||||
@@ -2051,18 +2051,20 @@ This section lists the classes used in the examples throughout this chapter.
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Inventor.kt
|
||||
----
|
||||
class Inventor(
|
||||
var name: String,
|
||||
var nationality: String,
|
||||
var inventions: Array<String>? = null,
|
||||
var birthdate: Date = GregorianCalendar().time,
|
||||
var placeOfBirth: PlaceOfBirth? = null)
|
||||
package org.spring.samples.spel.inventor
|
||||
|
||||
class Inventor(
|
||||
var name: String,
|
||||
var nationality: String,
|
||||
var inventions: Array<String>? = null,
|
||||
var birthdate: Date = GregorianCalendar().time,
|
||||
var placeOfBirth: PlaceOfBirth? = null)
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.PlaceOfBirth.java
|
||||
----
|
||||
package org.spring.samples.spel.inventor;
|
||||
@@ -2098,13 +2100,15 @@ class Inventor(
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.PlaceOfBirth.kt
|
||||
----
|
||||
package org.spring.samples.spel.inventor
|
||||
|
||||
class PlaceOfBirth(var city: String, var country: String? = null) {
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Society.java
|
||||
----
|
||||
package org.spring.samples.spel.inventor;
|
||||
@@ -2118,7 +2122,7 @@ class Inventor(
|
||||
public static String Advisors = "advisors";
|
||||
public static String President = "president";
|
||||
|
||||
private List<Inventor> members = new ArrayList<Inventor>();
|
||||
private List<Inventor> members = new ArrayList<>();
|
||||
private Map officers = new HashMap();
|
||||
|
||||
public List getMembers() {
|
||||
@@ -2147,7 +2151,7 @@ class Inventor(
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Society.kt
|
||||
----
|
||||
package org.spring.samples.spel.inventor
|
||||
|
||||
@@ -640,7 +640,7 @@ support for additional `PropertyEditor` instances to an `ApplicationContext`.
|
||||
Consider the following example, which defines a user class called `ExoticType` and
|
||||
another class called `DependsOnExoticType`, which needs `ExoticType` set as a property:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package example;
|
||||
@@ -663,7 +663,7 @@ another class called `DependsOnExoticType`, which needs `ExoticType` set as a pr
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package example
|
||||
@@ -689,12 +689,14 @@ string, which a `PropertyEditor` converts into an actual
|
||||
|
||||
The `PropertyEditor` implementation could look similar to the following:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
// converts string representation to ExoticType object
|
||||
package example;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
// converts string representation to ExoticType object
|
||||
public class ExoticTypeEditor extends PropertyEditorSupport {
|
||||
|
||||
public void setAsText(String text) {
|
||||
@@ -702,14 +704,14 @@ The `PropertyEditor` implementation could look similar to the following:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
// converts string representation to ExoticType object
|
||||
package example
|
||||
|
||||
import java.beans.PropertyEditorSupport
|
||||
|
||||
// converts string representation to ExoticType object
|
||||
class ExoticTypeEditor : PropertyEditorSupport() {
|
||||
|
||||
override fun setAsText(text: String) {
|
||||
@@ -752,7 +754,7 @@ instances for each bean creation attempt.
|
||||
|
||||
The following example shows how to create your own `PropertyEditorRegistrar` implementation:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package com.foo.editors.spring;
|
||||
@@ -768,7 +770,7 @@ The following example shows how to create your own `PropertyEditorRegistrar` imp
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package com.foo.editors.spring
|
||||
@@ -876,7 +878,7 @@ where type conversion is needed.
|
||||
The SPI to implement type conversion logic is simple and strongly typed, as the following
|
||||
interface definition shows:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.core.convert.converter;
|
||||
|
||||
@@ -901,7 +903,7 @@ Several converter implementations are provided in the `core.convert.support` pac
|
||||
a convenience. These include converters from strings to numbers and other common types.
|
||||
The following listing shows the `StringToInteger` class, which is a typical `Converter` implementation:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.core.convert.support;
|
||||
|
||||
@@ -922,7 +924,7 @@ When you need to centralize the conversion logic for an entire class hierarchy
|
||||
(for example, when converting from `String` to `Enum` objects), you can implement
|
||||
`ConverterFactory`, as the following example shows:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.core.convert.converter;
|
||||
|
||||
@@ -938,7 +940,7 @@ where T is a subclass of R.
|
||||
|
||||
Consider the `StringToEnumConverterFactory` as an example:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.core.convert.support;
|
||||
|
||||
@@ -975,7 +977,7 @@ context that you can use when you implement your conversion logic. Such context
|
||||
type conversion be driven by a field annotation or by generic information declared on a
|
||||
field signature. The following listing shows the interface definition of `GenericConverter`:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.core.convert.converter;
|
||||
|
||||
@@ -1039,7 +1041,7 @@ might match only if the target entity type declares a static finder method (for
|
||||
`ConversionService` defines a unified API for executing type conversion logic at
|
||||
runtime. Converters are often run behind the following facade interface:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.core.convert;
|
||||
|
||||
@@ -1223,7 +1225,7 @@ provides a unified type conversion API for both SPIs.
|
||||
The `Formatter` SPI to implement field formatting logic is simple and strongly typed. The
|
||||
following listing shows the `Formatter` interface definition:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.format;
|
||||
|
||||
@@ -1268,7 +1270,7 @@ a `java.text.DateFormat`.
|
||||
|
||||
The following `DateFormatter` is an example `Formatter` implementation:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package org.springframework.format.datetime;
|
||||
@@ -1302,7 +1304,7 @@ The following `DateFormatter` is an example `Formatter` implementation:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
class DateFormatter(private val pattern: String) : Formatter<Date> {
|
||||
@@ -1334,7 +1336,7 @@ Field formatting can be configured by field type or annotation. To bind
|
||||
an annotation to a `Formatter`, implement `AnnotationFormatterFactory`. The following
|
||||
listing shows the definition of the `AnnotationFormatterFactory` interface:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.format;
|
||||
|
||||
@@ -1350,15 +1352,14 @@ listing shows the definition of the `AnnotationFormatterFactory` interface:
|
||||
|
||||
To create an implementation:
|
||||
|
||||
. Parameterize A to be the field `annotationType` with which you wish to associate
|
||||
. Parameterize `A` to be the field `annotationType` with which you wish to associate
|
||||
formatting logic -- for example `org.springframework.format.annotation.DateTimeFormat`.
|
||||
. Have `getFieldTypes()` return the types of fields on which the annotation can be used.
|
||||
. Have `getPrinter()` return a `Printer` to print the value of an annotated field.
|
||||
. Have `getParser()` return a `Parser` to parse a `clientValue` for an annotated field.
|
||||
|
||||
The following example `AnnotationFormatterFactory` implementation binds the `@NumberFormat`
|
||||
annotation to a formatter to let a number style or pattern be
|
||||
specified:
|
||||
annotation to a formatter to let a number style or pattern be specified:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
.Java
|
||||
@@ -1366,10 +1367,12 @@ specified:
|
||||
public final class NumberFormatAnnotationFormatterFactory
|
||||
implements AnnotationFormatterFactory<NumberFormat> {
|
||||
|
||||
private static final Set<Class<?>> FIELD_TYPES = Set.of(Short.class,
|
||||
Integer.class, Long.class, Float.class, Double.class,
|
||||
BigDecimal.class, BigInteger.class);
|
||||
|
||||
public Set<Class<?>> getFieldTypes() {
|
||||
return new HashSet<Class<?>>(asList(new Class<?>[] {
|
||||
Short.class, Integer.class, Long.class, Float.class,
|
||||
Double.class, BigDecimal.class, BigInteger.class }));
|
||||
return FIELD_TYPES;
|
||||
}
|
||||
|
||||
public Printer<Number> getPrinter(NumberFormat annotation, Class<?> fieldType) {
|
||||
@@ -1383,16 +1386,13 @@ specified:
|
||||
private Formatter<Number> configureFormatterFrom(NumberFormat annotation, Class<?> fieldType) {
|
||||
if (!annotation.pattern().isEmpty()) {
|
||||
return new NumberStyleFormatter(annotation.pattern());
|
||||
} else {
|
||||
Style style = annotation.style();
|
||||
if (style == Style.PERCENT) {
|
||||
return new PercentStyleFormatter();
|
||||
} else if (style == Style.CURRENCY) {
|
||||
return new CurrencyStyleFormatter();
|
||||
} else {
|
||||
return new NumberStyleFormatter();
|
||||
}
|
||||
}
|
||||
// else
|
||||
return switch(annotation.style()) {
|
||||
case Style.PERCENT -> new PercentStyleFormatter();
|
||||
case Style.CURRENCY -> new CurrencyStyleFormatter();
|
||||
default -> new NumberStyleFormatter();
|
||||
};
|
||||
}
|
||||
}
|
||||
----
|
||||
@@ -1428,7 +1428,7 @@ specified:
|
||||
}
|
||||
----
|
||||
|
||||
To trigger formatting, you can annotate fields with @NumberFormat, as the following
|
||||
To trigger formatting, you can annotate fields with `@NumberFormat`, as the following
|
||||
example shows:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
@@ -1490,7 +1490,7 @@ for use with Spring's `DataBinder` and the Spring Expression Language (SpEL).
|
||||
|
||||
The following listing shows the `FormatterRegistry` SPI:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.format;
|
||||
|
||||
@@ -1526,7 +1526,7 @@ these rules once, and they are applied whenever formatting is needed.
|
||||
`FormatterRegistrar` is an SPI for registering formatters and converters through the
|
||||
FormatterRegistry. The following listing shows its interface definition:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.format;
|
||||
|
||||
@@ -1578,20 +1578,22 @@ For example, the following Java configuration registers a global `yyyyMMdd` form
|
||||
public FormattingConversionService conversionService() {
|
||||
|
||||
// Use the DefaultFormattingConversionService but do not register defaults
|
||||
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false);
|
||||
DefaultFormattingConversionService conversionService =
|
||||
new DefaultFormattingConversionService(false);
|
||||
|
||||
// Ensure @NumberFormat is still supported
|
||||
conversionService.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());
|
||||
conversionService.addFormatterForFieldAnnotation(
|
||||
new NumberFormatAnnotationFormatterFactory());
|
||||
|
||||
// Register JSR-310 date conversion with a specific global format
|
||||
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
|
||||
registrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||
registrar.registerFormatters(conversionService);
|
||||
DateTimeFormatterRegistrar dateTimeRegistrar = new DateTimeFormatterRegistrar();
|
||||
dateTimeRegistrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||
dateTimeRegistrar.registerFormatters(conversionService);
|
||||
|
||||
// Register date conversion with a specific global format
|
||||
DateFormatterRegistrar registrar = new DateFormatterRegistrar();
|
||||
registrar.setFormatter(new DateFormatter("yyyyMMdd"));
|
||||
registrar.registerFormatters(conversionService);
|
||||
DateFormatterRegistrar dateRegistrar = new DateFormatterRegistrar();
|
||||
dateRegistrar.setFormatter(new DateFormatter("yyyyMMdd"));
|
||||
dateRegistrar.registerFormatters(conversionService);
|
||||
|
||||
return conversionService;
|
||||
}
|
||||
@@ -1612,14 +1614,14 @@ For example, the following Java configuration registers a global `yyyyMMdd` form
|
||||
addFormatterForFieldAnnotation(NumberFormatAnnotationFormatterFactory())
|
||||
|
||||
// Register JSR-310 date conversion with a specific global format
|
||||
val registrar = DateTimeFormatterRegistrar()
|
||||
registrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyyMMdd"))
|
||||
registrar.registerFormatters(this)
|
||||
val dateTimeRegistrar = DateTimeFormatterRegistrar()
|
||||
dateTimeRegistrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyyMMdd"))
|
||||
dateTimeRegistrar.registerFormatters(this)
|
||||
|
||||
// Register date conversion with a specific global format
|
||||
val registrar = DateFormatterRegistrar()
|
||||
registrar.setFormatter(DateFormatter("yyyyMMdd"))
|
||||
registrar.registerFormatters(this)
|
||||
val dateRegistrar = DateFormatterRegistrar()
|
||||
dateRegistrar.setFormatter(DateFormatter("yyyyMMdd"))
|
||||
dateRegistrar.registerFormatters(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,7 +622,7 @@ transactions being created and then rolled back in response to the
|
||||
`UnsupportedOperationException` instance. The following listing shows the `FooService`
|
||||
interface:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
// the service interface that we want to make transactional
|
||||
@@ -641,7 +641,7 @@ interface:
|
||||
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
// the service interface that we want to make transactional
|
||||
@@ -662,7 +662,7 @@ interface:
|
||||
|
||||
The following example shows an implementation of the preceding interface:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package x.y.service;
|
||||
@@ -690,7 +690,7 @@ The following example shows an implementation of the preceding interface:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package x.y.service
|
||||
@@ -893,7 +893,7 @@ return type is reactive.
|
||||
The following listing shows a modified version of the previously used `FooService`, but
|
||||
this time the code uses reactive types:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
// the reactive service interface that we want to make transactional
|
||||
@@ -912,7 +912,7 @@ this time the code uses reactive types:
|
||||
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
// the reactive service interface that we want to make transactional
|
||||
@@ -933,7 +933,7 @@ this time the code uses reactive types:
|
||||
|
||||
The following example shows an implementation of the preceding interface:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package x.y.service;
|
||||
@@ -961,7 +961,7 @@ The following example shows an implementation of the preceding interface:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package x.y.service
|
||||
@@ -1028,12 +1028,30 @@ the call stack and makes a determination whether to mark the transaction for rol
|
||||
In its default configuration, the Spring Framework's transaction infrastructure code
|
||||
marks a transaction for rollback only in the case of runtime, unchecked exceptions.
|
||||
That is, when the thrown exception is an instance or subclass of `RuntimeException`.
|
||||
(`Error` instances also, by default, result in a rollback). Checked exceptions that are
|
||||
thrown from a transactional method do not result in rollback in the default
|
||||
configuration.
|
||||
(`Error` instances also, by default, result in a rollback).
|
||||
|
||||
You can configure exactly which `Exception` types mark a transaction for rollback,
|
||||
including checked exceptions by specifying _rollback rules_.
|
||||
As of Spring Framework 5.2, the default configuration also provides support for
|
||||
Vavr's `Try` method to trigger transaction rollbacks when it returns a 'Failure'.
|
||||
This allows you to handle functional-style errors using Try and have the transaction
|
||||
automatically rolled back in case of a failure. For more information on Vavr's Try,
|
||||
refer to the [official Vavr documentation](https://www.vavr.io/vavr-docs/#_try).
|
||||
|
||||
Here's an example of how to use Vavr's Try with a transactional method:
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
.Java
|
||||
----
|
||||
@Transactional
|
||||
public Try<String> myTransactionalMethod() {
|
||||
// If myDataAccessOperation throws an exception, it will be caught by the
|
||||
// Try instance created with Try.of() and wrapped inside the Failure class
|
||||
// which can be checked using the isFailure() method on the Try instance.
|
||||
return Try.of(delegate::myDataAccessOperation);
|
||||
}
|
||||
----
|
||||
|
||||
Checked exceptions that are thrown from a transactional method do not result in a rollback
|
||||
in the default configuration. You can configure exactly which `Exception` types mark a
|
||||
transaction for rollback, including checked exceptions by specifying _rollback rules_.
|
||||
|
||||
.Rollback rules
|
||||
[[transaction-declarative-rollback-rules]]
|
||||
@@ -2028,7 +2046,7 @@ configuration and AOP in general.
|
||||
|
||||
The following code shows the simple profiling aspect discussed earlier:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary",chomp="-packages"]
|
||||
.Java
|
||||
----
|
||||
package x.y;
|
||||
@@ -2065,9 +2083,15 @@ The following code shows the simple profiling aspect discussed earlier:
|
||||
}
|
||||
}
|
||||
----
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
|
||||
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
|
||||
.Kotlin
|
||||
----
|
||||
package x.y
|
||||
|
||||
import org.aspectj.lang.ProceedingJoinPoint
|
||||
import org.springframework.util.StopWatch
|
||||
import org.springframework.core.Ordered
|
||||
|
||||
class SimpleProfiler : Ordered {
|
||||
|
||||
private var order: Int = 0
|
||||
@@ -4522,7 +4546,7 @@ JDBC `?` placeholders:
|
||||
}
|
||||
|
||||
public int[] batchUpdate(final List<Actor> actors) {
|
||||
List<Object[]> batch = new ArrayList<Object[]>();
|
||||
List<Object[]> batch = new ArrayList<>();
|
||||
for (Actor actor : actors) {
|
||||
Object[] values = new Object[] {
|
||||
actor.getFirstName(), actor.getLastName(), actor.getId()};
|
||||
@@ -4686,7 +4710,7 @@ example uses only one configuration method (we show examples of multiple methods
|
||||
}
|
||||
|
||||
public void add(Actor actor) {
|
||||
Map<String, Object> parameters = new HashMap<String, Object>(3);
|
||||
Map<String, Object> parameters = new HashMap<>(3);
|
||||
parameters.put("id", actor.getId());
|
||||
parameters.put("first_name", actor.getFirstName());
|
||||
parameters.put("last_name", actor.getLastName());
|
||||
@@ -4744,7 +4768,7 @@ listing shows how it works:
|
||||
}
|
||||
|
||||
public void add(Actor actor) {
|
||||
Map<String, Object> parameters = new HashMap<String, Object>(2);
|
||||
Map<String, Object> parameters = new HashMap<>(2);
|
||||
parameters.put("first_name", actor.getFirstName());
|
||||
parameters.put("last_name", actor.getLastName());
|
||||
Number newId = insertActor.executeAndReturnKey(parameters);
|
||||
@@ -4804,7 +4828,7 @@ You can limit the columns for an insert by specifying a list of column names wit
|
||||
}
|
||||
|
||||
public void add(Actor actor) {
|
||||
Map<String, Object> parameters = new HashMap<String, Object>(2);
|
||||
Map<String, Object> parameters = new HashMap<>(2);
|
||||
parameters.put("first_name", actor.getFirstName());
|
||||
parameters.put("last_name", actor.getLastName());
|
||||
Number newId = insertActor.executeAndReturnKey(parameters);
|
||||
|
||||
@@ -13,7 +13,7 @@ Spring MVC Test, WebTestClient.
|
||||
JDBC, R2DBC, O/R Mapping, XML Marshalling.
|
||||
<<web.adoc#spring-web, Web Servlet>> :: Spring MVC, WebSocket, SockJS,
|
||||
STOMP Messaging.
|
||||
<<web-reactive.adoc#spring-webflux, Web Reactive>> :: Spring WebFlux, WebClient,
|
||||
<<web-reactive.adoc#spring-web-reactive, Web Reactive>> :: Spring WebFlux, WebClient,
|
||||
WebSocket, RSocket.
|
||||
<<integration.adoc#spring-integration, Integration>> :: REST Clients, JMS, JCA, JMX,
|
||||
Email, Tasks, Scheduling, Caching, Observability.
|
||||
|
||||
@@ -582,7 +582,7 @@ a similar contract to the JMS `MessageListener` interface but also gives the mes
|
||||
method access to the JMS `Session` from which the `Message` was received.
|
||||
The following listing shows the definition of the `SessionAwareMessageListener` interface:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.jms.listener;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ The core class in Spring's JMX framework is the `MBeanExporter`. This class is
|
||||
responsible for taking your Spring beans and registering them with a JMX `MBeanServer`.
|
||||
For example, consider the following class:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.jmx;
|
||||
|
||||
@@ -358,7 +358,7 @@ an operation or an attribute.
|
||||
The following example shows the annotated version of the `JmxTestBean` class that we
|
||||
used in <<jmx-exporting-mbeanserver>>:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.jmx;
|
||||
|
||||
@@ -1067,7 +1067,7 @@ example, consider the scenario where one would like to be informed (through a
|
||||
`Notification`) each and every time an attribute of a target MBean changes. The following
|
||||
example writes notifications to the console:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package com.example;
|
||||
|
||||
@@ -1317,7 +1317,7 @@ published, and invoke the `sendNotification(Notification)` on the
|
||||
In the following example, exported instances of the `JmxTestBean` publish a
|
||||
`NotificationEvent` every time the `add(int, int)` operation is invoked:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.jmx;
|
||||
|
||||
|
||||
@@ -9,6 +9,30 @@ Traces provide a holistic view of an entire system, crossing application boundar
|
||||
Spring Framework instruments various parts of its own codebase to publish observations if an `ObservationRegistry` is configured.
|
||||
You can learn more about {docs-spring-boot}/html/actuator.html#actuator.metrics[configuring the observability infrastructure in Spring Boot].
|
||||
|
||||
|
||||
[[integration.observability.list]]
|
||||
== List of produced Observations
|
||||
|
||||
Spring Framework instruments various features for observability.
|
||||
As outlined <<integration.observability,at the beginning of this section>>, observations can generate timer Metrics and/or Traces depending on the configuration.
|
||||
|
||||
.Observations produced by Spring Framework
|
||||
[%autowidth]
|
||||
|===
|
||||
|Observation name |Description
|
||||
|
||||
|<<integration.observability.http-client,`"http.client.requests"`>>
|
||||
|Time spent for HTTP client exchanges
|
||||
|
||||
|<<integration.observability.http-server,`"http.server.requests"`>>
|
||||
|Processing time for HTTP server exchanges at the Framework level
|
||||
|===
|
||||
|
||||
NOTE: Observations are using Micrometer's official naming convention, but Metrics names will be automatically converted
|
||||
https://micrometer.io/docs/concepts#_naming_meters[to the format preferred by the monitoring system backend]
|
||||
(Prometheus, Atlas, Graphite, InfluxDB...).
|
||||
|
||||
|
||||
[[integration.observability.concepts]]
|
||||
== Micrometer Observation concepts
|
||||
|
||||
|
||||
@@ -816,8 +816,7 @@ its properties from the job data mapped to properties of the job instance. So, i
|
||||
the `ExampleJob` contains a bean property named `timeout`, and the `JobDetail`
|
||||
has it applied automatically:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package example;
|
||||
|
||||
@@ -827,7 +826,7 @@ has it applied automatically:
|
||||
|
||||
/**
|
||||
* Setter called after the ExampleJob is instantiated
|
||||
* with the value from the JobDetailFactoryBean (5)
|
||||
* with the value from the JobDetailFactoryBean.
|
||||
*/
|
||||
public void setTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
|
||||
@@ -33,7 +33,7 @@ implement. Note that this interface is defined in plain Java. Dependent objects
|
||||
are injected with a reference to the `Messenger` do not know that the underlying
|
||||
implementation is a Groovy script. The following listing shows the `Messenger` interface:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.scripting;
|
||||
|
||||
@@ -45,7 +45,7 @@ implementation is a Groovy script. The following listing shows the `Messenger` i
|
||||
|
||||
The following example defines a class that has a dependency on the `Messenger` interface:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.scripting;
|
||||
|
||||
@@ -65,15 +65,14 @@ The following example defines a class that has a dependency on the `Messenger` i
|
||||
|
||||
The following example implements the `Messenger` interface in Groovy:
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,quotes"]
|
||||
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages",fold="none"]
|
||||
----
|
||||
// from the file 'Messenger.groovy'
|
||||
package org.springframework.scripting.groovy;
|
||||
package org.springframework.scripting.groovy
|
||||
|
||||
// import the Messenger interface (written in Java) that is to be implemented
|
||||
// Import the Messenger interface (written in Java) that is to be implemented
|
||||
import org.springframework.scripting.Messenger
|
||||
|
||||
// define the implementation in Groovy
|
||||
// Define the implementation in Groovy in file 'Messenger.groovy'
|
||||
class GroovyMessenger implements Messenger {
|
||||
|
||||
String message
|
||||
@@ -276,7 +275,7 @@ surrounded by quotation marks. The following listing shows the changes that you
|
||||
(the developer) should make to the `Messenger.groovy` source file when the
|
||||
execution of the program is paused:
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,quotes"]
|
||||
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.scripting
|
||||
|
||||
@@ -331,13 +330,13 @@ feature works:
|
||||
<lang:groovy id="messenger">
|
||||
<lang:inline-script>
|
||||
|
||||
package org.springframework.scripting.groovy;
|
||||
package org.springframework.scripting.groovy
|
||||
|
||||
import org.springframework.scripting.Messenger
|
||||
import org.springframework.scripting.Messenger
|
||||
|
||||
class GroovyMessenger implements Messenger {
|
||||
String message
|
||||
}
|
||||
class GroovyMessenger implements Messenger {
|
||||
String message
|
||||
}
|
||||
|
||||
</lang:inline-script>
|
||||
<lang:property name="message" value="I Can Do The Frug" />
|
||||
@@ -363,13 +362,13 @@ constructors and properties 100% clear, the following mixture of code and config
|
||||
does not work:
|
||||
|
||||
.An approach that cannot work
|
||||
[source,groovy,indent=0,subs="verbatim,quotes"]
|
||||
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
// from the file 'Messenger.groovy'
|
||||
package org.springframework.scripting.groovy;
|
||||
package org.springframework.scripting.groovy
|
||||
|
||||
import org.springframework.scripting.Messenger
|
||||
|
||||
// from the file 'Messenger.groovy'
|
||||
class GroovyMessenger implements Messenger {
|
||||
|
||||
GroovyMessenger() {}
|
||||
@@ -420,7 +419,7 @@ If you have read this chapter straight from the top, you have already
|
||||
<<dynamic-language-a-first-example, seen an example>> of a Groovy-dynamic-language-backed
|
||||
bean. Now consider another example (again using an example from the Spring test suite):
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.scripting;
|
||||
|
||||
@@ -432,11 +431,11 @@ bean. Now consider another example (again using an example from the Spring test
|
||||
|
||||
The following example implements the `Calculator` interface in Groovy:
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,quotes"]
|
||||
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
// from the file 'calculator.groovy'
|
||||
package org.springframework.scripting.groovy
|
||||
|
||||
// from the file 'calculator.groovy'
|
||||
class GroovyCalculator implements Calculator {
|
||||
|
||||
int add(int x, int y) {
|
||||
@@ -457,7 +456,7 @@ The following bean definition uses the calculator defined in Groovy:
|
||||
|
||||
Finally, the following small application exercises the preceding configuration:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.scripting;
|
||||
|
||||
@@ -596,7 +595,7 @@ Now we can show a fully working example of using a BeanShell-based bean that imp
|
||||
the `Messenger` interface that was defined earlier in this chapter. We again show the
|
||||
definition of the `Messenger` interface:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
package org.springframework.scripting;
|
||||
|
||||
@@ -676,9 +675,8 @@ beans, you have to enable the "`refreshable beans`" functionality. See
|
||||
The following example shows an `org.springframework.web.servlet.mvc.Controller` implemented
|
||||
by using the Groovy dynamic language:
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,quotes"]
|
||||
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
// from the file '/WEB-INF/groovy/FortuneController.groovy'
|
||||
package org.springframework.showcase.fortune.web
|
||||
|
||||
import org.springframework.showcase.fortune.service.FortuneService
|
||||
@@ -689,6 +687,7 @@ by using the Groovy dynamic language:
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import jakarta.servlet.http.HttpServletResponse
|
||||
|
||||
// from the file '/WEB-INF/groovy/FortuneController.groovy'
|
||||
class FortuneController implements Controller {
|
||||
|
||||
@Property FortuneService fortuneService
|
||||
|
||||
@@ -251,7 +251,7 @@ By default global configuration enables the following:
|
||||
* `GET`, `HEAD`, and `POST` methods.
|
||||
|
||||
`allowedCredentials` is not enabled by default, since that establishes a trust level
|
||||
that exposes sensitive user-specific information( such as cookies and CSRF tokens) and
|
||||
that exposes sensitive user-specific information (such as cookies and CSRF tokens) and
|
||||
should be used only where appropriate. When it is enabled either `allowOrigins` must be
|
||||
set to one or more specific domain (but not the special value `"*"`) or alternatively
|
||||
the `allowOriginPatterns` property may be used to match to a dynamic set of origins.
|
||||
|
||||
@@ -1655,7 +1655,7 @@ content types that a controller method produces, as the following example shows:
|
||||
----
|
||||
@GetMapping("/pets/{petId}", produces = ["application/json"])
|
||||
@ResponseBody
|
||||
fun getPet(@PathVariable String petId): Pet {
|
||||
fun getPet(@PathVariable petId: String): Pet {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
@@ -1704,7 +1704,7 @@ You can also use the same with request header conditions, as the following examp
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
.Java
|
||||
----
|
||||
@GetMapping(path = "/pets", headers = "myHeader=myValue") // <1>
|
||||
@GetMapping(path = "/pets/{petId}", headers = "myHeader=myValue") // <1>
|
||||
public void findPet(@PathVariable String petId) {
|
||||
// ...
|
||||
}
|
||||
@@ -1714,7 +1714,7 @@ You can also use the same with request header conditions, as the following examp
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
@GetMapping("/pets", headers = ["myHeader=myValue"]) // <1>
|
||||
@GetMapping("/pets/{petId}", headers = ["myHeader=myValue"]) // <1>
|
||||
fun findPet(@PathVariable petId: String) {
|
||||
// ...
|
||||
}
|
||||
@@ -2504,7 +2504,7 @@ reactive type, as the following example shows:
|
||||
----
|
||||
|
||||
Note that use of `@ModelAttribute` is optional -- for example, to set its attributes.
|
||||
By default, any argument that is not a simple value type( as determined by
|
||||
By default, any argument that is not a simple value type (as determined by
|
||||
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty])
|
||||
and is not resolved by any other argument resolver is treated as if it were annotated
|
||||
with `@ModelAttribute`.
|
||||
|
||||
@@ -743,7 +743,7 @@ or to render a JSON response, as the following example shows:
|
||||
|
||||
@RequestMapping(path = "/error")
|
||||
public Map<String, Object> handle(HttpServletRequest request) {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("status", request.getAttribute("jakarta.servlet.error.status_code"));
|
||||
map.put("reason", request.getAttribute("jakarta.servlet.error.message"));
|
||||
return map;
|
||||
@@ -1903,7 +1903,7 @@ You can also use the same with request header conditions, as the following examp
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
.Java
|
||||
----
|
||||
@GetMapping(path = "/pets", headers = "myHeader=myValue") // <1>
|
||||
@GetMapping(path = "/pets/{petId}", headers = "myHeader=myValue") // <1>
|
||||
public void findPet(@PathVariable String petId) {
|
||||
// ...
|
||||
}
|
||||
@@ -1913,7 +1913,7 @@ You can also use the same with request header conditions, as the following examp
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
.Kotlin
|
||||
----
|
||||
@GetMapping("/pets", headers = ["myHeader=myValue"]) // <1>
|
||||
@GetMapping("/pets/{petId}", headers = ["myHeader=myValue"]) // <1>
|
||||
fun findPet(@PathVariable petId: String) {
|
||||
// ...
|
||||
}
|
||||
@@ -4393,7 +4393,7 @@ return value with `DeferredResult`, as the following example shows:
|
||||
@GetMapping("/quotes")
|
||||
@ResponseBody
|
||||
public DeferredResult<String> quotes() {
|
||||
DeferredResult<String> deferredResult = new DeferredResult<String>();
|
||||
DeferredResult<String> deferredResult = new DeferredResult<>();
|
||||
// Save the deferredResult somewhere..
|
||||
return deferredResult;
|
||||
}
|
||||
|
||||
@@ -8,32 +8,32 @@ javaPlatform {
|
||||
|
||||
dependencies {
|
||||
api(platform("com.fasterxml.jackson:jackson-bom:2.14.2"))
|
||||
api(platform("io.micrometer:micrometer-bom:1.10.4"))
|
||||
api(platform("io.netty:netty-bom:4.1.89.Final"))
|
||||
api(platform("io.micrometer:micrometer-bom:1.10.6"))
|
||||
api(platform("io.netty:netty-bom:4.1.91.Final"))
|
||||
api(platform("io.netty:netty5-bom:5.0.0.Alpha5"))
|
||||
api(platform("io.projectreactor:reactor-bom:2022.0.3"))
|
||||
api(platform("io.projectreactor:reactor-bom:2022.0.6"))
|
||||
api(platform("io.rsocket:rsocket-bom:1.1.3"))
|
||||
api(platform("org.apache.groovy:groovy-bom:4.0.8"))
|
||||
api(platform("org.apache.logging.log4j:log4j-bom:2.19.0"))
|
||||
api(platform("org.eclipse.jetty:jetty-bom:11.0.13"))
|
||||
api(platform("org.apache.groovy:groovy-bom:4.0.11"))
|
||||
api(platform("org.apache.logging.log4j:log4j-bom:2.20.0"))
|
||||
api(platform("org.eclipse.jetty:jetty-bom:11.0.14"))
|
||||
api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4"))
|
||||
api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.4.0"))
|
||||
api(platform("org.junit:junit-bom:5.9.2"))
|
||||
api(platform("org.mockito:mockito-bom:5.1.1"))
|
||||
api(platform("org.mockito:mockito-bom:5.3.0"))
|
||||
|
||||
constraints {
|
||||
api("com.fasterxml:aalto-xml:1.3.1")
|
||||
api("com.fasterxml:aalto-xml:1.3.2")
|
||||
api("com.fasterxml.woodstox:woodstox-core:6.5.0")
|
||||
api("com.github.ben-manes.caffeine:caffeine:3.1.2")
|
||||
api("com.github.ben-manes.caffeine:caffeine:3.1.5")
|
||||
api("com.github.librepdf:openpdf:1.3.30")
|
||||
api("com.google.code.findbugs:findbugs:3.0.1")
|
||||
api("com.google.code.findbugs:jsr305:3.0.2")
|
||||
api("com.google.code.gson:gson:2.10")
|
||||
api("com.google.code.gson:gson:2.10.1")
|
||||
api("com.google.protobuf:protobuf-java-util:3.21.12")
|
||||
api("com.googlecode.protobuf-java-format:protobuf-java-format:1.4")
|
||||
api("com.h2database:h2:2.1.214")
|
||||
api("com.jayway.jsonpath:json-path:2.7.0")
|
||||
api("com.rometools:rome:1.18.0")
|
||||
api("com.jayway.jsonpath:json-path:2.8.0")
|
||||
api("com.rometools:rome:1.19.0")
|
||||
api("com.squareup.okhttp3:mockwebserver:3.14.9")
|
||||
api("com.squareup.okhttp3:okhttp:3.14.9")
|
||||
api("com.sun.activation:jakarta.activation:2.0.1")
|
||||
@@ -41,31 +41,31 @@ dependencies {
|
||||
api("com.sun.xml.bind:jaxb-core:3.0.2")
|
||||
api("com.sun.xml.bind:jaxb-impl:3.0.2")
|
||||
api("com.sun.xml.bind:jaxb-xjc:3.0.2")
|
||||
api("com.thoughtworks.qdox:qdox:2.0.2")
|
||||
api("com.thoughtworks.xstream:xstream:1.4.19")
|
||||
api("com.thoughtworks.qdox:qdox:2.0.3")
|
||||
api("com.thoughtworks.xstream:xstream:1.4.20")
|
||||
api("commons-io:commons-io:2.11.0")
|
||||
api("de.bechte.junit:junit-hierarchicalcontextrunner:4.12.1")
|
||||
api("info.picocli:picocli:4.7.0")
|
||||
api("de.bechte.junit:junit-hierarchicalcontextrunner:4.12.2")
|
||||
api("info.picocli:picocli:4.7.1")
|
||||
api("io.micrometer:context-propagation:1.0.0")
|
||||
api("io.mockk:mockk:1.12.1")
|
||||
api("io.mockk:mockk:1.13.4")
|
||||
api("io.projectreactor.netty:reactor-netty5-http:2.0.0-M3")
|
||||
api("io.projectreactor.tools:blockhound:1.0.6.RELEASE")
|
||||
api("io.projectreactor.tools:blockhound:1.0.7.RELEASE")
|
||||
api("io.r2dbc:r2dbc-h2:1.0.0.RELEASE")
|
||||
api("io.r2dbc:r2dbc-spi-test:1.0.0.RELEASE")
|
||||
api("io.r2dbc:r2dbc-spi:1.0.0.RELEASE")
|
||||
api("io.reactivex.rxjava3:rxjava:3.1.5")
|
||||
api("io.smallrye.reactive:mutiny:1.8.0")
|
||||
api("io.undertow:undertow-core:2.3.3.Final")
|
||||
api("io.undertow:undertow-servlet:2.3.3.Final")
|
||||
api("io.undertow:undertow-websockets-jsr:2.3.3.Final")
|
||||
api("io.reactivex.rxjava3:rxjava:3.1.6")
|
||||
api("io.smallrye.reactive:mutiny:1.9.0")
|
||||
api("io.undertow:undertow-core:2.3.5.Final")
|
||||
api("io.undertow:undertow-servlet:2.3.5.Final")
|
||||
api("io.undertow:undertow-websockets-jsr:2.3.5.Final")
|
||||
api("io.vavr:vavr:0.10.4")
|
||||
api("jakarta.activation:jakarta.activation-api:2.0.1")
|
||||
api("jakarta.annotation:jakarta.annotation-api:2.0.0")
|
||||
api("jakarta.ejb:jakarta.ejb-api:4.0.0")
|
||||
api("jakarta.ejb:jakarta.ejb-api:4.0.1")
|
||||
api("jakarta.el:jakarta.el-api:4.0.0")
|
||||
api("jakarta.enterprise.concurrent:jakarta.enterprise.concurrent-api:2.0.0")
|
||||
api("jakarta.faces:jakarta.faces-api:3.0.0")
|
||||
api("jakarta.inject:jakarta.inject-api:2.0.0")
|
||||
api("jakarta.inject:jakarta.inject-api:2.0.1")
|
||||
api("jakarta.inject:jakarta.inject-tck:2.0.1")
|
||||
api("jakarta.interceptor:jakarta.interceptor-api:2.0.0")
|
||||
api("jakarta.jms:jakarta.jms-api:3.0.0")
|
||||
@@ -75,7 +75,7 @@ dependencies {
|
||||
api("jakarta.persistence:jakarta.persistence-api:3.0.0")
|
||||
api("jakarta.resource:jakarta.resource-api:2.0.0")
|
||||
api("jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api:3.0.0")
|
||||
api("jakarta.servlet.jsp:jakarta.servlet.jsp-api:3.1.0")
|
||||
api("jakarta.servlet.jsp:jakarta.servlet.jsp-api:3.1.1")
|
||||
api("jakarta.servlet:jakarta.servlet-api:6.0.0")
|
||||
api("jakarta.transaction:jakarta.transaction-api:2.0.1")
|
||||
api("jakarta.validation:jakarta.validation-api:3.0.2")
|
||||
@@ -89,9 +89,9 @@ dependencies {
|
||||
api("net.sf.jopt-simple:jopt-simple:5.0.4")
|
||||
api("net.sourceforge.htmlunit:htmlunit:2.70.0")
|
||||
api("org.apache-extras.beanshell:bsh:2.0b6")
|
||||
api("org.apache.activemq:activemq-broker:5.16.2")
|
||||
api("org.apache.activemq:activemq-kahadb-store:5.16.2")
|
||||
api("org.apache.activemq:activemq-stomp:5.16.2")
|
||||
api("org.apache.activemq:activemq-broker:5.17.2")
|
||||
api("org.apache.activemq:activemq-kahadb-store:5.17.2")
|
||||
api("org.apache.activemq:activemq-stomp:5.17.2")
|
||||
api("org.apache.commons:commons-pool2:2.9.0")
|
||||
api("org.apache.derby:derby:10.16.1.1")
|
||||
api("org.apache.derby:derbyclient:10.16.1.1")
|
||||
@@ -99,45 +99,45 @@ dependencies {
|
||||
api("org.apache.httpcomponents.client5:httpclient5:5.2.1")
|
||||
api("org.apache.httpcomponents.core5:httpcore5-reactive:5.2.1")
|
||||
api("org.apache.poi:poi-ooxml:5.2.3")
|
||||
api("org.apache.tomcat.embed:tomcat-embed-core:10.1.5")
|
||||
api("org.apache.tomcat.embed:tomcat-embed-websocket:10.1.5")
|
||||
api("org.apache.tomcat:tomcat-util:10.1.5")
|
||||
api("org.apache.tomcat:tomcat-websocket:10.1.5")
|
||||
api("org.aspectj:aspectjrt:1.9.9.1")
|
||||
api("org.aspectj:aspectjtools:1.9.9.1")
|
||||
api("org.aspectj:aspectjweaver:1.9.9.1")
|
||||
api("org.apache.tomcat.embed:tomcat-embed-core:10.1.7")
|
||||
api("org.apache.tomcat.embed:tomcat-embed-websocket:10.1.7")
|
||||
api("org.apache.tomcat:tomcat-util:10.1.7")
|
||||
api("org.apache.tomcat:tomcat-websocket:10.1.7")
|
||||
api("org.aspectj:aspectjrt:1.9.19")
|
||||
api("org.aspectj:aspectjtools:1.9.19")
|
||||
api("org.aspectj:aspectjweaver:1.9.19")
|
||||
api("org.assertj:assertj-core:3.24.2")
|
||||
api("org.awaitility:awaitility:3.1.6")
|
||||
api("org.bouncycastle:bcpkix-jdk18on:1.71")
|
||||
api("org.codehaus.jettison:jettison:1.3.8")
|
||||
api("org.dom4j:dom4j:2.1.3")
|
||||
api("org.eclipse.jetty:jetty-reactive-httpclient:3.0.7")
|
||||
api("org.awaitility:awaitility:4.2.0")
|
||||
api("org.bouncycastle:bcpkix-jdk18on:1.72")
|
||||
api("org.codehaus.jettison:jettison:1.5.4")
|
||||
api("org.dom4j:dom4j:2.1.4")
|
||||
api("org.eclipse.jetty:jetty-reactive-httpclient:3.0.8")
|
||||
api("org.eclipse.persistence:org.eclipse.persistence.jpa:3.0.3")
|
||||
api("org.eclipse:yasson:2.0.4")
|
||||
api("org.ehcache:ehcache:3.4.0")
|
||||
api("org.ehcache:ehcache:3.10.8")
|
||||
api("org.ehcache:jcache:1.0.1")
|
||||
api("org.freemarker:freemarker:2.3.32")
|
||||
// Substitute for "javax.management:jmxremote_optional:1.0.1_04" which
|
||||
// is not available on Maven Central
|
||||
api("org.glassfish.external:opendmk_jmxremote_optional_jar:1.0-b01-ea")
|
||||
api("org.glassfish.tyrus:tyrus-container-servlet:2.0.1")
|
||||
api("org.glassfish.tyrus:tyrus-container-servlet:2.1.3")
|
||||
api("org.glassfish:jakarta.el:4.0.2")
|
||||
api("org.graalvm.sdk:graal-sdk:22.3.0")
|
||||
api("org.graalvm.sdk:graal-sdk:22.3.1")
|
||||
api("org.hamcrest:hamcrest:2.2")
|
||||
api("org.hibernate:hibernate-core-jakarta:5.6.15.Final")
|
||||
api("org.hibernate:hibernate-validator:7.0.5.Final")
|
||||
api("org.hsqldb:hsqldb:2.7.1")
|
||||
api("org.javamoney:moneta:1.4.2")
|
||||
api("org.jruby:jruby:9.4.0.0")
|
||||
api("org.jruby:jruby:9.4.2.0")
|
||||
api("org.junit.support:testng-engine:1.0.4")
|
||||
api("org.mozilla:rhino:1.7.11")
|
||||
api("org.mozilla:rhino:1.7.14")
|
||||
api("org.ogce:xpp3:1.1.6")
|
||||
api("org.python:jython-standalone:2.7.1")
|
||||
api("org.python:jython-standalone:2.7.3")
|
||||
api("org.quartz-scheduler:quartz:2.3.2")
|
||||
api("org.seleniumhq.selenium:htmlunit-driver:2.70.0")
|
||||
api("org.seleniumhq.selenium:selenium-java:3.141.59")
|
||||
api("org.skyscreamer:jsonassert:1.5.0")
|
||||
api("org.slf4j:slf4j-api:2.0.6")
|
||||
api("org.skyscreamer:jsonassert:1.5.1")
|
||||
api("org.slf4j:slf4j-api:2.0.7")
|
||||
api("org.testng:testng:7.7.1")
|
||||
api("org.webjars:underscorejs:1.8.3")
|
||||
api("org.webjars:webjars-locator-core:0.52")
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=6.0.5
|
||||
version=6.0.8
|
||||
|
||||
org.gradle.caching=true
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
* One can choose the toolchain to use for compiling the MAIN sources and/or compiling
|
||||
* and running the TEST sources. These options apply to Java, Kotlin and Groovy sources
|
||||
* when available.
|
||||
* {@code "./gradlew check -PmainToolchain=17 -PtestToolchain=19"} will use:
|
||||
* {@code "./gradlew check -PmainToolchain=17 -PtestToolchain=20"} will use:
|
||||
* <ul>
|
||||
* <li>a JDK17 toolchain for compiling the main SourceSet
|
||||
* <li>a JDK19 toolchain for compiling and running the test SourceSet
|
||||
* <li>a JDK20 toolchain for compiling and running the test SourceSet
|
||||
* </ul>
|
||||
*
|
||||
* By default, the build will fall back to using the current JDK and 17 language level for all sourceSets.
|
||||
@@ -23,9 +23,9 @@
|
||||
* {@code
|
||||
* $ echo JDK17
|
||||
* /opt/openjdk/java17
|
||||
* $ echo JDK19
|
||||
* /opt/openjdk/java18
|
||||
* $ ./gradlew -Porg.gradle.java.installations.fromEnv=JDK17,JDK19 check
|
||||
* $ echo JDK20
|
||||
* /opt/openjdk/java20
|
||||
* $ ./gradlew -Porg.gradle.java.installations.fromEnv=JDK17,JDK20 check
|
||||
* }
|
||||
*
|
||||
* @author Brian Clozel
|
||||
@@ -81,6 +81,7 @@ plugins.withType(JavaPlugin) {
|
||||
javaLauncher = javaToolchains.launcherFor {
|
||||
languageVersion = testLanguageVersion
|
||||
}
|
||||
jvmArgs += ['-Djava.locale.providers=COMPAT']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -144,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@@ -152,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -99,7 +99,7 @@ class AopNamespaceHandlerScopeIntegrationTests {
|
||||
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(oldRequest));
|
||||
assertThat(requestScoped.getName()).isEqualTo(bram);
|
||||
|
||||
assertThat(((Advised) requestScoped).getAdvisors().length > 0).as("Should have advisors").isTrue();
|
||||
assertThat(((Advised) requestScoped).getAdvisors()).as("Should have advisors").isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -131,7 +131,7 @@ class AopNamespaceHandlerScopeIntegrationTests {
|
||||
request.setSession(oldSession);
|
||||
assertThat(sessionScoped.getName()).isEqualTo(bram);
|
||||
|
||||
assertThat(((Advised) sessionScoped).getAdvisors().length > 0).as("Should have advisors").isTrue();
|
||||
assertThat(((Advised) sessionScoped).getAdvisors()).as("Should have advisors").isNotEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -52,25 +52,25 @@ class ComponentBeanDefinitionParserTests {
|
||||
@Test
|
||||
void testBionicBasic() {
|
||||
Component cp = getBionicFamily();
|
||||
assertThat("Bionic-1").isEqualTo(cp.getName());
|
||||
assertThat(cp.getName()).isEqualTo("Bionic-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBionicFirstLevelChildren() {
|
||||
Component cp = getBionicFamily();
|
||||
List<Component> components = cp.getComponents();
|
||||
assertThat(2).isEqualTo(components.size());
|
||||
assertThat("Mother-1").isEqualTo(components.get(0).getName());
|
||||
assertThat("Rock-1").isEqualTo(components.get(1).getName());
|
||||
assertThat(components).hasSize(2);
|
||||
assertThat(components.get(0).getName()).isEqualTo("Mother-1");
|
||||
assertThat(components.get(1).getName()).isEqualTo("Rock-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBionicSecondLevelChildren() {
|
||||
Component cp = getBionicFamily();
|
||||
List<Component> components = cp.getComponents().get(0).getComponents();
|
||||
assertThat(2).isEqualTo(components.size());
|
||||
assertThat("Karate-1").isEqualTo(components.get(0).getName());
|
||||
assertThat("Sport-1").isEqualTo(components.get(1).getName());
|
||||
assertThat(components).hasSize(2);
|
||||
assertThat(components.get(0).getName()).isEqualTo("Karate-1");
|
||||
assertThat(components.get(1).getName()).isEqualTo("Sport-1");
|
||||
}
|
||||
|
||||
private Component getBionicFamily() {
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "com.gradle.enterprise" version "3.12.3"
|
||||
id "com.gradle.enterprise" version "3.12.6"
|
||||
id "io.spring.ge.conventions" version "0.0.13"
|
||||
}
|
||||
|
||||
|
||||
+15
-9
@@ -248,20 +248,26 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
|
||||
}
|
||||
|
||||
/**
|
||||
* Set by creator of this advice object if the argument names are known.
|
||||
* <p>This could be for example because they have been explicitly specified in XML,
|
||||
* Set by the creator of this advice object if the argument names are known.
|
||||
* <p>This could be for example because they have been explicitly specified in XML
|
||||
* or in an advice annotation.
|
||||
* @param argNames comma delimited list of arg names
|
||||
* @param argumentNames comma delimited list of argument names
|
||||
*/
|
||||
public void setArgumentNames(String argNames) {
|
||||
String[] tokens = StringUtils.commaDelimitedListToStringArray(argNames);
|
||||
public void setArgumentNames(String argumentNames) {
|
||||
String[] tokens = StringUtils.commaDelimitedListToStringArray(argumentNames);
|
||||
setArgumentNamesFromStringArray(tokens);
|
||||
}
|
||||
|
||||
public void setArgumentNamesFromStringArray(String... args) {
|
||||
this.argumentNames = new String[args.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
this.argumentNames[i] = args[i].strip();
|
||||
/**
|
||||
* Set by the creator of this advice object if the argument names are known.
|
||||
* <p>This could be for example because they have been explicitly specified in XML
|
||||
* or in an advice annotation.
|
||||
* @param argumentNames list of argument names
|
||||
*/
|
||||
public void setArgumentNamesFromStringArray(String... argumentNames) {
|
||||
this.argumentNames = new String[argumentNames.length];
|
||||
for (int i = 0; i < argumentNames.length; i++) {
|
||||
this.argumentNames[i] = argumentNames[i].strip();
|
||||
if (!isVariableName(this.argumentNames[i])) {
|
||||
throw new IllegalArgumentException(
|
||||
"'argumentNames' property of AbstractAspectJAdvice contains an argument name '" +
|
||||
|
||||
+32
-47
@@ -38,6 +38,14 @@ import org.springframework.util.StringUtils;
|
||||
* for an advice method from the pointcut expression, returning, and throwing clauses.
|
||||
* If an unambiguous interpretation is not available, it returns {@code null}.
|
||||
*
|
||||
* <h3>Algorithm Summary</h3>
|
||||
* <p>If an unambiguous binding can be deduced, then it is.
|
||||
* If the advice requirements cannot possibly be satisfied, then {@code null}
|
||||
* is returned. By setting the {@link #setRaiseExceptions(boolean) raiseExceptions}
|
||||
* property to {@code true}, descriptive exceptions will be thrown instead of
|
||||
* returning {@code null} in the case that the parameter names cannot be discovered.
|
||||
*
|
||||
* <h3>Algorithm Details</h3>
|
||||
* <p>This class interprets arguments in the following way:
|
||||
* <ol>
|
||||
* <li>If the first parameter of the method is of type {@link JoinPoint}
|
||||
@@ -65,15 +73,15 @@ import org.springframework.util.StringUtils;
|
||||
* zero we proceed to the next stage. If {@code a} > 1 then an
|
||||
* {@code AmbiguousBindingException} is raised. If {@code a} == 1,
|
||||
* and there are no unbound arguments of type {@code Annotation+},
|
||||
* then an {@code IllegalArgumentException} is raised. if there is
|
||||
* then an {@code IllegalArgumentException} is raised. If there is
|
||||
* exactly one such argument, then the corresponding parameter name is
|
||||
* assigned the value from the pointcut expression.</li>
|
||||
* <li>If a returningName has been set, and there are no unbound arguments
|
||||
* <li>If a {@code returningName} has been set, and there are no unbound arguments
|
||||
* then an {@code IllegalArgumentException} is raised. If there is
|
||||
* more than one unbound argument then an
|
||||
* {@code AmbiguousBindingException} is raised. If there is exactly
|
||||
* one unbound argument then the corresponding parameter name is assigned
|
||||
* the value <returningName>.</li>
|
||||
* the value of the {@code returningName}.</li>
|
||||
* <li>If there remain unbound arguments, then the pointcut expression is
|
||||
* examined once more for {@code this}, {@code target}, and
|
||||
* {@code args} pointcut expressions used in the binding form (binding
|
||||
@@ -99,20 +107,12 @@ import org.springframework.util.StringUtils;
|
||||
* <p>The behavior on raising an {@code IllegalArgumentException} or
|
||||
* {@code AmbiguousBindingException} is configurable to allow this discoverer
|
||||
* to be used as part of a chain-of-responsibility. By default the condition will
|
||||
* be logged and the {@code getParameterNames(..)} method will simply return
|
||||
* be logged and the {@link #getParameterNames(Method)} method will simply return
|
||||
* {@code null}. If the {@link #setRaiseExceptions(boolean) raiseExceptions}
|
||||
* property is set to {@code true}, the conditions will be thrown as
|
||||
* {@code IllegalArgumentException} and {@code AmbiguousBindingException},
|
||||
* respectively.
|
||||
*
|
||||
* <p>Was that perfectly clear? ;)
|
||||
*
|
||||
* <p>Short version: If an unambiguous binding can be deduced, then it is.
|
||||
* If the advice requirements cannot possibly be satisfied, then {@code null}
|
||||
* is returned. By setting the {@link #setRaiseExceptions(boolean) raiseExceptions}
|
||||
* property to {@code true}, descriptive exceptions will be thrown instead of
|
||||
* returning {@code null} in the case that the parameter names cannot be discovered.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
@@ -197,7 +197,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
|
||||
/**
|
||||
* If {@code afterReturning} advice binds the return value, the
|
||||
* returning variable name must be specified.
|
||||
* {@code returning} variable name must be specified.
|
||||
* @param returningName the name of the returning variable
|
||||
*/
|
||||
public void setReturningName(@Nullable String returningName) {
|
||||
@@ -206,18 +206,17 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
|
||||
/**
|
||||
* If {@code afterThrowing} advice binds the thrown value, the
|
||||
* throwing variable name must be specified.
|
||||
* {@code throwing} variable name must be specified.
|
||||
* @param throwingName the name of the throwing variable
|
||||
*/
|
||||
public void setThrowingName(@Nullable String throwingName) {
|
||||
this.throwingName = throwingName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deduce the parameter names for an advice method.
|
||||
* <p>See the {@link AspectJAdviceParameterNameDiscoverer class level javadoc}
|
||||
* for this class for details of the algorithm used.
|
||||
* <p>See the {@link AspectJAdviceParameterNameDiscoverer class-level javadoc}
|
||||
* for this class for details on the algorithm used.
|
||||
* @param method the target {@link Method}
|
||||
* @return the parameter names
|
||||
*/
|
||||
@@ -309,7 +308,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
}
|
||||
|
||||
/**
|
||||
* If the first parameter is of type JoinPoint or ProceedingJoinPoint,bind "thisJoinPoint" as
|
||||
* If the first parameter is of type JoinPoint or ProceedingJoinPoint, bind "thisJoinPoint" as
|
||||
* parameter name and return true, else return false.
|
||||
*/
|
||||
private boolean maybeBindThisJoinPoint() {
|
||||
@@ -348,14 +347,14 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
// Second candidate we've found - ambiguous binding
|
||||
throw new AmbiguousBindingException("Binding of throwing parameter '" +
|
||||
this.throwingName + "' is ambiguous: could be bound to argument " +
|
||||
throwableIndex + " or argument " + i);
|
||||
throwableIndex + " or " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (throwableIndex == -1) {
|
||||
throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName
|
||||
+ "' could not be completed as no available arguments are a subtype of Throwable");
|
||||
throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName +
|
||||
"' could not be completed as no available arguments are a subtype of Throwable");
|
||||
}
|
||||
else {
|
||||
bindParameterName(throwableIndex, this.throwingName);
|
||||
@@ -374,7 +373,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
if (this.returningName != null) {
|
||||
if (this.numberOfRemainingUnboundArguments > 1) {
|
||||
throw new AmbiguousBindingException("Binding of returning parameter '" + this.returningName +
|
||||
"' is ambiguous, there are " + this.numberOfRemainingUnboundArguments + " candidates.");
|
||||
"' is ambiguous: there are " + this.numberOfRemainingUnboundArguments + " candidates.");
|
||||
}
|
||||
|
||||
// We're all set... find the unbound parameter, and bind it.
|
||||
@@ -387,7 +386,6 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the string pointcut expression looking for:
|
||||
* @this, @target, @args, @within, @withincode, @annotation.
|
||||
@@ -431,7 +429,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
int numAnnotationSlots = countNumberOfUnboundAnnotationArguments();
|
||||
if (numAnnotationSlots > 1) {
|
||||
throw new AmbiguousBindingException("Found " + varNames.size() +
|
||||
" potential annotation variable(s), and " +
|
||||
" potential annotation variable(s) and " +
|
||||
numAnnotationSlots + " potential argument slots");
|
||||
}
|
||||
else if (numAnnotationSlots == 1) {
|
||||
@@ -452,7 +450,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* If the token starts meets Java identifier conventions, it's in.
|
||||
*/
|
||||
@Nullable
|
||||
@@ -488,7 +486,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
private void maybeBindThisOrTargetOrArgsFromPointcutExpression() {
|
||||
if (this.numberOfRemainingUnboundArguments > 1) {
|
||||
throw new AmbiguousBindingException("Still " + this.numberOfRemainingUnboundArguments
|
||||
+ " unbound args at this(),target(),args() binding stage, with no way to determine between them");
|
||||
+ " unbound args at this()/target()/args() binding stage, with no way to determine between them");
|
||||
}
|
||||
|
||||
List<String> varNames = new ArrayList<>();
|
||||
@@ -520,10 +518,9 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (varNames.size() > 1) {
|
||||
throw new AmbiguousBindingException("Found " + varNames.size() +
|
||||
" candidate this(), target() or args() variables but only one unbound argument slot");
|
||||
" candidate this(), target(), or args() variables but only one unbound argument slot");
|
||||
}
|
||||
else if (varNames.size() == 1) {
|
||||
for (int j = 0; j < this.parameterNameBindings.length; j++) {
|
||||
@@ -596,7 +593,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
// else varNames.size must be 0 and we have nothing to bind.
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* We've found the start of a binding pointcut at the given index into the
|
||||
* token array. Now we need to extract the pointcut body and return it.
|
||||
*/
|
||||
@@ -649,8 +646,8 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
private void maybeBindPrimitiveArgsFromPointcutExpression() {
|
||||
int numUnboundPrimitives = countNumberOfUnboundPrimitiveArguments();
|
||||
if (numUnboundPrimitives > 1) {
|
||||
throw new AmbiguousBindingException("Found '" + numUnboundPrimitives +
|
||||
"' unbound primitive arguments with no way to distinguish between them.");
|
||||
throw new AmbiguousBindingException("Found " + numUnboundPrimitives +
|
||||
" unbound primitive arguments with no way to distinguish between them.");
|
||||
}
|
||||
if (numUnboundPrimitives == 1) {
|
||||
// Look for arg variable and bind it if we find exactly one...
|
||||
@@ -696,7 +693,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Return {@code true} if the given argument type is a subclass
|
||||
* of the given supertype.
|
||||
*/
|
||||
@@ -724,7 +721,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Find the argument index with the given type, and bind the given
|
||||
* {@code varName} in that position.
|
||||
*/
|
||||
@@ -741,22 +738,10 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
|
||||
|
||||
|
||||
/**
|
||||
* Simple struct to hold the extracted text from a pointcut body, together
|
||||
* Simple record to hold the extracted text from a pointcut body, together
|
||||
* with the number of tokens consumed in extracting it.
|
||||
*/
|
||||
private static class PointcutBody {
|
||||
|
||||
private final int numTokensConsumed;
|
||||
|
||||
@Nullable
|
||||
private final String text;
|
||||
|
||||
public PointcutBody(int tokens, @Nullable String text) {
|
||||
this.numTokensConsumed = tokens;
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
private record PointcutBody(int numTokensConsumed, @Nullable String text) {}
|
||||
|
||||
/**
|
||||
* Thrown in response to an ambiguous binding being detected when
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -117,7 +117,7 @@ public class TypePatternClassFilter implements ClassFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return (this == obj || (obj instanceof TypePatternClassFilter that &&
|
||||
ObjectUtils.nullSafeEquals(this.typePattern, that.typePattern)));
|
||||
}
|
||||
|
||||
+24
-22
@@ -121,21 +121,21 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
|
||||
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
|
||||
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
|
||||
if (foundAnnotation != null) {
|
||||
return foundAnnotation;
|
||||
protected static AspectJAnnotation findAspectJAnnotationOnMethod(Method method) {
|
||||
for (Class<?> annotationType : ASPECTJ_ANNOTATION_CLASSES) {
|
||||
AspectJAnnotation annotation = findAnnotation(method, (Class<Annotation>) annotationType);
|
||||
if (annotation != null) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
|
||||
A result = AnnotationUtils.findAnnotation(method, toLookFor);
|
||||
if (result != null) {
|
||||
return new AspectJAnnotation<>(result);
|
||||
private static AspectJAnnotation findAnnotation(Method method, Class<? extends Annotation> annotationType) {
|
||||
Annotation annotation = AnnotationUtils.findAnnotation(method, annotationType);
|
||||
if (annotation != null) {
|
||||
return new AspectJAnnotation(annotation);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
@@ -156,9 +156,8 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
/**
|
||||
* Class modeling an AspectJ annotation, exposing its type enumeration and
|
||||
* pointcut String.
|
||||
* @param <A> the annotation type
|
||||
*/
|
||||
protected static class AspectJAnnotation<A extends Annotation> {
|
||||
protected static class AspectJAnnotation {
|
||||
|
||||
private static final String[] EXPRESSION_ATTRIBUTES = {"pointcut", "value"};
|
||||
|
||||
@@ -171,7 +170,7 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
AfterThrowing.class, AspectJAnnotationType.AtAfterThrowing //
|
||||
);
|
||||
|
||||
private final A annotation;
|
||||
private final Annotation annotation;
|
||||
|
||||
private final AspectJAnnotationType annotationType;
|
||||
|
||||
@@ -179,11 +178,11 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
|
||||
private final String argumentNames;
|
||||
|
||||
public AspectJAnnotation(A annotation) {
|
||||
public AspectJAnnotation(Annotation annotation) {
|
||||
this.annotation = annotation;
|
||||
this.annotationType = determineAnnotationType(annotation);
|
||||
try {
|
||||
this.pointcutExpression = resolveExpression(annotation);
|
||||
this.pointcutExpression = resolvePointcutExpression(annotation);
|
||||
Object argNames = AnnotationUtils.getValue(annotation, "argNames");
|
||||
this.argumentNames = (argNames instanceof String names ? names : "");
|
||||
}
|
||||
@@ -192,7 +191,7 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
}
|
||||
}
|
||||
|
||||
private AspectJAnnotationType determineAnnotationType(A annotation) {
|
||||
private AspectJAnnotationType determineAnnotationType(Annotation annotation) {
|
||||
AspectJAnnotationType type = annotationTypeMap.get(annotation.annotationType());
|
||||
if (type != null) {
|
||||
return type;
|
||||
@@ -200,21 +199,21 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
throw new IllegalStateException("Unknown annotation type: " + annotation);
|
||||
}
|
||||
|
||||
private String resolveExpression(A annotation) {
|
||||
private String resolvePointcutExpression(Annotation annotation) {
|
||||
for (String attributeName : EXPRESSION_ATTRIBUTES) {
|
||||
Object val = AnnotationUtils.getValue(annotation, attributeName);
|
||||
if (val instanceof String str && !str.isEmpty()) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Failed to resolve expression in: " + annotation);
|
||||
throw new IllegalStateException("Failed to resolve pointcut expression in: " + annotation);
|
||||
}
|
||||
|
||||
public AspectJAnnotationType getAnnotationType() {
|
||||
return this.annotationType;
|
||||
}
|
||||
|
||||
public A getAnnotation() {
|
||||
public Annotation getAnnotation() {
|
||||
return this.annotation;
|
||||
}
|
||||
|
||||
@@ -239,19 +238,22 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
|
||||
*/
|
||||
private static class AspectJAnnotationParameterNameDiscoverer implements ParameterNameDiscoverer {
|
||||
|
||||
private static final String[] EMPTY_ARRAY = new String[0];
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String[] getParameterNames(Method method) {
|
||||
if (method.getParameterCount() == 0) {
|
||||
return new String[0];
|
||||
return EMPTY_ARRAY;
|
||||
}
|
||||
AspectJAnnotation<?> annotation = findAspectJAnnotationOnMethod(method);
|
||||
AspectJAnnotation annotation = findAspectJAnnotationOnMethod(method);
|
||||
if (annotation == null) {
|
||||
return null;
|
||||
}
|
||||
StringTokenizer nameTokens = new StringTokenizer(annotation.getArgumentNames(), ",");
|
||||
if (nameTokens.countTokens() > 0) {
|
||||
String[] names = new String[nameTokens.countTokens()];
|
||||
int numTokens = nameTokens.countTokens();
|
||||
if (numTokens > 0) {
|
||||
String[] names = new String[numTokens];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
names[i] = nameTokens.nextToken();
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -35,7 +35,8 @@ import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Internal implementation of AspectJPointcutAdvisor.
|
||||
* Note that there will be one instance of this advisor for each target method.
|
||||
*
|
||||
* <p>Note that there will be one instance of this advisor for each target method.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
@@ -212,7 +213,7 @@ final class InstantiationModelAwarePointcutAdvisorImpl
|
||||
* creation of the advice.
|
||||
*/
|
||||
private void determineAdviceType() {
|
||||
AspectJAnnotation<?> aspectJAnnotation =
|
||||
AspectJAnnotation aspectJAnnotation =
|
||||
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(this.aspectJAdviceMethod);
|
||||
if (aspectJAnnotation == null) {
|
||||
this.isBeforeAdvice = false;
|
||||
|
||||
+3
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -23,10 +23,6 @@ import org.springframework.lang.Nullable;
|
||||
* Subinterface of {@link org.springframework.aop.aspectj.AspectInstanceFactory}
|
||||
* that returns {@link AspectMetadata} associated with AspectJ-annotated classes.
|
||||
*
|
||||
* <p>Ideally, AspectInstanceFactory would include this method itself, but because
|
||||
* AspectMetadata uses Java-5-only {@link org.aspectj.lang.reflect.AjType},
|
||||
* we need to split out this subinterface.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since 2.0
|
||||
* @see AspectMetadata
|
||||
@@ -35,13 +31,13 @@ import org.springframework.lang.Nullable;
|
||||
public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory {
|
||||
|
||||
/**
|
||||
* Return the AspectJ AspectMetadata for this factory's aspect.
|
||||
* Get the AspectJ AspectMetadata for this factory's aspect.
|
||||
* @return the aspect metadata
|
||||
*/
|
||||
AspectMetadata getAspectMetadata();
|
||||
|
||||
/**
|
||||
* Return the best possible creation mutex for this factory.
|
||||
* Get the best possible creation mutex for this factory.
|
||||
* @return the mutex object (may be {@code null} for no mutex to use)
|
||||
* @since 4.3
|
||||
*/
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -87,7 +87,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
new InstanceComparator<>(
|
||||
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
|
||||
(Converter<Method, Annotation>) method -> {
|
||||
AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
|
||||
AspectJAnnotation ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
|
||||
return (ann != null ? ann.getAnnotation() : null);
|
||||
});
|
||||
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
|
||||
@@ -216,7 +216,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
|
||||
@Nullable
|
||||
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
|
||||
AspectJAnnotation<?> aspectJAnnotation =
|
||||
AspectJAnnotation aspectJAnnotation =
|
||||
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
|
||||
if (aspectJAnnotation == null) {
|
||||
return null;
|
||||
@@ -240,7 +240,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
||||
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
|
||||
validate(candidateAspectClass);
|
||||
|
||||
AspectJAnnotation<?> aspectJAnnotation =
|
||||
AspectJAnnotation aspectJAnnotation =
|
||||
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
|
||||
if (aspectJAnnotation == null) {
|
||||
return null;
|
||||
|
||||
+7
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 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.
|
||||
@@ -21,20 +21,13 @@ import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
|
||||
/**
|
||||
* Internal framework class, combining a MethodInterceptor instance
|
||||
* with a MethodMatcher for use as an element in the advisor chain.
|
||||
* Internal framework record, combining a {@link MethodInterceptor} instance
|
||||
* with a {@link MethodMatcher} for use as an element in the advisor chain.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Sam Brannen
|
||||
* @param interceptor the {@code MethodInterceptor}
|
||||
* @param matcher the {@code MethodMatcher}
|
||||
*/
|
||||
class InterceptorAndDynamicMethodMatcher {
|
||||
|
||||
final MethodInterceptor interceptor;
|
||||
|
||||
final MethodMatcher methodMatcher;
|
||||
|
||||
public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {
|
||||
this.interceptor = interceptor;
|
||||
this.methodMatcher = methodMatcher;
|
||||
}
|
||||
|
||||
record InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher matcher) {
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -120,6 +120,11 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
|
||||
}
|
||||
if (classLoader == null || classLoader.getParent() == null) {
|
||||
// JDK bootstrap loader or platform loader suggested ->
|
||||
// use higher-level loader which can see Spring infrastructure classes
|
||||
classLoader = getClass().getClassLoader();
|
||||
}
|
||||
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -169,8 +169,8 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea
|
||||
// Evaluate dynamic method matcher here: static part will already have
|
||||
// been evaluated and found to match.
|
||||
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
|
||||
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
|
||||
return dm.interceptor.invoke(this);
|
||||
if (dm.matcher().matches(this.method, targetClass, this.arguments)) {
|
||||
return dm.interceptor().invoke(this);
|
||||
}
|
||||
else {
|
||||
// Dynamic matching failed.
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -92,8 +92,7 @@ public class BeanFactoryAdvisorRetrievalHelper {
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
Throwable rootCause = ex.getMostSpecificCause();
|
||||
if (rootCause instanceof BeanCurrentlyInCreationException) {
|
||||
BeanCreationException bce = (BeanCreationException) rootCause;
|
||||
if (rootCause instanceof BeanCurrentlyInCreationException bce) {
|
||||
String bceBeanName = bce.getBeanName();
|
||||
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -58,11 +58,11 @@ public abstract class AbstractBeanFactoryBasedTargetSourceCreator
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@Nullable
|
||||
private ConfigurableBeanFactory beanFactory;
|
||||
|
||||
/** Internally used DefaultListableBeanFactory instances, keyed by bean name. */
|
||||
private final Map<String, DefaultListableBeanFactory> internalBeanFactories =
|
||||
new HashMap<>();
|
||||
private final Map<String, DefaultListableBeanFactory> internalBeanFactories = new HashMap<>();
|
||||
|
||||
|
||||
@Override
|
||||
@@ -77,6 +77,7 @@ public abstract class AbstractBeanFactoryBasedTargetSourceCreator
|
||||
/**
|
||||
* Return the BeanFactory that this TargetSourceCreators runs in.
|
||||
*/
|
||||
@Nullable
|
||||
protected final BeanFactory getBeanFactory() {
|
||||
return this.beanFactory;
|
||||
}
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Various {@link org.springframework.aop.framework.autoproxy.TargetSourceCreator}
|
||||
* implementations for use with Spring's AOP auto-proxying support.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.aop.framework.autoproxy.target;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -55,8 +55,8 @@ class ScopedProxyBeanRegistrationAotProcessor implements BeanRegistrationAotProc
|
||||
|
||||
@Override
|
||||
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
|
||||
Class<?> beanType = registeredBean.getBeanType().toClass();
|
||||
if (beanType.equals(ScopedProxyFactoryBean.class)) {
|
||||
Class<?> beanClass = registeredBean.getBeanClass();
|
||||
if (beanClass.equals(ScopedProxyFactoryBean.class)) {
|
||||
String targetBeanName = getTargetBeanName(registeredBean.getMergedBeanDefinition());
|
||||
BeanDefinition targetBeanDefinition =
|
||||
getTargetBeanDefinition(registeredBean.getBeanFactory(), targetBeanName);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.aop.support;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -45,7 +46,7 @@ public class RootClassFilter implements ClassFilter, Serializable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return (this == obj || (obj instanceof RootClassFilter that &&
|
||||
this.clazz.equals(that.clazz)));
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -183,7 +183,7 @@ public class AnnotationMatchingPointcut implements Pointcut {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -169,7 +170,7 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -181,7 +181,7 @@ public class CommonsPool2TargetSource extends AbstractPoolingTargetSource implem
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the call should bock when the pool is exhausted.
|
||||
* Set whether the call should block when the pool is exhausted.
|
||||
*/
|
||||
public void setBlockWhenExhausted(boolean blockWhenExhausted) {
|
||||
this.blockWhenExhausted = blockWhenExhausted;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -131,7 +131,7 @@ public final class EmptyTargetSource implements TargetSource, Serializable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.aop.target;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -100,7 +101,7 @@ public class HotSwappableTargetSource implements TargetSource, Serializable {
|
||||
* objects are equal.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return (this == obj || (obj instanceof HotSwappableTargetSource that &&
|
||||
this.target.equals(that.target)));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -65,7 +65,6 @@ public class LazyInitTargetSource extends AbstractBeanFactoryBasedTargetSource {
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public synchronized Object getTarget() throws BeansException {
|
||||
if (this.target == null) {
|
||||
this.target = getBeanFactory().getBean(getTargetBeanName());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.aop.target;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -82,7 +83,7 @@ public class SingletonTargetSource implements TargetSource, Serializable {
|
||||
* targets or the targets are equal.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Support for dynamic, refreshable {@link org.springframework.aop.TargetSource}
|
||||
* implementations for use with Spring AOP.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.aop.target.dynamic;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Various {@link org.springframework.aop.TargetSource} implementations for use
|
||||
* with Spring AOP.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.aop.target;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
+55
-67
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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,7 +17,6 @@
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
@@ -43,17 +42,17 @@ class AspectJAdviceParameterNameDiscovererTests {
|
||||
|
||||
@Test
|
||||
void noArgs() {
|
||||
assertParameterNames(getMethod("noArgs"), "execution(* *(..))", new String[0]);
|
||||
assertParameterNames(getMethod("noArgs"), "execution(* *(..))");
|
||||
}
|
||||
|
||||
@Test
|
||||
void joinPointOnly() {
|
||||
assertParameterNames(getMethod("tjp"), "execution(* *(..))", new String[] {"thisJoinPoint"});
|
||||
assertParameterNames(getMethod("tjp"), "execution(* *(..))", "thisJoinPoint");
|
||||
}
|
||||
|
||||
@Test
|
||||
void joinPointStaticPartOnly() {
|
||||
assertParameterNames(getMethod("tjpsp"), "execution(* *(..))", new String[] {"thisJoinPointStaticPart"});
|
||||
assertParameterNames(getMethod("tjpsp"), "execution(* *(..))", "thisJoinPointStaticPart");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -64,18 +63,18 @@ class AspectJAdviceParameterNameDiscovererTests {
|
||||
|
||||
@Test
|
||||
void oneThrowable() {
|
||||
assertParameterNames(getMethod("oneThrowable"), "foo()", null, "ex", new String[] {"ex"});
|
||||
assertParameterNamesExtended(getMethod("oneThrowable"), "foo()", null, "ex", "ex");
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneJPAndOneThrowable() {
|
||||
assertParameterNames(getMethod("jpAndOneThrowable"), "foo()", null, "ex", new String[] {"thisJoinPoint", "ex"});
|
||||
assertParameterNamesExtended(getMethod("jpAndOneThrowable"), "foo()", null, "ex", "thisJoinPoint", "ex");
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneJPAndTwoThrowables() {
|
||||
assertException(getMethod("jpAndTwoThrowables"), "foo()", null, "ex", AmbiguousBindingException.class,
|
||||
"Binding of throwing parameter 'ex' is ambiguous: could be bound to argument 1 or argument 2");
|
||||
"Binding of throwing parameter 'ex' is ambiguous: could be bound to argument 1 or 2");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -86,13 +85,13 @@ class AspectJAdviceParameterNameDiscovererTests {
|
||||
|
||||
@Test
|
||||
void returning() {
|
||||
assertParameterNames(getMethod("oneObject"), "foo()", "obj", null, new String[] {"obj"});
|
||||
assertParameterNamesExtended(getMethod("oneObject"), "foo()", "obj", null, "obj");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ambiguousReturning() {
|
||||
assertException(getMethod("twoObjects"), "foo()", "obj", null, AmbiguousBindingException.class,
|
||||
"Binding of returning parameter 'obj' is ambiguous, there are 2 candidates.");
|
||||
"Binding of returning parameter 'obj' is ambiguous: there are 2 candidates.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -103,22 +102,22 @@ class AspectJAdviceParameterNameDiscovererTests {
|
||||
|
||||
@Test
|
||||
void thisBindingOneCandidate() {
|
||||
assertParameterNames(getMethod("oneObject"), "this(x)", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "this(x)", "x");
|
||||
}
|
||||
|
||||
@Test
|
||||
void thisBindingWithAlternateTokenizations() {
|
||||
assertParameterNames(getMethod("oneObject"), "this( x )", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "this( x)", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "this (x )", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "this(x )", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "foo() && this(x)", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "this( x )", "x");
|
||||
assertParameterNames(getMethod("oneObject"), "this( x)", "x");
|
||||
assertParameterNames(getMethod("oneObject"), "this (x )", "x");
|
||||
assertParameterNames(getMethod("oneObject"), "this(x )", "x");
|
||||
assertParameterNames(getMethod("oneObject"), "foo() && this(x)", "x");
|
||||
}
|
||||
|
||||
@Test
|
||||
void thisBindingTwoCandidates() {
|
||||
assertException(getMethod("oneObject"), "this(x) || this(y)", AmbiguousBindingException.class,
|
||||
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
|
||||
"Found 2 candidate this(), target(), or args() variables but only one unbound argument slot");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -131,22 +130,22 @@ class AspectJAdviceParameterNameDiscovererTests {
|
||||
|
||||
@Test
|
||||
void targetBindingOneCandidate() {
|
||||
assertParameterNames(getMethod("oneObject"), "target(x)", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "target(x)", "x");
|
||||
}
|
||||
|
||||
@Test
|
||||
void targetBindingWithAlternateTokenizations() {
|
||||
assertParameterNames(getMethod("oneObject"), "target( x )", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "target( x)", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "target (x )", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "target(x )", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "foo() && target(x)", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "target( x )", "x");
|
||||
assertParameterNames(getMethod("oneObject"), "target( x)", "x");
|
||||
assertParameterNames(getMethod("oneObject"), "target (x )", "x");
|
||||
assertParameterNames(getMethod("oneObject"), "target(x )", "x");
|
||||
assertParameterNames(getMethod("oneObject"), "foo() && target(x)", "x");
|
||||
}
|
||||
|
||||
@Test
|
||||
void targetBindingTwoCandidates() {
|
||||
assertException(getMethod("oneObject"), "target(x) || target(y)", AmbiguousBindingException.class,
|
||||
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
|
||||
"Found 2 candidate this(), target(), or args() variables but only one unbound argument slot");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -159,24 +158,24 @@ class AspectJAdviceParameterNameDiscovererTests {
|
||||
|
||||
@Test
|
||||
void argsBindingOneObject() {
|
||||
assertParameterNames(getMethod("oneObject"), "args(x)", new String[] {"x"});
|
||||
assertParameterNames(getMethod("oneObject"), "args(x)", "x");
|
||||
}
|
||||
|
||||
@Test
|
||||
void argsBindingOneObjectTwoCandidates() {
|
||||
assertException(getMethod("oneObject"), "args(x,y)", AmbiguousBindingException.class,
|
||||
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
|
||||
"Found 2 candidate this(), target(), or args() variables but only one unbound argument slot");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ambiguousArgsBinding() {
|
||||
assertException(getMethod("twoObjects"), "args(x,y)", AmbiguousBindingException.class,
|
||||
"Still 2 unbound args at this(),target(),args() binding stage, with no way to determine between them");
|
||||
"Still 2 unbound args at this()/target()/args() binding stage, with no way to determine between them");
|
||||
}
|
||||
|
||||
@Test
|
||||
void argsOnePrimitive() {
|
||||
assertParameterNames(getMethod("onePrimitive"), "args(count)", new String[] {"count"});
|
||||
assertParameterNames(getMethod("onePrimitive"), "args(count)", "count");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -188,37 +187,37 @@ class AspectJAdviceParameterNameDiscovererTests {
|
||||
@Test
|
||||
void thisAndPrimitive() {
|
||||
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && this(obj)",
|
||||
new String[] {"obj", "count"});
|
||||
"obj", "count");
|
||||
}
|
||||
|
||||
@Test
|
||||
void targetAndPrimitive() {
|
||||
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && target(obj)",
|
||||
new String[] {"obj", "count"});
|
||||
"obj", "count");
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwingAndPrimitive() {
|
||||
assertParameterNames(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex",
|
||||
new String[] {"ex", "count"});
|
||||
assertParameterNamesExtended(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex",
|
||||
"ex", "count");
|
||||
}
|
||||
|
||||
@Test
|
||||
void allTogetherNow() {
|
||||
assertParameterNames(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex",
|
||||
new String[] {"thisJoinPoint", "ex", "x", "foo"});
|
||||
assertParameterNamesExtended(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex",
|
||||
"thisJoinPoint", "ex", "x", "foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void referenceBinding() {
|
||||
assertParameterNames(getMethod("onePrimitive"),"somepc(foo)", new String[] {"foo"});
|
||||
assertParameterNames(getMethod("onePrimitive"),"somepc(foo)", "foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void referenceBindingWithAlternateTokenizations() {
|
||||
assertParameterNames(getMethod("onePrimitive"),"call(bar *) && somepc(foo)", new String[] {"foo"});
|
||||
assertParameterNames(getMethod("onePrimitive"),"somepc ( foo )", new String[] {"foo"});
|
||||
assertParameterNames(getMethod("onePrimitive"),"somepc( foo)", new String[] {"foo"});
|
||||
assertParameterNames(getMethod("onePrimitive"),"call(bar *) && somepc(foo)", "foo");
|
||||
assertParameterNames(getMethod("onePrimitive"),"somepc ( foo )", "foo");
|
||||
assertParameterNames(getMethod("onePrimitive"),"somepc( foo)", "foo");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,38 +229,38 @@ class AspectJAdviceParameterNameDiscovererTests {
|
||||
|
||||
@Test
|
||||
void atThis() {
|
||||
assertParameterNames(getMethod("oneAnnotation"),"@this(a)", new String[] {"a"});
|
||||
assertParameterNames(getMethod("oneAnnotation"),"@this(a)", "a");
|
||||
}
|
||||
|
||||
@Test
|
||||
void atTarget() {
|
||||
assertParameterNames(getMethod("oneAnnotation"),"@target(a)", new String[] {"a"});
|
||||
assertParameterNames(getMethod("oneAnnotation"),"@target(a)", "a");
|
||||
}
|
||||
|
||||
@Test
|
||||
void atArgs() {
|
||||
assertParameterNames(getMethod("oneAnnotation"),"@args(a)", new String[] {"a"});
|
||||
assertParameterNames(getMethod("oneAnnotation"),"@args(a)", "a");
|
||||
}
|
||||
|
||||
@Test
|
||||
void atWithin() {
|
||||
assertParameterNames(getMethod("oneAnnotation"),"@within(a)", new String[] {"a"});
|
||||
assertParameterNames(getMethod("oneAnnotation"),"@within(a)", "a");
|
||||
}
|
||||
|
||||
@Test
|
||||
void atWithincode() {
|
||||
assertParameterNames(getMethod("oneAnnotation"),"@withincode(a)", new String[] {"a"});
|
||||
assertParameterNames(getMethod("oneAnnotation"),"@withincode(a)", "a");
|
||||
}
|
||||
|
||||
@Test
|
||||
void atAnnotation() {
|
||||
assertParameterNames(getMethod("oneAnnotation"),"@annotation(a)", new String[] {"a"});
|
||||
assertParameterNames(getMethod("oneAnnotation"),"@annotation(a)", "a");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ambiguousAnnotationTwoVars() {
|
||||
assertException(getMethod("twoAnnotations"),"@annotation(a) && @this(x)", AmbiguousBindingException.class,
|
||||
"Found 2 potential annotation variable(s), and 2 potential argument slots");
|
||||
"Found 2 potential annotation variable(s) and 2 potential argument slots");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -272,15 +271,14 @@ class AspectJAdviceParameterNameDiscovererTests {
|
||||
|
||||
@Test
|
||||
void annotationMedley() {
|
||||
assertParameterNames(getMethod("annotationMedley"),"@annotation(a) && args(count) && this(foo)",
|
||||
null, "ex", new String[] {"ex", "foo", "count", "a"});
|
||||
assertParameterNamesExtended(getMethod("annotationMedley"),"@annotation(a) && args(count) && this(foo)",
|
||||
null, "ex", "ex", "foo", "count", "a");
|
||||
}
|
||||
|
||||
@Test
|
||||
void annotationBinding() {
|
||||
assertParameterNames(getMethod("pjpAndAnAnnotation"),
|
||||
"execution(* *(..)) && @annotation(ann)",
|
||||
new String[] {"thisJoinPoint","ann"});
|
||||
"execution(* *(..)) && @annotation(ann)", "thisJoinPoint", "ann");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -296,33 +294,23 @@ class AspectJAdviceParameterNameDiscovererTests {
|
||||
throw new AssertionError("Bad test specification, no method '" + name + "' found in test class");
|
||||
}
|
||||
|
||||
private void assertParameterNames(Method method, String pointcut, String[] parameterNames) {
|
||||
assertParameterNames(method, pointcut, null, null, parameterNames);
|
||||
private void assertParameterNames(Method method, String pointcut, String... parameterNames) {
|
||||
assertParameterNamesExtended(method, pointcut, null, null, parameterNames);
|
||||
}
|
||||
|
||||
private void assertParameterNames(
|
||||
Method method, String pointcut, String returning, String throwing, String[] parameterNames) {
|
||||
private void assertParameterNamesExtended(
|
||||
Method method, String pointcut, String returning, String throwing, String... parameterNames) {
|
||||
|
||||
assertThat(parameterNames.length).as("bad test specification, must have same number of parameter names as method arguments").isEqualTo(method.getParameterCount());
|
||||
assertThat(parameterNames)
|
||||
.as("bad test specification, must have same number of parameter names as method arguments")
|
||||
.hasSize(method.getParameterCount());
|
||||
|
||||
AspectJAdviceParameterNameDiscoverer discoverer = new AspectJAdviceParameterNameDiscoverer(pointcut);
|
||||
discoverer.setRaiseExceptions(true);
|
||||
discoverer.setReturningName(returning);
|
||||
discoverer.setThrowingName(throwing);
|
||||
String[] discoveredNames = discoverer.getParameterNames(method);
|
||||
|
||||
String formattedExpectedNames = Arrays.toString(parameterNames);
|
||||
String formattedActualNames = Arrays.toString(discoveredNames);
|
||||
|
||||
assertThat(discoveredNames.length).as("Expecting " + parameterNames.length + " parameter names in return set '" +
|
||||
formattedExpectedNames + "', but found " + discoveredNames.length +
|
||||
" '" + formattedActualNames + "'").isEqualTo(parameterNames.length);
|
||||
|
||||
for (int i = 0; i < discoveredNames.length; i++) {
|
||||
assertThat(discoveredNames[i]).as("Parameter names must never be null").isNotNull();
|
||||
assertThat(discoveredNames[i]).as("Expecting parameter " + i + " to be named '" +
|
||||
parameterNames[i] + "' but was '" + discoveredNames[i] + "'").isEqualTo(parameterNames[i]);
|
||||
}
|
||||
assertThat(discoverer.getParameterNames(method)).isEqualTo(parameterNames);
|
||||
}
|
||||
|
||||
private void assertException(Method method, String pointcut, Class<? extends Throwable> exceptionType, String message) {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -70,7 +70,7 @@ public class MethodInvocationProceedingJoinPointTests {
|
||||
AtomicInteger depth = new AtomicInteger();
|
||||
pf.addAdvice((MethodBeforeAdvice) (method, args, target) -> {
|
||||
JoinPoint jp = AbstractAspectJAdvice.currentJoinPoint();
|
||||
assertThat(jp.toString().contains(method.getName())).as("Method named in toString").isTrue();
|
||||
assertThat(jp.toString()).as("Method named in toString").contains(method.getName());
|
||||
// Ensure that these don't cause problems
|
||||
jp.toShortString();
|
||||
jp.toLongString();
|
||||
|
||||
+8
-8
@@ -319,10 +319,10 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
||||
@Test
|
||||
void introductionOnTargetNotImplementingInterface() {
|
||||
NotLockable notLockableTarget = new NotLockable();
|
||||
assertThat(notLockableTarget instanceof Lockable).isFalse();
|
||||
assertThat(notLockableTarget).isNotInstanceOf(Lockable.class);
|
||||
NotLockable notLockable1 = createProxy(notLockableTarget, NotLockable.class,
|
||||
getAdvisorFactory().getAdvisors(aspectInstanceFactory(new MakeLockable(), "someBean")));
|
||||
assertThat(notLockable1 instanceof Lockable).isTrue();
|
||||
assertThat(notLockable1).isInstanceOf(Lockable.class);
|
||||
Lockable lockable = (Lockable) notLockable1;
|
||||
assertThat(lockable.locked()).isFalse();
|
||||
lockable.lock();
|
||||
@@ -331,7 +331,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
||||
NotLockable notLockable2Target = new NotLockable();
|
||||
NotLockable notLockable2 = createProxy(notLockable2Target, NotLockable.class,
|
||||
getAdvisorFactory().getAdvisors(aspectInstanceFactory(new MakeLockable(), "someBean")));
|
||||
assertThat(notLockable2 instanceof Lockable).isTrue();
|
||||
assertThat(notLockable2).isInstanceOf(Lockable.class);
|
||||
Lockable lockable2 = (Lockable) notLockable2;
|
||||
assertThat(lockable2.locked()).isFalse();
|
||||
notLockable2.setIntValue(1);
|
||||
@@ -345,7 +345,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
||||
assertThat(AopUtils.findAdvisorsThatCanApply(
|
||||
getAdvisorFactory().getAdvisors(
|
||||
aspectInstanceFactory(new MakeLockable(), "someBean")),
|
||||
CannotBeUnlocked.class).isEmpty()).isTrue();
|
||||
CannotBeUnlocked.class)).isEmpty();
|
||||
assertThat(AopUtils.findAdvisorsThatCanApply(getAdvisorFactory().getAdvisors(
|
||||
aspectInstanceFactory(new MakeLockable(),"someBean")), NotLockable.class)).hasSize(2);
|
||||
}
|
||||
@@ -373,7 +373,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
||||
AopUtils.findAdvisorsThatCanApply(
|
||||
getAdvisorFactory().getAdvisors(aspectInstanceFactory(new MakeLockable(), "someBean")),
|
||||
List.class));
|
||||
assertThat(proxy instanceof Lockable).as("Type pattern must have excluded mixin").isFalse();
|
||||
assertThat(proxy).as("Type pattern must have excluded mixin").isNotInstanceOf(Lockable.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -430,7 +430,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
||||
UnsupportedOperationException expectedException = new UnsupportedOperationException();
|
||||
List<Advisor> advisors = getAdvisorFactory().getAdvisors(
|
||||
aspectInstanceFactory(new ExceptionThrowingAspect(expectedException), "someBean"));
|
||||
assertThat(advisors.size()).as("One advice method was found").isEqualTo(1);
|
||||
assertThat(advisors).as("One advice method was found").hasSize(1);
|
||||
ITestBean itb = createProxy(target, ITestBean.class, advisors);
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(itb::getAge);
|
||||
}
|
||||
@@ -443,7 +443,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
||||
RemoteException expectedException = new RemoteException();
|
||||
List<Advisor> advisors = getAdvisorFactory().getAdvisors(
|
||||
aspectInstanceFactory(new ExceptionThrowingAspect(expectedException), "someBean"));
|
||||
assertThat(advisors.size()).as("One advice method was found").isEqualTo(1);
|
||||
assertThat(advisors).as("One advice method was found").hasSize(1);
|
||||
ITestBean itb = createProxy(target, ITestBean.class, advisors);
|
||||
assertThatExceptionOfType(UndeclaredThrowableException.class)
|
||||
.isThrownBy(itb::getAge)
|
||||
@@ -456,7 +456,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
||||
TwoAdviceAspect twoAdviceAspect = new TwoAdviceAspect();
|
||||
List<Advisor> advisors = getAdvisorFactory().getAdvisors(
|
||||
aspectInstanceFactory(twoAdviceAspect, "someBean"));
|
||||
assertThat(advisors.size()).as("Two advice methods found").isEqualTo(2);
|
||||
assertThat(advisors).as("Two advice methods found").hasSize(2);
|
||||
ITestBean itb = createProxy(target, ITestBean.class, advisors);
|
||||
itb.setName("");
|
||||
assertThat(itb.getAge()).isEqualTo(0);
|
||||
|
||||
+44
-48
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -38,56 +38,55 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class ArgumentBindingTests {
|
||||
class ArgumentBindingTests {
|
||||
|
||||
@Test
|
||||
public void testBindingInPointcutUsedByAdvice() {
|
||||
TestBean tb = new TestBean();
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
|
||||
void bindingInPointcutUsedByAdvice() {
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
|
||||
proxyFactory.addAspect(NamedPointcutWithArgs.class);
|
||||
|
||||
ITestBean proxiedTestBean = proxyFactory.getProxy();
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
proxiedTestBean.setName("Supercalifragalisticexpialidocious"));
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> proxiedTestBean.setName("enigma"))
|
||||
.withMessage("enigma");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotationArgumentNameBinding() {
|
||||
TransactionalBean tb = new TransactionalBean();
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
|
||||
void annotationArgumentNameBinding() {
|
||||
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TransactionalBean());
|
||||
proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
|
||||
|
||||
ITransactionalBean proxiedTestBean = proxyFactory.getProxy();
|
||||
assertThatIllegalStateException().isThrownBy(
|
||||
proxiedTestBean::doInTransaction);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(proxiedTestBean::doInTransaction)
|
||||
.withMessage("Invoked with @Transactional");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameterNameDiscoverWithReferencePointcut() throws Exception {
|
||||
void parameterNameDiscoverWithReferencePointcut() throws Exception {
|
||||
AspectJAdviceParameterNameDiscoverer discoverer =
|
||||
new AspectJAdviceParameterNameDiscoverer("somepc(formal) && set(* *)");
|
||||
discoverer.setRaiseExceptions(true);
|
||||
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");
|
||||
Method method = getClass().getDeclaredMethod("methodWithOneParam", String.class);
|
||||
assertThat(discoverer.getParameterNames(method)).containsExactly("formal");
|
||||
}
|
||||
|
||||
|
||||
public void methodWithOneParam(String aParam) {
|
||||
@SuppressWarnings("unused")
|
||||
private void methodWithOneParam(String aParam) {
|
||||
}
|
||||
|
||||
|
||||
public interface ITransactionalBean {
|
||||
interface ITransactionalBean {
|
||||
|
||||
@Transactional
|
||||
void doInTransaction();
|
||||
}
|
||||
|
||||
|
||||
public static class TransactionalBean implements ITransactionalBean {
|
||||
static class TransactionalBean implements ITransactionalBean {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@@ -95,38 +94,35 @@ public 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 {
|
||||
|
||||
@Around(value = "execution(* org.springframework..*.*(..)) && @annotation(transactional)")
|
||||
public Object around(ProceedingJoinPoint pjp, Transactional transactional) throws Throwable {
|
||||
throw new IllegalStateException("Invoked with @Transactional");
|
||||
}
|
||||
|
||||
@Aspect
|
||||
class PointcutWithAnnotationArgument {
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@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-2022 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.
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package org.springframework.aop.framework;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Savepoint;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.accessibility.Accessible;
|
||||
@@ -194,11 +197,11 @@ public class ProxyFactoryTests {
|
||||
TestBeanSubclass raw = new TestBeanSubclass();
|
||||
ProxyFactory factory = new ProxyFactory(raw);
|
||||
//System.out.println("Proxied interfaces are " + StringUtils.arrayToDelimitedString(factory.getProxiedInterfaces(), ","));
|
||||
assertThat(factory.getProxiedInterfaces().length).as("Found correct number of interfaces").isEqualTo(5);
|
||||
assertThat(factory.getProxiedInterfaces()).as("Found correct number of interfaces").hasSize(5);
|
||||
ITestBean tb = (ITestBean) factory.getProxy();
|
||||
assertThat(tb).as("Picked up secondary interface").isInstanceOf(IOther.class);
|
||||
raw.setAge(25);
|
||||
assertThat(tb.getAge() == raw.getAge()).isTrue();
|
||||
assertThat(tb.getAge()).isEqualTo(raw.getAge());
|
||||
|
||||
long t = 555555L;
|
||||
TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(t);
|
||||
@@ -208,10 +211,10 @@ public class ProxyFactoryTests {
|
||||
factory.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class));
|
||||
|
||||
Class<?>[] newProxiedInterfaces = factory.getProxiedInterfaces();
|
||||
assertThat(newProxiedInterfaces.length).as("Advisor proxies one more interface after introduction").isEqualTo(oldProxiedInterfaces.length + 1);
|
||||
assertThat(newProxiedInterfaces).as("Advisor proxies one more interface after introduction").hasSize(oldProxiedInterfaces.length + 1);
|
||||
|
||||
TimeStamped ts = (TimeStamped) factory.getProxy();
|
||||
assertThat(ts.getTimeStamp() == t).isTrue();
|
||||
assertThat(ts.getTimeStamp()).isEqualTo(t);
|
||||
// Shouldn't fail;
|
||||
((IOther) ts).absquatulate();
|
||||
}
|
||||
@@ -231,13 +234,13 @@ public class ProxyFactoryTests {
|
||||
factory.addAdvice(0, di);
|
||||
assertThat(factory.getProxy()).isInstanceOf(ITestBean.class);
|
||||
assertThat(factory.adviceIncluded(di)).isTrue();
|
||||
assertThat(!factory.adviceIncluded(diUnused)).isTrue();
|
||||
assertThat(factory.countAdvicesOfType(NopInterceptor.class) == 1).isTrue();
|
||||
assertThat(factory.countAdvicesOfType(MyInterceptor.class) == 0).isTrue();
|
||||
assertThat(factory.adviceIncluded(diUnused)).isFalse();
|
||||
assertThat(factory.countAdvicesOfType(NopInterceptor.class)).isEqualTo(1);
|
||||
assertThat(factory.countAdvicesOfType(MyInterceptor.class)).isEqualTo(0);
|
||||
|
||||
factory.addAdvice(0, diUnused);
|
||||
assertThat(factory.adviceIncluded(diUnused)).isTrue();
|
||||
assertThat(factory.countAdvicesOfType(NopInterceptor.class) == 2).isTrue();
|
||||
assertThat(factory.countAdvicesOfType(NopInterceptor.class)).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -257,7 +260,8 @@ public class ProxyFactoryTests {
|
||||
public void testCanAddAndRemoveAspectInterfacesOnSingleton() {
|
||||
ProxyFactory config = new ProxyFactory(new TestBean());
|
||||
|
||||
assertThat(config.getProxy() instanceof TimeStamped).as("Shouldn't implement TimeStamped before manipulation").isFalse();
|
||||
assertThat(config.getProxy()).as("Shouldn't implement TimeStamped before manipulation")
|
||||
.isNotInstanceOf(TimeStamped.class);
|
||||
|
||||
long time = 666L;
|
||||
TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor();
|
||||
@@ -267,26 +271,26 @@ public class ProxyFactoryTests {
|
||||
int oldCount = config.getAdvisors().length;
|
||||
config.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class));
|
||||
|
||||
assertThat(config.getAdvisors().length == oldCount + 1).isTrue();
|
||||
assertThat(config.getAdvisors()).hasSize(oldCount + 1);
|
||||
|
||||
TimeStamped ts = (TimeStamped) config.getProxy();
|
||||
assertThat(ts.getTimeStamp() == time).isTrue();
|
||||
assertThat(ts.getTimeStamp()).isEqualTo(time);
|
||||
|
||||
// Can remove
|
||||
config.removeAdvice(ti);
|
||||
|
||||
assertThat(config.getAdvisors().length == oldCount).isTrue();
|
||||
assertThat(config.getAdvisors()).hasSize(oldCount);
|
||||
|
||||
assertThatRuntimeException()
|
||||
.as("Existing object won't implement this interface any more")
|
||||
.isThrownBy(ts::getTimeStamp); // Existing reference will fail
|
||||
|
||||
assertThat(config.getProxy() instanceof TimeStamped).as("Should no longer implement TimeStamped").isFalse();
|
||||
assertThat(config.getProxy()).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().length == oldCount).isTrue();
|
||||
assertThat(config.getAdvisors()).hasSize(oldCount);
|
||||
|
||||
ITestBean it = (ITestBean) ts;
|
||||
DebugInterceptor debugInterceptor = new DebugInterceptor();
|
||||
@@ -296,7 +300,7 @@ public class ProxyFactoryTests {
|
||||
config.removeAdvice(debugInterceptor);
|
||||
it.getSpouse();
|
||||
// not invoked again
|
||||
assertThat(debugInterceptor.getCount() == 1).isTrue();
|
||||
assertThat(debugInterceptor.getCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -305,13 +309,13 @@ public class ProxyFactoryTests {
|
||||
pf.setTargetClass(ITestBean.class);
|
||||
Object proxy = pf.getProxy();
|
||||
assertThat(AopUtils.isJdkDynamicProxy(proxy)).as("Proxy is a JDK proxy").isTrue();
|
||||
assertThat(proxy instanceof ITestBean).isTrue();
|
||||
assertThat(proxy).isInstanceOf(ITestBean.class);
|
||||
assertThat(AopProxyUtils.ultimateTargetClass(proxy)).isEqualTo(ITestBean.class);
|
||||
|
||||
ProxyFactory pf2 = new ProxyFactory(proxy);
|
||||
Object proxy2 = pf2.getProxy();
|
||||
assertThat(AopUtils.isJdkDynamicProxy(proxy2)).as("Proxy is a JDK proxy").isTrue();
|
||||
assertThat(proxy2 instanceof ITestBean).isTrue();
|
||||
assertThat(proxy2).isInstanceOf(ITestBean.class);
|
||||
assertThat(AopProxyUtils.ultimateTargetClass(proxy2)).isEqualTo(ITestBean.class);
|
||||
}
|
||||
|
||||
@@ -321,14 +325,14 @@ public class ProxyFactoryTests {
|
||||
pf.setTargetClass(TestBean.class);
|
||||
Object proxy = pf.getProxy();
|
||||
assertThat(AopUtils.isCglibProxy(proxy)).as("Proxy is a CGLIB proxy").isTrue();
|
||||
assertThat(proxy instanceof TestBean).isTrue();
|
||||
assertThat(proxy).isInstanceOf(TestBean.class);
|
||||
assertThat(AopProxyUtils.ultimateTargetClass(proxy)).isEqualTo(TestBean.class);
|
||||
|
||||
ProxyFactory pf2 = new ProxyFactory(proxy);
|
||||
pf2.setProxyTargetClass(true);
|
||||
Object proxy2 = pf2.getProxy();
|
||||
assertThat(AopUtils.isCglibProxy(proxy2)).as("Proxy is a CGLIB proxy").isTrue();
|
||||
assertThat(proxy2 instanceof TestBean).isTrue();
|
||||
assertThat(proxy2).isInstanceOf(TestBean.class);
|
||||
assertThat(AopProxyUtils.ultimateTargetClass(proxy2)).isEqualTo(TestBean.class);
|
||||
}
|
||||
|
||||
@@ -338,8 +342,8 @@ public class ProxyFactoryTests {
|
||||
JFrame frame = new JFrame();
|
||||
ProxyFactory proxyFactory = new ProxyFactory(frame);
|
||||
Object proxy = proxyFactory.getProxy();
|
||||
assertThat(proxy instanceof RootPaneContainer).isTrue();
|
||||
assertThat(proxy instanceof Accessible).isTrue();
|
||||
assertThat(proxy).isInstanceOf(RootPaneContainer.class);
|
||||
assertThat(proxy).isInstanceOf(Accessible.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -380,6 +384,40 @@ public class ProxyFactoryTests {
|
||||
assertThat(proxy.getName()).isEqualTo("tb");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCharSequenceProxy() {
|
||||
CharSequence target = "test";
|
||||
ProxyFactory pf = new ProxyFactory(target);
|
||||
ClassLoader cl = target.getClass().getClassLoader();
|
||||
assertThat(((CharSequence) pf.getProxy(cl)).toString()).isEqualTo(target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateProxy() {
|
||||
Date target = new Date();
|
||||
ProxyFactory pf = new ProxyFactory(target);
|
||||
pf.setProxyTargetClass(true);
|
||||
ClassLoader cl = target.getClass().getClassLoader();
|
||||
assertThat(((Date) pf.getProxy(cl)).getTime()).isEqualTo(target.getTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJdbcSavepointProxy() throws SQLException {
|
||||
Savepoint target = new Savepoint() {
|
||||
@Override
|
||||
public int getSavepointId() throws SQLException {
|
||||
return 1;
|
||||
}
|
||||
@Override
|
||||
public String getSavepointName() throws SQLException {
|
||||
return "sp";
|
||||
}
|
||||
};
|
||||
ProxyFactory pf = new ProxyFactory(target);
|
||||
ClassLoader cl = Savepoint.class.getClassLoader();
|
||||
assertThat(((Savepoint) pf.getProxy(cl)).getSavepointName()).isEqualTo("sp");
|
||||
}
|
||||
|
||||
|
||||
@Order(2)
|
||||
public static class A implements Runnable {
|
||||
@@ -391,7 +429,7 @@ public class ProxyFactoryTests {
|
||||
|
||||
|
||||
@Order(1)
|
||||
public static class B implements Runnable{
|
||||
public static class B implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -26,7 +26,7 @@ class InvocationCheckExposedInvocationTestBean extends ExposedInvocationTestBean
|
||||
|
||||
@Override
|
||||
protected void assertions(MethodInvocation invocation) {
|
||||
assertThat(invocation.getThis() == this).isTrue();
|
||||
assertThat(invocation.getThis()).isSameAs(this);
|
||||
assertThat(ITestBean.class.isAssignableFrom(invocation.getMethod().getDeclaringClass())).as("Invocation should be on ITestBean: " + invocation.getMethod()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -128,7 +128,7 @@ class ScopedProxyBeanRegistrationAotProcessorTests {
|
||||
this.beanFactory.registerBeanDefinition("test", scopedBean);
|
||||
compile((freshBeanFactory, compiled) -> {
|
||||
Object bean = freshBeanFactory.getBean("test");
|
||||
assertThat(bean).isNotNull().isInstanceOf(NumberHolder.class).isInstanceOf(AopInfrastructureBean.class);
|
||||
assertThat(bean).isInstanceOf(NumberHolder.class).isInstanceOf(AopInfrastructureBean.class);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -142,7 +142,7 @@ public class ComposablePointcutTests {
|
||||
pc1.intersection(GETTER_METHOD_MATCHER);
|
||||
|
||||
assertThat(pc1.equals(pc2)).isFalse();
|
||||
assertThat(pc1.hashCode() == pc2.hashCode()).isFalse();
|
||||
assertThat(pc1.hashCode()).isNotEqualTo(pc2.hashCode());
|
||||
|
||||
pc2.intersection(GETTER_METHOD_MATCHER);
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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,7 +97,7 @@ public class ControlFlowPointcutTests {
|
||||
assertThat(new ControlFlowPointcut(One.class, "getAge").equals(new ControlFlowPointcut(One.class))).isFalse();
|
||||
assertThat(new ControlFlowPointcut(One.class).hashCode()).isEqualTo(new ControlFlowPointcut(One.class).hashCode());
|
||||
assertThat(new ControlFlowPointcut(One.class, "getAge").hashCode()).isEqualTo(new ControlFlowPointcut(One.class, "getAge").hashCode());
|
||||
assertThat(new ControlFlowPointcut(One.class, "getAge").hashCode() == new ControlFlowPointcut(One.class).hashCode()).isFalse();
|
||||
assertThat(new ControlFlowPointcut(One.class, "getAge").hashCode()).isNotEqualTo(new ControlFlowPointcut(One.class).hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+14
-14
@@ -56,7 +56,7 @@ class DelegatingIntroductionInterceptorTests {
|
||||
@Test
|
||||
void testIntroductionInterceptorWithDelegation() throws Exception {
|
||||
TestBean raw = new TestBean();
|
||||
assertThat(! (raw instanceof TimeStamped)).isTrue();
|
||||
assertThat(raw).isNotInstanceOf(TimeStamped.class);
|
||||
ProxyFactory factory = new ProxyFactory(raw);
|
||||
|
||||
TimeStamped ts = mock();
|
||||
@@ -66,13 +66,13 @@ class DelegatingIntroductionInterceptorTests {
|
||||
factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts)));
|
||||
|
||||
TimeStamped tsp = (TimeStamped) factory.getProxy();
|
||||
assertThat(tsp.getTimeStamp() == timestamp).isTrue();
|
||||
assertThat(tsp.getTimeStamp()).isEqualTo(timestamp);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIntroductionInterceptorWithInterfaceHierarchy() throws Exception {
|
||||
TestBean raw = new TestBean();
|
||||
assertThat(! (raw instanceof SubTimeStamped)).isTrue();
|
||||
assertThat(raw).isNotInstanceOf(SubTimeStamped.class);
|
||||
ProxyFactory factory = new ProxyFactory(raw);
|
||||
|
||||
SubTimeStamped ts = mock();
|
||||
@@ -82,13 +82,13 @@ class DelegatingIntroductionInterceptorTests {
|
||||
factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts), SubTimeStamped.class));
|
||||
|
||||
SubTimeStamped tsp = (SubTimeStamped) factory.getProxy();
|
||||
assertThat(tsp.getTimeStamp() == timestamp).isTrue();
|
||||
assertThat(tsp.getTimeStamp()).isEqualTo(timestamp);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIntroductionInterceptorWithSuperInterface() throws Exception {
|
||||
TestBean raw = new TestBean();
|
||||
assertThat(! (raw instanceof TimeStamped)).isTrue();
|
||||
assertThat(raw).isNotInstanceOf(TimeStamped.class);
|
||||
ProxyFactory factory = new ProxyFactory(raw);
|
||||
|
||||
SubTimeStamped ts = mock();
|
||||
@@ -98,8 +98,8 @@ class DelegatingIntroductionInterceptorTests {
|
||||
factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts), TimeStamped.class));
|
||||
|
||||
TimeStamped tsp = (TimeStamped) factory.getProxy();
|
||||
assertThat(!(tsp instanceof SubTimeStamped)).isTrue();
|
||||
assertThat(tsp.getTimeStamp() == timestamp).isTrue();
|
||||
assertThat(tsp).isNotInstanceOf(SubTimeStamped.class);
|
||||
assertThat(tsp.getTimeStamp()).isEqualTo(timestamp);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -125,7 +125,7 @@ class DelegatingIntroductionInterceptorTests {
|
||||
//assertTrue(Arrays.binarySearch(pf.getProxiedInterfaces(), TimeStamped.class) != -1);
|
||||
TimeStamped ts = (TimeStamped) pf.getProxy();
|
||||
|
||||
assertThat(ts.getTimeStamp() == t).isTrue();
|
||||
assertThat(ts.getTimeStamp()).isEqualTo(t);
|
||||
((ITester) ts).foo();
|
||||
|
||||
((ITestBean) ts).getAge();
|
||||
@@ -160,10 +160,10 @@ class DelegatingIntroductionInterceptorTests {
|
||||
|
||||
assertThat(ts).isInstanceOf(TimeStamped.class);
|
||||
// Shouldn't proxy framework interfaces
|
||||
assertThat(!(ts instanceof MethodInterceptor)).isTrue();
|
||||
assertThat(!(ts instanceof IntroductionInterceptor)).isTrue();
|
||||
assertThat(ts).isNotInstanceOf(MethodInterceptor.class);
|
||||
assertThat(ts).isNotInstanceOf(IntroductionInterceptor.class);
|
||||
|
||||
assertThat(ts.getTimeStamp() == t).isTrue();
|
||||
assertThat(ts.getTimeStamp()).isEqualTo(t);
|
||||
((ITester) ts).foo();
|
||||
((ITestBean) ts).getAge();
|
||||
|
||||
@@ -174,14 +174,14 @@ class DelegatingIntroductionInterceptorTests {
|
||||
pf = new ProxyFactory(target);
|
||||
pf.addAdvisor(0, new DefaultIntroductionAdvisor(ii));
|
||||
Object o = pf.getProxy();
|
||||
assertThat(!(o instanceof TimeStamped)).isTrue();
|
||||
assertThat(o).isNotInstanceOf(TimeStamped.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@Test
|
||||
void testIntroductionInterceptorDoesntReplaceToString() throws Exception {
|
||||
TestBean raw = new TestBean();
|
||||
assertThat(! (raw instanceof TimeStamped)).isTrue();
|
||||
assertThat(raw).isNotInstanceOf(TimeStamped.class);
|
||||
ProxyFactory factory = new ProxyFactory(raw);
|
||||
|
||||
TimeStamped ts = new SerializableTimeStamped(0);
|
||||
@@ -266,7 +266,7 @@ class DelegatingIntroductionInterceptorTests {
|
||||
|
||||
TimeStamped ts = (TimeStamped) pf.getProxy();
|
||||
// From introduction interceptor, not target
|
||||
assertThat(ts.getTimeStamp() == t).isTrue();
|
||||
assertThat(ts.getTimeStamp()).isEqualTo(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -129,7 +129,7 @@ public class NameMatchMethodPointcutTests {
|
||||
|
||||
pc1.setMappedName(foo);
|
||||
assertThat(pc1.equals(pc2)).isFalse();
|
||||
assertThat(pc1.hashCode() != pc2.hashCode()).isTrue();
|
||||
assertThat(pc1.hashCode()).isNotEqualTo(pc2.hashCode());
|
||||
|
||||
pc2.setMappedName(foo);
|
||||
assertThat(pc2).isEqualTo(pc1);
|
||||
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -21,6 +21,8 @@ import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Abstract superclass for counting advices etc.
|
||||
*
|
||||
@@ -59,7 +61,7 @@ public class MethodCounter implements Serializable {
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
public boolean equals(@Nullable Object other) {
|
||||
return (other != null && other.getClass() == this.getClass());
|
||||
}
|
||||
|
||||
|
||||
+9
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -19,6 +19,8 @@ package org.springframework.aop.testfixture.interceptor;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Trivial interceptor that can be introduced in a chain to display it.
|
||||
*
|
||||
@@ -45,14 +47,14 @@ public class NopInterceptor implements MethodInterceptor {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof NopInterceptor)) {
|
||||
return false;
|
||||
}
|
||||
if (this == other) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
return this.count == ((NopInterceptor) other).count;
|
||||
if (!(obj instanceof NopInterceptor that)) {
|
||||
return false;
|
||||
}
|
||||
return this.count == that.count;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* Support for an HTTP service proxy created from an interface declaration.
|
||||
* AspectJ-based dependency injection support.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.web.reactive.service;
|
||||
package org.springframework.beans.factory.aspectj;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 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.cache.aspectj;
|
||||
|
||||
/**
|
||||
* Utility to trick the compiler to throw a valid checked
|
||||
* exceptions within the interceptor.
|
||||
* Utility to trick the compiler to throw valid checked exceptions masked as
|
||||
* runtime exceptions within the interceptor.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@@ -36,4 +36,5 @@ final class AnyThrow {
|
||||
private static <E extends Throwable> void throwAny(Throwable e) throws E {
|
||||
throw (E) e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* AspectJ-based caching support.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.cache.aspectj;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* AspectJ-based dependency injection support driven by the
|
||||
* {@link org.springframework.beans.factory.annotation.Configurable @Configurable}
|
||||
* annotation.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.context.annotation.aspectj;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* AspectJ-based scheduling support.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.scheduling.aspectj;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* AspectJ-based transaction management support.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
Vendored
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -543,7 +543,7 @@ public abstract class AbstractCacheAnnotationTests {
|
||||
Object r1 = service.multiConditionalCacheAndEvict(key);
|
||||
Object r3 = service.multiConditionalCacheAndEvict(key);
|
||||
|
||||
assertThat(!r1.equals(r3)).isTrue();
|
||||
assertThat(r1.equals(r3)).isFalse();
|
||||
assertThat(primary.get(key)).isNull();
|
||||
|
||||
Object key2 = 3;
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -92,7 +92,7 @@ public class AspectJEnableCachingIsolatedTests {
|
||||
load(MultiCacheManagerConfig.class);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertThat(ex.getMessage().contains("bean of type CacheManager")).isTrue();
|
||||
assertThat(ex.getMessage()).contains("bean of type CacheManager");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ public class AspectJEnableCachingIsolatedTests {
|
||||
load(MultiCacheManagerConfigurer.class, EnableCachingConfig.class);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertThat(ex.getMessage().contains("implementations of CachingConfigurer")).isTrue();
|
||||
assertThat(ex.getMessage()).contains("implementations of CachingConfigurer");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public class AspectJEnableCachingIsolatedTests {
|
||||
load(EmptyConfig.class);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertThat(ex.getMessage().contains("no bean of type CacheManager")).isTrue();
|
||||
assertThat(ex.getMessage()).contains("no bean of type CacheManager");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.cache.config;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -45,16 +46,11 @@ public class TestEntity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj instanceof TestEntity) {
|
||||
return ObjectUtils.nullSafeEquals(this.id, ((TestEntity) obj).id);
|
||||
}
|
||||
return false;
|
||||
return (obj instanceof TestEntity that && ObjectUtils.nullSafeEquals(this.id, that.id));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -29,6 +29,7 @@ import java.time.temporal.Temporal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -246,7 +247,8 @@ public abstract class BeanUtils {
|
||||
// A single public constructor
|
||||
return (Constructor<T>) ctors[0];
|
||||
}
|
||||
else if (ctors.length == 0){
|
||||
else if (ctors.length == 0) {
|
||||
// No public constructors -> check non-public
|
||||
ctors = clazz.getDeclaredConstructors();
|
||||
if (ctors.length == 1) {
|
||||
// A single non-public constructor, e.g. from a non-public record type
|
||||
@@ -790,11 +792,11 @@ public abstract class BeanUtils {
|
||||
actualEditable = editable;
|
||||
}
|
||||
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
|
||||
List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);
|
||||
Set<String> ignoredProps = (ignoreProperties != null ? new HashSet<>(Arrays.asList(ignoreProperties)) : null);
|
||||
|
||||
for (PropertyDescriptor targetPd : targetPds) {
|
||||
Method writeMethod = targetPd.getWriteMethod();
|
||||
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
|
||||
if (writeMethod != null && (ignoredProps == null || !ignoredProps.contains(targetPd.getName()))) {
|
||||
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
|
||||
if (sourcePd != null) {
|
||||
Method readMethod = sourcePd.getReadMethod();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -88,8 +88,9 @@ abstract class PropertyDescriptorUtils {
|
||||
BasicPropertyDescriptor pd = pdMap.get(propertyName);
|
||||
if (pd != null) {
|
||||
if (setter) {
|
||||
if (pd.getWriteMethod() == null ||
|
||||
pd.getWriteMethod().getParameterTypes()[0].isAssignableFrom(method.getParameterTypes()[0])) {
|
||||
Method writeMethod = pd.getWriteMethod();
|
||||
if (writeMethod == null ||
|
||||
writeMethod.getParameterTypes()[0].isAssignableFrom(method.getParameterTypes()[0])) {
|
||||
pd.setWriteMethod(method);
|
||||
}
|
||||
else {
|
||||
@@ -97,8 +98,9 @@ abstract class PropertyDescriptorUtils {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (pd.getReadMethod() == null ||
|
||||
(pd.getReadMethod().getReturnType() == method.getReturnType() && method.getName().startsWith("is"))) {
|
||||
Method readMethod = pd.getReadMethod();
|
||||
if (readMethod == null ||
|
||||
(readMethod.getReturnType() == method.getReturnType() && method.getName().startsWith("is"))) {
|
||||
pd.setReadMethod(method);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -280,6 +280,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
|
||||
Class<?> beanClass = registeredBean.getBeanClass();
|
||||
String beanName = registeredBean.getBeanName();
|
||||
@@ -323,10 +324,10 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
||||
checkLookupMethods(beanClass, beanName);
|
||||
|
||||
// Pick up subclass with fresh lookup method override from above
|
||||
if (this.beanFactory instanceof AbstractAutowireCapableBeanFactory aacbf) {
|
||||
if (this.beanFactory instanceof AbstractAutowireCapableBeanFactory aacBeanFactory) {
|
||||
RootBeanDefinition mbd = (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition(beanName);
|
||||
if (mbd.getFactoryMethodName() == null && mbd.hasBeanClass()) {
|
||||
return aacbf.getInstantiationStrategy().getActualBeanClass(mbd, beanName, this.beanFactory);
|
||||
return aacBeanFactory.getInstantiationStrategy().getActualBeanClass(mbd, beanName, aacBeanFactory);
|
||||
}
|
||||
}
|
||||
return beanClass;
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -157,6 +157,7 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
|
||||
RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition();
|
||||
beanDefinition.resolveDestroyMethodIfNecessary();
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -20,6 +20,7 @@ import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -31,7 +32,7 @@ import org.springframework.util.ClassUtils;
|
||||
class JakartaAnnotationsRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
if (ClassUtils.isPresent("jakarta.inject.Inject", classLoader)) {
|
||||
Stream.of("jakarta.inject.Inject", "jakarta.inject.Qualifier").forEach(annotationType ->
|
||||
hints.reflection().registerType(ClassUtils.resolveClassName(annotationType, classLoader)));
|
||||
|
||||
+4
-2
@@ -25,6 +25,7 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.beans.SimpleTypeConverter;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
@@ -240,10 +241,11 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
||||
}
|
||||
}
|
||||
if (targetAnnotation == null) {
|
||||
BeanFactory beanFactory = getBeanFactory();
|
||||
// Look for matching annotation on the target class
|
||||
if (getBeanFactory() != null) {
|
||||
if (beanFactory != null) {
|
||||
try {
|
||||
Class<?> beanType = getBeanFactory().getType(bdHolder.getBeanName());
|
||||
Class<?> beanType = beanFactory.getType(bdHolder.getBeanName());
|
||||
if (beanType != null) {
|
||||
targetAnnotation = AnnotationUtils.getAnnotation(ClassUtils.getUserClass(beanType), type);
|
||||
}
|
||||
|
||||
+3
-3
@@ -138,7 +138,7 @@ class BeanDefinitionMethodGenerator {
|
||||
ClassName topLevelClassName = target.topLevelClassName();
|
||||
GeneratedClass generatedClass = generationContext.getGeneratedClasses()
|
||||
.getOrAddForFeatureComponent("BeanDefinitions", topLevelClassName, type -> {
|
||||
type.addJavadoc("Bean definitions for {@link $T}", topLevelClassName);
|
||||
type.addJavadoc("Bean definitions for {@link $T}.", topLevelClassName);
|
||||
type.addModifiers(Modifier.PUBLIC);
|
||||
});
|
||||
|
||||
@@ -159,7 +159,7 @@ class BeanDefinitionMethodGenerator {
|
||||
|
||||
private static GeneratedClass createInnerClass(GeneratedClass generatedClass, String name, ClassName target) {
|
||||
return generatedClass.getOrAdd(name, type -> {
|
||||
type.addJavadoc("Bean definitions for {@link $T}", target);
|
||||
type.addJavadoc("Bean definitions for {@link $T}.", target);
|
||||
type.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
||||
});
|
||||
}
|
||||
@@ -186,7 +186,7 @@ class BeanDefinitionMethodGenerator {
|
||||
this.aotContributions.forEach(aotContribution -> aotContribution.applyTo(generationContext, codeGenerator));
|
||||
|
||||
return generatedMethods.add("getBeanDefinition", method -> {
|
||||
method.addJavadoc("Get the $L definition for '$L'",
|
||||
method.addJavadoc("Get the $L definition for '$L'.",
|
||||
(!this.registeredBean.isInnerBean()) ? "bean" : "inner-bean",
|
||||
getName());
|
||||
method.addModifiers(modifier, Modifier.STATIC);
|
||||
|
||||
+38
-57
@@ -27,9 +27,9 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.aot.hint.ExecutableMode;
|
||||
import org.springframework.beans.BeanInstantiationException;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.TypeConverter;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.InjectionPoint;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
@@ -97,11 +97,13 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
private BeanInstanceSupplier(ExecutableLookup lookup,
|
||||
@Nullable ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator,
|
||||
@Nullable String[] shortcuts) {
|
||||
|
||||
this.lookup = lookup;
|
||||
this.generator = generator;
|
||||
this.shortcuts = shortcuts;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@link BeanInstanceSupplier} that resolves
|
||||
* arguments for the specified bean constructor.
|
||||
@@ -109,9 +111,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
* @param parameterTypes the constructor parameter types
|
||||
* @return a new {@link BeanInstanceSupplier} instance
|
||||
*/
|
||||
public static <T> BeanInstanceSupplier<T> forConstructor(
|
||||
Class<?>... parameterTypes) {
|
||||
|
||||
public static <T> BeanInstanceSupplier<T> forConstructor(Class<?>... parameterTypes) {
|
||||
Assert.notNull(parameterTypes, "'parameterTypes' must not be null");
|
||||
Assert.noNullElements(parameterTypes, "'parameterTypes' must not contain null elements");
|
||||
return new BeanInstanceSupplier<>(new ConstructorLookup(parameterTypes), null, null);
|
||||
@@ -149,11 +149,11 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
* @param generator a {@link ThrowingBiFunction} that uses the
|
||||
* {@link RegisteredBean} and resolved {@link AutowiredArguments} to
|
||||
* instantiate the underlying bean
|
||||
* @return a new {@link BeanInstanceSupplier} instance with the specified
|
||||
* generator
|
||||
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
|
||||
*/
|
||||
public BeanInstanceSupplier<T> withGenerator(
|
||||
ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator) {
|
||||
|
||||
Assert.notNull(generator, "'generator' must not be null");
|
||||
return new BeanInstanceSupplier<>(this.lookup, generator, this.shortcuts);
|
||||
}
|
||||
@@ -163,11 +163,9 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
* {@code generator} function to instantiate the underlying bean.
|
||||
* @param generator a {@link ThrowingFunction} that uses the
|
||||
* {@link RegisteredBean} to instantiate the underlying bean
|
||||
* @return a new {@link BeanInstanceSupplier} instance with the specified
|
||||
* generator
|
||||
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
|
||||
*/
|
||||
public BeanInstanceSupplier<T> withGenerator(
|
||||
ThrowingFunction<RegisteredBean, T> generator) {
|
||||
public BeanInstanceSupplier<T> withGenerator(ThrowingFunction<RegisteredBean, T> generator) {
|
||||
Assert.notNull(generator, "'generator' must not be null");
|
||||
return new BeanInstanceSupplier<>(this.lookup,
|
||||
(registeredBean, args) -> generator.apply(registeredBean), this.shortcuts);
|
||||
@@ -176,10 +174,8 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
/**
|
||||
* Return a new {@link BeanInstanceSupplier} instance that uses the specified
|
||||
* {@code generator} supplier to instantiate the underlying bean.
|
||||
* @param generator a {@link ThrowingSupplier} to instantiate the underlying
|
||||
* bean
|
||||
* @return a new {@link BeanInstanceSupplier} instance with the specified
|
||||
* generator
|
||||
* @param generator a {@link ThrowingSupplier} to instantiate the underlying bean
|
||||
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
|
||||
*/
|
||||
public BeanInstanceSupplier<T> withGenerator(ThrowingSupplier<T> generator) {
|
||||
Assert.notNull(generator, "'generator' must not be null");
|
||||
@@ -282,8 +278,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
if (executable instanceof Method method) {
|
||||
return new MethodParameter(method, index);
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"Unsupported executable " + executable.getClass().getName());
|
||||
throw new IllegalStateException("Unsupported executable: " + executable.getClass().getName());
|
||||
}
|
||||
|
||||
private ConstructorArgumentValues resolveArgumentValues(
|
||||
@@ -303,9 +298,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
return resolved;
|
||||
}
|
||||
|
||||
private ValueHolder resolveArgumentValue(BeanDefinitionValueResolver resolver,
|
||||
ValueHolder valueHolder) {
|
||||
|
||||
private ValueHolder resolveArgumentValue(BeanDefinitionValueResolver resolver, ValueHolder valueHolder) {
|
||||
if (valueHolder.isConverted()) {
|
||||
return valueHolder;
|
||||
}
|
||||
@@ -331,8 +324,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
}
|
||||
try {
|
||||
try {
|
||||
return beanFactory.resolveDependency(dependencyDescriptor, beanName,
|
||||
autowiredBeans, typeConverter);
|
||||
return beanFactory.resolveDependency(dependencyDescriptor, beanName, autowiredBeans, typeConverter);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
if (parameterType.isArray()) {
|
||||
@@ -348,47 +340,45 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
}
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new UnsatisfiedDependencyException(null, beanName,
|
||||
new InjectionPoint(parameter), ex);
|
||||
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(parameter), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private T instantiate(ConfigurableBeanFactory beanFactory, Executable executable,
|
||||
Object[] arguments) {
|
||||
|
||||
try {
|
||||
if (executable instanceof Constructor<?> constructor) {
|
||||
return (T) instantiate(constructor, arguments);
|
||||
private T instantiate(ConfigurableBeanFactory beanFactory, Executable executable, Object[] args) {
|
||||
if (executable instanceof Constructor<?> constructor) {
|
||||
try {
|
||||
return (T) instantiate(constructor, args);
|
||||
}
|
||||
if (executable instanceof Method method) {
|
||||
return (T) instantiate(beanFactory, method, arguments);
|
||||
catch (Exception ex) {
|
||||
throw new BeanInstantiationException(constructor, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BeanCreationException(
|
||||
"Unable to instantiate bean using " + executable, ex);
|
||||
if (executable instanceof Method method) {
|
||||
try {
|
||||
return (T) instantiate(beanFactory, method, args);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BeanInstantiationException(method, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"Unsupported executable " + executable.getClass().getName());
|
||||
throw new IllegalStateException("Unsupported executable " + executable.getClass().getName());
|
||||
}
|
||||
|
||||
private Object instantiate(Constructor<?> constructor, Object[] arguments) throws Exception {
|
||||
private Object instantiate(Constructor<?> constructor, Object[] args) throws Exception {
|
||||
Class<?> declaringClass = constructor.getDeclaringClass();
|
||||
if (ClassUtils.isInnerClass(declaringClass)) {
|
||||
Object enclosingInstance = createInstance(declaringClass.getEnclosingClass());
|
||||
arguments = ObjectUtils.addObjectToArray(arguments, enclosingInstance, 0);
|
||||
args = ObjectUtils.addObjectToArray(args, enclosingInstance, 0);
|
||||
}
|
||||
ReflectionUtils.makeAccessible(constructor);
|
||||
return constructor.newInstance(arguments);
|
||||
return constructor.newInstance(args);
|
||||
}
|
||||
|
||||
private Object instantiate(ConfigurableBeanFactory beanFactory, Method method,
|
||||
Object[] arguments) {
|
||||
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
private Object instantiate(ConfigurableBeanFactory beanFactory, Method method, Object[] args) throws Exception {
|
||||
Object target = getFactoryMethodTarget(beanFactory, method);
|
||||
return ReflectionUtils.invokeMethod(method, target, arguments);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
return method.invoke(target, args);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -416,13 +406,13 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
return Arrays.stream(parameterTypes).map(Class::getName).collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs lookup of the {@link Executable}.
|
||||
*/
|
||||
static abstract class ExecutableLookup {
|
||||
|
||||
abstract Executable get(RegisteredBean registeredBean);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -433,12 +423,10 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
|
||||
private final Class<?>[] parameterTypes;
|
||||
|
||||
|
||||
ConstructorLookup(Class<?>[] parameterTypes) {
|
||||
this.parameterTypes = parameterTypes;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Executable get(RegisteredBean registeredBean) {
|
||||
Class<?> beanClass = registeredBean.getBeanClass();
|
||||
@@ -456,10 +444,8 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Constructor with parameter types [%s]".formatted(
|
||||
toCommaSeparatedNames(this.parameterTypes));
|
||||
return "Constructor with parameter types [%s]".formatted(toCommaSeparatedNames(this.parameterTypes));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -474,23 +460,19 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
|
||||
private final Class<?>[] parameterTypes;
|
||||
|
||||
|
||||
FactoryMethodLookup(Class<?> declaringClass, String methodName,
|
||||
Class<?>[] parameterTypes) {
|
||||
FactoryMethodLookup(Class<?> declaringClass, String methodName, Class<?>[] parameterTypes) {
|
||||
this.declaringClass = declaringClass;
|
||||
this.methodName = methodName;
|
||||
this.parameterTypes = parameterTypes;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Executable get(RegisteredBean registeredBean) {
|
||||
return get();
|
||||
}
|
||||
|
||||
Method get() {
|
||||
Method method = ReflectionUtils.findMethod(this.declaringClass,
|
||||
this.methodName, this.parameterTypes);
|
||||
Method method = ReflectionUtils.findMethod(this.declaringClass, this.methodName, this.parameterTypes);
|
||||
Assert.notNull(method, () -> "%s cannot be found".formatted(this));
|
||||
return method;
|
||||
}
|
||||
@@ -501,7 +483,6 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||
this.methodName, toCommaSeparatedNames(this.parameterTypes),
|
||||
this.declaringClass);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.aot;
|
||||
|
||||
/**
|
||||
* Record class holding key information for beans registered in a bean factory.
|
||||
*
|
||||
* @param beanName the name of the registered bean
|
||||
* @param beanClass the type of the registered bean
|
||||
* @author Brian Clozel
|
||||
* @since 6.0.8
|
||||
*/
|
||||
record BeanRegistrationKey(String beanName, Class<?> beanClass) {
|
||||
}
|
||||
+22
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -26,6 +26,8 @@ import org.springframework.aot.generate.GeneratedMethods;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.generate.MethodReference;
|
||||
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.javapoet.ClassName;
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
@@ -38,6 +40,7 @@ import org.springframework.javapoet.MethodSpec;
|
||||
* @author Phillip Webb
|
||||
* @author Sebastien Deleuze
|
||||
* @author Stephane Nicoll
|
||||
* @author Brian Clozel
|
||||
* @since 6.0
|
||||
* @see BeanRegistrationsAotProcessor
|
||||
*/
|
||||
@@ -46,9 +49,10 @@ class BeanRegistrationsAotContribution
|
||||
|
||||
private static final String BEAN_FACTORY_PARAMETER_NAME = "beanFactory";
|
||||
|
||||
private final Map<String, Registration> registrations;
|
||||
private final Map<BeanRegistrationKey, Registration> registrations;
|
||||
|
||||
BeanRegistrationsAotContribution(Map<String, Registration> registrations) {
|
||||
|
||||
BeanRegistrationsAotContribution(Map<BeanRegistrationKey, Registration> registrations) {
|
||||
this.registrations = registrations;
|
||||
}
|
||||
|
||||
@@ -69,26 +73,23 @@ class BeanRegistrationsAotContribution
|
||||
GeneratedMethod generatedAliasesMethod = codeGenerator.getMethods().add("registerAliases",
|
||||
this::generateRegisterAliasesMethod);
|
||||
beanFactoryInitializationCode.addInitializer(generatedAliasesMethod.toMethodReference());
|
||||
generateRegisterHints(generationContext.getRuntimeHints(), this.registrations);
|
||||
}
|
||||
|
||||
private void generateRegisterBeanDefinitionsMethod(MethodSpec.Builder method,
|
||||
GenerationContext generationContext,
|
||||
BeanRegistrationsCode beanRegistrationsCode) {
|
||||
GenerationContext generationContext, BeanRegistrationsCode beanRegistrationsCode) {
|
||||
|
||||
method.addJavadoc("Register the bean definitions.");
|
||||
method.addModifiers(Modifier.PUBLIC);
|
||||
method.addParameter(DefaultListableBeanFactory.class,
|
||||
BEAN_FACTORY_PARAMETER_NAME);
|
||||
method.addParameter(DefaultListableBeanFactory.class, BEAN_FACTORY_PARAMETER_NAME);
|
||||
CodeBlock.Builder code = CodeBlock.builder();
|
||||
this.registrations.forEach((beanName, registration) -> {
|
||||
this.registrations.forEach((registeredBean, registration) -> {
|
||||
MethodReference beanDefinitionMethod = registration.methodGenerator
|
||||
.generateBeanDefinitionMethod(generationContext,
|
||||
beanRegistrationsCode);
|
||||
.generateBeanDefinitionMethod(generationContext, beanRegistrationsCode);
|
||||
CodeBlock methodInvocation = beanDefinitionMethod.toInvokeCodeBlock(
|
||||
ArgumentCodeGenerator.none(), beanRegistrationsCode.getClassName());
|
||||
code.addStatement("$L.registerBeanDefinition($S, $L)",
|
||||
BEAN_FACTORY_PARAMETER_NAME, beanName,
|
||||
methodInvocation);
|
||||
BEAN_FACTORY_PARAMETER_NAME, registeredBean.beanName(), methodInvocation);
|
||||
});
|
||||
method.addCode(code.build());
|
||||
}
|
||||
@@ -96,18 +97,22 @@ class BeanRegistrationsAotContribution
|
||||
private void generateRegisterAliasesMethod(MethodSpec.Builder method) {
|
||||
method.addJavadoc("Register the aliases.");
|
||||
method.addModifiers(Modifier.PUBLIC);
|
||||
method.addParameter(DefaultListableBeanFactory.class,
|
||||
BEAN_FACTORY_PARAMETER_NAME);
|
||||
method.addParameter(DefaultListableBeanFactory.class, BEAN_FACTORY_PARAMETER_NAME);
|
||||
CodeBlock.Builder code = CodeBlock.builder();
|
||||
this.registrations.forEach((beanName, registration) -> {
|
||||
this.registrations.forEach((registeredBean, registration) -> {
|
||||
for (String alias : registration.aliases) {
|
||||
code.addStatement("$L.registerAlias($S, $S)",
|
||||
BEAN_FACTORY_PARAMETER_NAME, beanName, alias);
|
||||
code.addStatement("$L.registerAlias($S, $S)", BEAN_FACTORY_PARAMETER_NAME,
|
||||
registeredBean.beanName(), alias);
|
||||
}
|
||||
});
|
||||
method.addCode(code.build());
|
||||
}
|
||||
|
||||
private void generateRegisterHints(RuntimeHints runtimeHints, Map<BeanRegistrationKey, Registration> registrations) {
|
||||
registrations.keySet().forEach(beanRegistrationKey -> runtimeHints.reflection()
|
||||
.registerType(beanRegistrationKey.beanClass(), MemberCategory.INTROSPECT_DECLARED_METHODS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gather the necessary information to register a particular bean.
|
||||
* @param methodGenerator the {@link BeanDefinitionMethodGenerator} to use
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -31,6 +31,7 @@ import org.springframework.lang.Nullable;
|
||||
* @author Phillip Webb
|
||||
* @author Sebastien Deleuze
|
||||
* @author Stephane Nicoll
|
||||
* @author Brian Clozel
|
||||
* @since 6.0
|
||||
*/
|
||||
class BeanRegistrationsAotProcessor implements BeanFactoryInitializationAotProcessor {
|
||||
@@ -40,15 +41,15 @@ class BeanRegistrationsAotProcessor implements BeanFactoryInitializationAotProce
|
||||
public BeanRegistrationsAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {
|
||||
BeanDefinitionMethodGeneratorFactory beanDefinitionMethodGeneratorFactory =
|
||||
new BeanDefinitionMethodGeneratorFactory(beanFactory);
|
||||
Map<String, Registration> registrations = new LinkedHashMap<>();
|
||||
Map<BeanRegistrationKey, Registration> registrations = new LinkedHashMap<>();
|
||||
|
||||
for (String beanName : beanFactory.getBeanDefinitionNames()) {
|
||||
RegisteredBean registeredBean = RegisteredBean.of(beanFactory, beanName);
|
||||
BeanDefinitionMethodGenerator beanDefinitionMethodGenerator =
|
||||
beanDefinitionMethodGeneratorFactory.getBeanDefinitionMethodGenerator(registeredBean);
|
||||
if (beanDefinitionMethodGenerator != null) {
|
||||
registrations.put(beanName, new Registration(beanDefinitionMethodGenerator,
|
||||
beanFactory.getAliases(beanName)));
|
||||
registrations.put(new BeanRegistrationKey(beanName, registeredBean.getBeanClass()),
|
||||
new Registration(beanDefinitionMethodGenerator, beanFactory.getAliases(beanName)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
|
||||
+4
-4
@@ -130,10 +130,10 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
|
||||
* {@link BeanPostProcessor BeanPostProcessors}.
|
||||
* <p>Note: This is intended for creating a fresh instance, populating annotated
|
||||
* fields and methods as well as applying all standard bean initialization callbacks.
|
||||
* Constructor resolution is done via {@link #AUTOWIRE_CONSTRUCTOR}, also influenced
|
||||
* by {@link SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors}.
|
||||
* It does <i>not</i> imply traditional by-name or by-type autowiring of properties;
|
||||
* use {@link #createBean(Class, int, boolean)} for those purposes.
|
||||
* Constructor resolution is based on Kotlin primary / single public / single non-public,
|
||||
* with a fallback to the default constructor in ambiguous scenarios, also influenced
|
||||
* by {@link SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors}
|
||||
* (e.g. for annotation-driven constructor selection).
|
||||
* @param beanClass the class of the bean to create
|
||||
* @return the new bean instance
|
||||
* @throws BeansException if instantiation or wiring failed
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -188,7 +188,7 @@ public class ConstructorArgumentValues {
|
||||
* rather than matched multiple times.
|
||||
* @param value the argument value
|
||||
*/
|
||||
public void addGenericArgumentValue(Object value) {
|
||||
public void addGenericArgumentValue(@Nullable Object value) {
|
||||
this.genericArgumentValues.add(new ValueHolder(value));
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -53,6 +53,7 @@ import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||
import org.springframework.core.io.DescriptiveResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.EncodedResource;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -149,8 +150,10 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
|
||||
private MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass());
|
||||
|
||||
@Nullable
|
||||
private Binding binding;
|
||||
|
||||
@Nullable
|
||||
private GroovyBeanDefinitionWrapper currentBeanDefinition;
|
||||
|
||||
|
||||
@@ -203,6 +206,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
|
||||
/**
|
||||
* Return a specified binding for Groovy variables, if any.
|
||||
*/
|
||||
@Nullable
|
||||
public Binding getBinding() {
|
||||
return this.binding;
|
||||
}
|
||||
|
||||
+28
-30
@@ -16,9 +16,9 @@
|
||||
|
||||
package org.springframework.beans.factory.groovy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import groovy.lang.GroovyObjectSupport;
|
||||
|
||||
@@ -30,6 +30,8 @@ import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
@@ -51,58 +53,54 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||
private static final String DESTROY_METHOD = "destroyMethod";
|
||||
private static final String SINGLETON = "singleton";
|
||||
|
||||
private static final List<String> dynamicProperties = new ArrayList<>(8);
|
||||
|
||||
static {
|
||||
dynamicProperties.add(PARENT);
|
||||
dynamicProperties.add(AUTOWIRE);
|
||||
dynamicProperties.add(CONSTRUCTOR_ARGS);
|
||||
dynamicProperties.add(FACTORY_BEAN);
|
||||
dynamicProperties.add(FACTORY_METHOD);
|
||||
dynamicProperties.add(INIT_METHOD);
|
||||
dynamicProperties.add(DESTROY_METHOD);
|
||||
dynamicProperties.add(SINGLETON);
|
||||
}
|
||||
private static final Set<String> dynamicProperties = Set.of(PARENT, AUTOWIRE, CONSTRUCTOR_ARGS,
|
||||
FACTORY_BEAN, FACTORY_METHOD, INIT_METHOD, DESTROY_METHOD, SINGLETON);
|
||||
|
||||
|
||||
@Nullable
|
||||
private String beanName;
|
||||
|
||||
private Class<?> clazz;
|
||||
@Nullable
|
||||
private final Class<?> clazz;
|
||||
|
||||
private Collection<?> constructorArgs;
|
||||
@Nullable
|
||||
private final Collection<?> constructorArgs;
|
||||
|
||||
@Nullable
|
||||
private AbstractBeanDefinition definition;
|
||||
|
||||
@Nullable
|
||||
private BeanWrapper definitionWrapper;
|
||||
|
||||
@Nullable
|
||||
private String parentName;
|
||||
|
||||
|
||||
public GroovyBeanDefinitionWrapper(String beanName) {
|
||||
this.beanName = beanName;
|
||||
GroovyBeanDefinitionWrapper(String beanName) {
|
||||
this(beanName, null);
|
||||
}
|
||||
|
||||
public GroovyBeanDefinitionWrapper(String beanName, Class<?> clazz) {
|
||||
this.beanName = beanName;
|
||||
this.clazz = clazz;
|
||||
GroovyBeanDefinitionWrapper(@Nullable String beanName, @Nullable Class<?> clazz) {
|
||||
this(beanName, clazz, null);
|
||||
}
|
||||
|
||||
public GroovyBeanDefinitionWrapper(String beanName, Class<?> clazz, Collection<?> constructorArgs) {
|
||||
GroovyBeanDefinitionWrapper(@Nullable String beanName, Class<?> clazz, @Nullable Collection<?> constructorArgs) {
|
||||
this.beanName = beanName;
|
||||
this.clazz = clazz;
|
||||
this.constructorArgs = constructorArgs;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public String getBeanName() {
|
||||
return this.beanName;
|
||||
}
|
||||
|
||||
public void setBeanDefinition(AbstractBeanDefinition definition) {
|
||||
void setBeanDefinition(AbstractBeanDefinition definition) {
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
public AbstractBeanDefinition getBeanDefinition() {
|
||||
AbstractBeanDefinition getBeanDefinition() {
|
||||
if (this.definition == null) {
|
||||
this.definition = createBeanDefinition();
|
||||
}
|
||||
@@ -126,19 +124,17 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||
return bd;
|
||||
}
|
||||
|
||||
public void setBeanDefinitionHolder(BeanDefinitionHolder holder) {
|
||||
void setBeanDefinitionHolder(BeanDefinitionHolder holder) {
|
||||
this.definition = (AbstractBeanDefinition) holder.getBeanDefinition();
|
||||
this.beanName = holder.getBeanName();
|
||||
}
|
||||
|
||||
public BeanDefinitionHolder getBeanDefinitionHolder() {
|
||||
BeanDefinitionHolder getBeanDefinitionHolder() {
|
||||
return new BeanDefinitionHolder(getBeanDefinition(), getBeanName());
|
||||
}
|
||||
|
||||
public void setParent(Object obj) {
|
||||
if (obj == null) {
|
||||
throw new IllegalArgumentException("Parent bean cannot be set to a null runtime bean reference!");
|
||||
}
|
||||
void setParent(Object obj) {
|
||||
Assert.notNull(obj, "Parent bean cannot be set to a null runtime bean reference.");
|
||||
if (obj instanceof String name) {
|
||||
this.parentName = name;
|
||||
}
|
||||
@@ -152,7 +148,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||
getBeanDefinition().setAbstract(false);
|
||||
}
|
||||
|
||||
public GroovyBeanDefinitionWrapper addProperty(String propertyName, Object propertyValue) {
|
||||
GroovyBeanDefinitionWrapper addProperty(String propertyName, Object propertyValue) {
|
||||
if (propertyValue instanceof GroovyBeanDefinitionWrapper wrapper) {
|
||||
propertyValue = wrapper.getBeanDefinition();
|
||||
}
|
||||
@@ -163,6 +159,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||
|
||||
@Override
|
||||
public Object getProperty(String property) {
|
||||
Assert.state(this.definitionWrapper != null, "BeanDefinition wrapper not initialized");
|
||||
if (this.definitionWrapper.isReadableProperty(property)) {
|
||||
return this.definitionWrapper.getPropertyValue(property);
|
||||
}
|
||||
@@ -179,6 +176,7 @@ class GroovyBeanDefinitionWrapper extends GroovyObjectSupport {
|
||||
}
|
||||
else {
|
||||
AbstractBeanDefinition bd = getBeanDefinition();
|
||||
Assert.state(this.definitionWrapper != null, "BeanDefinition wrapper not initialized");
|
||||
if (AUTOWIRE.equals(property)) {
|
||||
if ("byName".equals(newValue)) {
|
||||
bd.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user